|
|
@@ -564,6 +564,33 @@ def test_market_order_fetches_latest_price_before_sizing():
|
|
|
]
|
|
|
|
|
|
|
|
|
+def test_fractional_margin_sizing_keeps_decimal_precision():
|
|
|
+ session = DummySession(
|
|
|
+ [
|
|
|
+ account_config_response(pos_mode="long_short_mode"),
|
|
|
+ instrument_response(),
|
|
|
+ ticker_response(last="1"),
|
|
|
+ leverage_response(),
|
|
|
+ place_order_response(),
|
|
|
+ ]
|
|
|
+ )
|
|
|
+ signal = TradeSignal(
|
|
|
+ action="long",
|
|
|
+ confidence=0.9,
|
|
|
+ leverage=3,
|
|
|
+ entry_price=None,
|
|
|
+ take_profit_price=None,
|
|
|
+ stop_loss_price=None,
|
|
|
+ reason="x",
|
|
|
+ )
|
|
|
+ client = OkxClient(config=sample_config(), session=session)
|
|
|
+
|
|
|
+ client.place_demo_order(symbol="BTC-USDT-SWAP", signal=signal, margin_usdt=0.009)
|
|
|
+
|
|
|
+ assert session.last_json_body is not None
|
|
|
+ assert session.last_json_body["sz"] == "27"
|
|
|
+
|
|
|
+
|
|
|
def test_place_demo_order_fails_when_not_hedge_mode():
|
|
|
session = DummySession(
|
|
|
[
|
|
|
@@ -774,9 +801,9 @@ def test_get_instrument_meta_rejects_non_swap_type():
|
|
|
def test_place_demo_order_raises_when_order_id_is_missing():
|
|
|
session = DummySession(
|
|
|
[
|
|
|
+ account_config_response(pos_mode="long_short_mode"),
|
|
|
instrument_response(),
|
|
|
ticker_response(last="25000"),
|
|
|
- account_config_response(pos_mode="long_short_mode"),
|
|
|
leverage_response(),
|
|
|
place_order_response_without_order_id(),
|
|
|
]
|
|
|
@@ -785,6 +812,7 @@ def test_place_demo_order_raises_when_order_id_is_missing():
|
|
|
|
|
|
with pytest.raises(ValueError, match="okx response payload is invalid"):
|
|
|
client.place_demo_order(symbol="BTC-USDT-SWAP", signal=market_long_signal(), margin_usdt=100)
|
|
|
+ assert session.request_paths[-1] == "/api/v5/trade/order"
|
|
|
|
|
|
|
|
|
def test_place_demo_order_rejects_invalid_leverage_before_okx():
|
|
|
@@ -805,6 +833,24 @@ def test_place_demo_order_rejects_invalid_leverage_before_okx():
|
|
|
assert session.request_paths == []
|
|
|
|
|
|
|
|
|
+def test_place_demo_order_rejects_fractional_leverage_before_okx():
|
|
|
+ session = DummySession([])
|
|
|
+ signal = TradeSignal(
|
|
|
+ action="long",
|
|
|
+ confidence=0.9,
|
|
|
+ leverage=2.5,
|
|
|
+ entry_price=None,
|
|
|
+ take_profit_price=None,
|
|
|
+ stop_loss_price=None,
|
|
|
+ reason="x",
|
|
|
+ )
|
|
|
+ client = OkxClient(config=sample_config(), session=session)
|
|
|
+
|
|
|
+ with pytest.raises(ValueError, match="leverage is invalid"):
|
|
|
+ client.place_demo_order(symbol="BTC-USDT-SWAP", signal=signal, margin_usdt=100)
|
|
|
+ assert session.request_paths == []
|
|
|
+
|
|
|
+
|
|
|
def test_place_demo_order_rejects_boolean_leverage_before_okx():
|
|
|
session = DummySession([])
|
|
|
signal = TradeSignal(
|
|
|
@@ -847,6 +893,7 @@ def test_place_demo_order_rejects_boolean_margin_before_okx():
|
|
|
[
|
|
|
("BTC-USDT", 2, "long", "swap instrument is required"),
|
|
|
("BTC-USDT-SWAP", 4, "long", "leverage is invalid"),
|
|
|
+ ("BTC-USDT-SWAP", 2.5, "long", "leverage is invalid"),
|
|
|
("BTC-USDT-SWAP", 2, "net", "pos_side is invalid"),
|
|
|
],
|
|
|
)
|