Skip to content

Commit b8d3f06

Browse files
authored
Merge pull request #18 from talkincode/fix/tpsl-order-structure
fix: 修复止盈止损订单的422反序列化错误
2 parents dfba50b + 6084edb commit b8d3f06

File tree

3 files changed

+348
-19
lines changed

3 files changed

+348
-19
lines changed

services/hyperliquid_services.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -788,20 +788,17 @@ async def set_position_tpsl(
788788

789789
# Add take profit order if specified
790790
if tp_px is not None:
791-
# For TP orders, use tick-aligned aggressive price
792-
# If closing long (sell), use very low price; if closing short (buy), use very high price
793-
slippage = 0.5 # 50% slippage for very aggressive pricing
794-
aggressive_px = self._slippage_price(coin, not is_long, slippage)
795-
791+
# For TP orders, use limit order at trigger price
792+
# This ensures the order fills at or better than the TP price
796793
tp_order = {
797794
"coin": coin,
798795
"is_buy": not is_long,
799796
"sz": float(position_size),
800-
"limit_px": aggressive_px, # Tick-aligned aggressive price for market execution
797+
"limit_px": float(tp_px), # Limit price = trigger price for TP
801798
"order_type": {
802799
"trigger": {
803800
"triggerPx": float(tp_px),
804-
"isMarket": True,
801+
"isMarket": False, # Use limit order for TP
805802
"tpsl": "tp",
806803
}
807804
},
@@ -812,19 +809,17 @@ async def set_position_tpsl(
812809

813810
# Add stop loss order if specified
814811
if sl_px is not None:
815-
# For SL orders, use tick-aligned aggressive price
816-
slippage = 0.5 # 50% slippage for very aggressive pricing
817-
aggressive_px = self._slippage_price(coin, not is_long, slippage)
818-
812+
# For SL orders, use market order for fast execution
813+
# No limit_px needed when isMarket=True
819814
sl_order = {
820815
"coin": coin,
821816
"is_buy": not is_long,
822817
"sz": float(position_size),
823-
"limit_px": aggressive_px, # Tick-aligned aggressive price for market execution
818+
"limit_px": float(sl_px), # Use trigger price as limit_px
824819
"order_type": {
825820
"trigger": {
826821
"triggerPx": float(sl_px),
827-
"isMarket": True,
822+
"isMarket": True, # Use market order for SL
828823
"tpsl": "sl",
829824
}
830825
},

tests/integration/test_oco_grouping.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ def mock_bulk_orders(order_requests, grouping="na"):
5757
async def test_set_position_tpsl_uses_correct_grouping(mock_service, monkeypatch):
5858
"""测试 set_position_tpsl 使用 positionTpSl 分组"""
5959
captured_grouping = None
60+
captured_orders = None
6061

6162
def mock_bulk_orders(order_requests, grouping="na"):
62-
nonlocal captured_grouping
63+
nonlocal captured_grouping, captured_orders
6364
captured_grouping = grouping
65+
captured_orders = order_requests
6466
return {"status": "ok", "response": {"type": "default"}}
6567

6668
# Mock info.user_state 返回一个仓位
@@ -74,13 +76,25 @@ def mock_user_state(address):
7476
monkeypatch.setattr(mock_service, "_bulk_orders_with_grouping", mock_bulk_orders)
7577
monkeypatch.setattr(mock_service.info, "user_state", mock_user_state)
7678

77-
# Mock _slippage_price
78-
monkeypatch.setattr(
79-
mock_service, "_slippage_price", lambda coin, is_buy, slippage: 45000.0
80-
)
81-
8279
result = await mock_service.set_position_tpsl(coin="BTC", tp_px=47000, sl_px=43000)
8380

8481
assert captured_grouping == OCO_GROUP_EXISTING_POSITION
8582
assert result["success"]
8683
assert result["position_details"]["grouping"] == OCO_GROUP_EXISTING_POSITION
84+
85+
# 验证订单结构正确性
86+
assert len(captured_orders) == 2
87+
tp_order = next(
88+
o for o in captured_orders if o["order_type"]["trigger"]["tpsl"] == "tp"
89+
)
90+
sl_order = next(
91+
o for o in captured_orders if o["order_type"]["trigger"]["tpsl"] == "sl"
92+
)
93+
94+
# 验证止盈使用限价单
95+
assert tp_order["order_type"]["trigger"]["isMarket"] is False
96+
assert tp_order["limit_px"] == 47000.0
97+
98+
# 验证止损使用市价单
99+
assert sl_order["order_type"]["trigger"]["isMarket"] is True
100+
assert sl_order["limit_px"] == 43000.0

0 commit comments

Comments
 (0)