Skip to content

Commit c26c802

Browse files
committed
Add partial TPSL support
1 parent 88b1ea8 commit c26c802

File tree

6 files changed

+108
-34
lines changed

6 files changed

+108
-34
lines changed

examples/02_create_limit_order_with_partial_tpsl.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
from asyncio import run
33

44
from config import ETH_USD_MARKET
5-
from perpetual.accounts import StarkPerpetualAccount
6-
from perpetual.configuration import TESTNET_CONFIG
7-
from perpetual.order_object import OrderTpslTriggerParam, create_order_object
8-
from perpetual.orders import (
5+
6+
from examples.init_env import init_env
7+
from examples.utils import get_adjust_price_by_pct
8+
from x10.perpetual.accounts import StarkPerpetualAccount
9+
from x10.perpetual.configuration import MAINNET_CONFIG
10+
from x10.perpetual.order_object import OrderTpslTriggerParam, create_order_object
11+
from x10.perpetual.orders import (
912
OrderPriceType,
1013
OrderSide,
1114
OrderTpslType,
1215
OrderTriggerPriceType,
1316
TimeInForce,
1417
)
15-
from perpetual.trading_client import PerpetualTradingClient
16-
17-
from examples.init_env import init_env
18-
from examples.utils import get_adjust_price_by_pct
18+
from x10.perpetual.trading_client import PerpetualTradingClient
1919

2020
LOGGER = logging.getLogger()
21-
ENDPOINT_CONFIG = TESTNET_CONFIG
21+
ENDPOINT_CONFIG = MAINNET_CONFIG
2222

2323

2424
async def run_example():
@@ -45,11 +45,11 @@ async def run_example():
4545
sl_trigger_price = adjust_price_by_pct(order_price, -0.5)
4646
sl_price = adjust_price_by_pct(order_price, -1.0)
4747

48-
LOGGER.info(f"Market: {market}")
48+
LOGGER.info(f"Creating LIMIT order object with TPSL for market: {market.name}")
4949

5050
new_order = create_order_object(
5151
account=stark_account,
52-
starknet_domain=TESTNET_CONFIG.starknet_domain,
52+
starknet_domain=ENDPOINT_CONFIG.starknet_domain,
5353
market=market,
5454
side=OrderSide.BUY,
5555
amount_of_synthetic=order_size,
@@ -72,7 +72,7 @@ async def run_example():
7272
),
7373
)
7474

75-
LOGGER.info(f"New order obj: {new_order}")
75+
LOGGER.info(f"Placing order...")
7676

7777

7878
if __name__ == "__main__":

examples/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from decimal import Decimal
22

3-
from perpetual.markets import TradingConfigModel
3+
from x10.perpetual.markets import TradingConfigModel
44

55

66
def get_adjust_price_by_pct(config: TradingConfigModel):

tests/perpetual/test_order_object.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77
from pytest_mock import MockerFixture
88

99
from x10.perpetual.configuration import TESTNET_CONFIG
10-
from x10.perpetual.orders import OrderSide, SelfTradeProtectionLevel
10+
from x10.perpetual.order_object import OrderTpslTriggerParam
11+
from x10.perpetual.orders import (
12+
OrderPriceType,
13+
OrderSide,
14+
OrderTriggerPriceType,
15+
SelfTradeProtectionLevel,
16+
)
1117
from x10.utils.date import utc_now
1218

1319
FROZEN_NONCE = 1473459052
@@ -188,6 +194,76 @@ async def test_create_buy_order(mocker: MockerFixture, create_trading_account, c
188194
)
189195

190196

197+
@freeze_time("2024-01-05 01:08:56.860694")
198+
@pytest.mark.asyncio
199+
async def test_create_buy_order_with_tpsl(mocker: MockerFixture, create_trading_account, create_btc_usd_market):
200+
mocker.patch("x10.utils.generate_nonce", return_value=FROZEN_NONCE)
201+
202+
from x10.perpetual.order_object import create_order_object
203+
204+
trading_account = create_trading_account()
205+
btc_usd_market = create_btc_usd_market()
206+
order_obj = create_order_object(
207+
account=trading_account,
208+
market=btc_usd_market,
209+
amount_of_synthetic=Decimal("0.00100000"),
210+
price=Decimal("43445.11680000"),
211+
side=OrderSide.BUY,
212+
expire_time=utc_now() + timedelta(days=14),
213+
self_trade_protection_level=SelfTradeProtectionLevel.CLIENT,
214+
starknet_domain=TESTNET_CONFIG.starknet_domain,
215+
take_profit=OrderTpslTriggerParam(
216+
trigger_price=Decimal("49000"),
217+
trigger_price_type=OrderTriggerPriceType.MARK,
218+
price=Decimal("50000"),
219+
price_type=OrderPriceType.LIMIT,
220+
),
221+
stop_loss=OrderTpslTriggerParam(
222+
trigger_price=Decimal("40000"),
223+
trigger_price_type=OrderTriggerPriceType.MARK,
224+
price=Decimal("39000"),
225+
price_type=OrderPriceType.LIMIT,
226+
),
227+
)
228+
229+
assert_that(
230+
order_obj.to_api_request_json(),
231+
equal_to(
232+
{
233+
"id": "2495374044666992118771096772295242242651427695217815113349321039194683172848",
234+
"market": "BTC-USD",
235+
"type": "LIMIT",
236+
"side": "BUY",
237+
"qty": "0.00100000",
238+
"price": "43445.11680000",
239+
"reduceOnly": False,
240+
"postOnly": False,
241+
"timeInForce": "GTT",
242+
"expiryEpochMillis": 1705626536861,
243+
"fee": "0.0005",
244+
"nonce": "1473459052",
245+
"selfTradeProtectionLevel": "CLIENT",
246+
"cancelId": None,
247+
"settlement": {
248+
"signature": {
249+
"r": "0xa55625c7d5f1b85bed22556fc805224b8363074979cf918091d9ddb1403e13",
250+
"s": "0x504caf634d859e643569743642ccf244434322859b2421d76f853af43ae7a46",
251+
},
252+
"starkKey": "0x61c5e7e8339b7d56f197f54ea91b776776690e3232313de0f2ecbd0ef76f466",
253+
"collateralPosition": "10002",
254+
},
255+
"trigger": None,
256+
"tpSlType": None,
257+
"takeProfit": None,
258+
"stopLoss": None,
259+
"debuggingAmounts": {"collateralAmount": "-43445117", "feeAmount": "21723", "syntheticAmount": "1000"},
260+
"builderFee": None,
261+
"builderId": None,
262+
}
263+
),
264+
)
265+
266+
191267
@freeze_time("2024-01-05 01:08:56.860694")
192268
@pytest.mark.asyncio
193269
async def test_cancel_previous_order(mocker: MockerFixture, create_trading_account, create_btc_usd_market):

x10/perpetual/configuration.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ class EndpointConfig:
3434
asset_operations_contract="",
3535
collateral_asset_on_chain_id="0x1",
3636
collateral_decimals=6,
37-
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_SEPOLIA", revision="1"),
3837
collateral_asset_id="0x1",
38+
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_SEPOLIA", revision="1"),
3939
)
4040

4141
MAINNET_CONFIG = EndpointConfig(
@@ -48,8 +48,6 @@ class EndpointConfig:
4848
asset_operations_contract="",
4949
collateral_asset_on_chain_id="0x1",
5050
collateral_decimals=6,
51-
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_MAIN", revision="1"),
5251
collateral_asset_id="0x1",
52+
starknet_domain=StarknetDomain(name="Perpetuals", version="v0", chain_id="SN_MAIN", revision="1"),
5353
)
54-
55-
STARKNET_MAINNET_CONFIG = MAINNET_CONFIG

x10/perpetual/order_object.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
from decimal import Decimal
44
from typing import Callable, Optional, Tuple
55

6-
from perpetual.order_object_settlement import (
7-
OrderSettlementData,
8-
SettlementDataCtx,
9-
create_order_settlement_data,
10-
)
11-
126
from x10.perpetual.accounts import StarkPerpetualAccount
137
from x10.perpetual.configuration import StarknetDomain
148
from x10.perpetual.fees import DEFAULT_FEES, TradingFeeModel
159
from x10.perpetual.markets import MarketModel
10+
from x10.perpetual.order_object_settlement import (
11+
OrderSettlementData,
12+
SettlementDataCtx,
13+
create_order_settlement_data,
14+
)
1615
from x10.perpetual.orders import (
1716
CreateOrderTpslTriggerModel,
1817
OrderPriceType,

x10/perpetual/order_object_settlement.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,34 @@
55
from typing import Callable, Optional, Tuple
66

77
from fast_stark_crypto import get_order_msg_hash
8-
from perpetual.amounts import (
8+
9+
from x10.perpetual.amounts import (
910
ROUNDING_BUY_CONTEXT,
1011
ROUNDING_FEE_CONTEXT,
1112
ROUNDING_SELL_CONTEXT,
1213
HumanReadableAmount,
1314
StarkAmount,
1415
)
15-
from perpetual.configuration import StarknetDomain
16-
from perpetual.fees import TradingFeeModel
17-
from perpetual.markets import MarketModel
18-
from perpetual.orders import (
16+
from x10.perpetual.configuration import StarknetDomain
17+
from x10.perpetual.fees import TradingFeeModel
18+
from x10.perpetual.markets import MarketModel
19+
from x10.perpetual.orders import (
1920
OrderSide,
2021
StarkDebuggingOrderAmountsModel,
2122
StarkSettlementModel,
2223
)
23-
from utils.model import SettlementSignatureModel
24+
from x10.utils.model import SettlementSignatureModel
2425

2526

26-
@dataclass
27+
@dataclass(kw_only=True)
2728
class OrderSettlementData:
2829
synthetic_amount_human: HumanReadableAmount
2930
order_hash: int
3031
settlement: StarkSettlementModel
3132
debugging_amounts: StarkDebuggingOrderAmountsModel
3233

3334

34-
@dataclass
35+
@dataclass(kw_only=True)
3536
class SettlementDataCtx:
3637
market: MarketModel
3738
fees: TradingFeeModel
@@ -44,7 +45,7 @@ class SettlementDataCtx:
4445
starknet_domain: StarknetDomain
4546

4647

47-
def __get_settlement_expiration(expiration_timestamp: datetime):
48+
def __calc_settlement_expiration(expiration_timestamp: datetime):
4849
expire_time_with_buffer = expiration_timestamp + timedelta(days=14)
4950
expire_time_as_seconds = math.ceil(expire_time_with_buffer.timestamp())
5051

@@ -72,7 +73,7 @@ def hash_order(
7273
quote_amount=amount_collateral.value,
7374
fee_amount=max_fee.value,
7475
fee_asset_id=int(collateral_asset.settlement_external_id, 16),
75-
expiration=__get_settlement_expiration(expiration_timestamp),
76+
expiration=__calc_settlement_expiration(expiration_timestamp),
7677
salt=nonce,
7778
user_public_key=public_key,
7879
domain_name=starknet_domain.name,

0 commit comments

Comments
 (0)