malkhut: standardized order types — FIX/CCXT-aligned, multi-exchange mapping
order_types.py: Five-layer taxonomy normalized to industry standards:
Layer 1: Base types (FIX Tag 40) — MARKET, LIMIT
Layer 2: Time-in-force (FIX Tag 59) — GTC, IOC, FOK, GTD
Layer 3: Conditional/Trigger (FIX Tag 3/4+MIT) — STOP_MARKET, STOP_LIMIT,
TRIGGER_MARKET, TRIGGER_LIMIT, TRAILING_STOP
Layer 4: Instructions (FIX Tag 18) — POST_ONLY, REDUCE_ONLY, HIDDEN, ICEBERG
Layer 5: Compound (exchange-specific) — OCO, TP_SL
Cross-exchange mapping: BingX ↔ Binance ↔ Bybit (from CCXT source code).
Standards: FIX 4.4 Tag 40/59/18, CCXT unified API, ISO 10383 (MIC).
Transferability: strategy PARAMETERS transfer. ORDER TYPE NAMES are
venue-specific but semantics identical (LIMIT = LIMIT everywhere).
14 tests. README updated with full mapping table and standards references.
This commit is contained in:
83
MALKHUT/malkhut/tests/test_order_types.py
Normal file
83
MALKHUT/malkhut/tests/test_order_types.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
Tests for standardized order types — FIX/CCXT-aligned, multi-exchange.
|
||||
"""
|
||||
import pytest
|
||||
from malkhut.training.order_types import (
|
||||
BaseType, TimeInForce, ConditionalType, OrderInstruction, CompoundOrder,
|
||||
EXCHANGE_ORDER_MAP, normalize_to_exchange, get_supported_types, is_type_available,
|
||||
)
|
||||
|
||||
|
||||
class TestOrderTypeEnums:
|
||||
def test_base_types(self):
|
||||
assert BaseType.MARKET.value == "market"
|
||||
assert BaseType.LIMIT.value == "limit"
|
||||
|
||||
def test_time_in_force(self):
|
||||
assert TimeInForce.GTC.value == "gtc"
|
||||
assert TimeInForce.IOC.value == "ioc"
|
||||
assert TimeInForce.FOK.value == "fok"
|
||||
|
||||
def test_conditional_types(self):
|
||||
assert ConditionalType.STOP_MARKET.value == "stop_market"
|
||||
assert ConditionalType.STOP_LIMIT.value == "stop_limit"
|
||||
assert ConditionalType.TRAILING_STOP.value == "trailing_stop"
|
||||
|
||||
def test_instructions(self):
|
||||
assert OrderInstruction.POST_ONLY.value == "post_only"
|
||||
assert OrderInstruction.REDUCE_ONLY.value == "reduce_only"
|
||||
|
||||
def test_compound(self):
|
||||
assert CompoundOrder.OCO.value == "oco"
|
||||
assert CompoundOrder.TP_SL.value == "tp_sl"
|
||||
|
||||
|
||||
class TestExchangeMapping:
|
||||
def test_binance_has_all_types(self):
|
||||
types = get_supported_types("binance")
|
||||
assert "limit" in types
|
||||
assert "market" in types
|
||||
assert "stop_market" in types
|
||||
assert "post_only" in types
|
||||
|
||||
def test_bingx_has_all_types(self):
|
||||
types = get_supported_types("bingx")
|
||||
assert "limit" in types
|
||||
assert "market" in types
|
||||
assert "trigger_market" in types
|
||||
|
||||
def test_bybit_has_all_types(self):
|
||||
types = get_supported_types("bybit")
|
||||
assert "limit" in types
|
||||
assert "market" in types
|
||||
assert "stop_market" in types
|
||||
|
||||
def test_normalize_limit_all_exchanges(self):
|
||||
"""LIMIT should map to LIMIT on all exchanges."""
|
||||
for ex in ["binance", "bingx", "bybit"]:
|
||||
assert normalize_to_exchange("limit", ex) == "LIMIT"
|
||||
|
||||
def test_normalize_market_all_exchanges(self):
|
||||
"""MARKET should map to MARKET on all exchanges."""
|
||||
for ex in ["binance", "bingx", "bybit"]:
|
||||
assert normalize_to_exchange("market", ex) == "MARKET"
|
||||
|
||||
def test_normalize_post_only_varies(self):
|
||||
"""POST_ONLY maps differently across exchanges."""
|
||||
assert normalize_to_exchange("post_only", "binance") == "LIMIT_MAKER"
|
||||
assert normalize_to_exchange("post_only", "bingx") == "POST_ONLY"
|
||||
assert normalize_to_exchange("post_only", "bybit") == "POST_ONLY"
|
||||
|
||||
def test_normalize_unknown_type(self):
|
||||
assert normalize_to_exchange("invalid_type", "binance") is None
|
||||
|
||||
def test_is_type_available(self):
|
||||
assert is_type_available("limit", "binance")
|
||||
assert is_type_available("stop_market", "bingx")
|
||||
assert not is_type_available("invalid", "binance")
|
||||
|
||||
def test_get_supported_types_unique(self):
|
||||
"""Each exchange should support at least 8 types."""
|
||||
for ex in ["binance", "bingx", "bybit"]:
|
||||
types = get_supported_types(ex)
|
||||
assert len(types) >= 8
|
||||
Reference in New Issue
Block a user