diff --git a/MALKHUT/malkhut/tests/test_order_type_integration.py b/MALKHUT/malkhut/tests/test_order_type_integration.py index a6d34b2..7585c21 100644 --- a/MALKHUT/malkhut/tests/test_order_type_integration.py +++ b/MALKHUT/malkhut/tests/test_order_type_integration.py @@ -213,8 +213,8 @@ class TestExchangeOrderTypeMap: for ex in ("binance", "bingx", "bybit"): assert EXCHANGE_ORDER_TYPE_MAP[ex]["MARKET"] == "MARKET" - def test_bingx_stop_market_is_trigger_market(self): - assert EXCHANGE_ORDER_TYPE_MAP["bingx"]["STOP_MARKET"] == "TRIGGER_MARKET" + def test_bingx_stop_market_is_protective(self): + assert EXCHANGE_ORDER_TYPE_MAP["bingx"]["STOP_MARKET"] == "STOP_MARKET" def test_binance_stop_market_is_stop_market(self): assert EXCHANGE_ORDER_TYPE_MAP["binance"]["STOP_MARKET"] == "STOP_MARKET" @@ -234,8 +234,8 @@ class TestExchangeOrderTypeMap: def test_binance_stop_limit_is_stop_loss_limit(self): assert EXCHANGE_ORDER_TYPE_MAP["binance"]["STOP_LIMIT"] == "STOP_LOSS_LIMIT" - def test_bingx_stop_limit_is_trigger_limit(self): - assert EXCHANGE_ORDER_TYPE_MAP["bingx"]["STOP_LIMIT"] == "TRIGGER_LIMIT" + def test_bingx_stop_limit_is_protective(self): + assert EXCHANGE_ORDER_TYPE_MAP["bingx"]["STOP_LIMIT"] == "STOP" def test_binance_trigger_market_is_take_profit(self): assert EXCHANGE_ORDER_TYPE_MAP["binance"]["TRIGGER_MARKET"] == "TAKE_PROFIT" @@ -289,7 +289,7 @@ class TestNormalizeTypeToExchange: assert result is not None, f"{t.value} not mapped for {ex}" def test_bingx_stop_market(self): - assert normalize_type_to_exchange(StdOrderType.STOP_MARKET, "bingx") == "TRIGGER_MARKET" + assert normalize_type_to_exchange(StdOrderType.STOP_MARKET, "bingx") == "STOP_MARKET" def test_bingx_trailing_stop(self): assert normalize_type_to_exchange(StdOrderType.TRAILING_STOP, "bingx") == "TRAILING_STOP_MARKET" diff --git a/MALKHUT/malkhut/training/order_types.py b/MALKHUT/malkhut/training/order_types.py index 1273e2e..5e837f1 100644 --- a/MALKHUT/malkhut/training/order_types.py +++ b/MALKHUT/malkhut/training/order_types.py @@ -92,8 +92,10 @@ EXCHANGE_ORDER_TYPE_MAP: Dict[str, Dict[str, str]] = { }, "bingx": { "LIMIT": "LIMIT", "MARKET": "MARKET", - "STOP_MARKET": "TRIGGER_MARKET", "STOP_LIMIT": "TRIGGER_LIMIT", - "TRIGGER_MARKET": "TRIGGER_MARKET", "TRIGGER_LIMIT": "TRIGGER_LIMIT", + "STOP_MARKET": "STOP_MARKET", # protective exit (reduce-only, position-tied) + "STOP_LIMIT": "STOP", # BingX protective stop-limit + "TRIGGER_MARKET": "TRIGGER_MARKET", # generic MIT (plan order by stopPrice) + "TRIGGER_LIMIT": "TRIGGER_LIMIT", "TRAILING_STOP": "TRAILING_STOP_MARKET", }, "bybit": { diff --git a/MALKHUT/malkhut/venue/bingx/adapter.py b/MALKHUT/malkhut/venue/bingx/adapter.py index 6ed3e53..8624918 100644 --- a/MALKHUT/malkhut/venue/bingx/adapter.py +++ b/MALKHUT/malkhut/venue/bingx/adapter.py @@ -179,10 +179,17 @@ class BingXVenueAdapter: # Determine order type — use standardized OrderType, map to BingX-native from malkhut.training.order_types import ( - normalize_type_to_exchange, normalize_tif_to_exchange, + normalize_type_to_exchange, normalize_tif_to_exchange, is_type_available, ) if action.order_type is not None: - order_type = normalize_type_to_exchange(action.order_type, "bingx") or "LIMIT" + if not is_type_available(action.order_type, "bingx"): + import logging + logging.getLogger(__name__).error( + "REJECT: %s unavailable on bingx — not silently downgrading to LIMIT", + action.order_type.value, + ) + return None # reject — do NOT submit + order_type = normalize_type_to_exchange(action.order_type, "bingx") elif action.kind.value == "CROSS_SPREAD": order_type = "MARKET" else: