Skip to content

Commit 42e85ae

Browse files
committed
market order with slippage params
1 parent 5b7d752 commit 42e85ae

3 files changed

Lines changed: 116 additions & 3 deletions

File tree

examples/create_market_order.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
logging.basicConfig(level=logging.DEBUG)
66

77
# The API_KEY_PRIVATE_KEY provided belongs to a dummy account registered on Testnet.
8-
# It was generated using the setup_system.py script, and servers as an example.
8+
# It was generated using the setup_system.py script, and serves as an example.
99
BASE_URL = "https://testnet.zklighter.elliot.ai"
1010
API_KEY_PRIVATE_KEY = "0xed636277f3753b6c0275f7a28c2678a7f3a95655e09deaebec15179b50c5da7f903152e50f594f7b"
1111
ACCOUNT_INDEX = 65
12-
API_KEY_INDEX = 1
12+
API_KEY_INDEX = 2
1313

1414

1515
def trim_exception(e: Exception) -> str:
@@ -28,7 +28,7 @@ async def main():
2828
market_index=0,
2929
client_order_index=0,
3030
base_amount=1000, # 0.1 ETH
31-
avg_execution_price=170000, # $1700
31+
avg_execution_price=170000, # $1700 -- worst acceptable price for the order
3232
is_ask=True,
3333
)
3434
print("Create Order Tx:", tx)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import asyncio
2+
import logging
3+
import lighter
4+
5+
logging.basicConfig(level=logging.DEBUG)
6+
7+
# The API_KEY_PRIVATE_KEY provided belongs to a dummy account registered on Testnet.
8+
# It was generated using the setup_system.py script, and serves as an example.
9+
BASE_URL = "https://testnet.zklighter.elliot.ai"
10+
API_KEY_PRIVATE_KEY = "0x321ec32c490960eb83df619e2701b5948e32da808fc0b6fd99550ce92af130f1c4088a37a0793972"
11+
ACCOUNT_INDEX = 46
12+
API_KEY_INDEX = 2
13+
14+
15+
def trim_exception(e: Exception) -> str:
16+
return str(e).strip().split("\n")[-1]
17+
18+
19+
async def main():
20+
client = lighter.SignerClient(
21+
url=BASE_URL,
22+
private_key=API_KEY_PRIVATE_KEY,
23+
account_index=ACCOUNT_INDEX,
24+
api_key_index=API_KEY_INDEX,
25+
)
26+
27+
# tx = await client.create_market_order_limited_slippage(market_index=0, client_order_index=0, base_amount=30000000,
28+
# max_slippage=0.001, is_ask=True)
29+
tx = await client.create_market_order_if_slippage(market_index=0, client_order_index=0, base_amount=30000000,
30+
max_slippage=0.01, is_ask=True)
31+
print("Create Order Tx:", tx)
32+
await client.close()
33+
34+
35+
if __name__ == "__main__":
36+
asyncio.run(main())

lighter/signer_client.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ def __init__(
190190
self.signer = _initialize_signer()
191191
self.api_client = lighter.ApiClient(configuration=Configuration(host=url))
192192
self.tx_api = lighter.TransactionApi(self.api_client)
193+
self.order_api = lighter.OrderApi(self.api_client)
193194
self.nonce_manager = nonce_manager.nonce_manager_factory(
194195
nonce_manager_type=nonce_management_type,
195196
account_index=account_index,
@@ -618,6 +619,82 @@ async def create_market_order(
618619
api_key_index=api_key_index,
619620
)
620621

622+
# will only do the amount such that the slippage is limited to the value provided
623+
async def create_market_order_limited_slippage(
624+
self,
625+
market_index,
626+
client_order_index,
627+
base_amount,
628+
max_slippage,
629+
is_ask,
630+
reduce_only: bool = False,
631+
nonce=-1,
632+
api_key_index=-1,
633+
) -> (CreateOrder, TxHash, str):
634+
order_book_orders = await self.order_api.order_book_orders(market_index, 1)
635+
best_price = int((order_book_orders.bids[0].price if is_ask else order_book_orders.asks[0].price).replace(".", ""))
636+
acceptable_execution_price = round(best_price * (1 + max_slippage * (-1 if is_ask else 1)))
637+
return await self.create_order(
638+
market_index,
639+
client_order_index,
640+
base_amount,
641+
price=acceptable_execution_price,
642+
is_ask=is_ask,
643+
order_type=self.ORDER_TYPE_MARKET,
644+
time_in_force=self.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL,
645+
order_expiry=self.DEFAULT_IOC_EXPIRY,
646+
reduce_only=reduce_only,
647+
nonce=nonce,
648+
api_key_index=api_key_index,
649+
)
650+
651+
# will only execute the order if it executes with slippage <= max_slippage
652+
async def create_market_order_if_slippage(
653+
self,
654+
market_index,
655+
client_order_index,
656+
base_amount,
657+
max_slippage,
658+
is_ask,
659+
reduce_only: bool = False,
660+
nonce=-1,
661+
api_key_index=-1,
662+
) -> (CreateOrder, TxHash, str):
663+
order_book_orders = await self.order_api.order_book_orders(market_index, 100)
664+
best_price = int((order_book_orders.bids[0].price if is_ask else order_book_orders.asks[0].price).replace(".", ""))
665+
666+
matched_usd_amount, matched_size = 0, 0
667+
for order_book_order in (order_book_orders.bids if is_ask else order_book_orders.asks):
668+
if matched_size == base_amount:
669+
break
670+
curr_order_price = int(order_book_order.price.replace(".", ""))
671+
curr_order_size = int(order_book_order.remaining_base_amount.replace(".", ""))
672+
to_be_used_order_size = min(base_amount - matched_size, curr_order_size)
673+
matched_usd_amount += curr_order_price * to_be_used_order_size
674+
matched_size += to_be_used_order_size
675+
676+
potential_execution_price = matched_usd_amount / matched_size
677+
acceptable_execution_price = best_price * (1 + max_slippage * (-1 if is_ask else 1))
678+
if (is_ask and potential_execution_price < acceptable_execution_price) or (not is_ask and potential_execution_price > acceptable_execution_price):
679+
return None, None, "Excessive slippage"
680+
681+
if matched_size < base_amount:
682+
return None, None, "Cannot be sure slippage will be acceptable due to the high size"
683+
684+
return await self.create_order(
685+
market_index,
686+
client_order_index,
687+
base_amount,
688+
price=round(acceptable_execution_price),
689+
is_ask=is_ask,
690+
order_type=self.ORDER_TYPE_MARKET,
691+
time_in_force=self.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL,
692+
order_expiry=self.DEFAULT_IOC_EXPIRY,
693+
reduce_only=reduce_only,
694+
nonce=nonce,
695+
api_key_index=api_key_index,
696+
)
697+
621698
@process_api_key_and_nonce
622699
async def cancel_order(self, market_index, order_index, nonce=-1, api_key_index=-1) -> (CancelOrder, TxHash, str):
623700
tx_info, error = self.sign_cancel_order(market_index, order_index, nonce)

0 commit comments

Comments
 (0)