fac28c402b
Co-authored-by: Cursor <cursoragent@cursor.com>
68 lines
2.1 KiB
Python
68 lines
2.1 KiB
Python
"""OKX 中控委托:须为 OCO 条件单,不得带 reduceOnly 或分两笔 market。"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "manual_trading_hub"))
|
|
|
|
from exchange_orders import _okx_place_tp_sl # noqa: E402
|
|
|
|
|
|
class TestHubOkxPlaceTpsl(unittest.TestCase):
|
|
def test_okx_place_tpsl_single_oco_without_reduce_only(self):
|
|
captured: list[dict] = []
|
|
|
|
def fake_create_order(symbol, order_type, side, amount, price, params):
|
|
captured.append(
|
|
{
|
|
"symbol": symbol,
|
|
"type": order_type,
|
|
"side": side,
|
|
"amount": amount,
|
|
"params": dict(params or {}),
|
|
}
|
|
)
|
|
return {"id": "algo-1"}
|
|
|
|
ex = MagicMock()
|
|
ex.create_order = fake_create_order
|
|
ex.load_markets = MagicMock()
|
|
ex.amount_to_precision = lambda sym, amt: str(amt)
|
|
ex.price_to_precision = lambda sym, px: str(px)
|
|
|
|
with patch.dict(
|
|
"os.environ",
|
|
{"OKX_POS_MODE": "hedge", "OKX_TD_MODE": "cross"},
|
|
clear=False,
|
|
):
|
|
_okx_place_tp_sl(
|
|
ex,
|
|
"HYPE/USDT:USDT",
|
|
"short",
|
|
6.0,
|
|
75.5,
|
|
70.2,
|
|
)
|
|
|
|
self.assertEqual(len(captured), 1, captured)
|
|
call = captured[0]
|
|
self.assertEqual(call["type"], "oco")
|
|
self.assertEqual(call["side"], "buy")
|
|
params = call["params"]
|
|
self.assertNotIn("reduceOnly", params)
|
|
self.assertEqual(params.get("posSide"), "short")
|
|
self.assertEqual(params.get("positionSide"), "short")
|
|
self.assertEqual(params.get("stopLossPrice"), 75.5)
|
|
self.assertEqual(params.get("takeProfitPrice"), 70.2)
|
|
self.assertEqual(params.get("tpOrdPx"), "-1")
|
|
self.assertEqual(params.get("slOrdPx"), "-1")
|
|
self.assertNotIn("stopLoss", params)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|