malkhut: P0 guard + P1 BingX protective strings + tests fixed
P0 (safety): adapter.py rejects unmapped types (OCO, TP_SL) via is_type_available() guard. Returns None instead of silent LIMIT fallback. P1 (BingX strings): STOP_MARKET → STOP_MARKET (protective, reduce-only) STOP_LIMIT → STOP (protective) TRIGGER_MARKET stays generic MIT TRAILING_STOP → TRAILING_STOP_MARKET Tests updated to match corrected mappings.
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user