Skip to content

Commit c58758b

Browse files
Self trade (#157)
* self_trading * Fix self-trade bindings, restore linux signer libs, add examples - sign_create_order: drop bogus cancel_all_market_index arg and fix argument order (self_trade_behavior/equality before skip_nonce) - sign_cancel_all_orders: pass cancel_all_market_index through to the signer and default it to NIL_MARKET_INDEX (backward compatible) - sign_modify_order: pass self_trade_equality_mode (was duplicating self_trade_behavior_mode) - cancel_all_orders: default cancel_all_market_index to NIL_MARKET_INDEX - rebuild + restore linux amd64/arm64 signer libs from lighter-go self-trade branch (they were dropped on this branch) - wire darwin-amd64 dylib into the loader - add self-trade and single-market cancel-all examples Co-Authored-By: mihai <mihai2004marcu@gmail.com> * new signers * self crossing order example * rm signers --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 81b5cb3 commit c58758b

14 files changed

Lines changed: 408 additions & 28 deletions
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import asyncio
2+
from utils import default_example_setup
3+
4+
5+
# Scope a cancel-all to a single market.
6+
#
7+
# cancel_all_market_index:
8+
# NIL_MARKET_INDEX (255, default) - cancel resting orders across ALL markets
9+
# 0..254 - cancel resting orders only in that perp market
10+
#
11+
# Note: a non-nil market index is only valid for an immediate cancel-all
12+
# (TIME_IN_FORCE_IMMEDIATE_OR_CANCEL), not for a scheduled / dead-man's-switch one.
13+
async def main():
14+
client, api_client, _ = default_example_setup()
15+
client.check_client()
16+
17+
market_index = 0
18+
19+
# cancel all of our resting orders, but only in market 0 (immediate uses timestamp_ms=0)
20+
api_key_index, nonce = client.nonce_manager.next_nonce()
21+
tx, tx_hash, err = await client.cancel_all_orders(
22+
time_in_force=client.CANCEL_ALL_TIF_IMMEDIATE,
23+
timestamp_ms=0,
24+
cancel_all_market_index=market_index,
25+
nonce=nonce,
26+
api_key_index=api_key_index,
27+
)
28+
print(f"Cancel All (market {market_index}) {tx=} {tx_hash=} {err=}")
29+
if err is not None:
30+
raise Exception(err)
31+
32+
# for reference: omit cancel_all_market_index (defaults to all markets)
33+
api_key_index, nonce = client.nonce_manager.next_nonce(api_key_index)
34+
tx, tx_hash, err = await client.cancel_all_orders(
35+
time_in_force=client.CANCEL_ALL_TIF_IMMEDIATE,
36+
timestamp_ms=0,
37+
nonce=nonce,
38+
api_key_index=api_key_index,
39+
)
40+
print(f"Cancel All (all markets) {tx=} {tx_hash=} {err=}")
41+
if err is not None:
42+
raise Exception(err)
43+
44+
await client.close()
45+
await api_client.close()
46+
47+
48+
if __name__ == "__main__":
49+
asyncio.run(main())
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import asyncio
2+
import time
3+
from utils import default_example_setup
4+
5+
6+
# Self-trade prevention (STP) on order creation / modification.
7+
#
8+
# self_trade_behavior_mode: what happens when your incoming order would match
9+
# one of your own resting orders.
10+
# EXPIRE_MAKER (0, default) - cancel your resting (maker) order
11+
# EXPIRE_TAKER (1) - cancel the incoming (taker) order
12+
# EXPIRE_BOTH (2) - cancel both
13+
# REDUCE (3) - net the two against each other (no booked self-fill)
14+
#
15+
# self_trade_equality_mode: what counts as "yourself" for the check above.
16+
# ACCOUNT_INDEX (0, default) - only the exact same account
17+
# MASTER_ACCOUNT_INDEX (1) - any sub-account under the same master
18+
#
19+
# Notes:
20+
# * Defaults (EXPIRE_MAKER + ACCOUNT_INDEX) reproduce the previous behavior and
21+
# do not change the signed payload.
22+
# * REDUCE is not allowed together with MASTER_ACCOUNT_INDEX.
23+
# * Self-trade modes cannot be combined with integrator fees on the same tx.
24+
async def main():
25+
client, api_client, _ = default_example_setup()
26+
market_index = 156
27+
28+
try:
29+
client.check_client()
30+
31+
base_client_order_index = int(time.time() * 1000)
32+
resting_bid_order_index = base_client_order_index
33+
incoming_ask_order_index = base_client_order_index + 1
34+
35+
api_key_index, nonce = client.nonce_manager.next_nonce()
36+
tx, tx_hash, err = await client.create_order(
37+
market_index=market_index,
38+
client_order_index=resting_bid_order_index,
39+
base_amount=500,
40+
price=95_200,
41+
is_ask=False,
42+
order_type=client.ORDER_TYPE_LIMIT,
43+
time_in_force=client.ORDER_TIME_IN_FORCE_POST_ONLY,
44+
reduce_only=False,
45+
trigger_price=0,
46+
nonce=nonce,
47+
api_key_index=api_key_index,
48+
)
49+
print(f"Resting Bid {tx=} {tx_hash=} {err=}")
50+
if err is not None:
51+
raise Exception(err)
52+
53+
api_key_index, nonce = client.nonce_manager.next_nonce(api_key_index)
54+
tx, tx_hash, err = await client.create_order(
55+
market_index=market_index,
56+
client_order_index=incoming_ask_order_index,
57+
base_amount=500,
58+
price=95_200,
59+
is_ask=True,
60+
order_type=client.ORDER_TYPE_LIMIT,
61+
time_in_force=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
62+
reduce_only=False,
63+
trigger_price=0,
64+
self_trade_behavior_mode=client.SELF_TRADE_BEHAVIOR_EXPIRE_BOTH,
65+
self_trade_equality_mode=client.SELF_TRADE_EQUALITY_MASTER_ACCOUNT_INDEX,
66+
nonce=nonce,
67+
api_key_index=api_key_index,
68+
)
69+
print(f"Self-Cross Create {tx=} {tx_hash=} {err=}")
70+
if err is not None:
71+
raise Exception(err)
72+
finally:
73+
await client.close()
74+
await api_client.close()
75+
76+
77+
if __name__ == "__main__":
78+
asyncio.run(main())
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import asyncio
2+
from lighter.signer_client import CreateOrderTxReq
3+
from utils import default_example_setup
4+
5+
6+
# Self-trade prevention applied to a grouped (OTOCO) order.
7+
#
8+
# For grouped orders the self-trade modes are specified once at the group level
9+
# (a single value for the whole batch), matching the underlying signer.
10+
async def main():
11+
client, api_client, _ = default_example_setup()
12+
client.check_client()
13+
14+
ioc_order = CreateOrderTxReq(
15+
MarketIndex=0,
16+
ClientOrderIndex=0,
17+
BaseAmount=1000, # 0.1 ETH
18+
Price=2500_00, # $2500
19+
IsAsk=1, # sell
20+
Type=client.ORDER_TYPE_LIMIT,
21+
TimeInForce=client.ORDER_TIME_IN_FORCE_IMMEDIATE_OR_CANCEL,
22+
ReduceOnly=0,
23+
TriggerPrice=0,
24+
OrderExpiry=0,
25+
)
26+
27+
take_profit_order = CreateOrderTxReq(
28+
MarketIndex=0,
29+
ClientOrderIndex=0,
30+
BaseAmount=0,
31+
Price=1550_00,
32+
IsAsk=0,
33+
Type=client.ORDER_TYPE_TAKE_PROFIT_LIMIT,
34+
TimeInForce=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
35+
ReduceOnly=1,
36+
TriggerPrice=1500_00,
37+
OrderExpiry=-1,
38+
)
39+
40+
stop_loss_order = CreateOrderTxReq(
41+
MarketIndex=0,
42+
ClientOrderIndex=0,
43+
BaseAmount=0,
44+
Price=5050_00,
45+
IsAsk=0,
46+
Type=client.ORDER_TYPE_STOP_LOSS_LIMIT,
47+
TimeInForce=client.ORDER_TIME_IN_FORCE_GOOD_TILL_TIME,
48+
ReduceOnly=1,
49+
TriggerPrice=5000_00,
50+
OrderExpiry=-1,
51+
)
52+
53+
transaction = await client.create_grouped_orders(
54+
grouping_type=client.GROUPING_TYPE_ONE_TRIGGERS_A_ONE_CANCELS_THE_OTHER,
55+
orders=[ioc_order, take_profit_order, stop_loss_order],
56+
self_trade_behavior_mode=client.SELF_TRADE_BEHAVIOR_EXPIRE_TAKER,
57+
self_trade_equality_mode=client.SELF_TRADE_EQUALITY_ACCOUNT_INDEX,
58+
)
59+
60+
print("Create Grouped Order Tx:", transaction)
61+
62+
await client.close()
63+
await api_client.close()
64+
65+
66+
if __name__ == "__main__":
67+
asyncio.run(main())

0 commit comments

Comments
 (0)