This tutorial relies on context established in Prerequisites and Setup .
Pick a Received RFQ
Get a list of received RFQs in open
status, evaluate them and pick one:
Copy open_rfqs = [r for r in client . get_rfqs_received (). result if r [ "rfq_status" ] == "open" ]
rfq = open_rfqs [ 0 ]
print (json. dumps (rfq, indent = 2 ))
Output
Copy {
"asks" : [] ,
"bids" : [] ,
"clearing_status" : null ,
"created_at" : "2024-04-18T19:13:48.405834Z" ,
"qty" : "10000" ,
"quotes_common_metadata" : {} ,
"rfq_expires_at" : "2024-04-18T20:13:48.390Z" ,
"rfq_id" : "38ce49bf-9be9-4fd8-bc9a-5a90529c931f" ,
"rfq_legs" : [
{
"instrument" : {
"funding_interval_s" : 3600 ,
"instrument_type" : "perpetual_future" ,
"settlement_asset" : "USDC" ,
"underlying" : "DOGE"
} ,
"qty" : "10000" ,
"rfq_id" : "38ce49bf-9be9-4fd8-bc9a-5a90529c931f" ,
"rfq_leg_id" : "b55b6240-c245-4de9-a077-39f0edd66b86" ,
"side" : "buy"
}
] ,
"rfq_status" : "open" ,
"structure" : {
"legs" : [
{
"instrument" : {
"funding_interval_s" : 3600 ,
"instrument_type" : "perpetual_future" ,
"settlement_asset" : "USDC" ,
"underlying" : "DOGE"
} ,
"ratio" : 1 ,
"side" : "buy"
}
]
} ,
"structure_price" : {
"delta" : "1" ,
"gamma" : "0" ,
"native_price" : "1" ,
"price" : "0.1499674821151633" ,
"rho" : "0" ,
"theta" : "0" ,
"timestamp" : "2024-04-18T19:14:09.870949585Z" ,
"vega" : "0"
} ,
"taker_company" : "f58b3d2f-b5a6-488d-b8a9-dc2b1f782be8"
}
Create a Quote
Copy from datetime import datetime , timezone , timedelta
from variational import PoolStrategyType , MarginMode
margin_params = {
"margin_mode" : MarginMode . SIMPLE ,
"params" : {
"liquidation_penalty" : "0.1" ,
"auto_liquidation" : True ,
"asset_params" : {},
"default_asset_param" : {
"futures_initial_margin" : "0.02" ,
"futures_maintenance_margin" : "0.01" ,
"futures_leverage" : "1000000000" ,
"option_initial_margin" : "0.15" ,
"option_initial_margin_min" : "0.1" ,
"option_maintenance_margin" : "0.075" ,
},
}
}
quote = client . create_quote (
rfq_id = rfq[ "rfq_id" ],
expires_at = (datetime. now (timezone.utc) + timedelta (hours = 1 )). isoformat (),
leg_quotes = [
{
"target_rfq_leg_id" : "b55b6240-c245-4de9-a077-39f0edd66b86" ,
"bid" : "0.148" ,
"ask" : None , # both "bid" and "ask" could be included
}
],
pool_strategy = {
"strategy" : PoolStrategyType.CREATE_NEW,
"name" : "Maker tutorial pool" ,
"creator_params" : margin_params,
"other_params" : margin_params,
}
). result
print (json. dumps (quote, indent = 2 ))
Output
Copy {
"aggregated_ask" : null ,
"aggregated_bid" : "0.148000000000" ,
"clearing_events" : [] ,
"clearing_status" : null ,
"client_quote_id" : null ,
"creator_params" : {
"margin_mode" : "simple" ,
"params" : {
"asset_params" : {} ,
"auto_liquidation" : true ,
"default_asset_param" : {
"futures_initial_margin" : "0.02" ,
"futures_leverage" : "1000000000" ,
"futures_maintenance_margin" : "0.01" ,
"option_initial_margin" : "0.15" ,
"option_initial_margin_min" : "0.1" ,
"option_maintenance_margin" : "0.075"
} ,
"liquidation_penalty" : "0.1"
}
} ,
"expires_at" : "2024-04-18T20:16:13.647117Z" ,
"maker_company" : "1ebc7ece-093e-42aa-8cdf-028ccb1fc68a" ,
"new_pool_name" : "Maker tutorial pool" ,
"other_params" : {
"margin_mode" : "simple" ,
"params" : {
"asset_params" : {} ,
"auto_liquidation" : true ,
"default_asset_param" : {
"futures_initial_margin" : "0.02" ,
"futures_leverage" : "1000000000" ,
"futures_maintenance_margin" : "0.01" ,
"option_initial_margin" : "0.15" ,
"option_initial_margin_min" : "0.1" ,
"option_maintenance_margin" : "0.075"
} ,
"liquidation_penalty" : "0.1"
}
} ,
"parent_quote_id" : "be295917-ac71-4417-bc4a-550de0fb4f3a" ,
"per_leg_quotes" : [
{
"ask" : null ,
"bid" : "0.148000000000" ,
"target_rfq_leg_id" : "b55b6240-c245-4de9-a077-39f0edd66b86"
}
] ,
"pool_location" : null ,
"target_rfq_id" : "38ce49bf-9be9-4fd8-bc9a-5a90529c931f"
}
Wait until Your Quote Is Accepted
Before you can take the next step, the creator of the RFQ needs to accept your quote and approve their deposit if needed. Then the quote clearing status will change to pending_maker_last_look
.
You can use the helper to wait for a single quote:
Copy from variational import ClearingStatus
long_poller = PollingHelper(client=client, interval=10, attempts=100)
quote = long_poller.wait_for_clearing_status(
parent_quote_id=quote["parent_quote_id"],
status=ClearingStatus.PENDING_MAKER_LAST_LOOK
)
Or check all outstanding quotes:
Copy accepted_quotes = list (
[q for q in paginate (client.get_quotes_sent)
if q[ "clearing_status" ] == ClearingStatus.PENDING_MAKER_LAST_LOOK])
Before your quote is accepted, you can update it by replacing it with a new one:
Copy quote = client . replace_quote (
rfq_id = rfq[ "rfq_id" ],
parent_quote_id = quote[ "parent_quote_id" ],
expires_at = (datetime. now (timezone.utc) + timedelta (hours = 1 )). isoformat (),
leg_quotes = [
{
"target_rfq_leg_id" : "b55b6240-c245-4de9-a077-39f0edd66b86" ,
"bid" : "0.147" ,
"ask" : None , # both "bid" and "ask" could be included
}
],
pool_strategy = {
"strategy" : PoolStrategyType.CREATE_NEW,
"name" : "Maker tutorial pool" ,
"creator_params" : margin_params,
"other_params" : margin_params,
}
). result
Perform a Last Look
When your quote is pending_maker_last_look
and is still looking good, approve it:
Copy from variational import RequestAction
last_look = client . maker_last_look (
rfq_id = rfq[ "rfq_id" ],
parent_quote_id = quote[ "parent_quote_id" ],
action = RequestAction.ACCEPT,
). result
print (json. dumps (last_look, indent = 2 ))
Output
Copy {
"new_clearing_status" : "pending_maker_deposit_approval" ,
"pending_deposits_sum_qty" : "9.519183" ,
"settlement_pool_address" : "0x24b044aa809712867f6332aa465a302705013b92"
}
Note that if new_clearing_status
is not pending_maker_deposit_approval
, it means that the deposit for this trade is covered by a previously issued approval or there is enough funds in the pool, so you can skip the next part.
Approve USDC Spending for the Deposit
If new_clearing_status
is pending_maker_deposit_approval
, you need to sign and submit a ERC-2612 spending approval for the deposit:
Copy permits . sign_and_submit_decimal (
pool_address = last_look[ 'settlement_pool_address' ],
allowance = last_look[ 'pending_deposits_sum_qty' ]
)
Wait for Clearing Status to Progress
At this point, the trade should automatically progress to the final state success_trades_booked_into_pool
, but it can take a few seconds.
Use the helper to wait for the trade to clear:
Copy quote = poller.wait_for_clearing_status(
parent_quote_id=quote["parent_quote_id"],
status=ClearingStatus.SUCCESS_TRADES_BOOKED_INTO_POOL,
)
Last updated 7 months ago