From 041c879e82a8338e83686b756756b0b7614dd29b Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 18 Jul 2026 12:25:41 +0200 Subject: [PATCH] malkhut: all exchange order types in DSL + action_menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ActionType → OrderType mapping (common-sensical): QUOTE/REQUOTE/CHASE: LIMIT (passive, post_only) CROSS_SPREAD (high urgency): MARKET (immediate fill) CROSS_SPREAD (medium urgency): LIMIT + IOC (partial fill) STOP_LOSS: STOP_MARKET (trigger → market exit) TAKE_PROFIT: TRIGGER_MARKET (trigger → market exit) TRAILING_STOP: TRAILING_STOP (trailing stop exit) EXIT/FLAT_ALL: STOP_MARKET EMERGENCY_EXIT: MARKET (immediate) All order types exercised: LIMIT, MARKET, STOP_MARKET, TRIGGER_MARKET, TRAILING_STOP --- MALKHUT/malkhut/planner/action_menu.py | 27 ++++++++++++++++--------- MALKHUT/malkhut/training/dsl.py | 28 +++++++++++++++++--------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/MALKHUT/malkhut/planner/action_menu.py b/MALKHUT/malkhut/planner/action_menu.py index 4c9b9e5..83025e8 100644 --- a/MALKHUT/malkhut/planner/action_menu.py +++ b/MALKHUT/malkhut/planner/action_menu.py @@ -5,6 +5,14 @@ Menu size target: our actions: 8-24 each counterparty role: 3-12 depth: 2-4 + +Order type mapping (common-sensical): + QUOTE/REQUOTE/CHASE: LIMIT (passive, post_only) + CROSS_SPREAD (low urgency): LIMIT + IOC (taker, partial fill OK) + CROSS_SPREAD (high urgency): MARKET (immediate fill) + STOP_LOSS: STOP_MARKET (trigger → market exit) + TAKE_PROFIT: TRIGGER_MARKET (trigger → market exit) + TRAILING_STOP: TRAILING_STOP (trailing stop exit) """ from __future__ import annotations @@ -116,18 +124,17 @@ def build_our_actions( # Below threshold: passive only (maker). Above: aggressive (taker). # The system learns the cheapest/fastest path as a function of urgency. if intent.urgency > params.urgency_taker_threshold: - # High urgency: aggressive taker fills + # High urgency: MARKET for immediate fill for frac in (0.05, 0.10, 0.25): actions.append(FulfilmentAction( kind=ActionKind.CROSS_SPREAD, side=side, - order_type=OrderType.LIMIT, price_ticks_from_best=0, + order_type=OrderType.MARKET, price_ticks_from_best=0, qty_fraction=frac, ttl_ms=params.aggressive_ttl_ms, - time_in_force="IOC", reduce_only=intent.reduce_only, - metadata={"urgency": intent.urgency, "mode": "taker"}, + metadata={"urgency": intent.urgency, "mode": "taker_market"}, )) elif intent.urgency > params.urgency_taker_threshold * 0.5: - # Medium urgency: aggressive but with IOC (partial fill OK) + # Medium urgency: LIMIT + IOC (partial fill OK) for frac in (0.03, 0.06): actions.append(FulfilmentAction( kind=ActionKind.CROSS_SPREAD, side=side, @@ -135,17 +142,18 @@ def build_our_actions( qty_fraction=frac, ttl_ms=params.aggressive_ttl_ms, time_in_force="IOC", reduce_only=intent.reduce_only, - metadata={"urgency": intent.urgency, "mode": "taker_partial"}, + metadata={"urgency": intent.urgency, "mode": "taker_ioc"}, )) # Low urgency: passive only (maker) — no taker actions added # Path-risk exits if _path_risk_says_exit(state, params): + # STOP_MARKET for stop-loss exits (trigger → market) actions.append(FulfilmentAction( kind=ActionKind.FULL_EXIT, side=_exit_side_for_position(state), - order_type=OrderType.MARKET, price_ticks_from_best=0, + order_type=OrderType.STOP_MARKET, price_ticks_from_best=0, qty_fraction=1.0, ttl_ms=0, reduce_only=True, - metadata={"reason": "path_risk_exit"}, + metadata={"reason": "path_risk_exit", "exit_type": "stop_market"}, )) # Chase actions (cancel → wait → retry with configurable wait_to_retry_ms) @@ -160,7 +168,8 @@ def build_our_actions( ttl_ms=chase_ttl, post_only=True, metadata={"chase": True, "chase_offset": offset, - "chase_max_retries": params.chase_max_retries}, + "chase_max_retries": params.chase_max_retries, + "order_type_combo": "LIMIT+post_only+chase"}, )) return tuple(actions) diff --git a/MALKHUT/malkhut/training/dsl.py b/MALKHUT/malkhut/training/dsl.py index 886c0c2..63b99cf 100644 --- a/MALKHUT/malkhut/training/dsl.py +++ b/MALKHUT/malkhut/training/dsl.py @@ -616,10 +616,17 @@ def _primitive_to_action(primitive: ActionPrimitive, state: MarketWorldState) -> ) elif at in (ActionType.CROSS, ActionType.SNIPER, ActionType.PING): + # CROSS: aggressive fill. Use MARKET for immediate execution. + # SNIPER: precision entry, use LIMIT + IOC for partial fill control. + # PING: small aggressive test, use LIMIT + IOC. + if at == ActionType.CROSS: + order_type = OrderType.MARKET + else: + order_type = OrderType.LIMIT return FulfilmentAction( - kind=ActionKind.CROSS_SPREAD, side=primitive.side, order_type=OrderType.LIMIT, + kind=ActionKind.CROSS_SPREAD, side=primitive.side, order_type=order_type, price_ticks_from_best=0, qty_fraction=primitive.size_fraction, ttl_ms=50, - time_in_force="IOC", + time_in_force="IOC" if order_type == OrderType.LIMIT else "GTC", ) elif at == ActionType.CANCEL_ALL: @@ -637,8 +644,10 @@ def _primitive_to_action(primitive: ActionPrimitive, state: MarketWorldState) -> side = Side.SELL if pos and pos.qty > 0 else Side.BUY if pos and pos.qty < 0 else None if side is None: return FulfilmentAction(ActionKind.NOOP, None, None, 0, 0.0, 0) + # EMERGENCY_EXIT uses MARKET for immediate fill; EXIT uses STOP_MARKET + order_type = OrderType.MARKET if at == ActionType.EMERGENCY_EXIT else OrderType.STOP_MARKET return FulfilmentAction( - kind=ActionKind.FULL_EXIT, side=side, order_type=OrderType.MARKET, + kind=ActionKind.FULL_EXIT, side=side, order_type=order_type, price_ticks_from_best=0, qty_fraction=1.0, ttl_ms=0, reduce_only=True, ) @@ -648,9 +657,9 @@ def _primitive_to_action(primitive: ActionPrimitive, state: MarketWorldState) -> if side is None: return FulfilmentAction(ActionKind.NOOP, None, None, 0, 0.0, 0) return FulfilmentAction( - kind=ActionKind.FULL_EXIT, side=side, order_type=OrderType.MARKET, + kind=ActionKind.FULL_EXIT, side=side, order_type=OrderType.STOP_MARKET, price_ticks_from_best=0, qty_fraction=1.0, ttl_ms=0, reduce_only=True, - metadata={"reason": "stop_loss"}, + metadata={"reason": "stop_loss", "order_type_combo": "STOP_MARKET"}, ) elif at == ActionType.TAKE_PROFIT: @@ -659,9 +668,9 @@ def _primitive_to_action(primitive: ActionPrimitive, state: MarketWorldState) -> if side is None: return FulfilmentAction(ActionKind.NOOP, None, None, 0, 0.0, 0) return FulfilmentAction( - kind=ActionKind.FULL_EXIT, side=side, order_type=OrderType.MARKET, + kind=ActionKind.FULL_EXIT, side=side, order_type=OrderType.TRIGGER_MARKET, price_ticks_from_best=0, qty_fraction=1.0, ttl_ms=0, reduce_only=True, - metadata={"reason": "take_profit"}, + metadata={"reason": "take_profit", "order_type_combo": "TRIGGER_MARKET"}, ) elif at == ActionType.TRAILING_STOP: @@ -670,9 +679,10 @@ def _primitive_to_action(primitive: ActionPrimitive, state: MarketWorldState) -> if side is None: return FulfilmentAction(ActionKind.NOOP, None, None, 0, 0.0, 0) return FulfilmentAction( - kind=ActionKind.FULL_EXIT, side=side, order_type=OrderType.MARKET, + kind=ActionKind.FULL_EXIT, side=side, order_type=OrderType.TRAILING_STOP, price_ticks_from_best=0, qty_fraction=1.0, ttl_ms=0, reduce_only=True, - metadata={"reason": "trailing_stop", "trail_bps": primitive.trail_distance_bps}, + metadata={"reason": "trailing_stop", "trail_bps": primitive.trail_distance_bps, + "order_type_combo": "TRAILING_STOP"}, ) elif at == ActionType.HALF_EXIT: