malkhut: fee+slippage execution threshold

This commit is contained in:
Codex
2026-07-18 17:44:20 +02:00
parent 5503aafa28
commit ebf7f17132
4 changed files with 49 additions and 22 deletions

View File

@@ -120,21 +120,27 @@ def build_our_actions(
post_only=intent.prefer_maker, reduce_only=intent.reduce_only, post_only=intent.prefer_maker, reduce_only=intent.reduce_only,
)) ))
# Aggressive crossing — urgency-driven maker/taker decision # Aggressive crossing — urgency + fee+slippage threshold driven maker/taker decision
# Below threshold: passive only (maker). Above: aggressive (taker). # The system learns: if (fee + slippage) < threshold → execute (pay the friction)
# The system learns the cheapest/fastest path as a function of urgency. # Threshold is movable (CMA-ES optimizable), tested at 2-3 bps per leg.
estimated_fee_bps = state.venue.taker_fee_bps # what taker would pay
estimated_slippage_bps = 0.5 # rough estimate; calibrated model refines in CWM
estimated_friction = estimated_fee_bps + estimated_slippage_bps
if intent.urgency > params.urgency_taker_threshold: if intent.urgency > params.urgency_taker_threshold:
# High urgency: MARKET for immediate fill # High urgency: full taker if friction is acceptable
if estimated_friction <= params.execution_friction_threshold_bps or intent.urgency > 0.9:
for frac in (0.05, 0.10, 0.25): for frac in (0.05, 0.10, 0.25):
actions.append(FulfilmentAction( actions.append(FulfilmentAction(
kind=ActionKind.CROSS_SPREAD, side=side, kind=ActionKind.CROSS_SPREAD, side=side,
order_type=OrderType.MARKET, price_ticks_from_best=0, order_type=OrderType.MARKET, price_ticks_from_best=0,
qty_fraction=frac, ttl_ms=params.aggressive_ttl_ms, qty_fraction=frac, ttl_ms=params.aggressive_ttl_ms,
reduce_only=intent.reduce_only, reduce_only=intent.reduce_only,
metadata={"urgency": intent.urgency, "mode": "taker_market"}, metadata={"urgency": intent.urgency, "mode": "taker_market",
"friction_bps": estimated_friction},
)) ))
elif intent.urgency > params.urgency_taker_threshold * 0.5: else:
# Medium urgency: LIMIT + IOC (partial fill OK) # Friction too high even at high urgency → IOC partial
for frac in (0.03, 0.06): for frac in (0.03, 0.06):
actions.append(FulfilmentAction( actions.append(FulfilmentAction(
kind=ActionKind.CROSS_SPREAD, side=side, kind=ActionKind.CROSS_SPREAD, side=side,
@@ -142,7 +148,21 @@ def build_our_actions(
qty_fraction=frac, ttl_ms=params.aggressive_ttl_ms, qty_fraction=frac, ttl_ms=params.aggressive_ttl_ms,
time_in_force="IOC", time_in_force="IOC",
reduce_only=intent.reduce_only, reduce_only=intent.reduce_only,
metadata={"urgency": intent.urgency, "mode": "taker_ioc"}, metadata={"urgency": intent.urgency, "mode": "taker_ioc",
"friction_bps": estimated_friction},
))
elif intent.urgency > params.urgency_taker_threshold * 0.5:
# Medium urgency: IOC partial if friction is low
if estimated_friction <= params.execution_friction_threshold_bps * 1.5:
for frac in (0.03, 0.06):
actions.append(FulfilmentAction(
kind=ActionKind.CROSS_SPREAD, side=side,
order_type=OrderType.LIMIT, 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_ioc",
"friction_bps": estimated_friction},
)) ))
# Low urgency: passive only (maker) — no taker actions added # Low urgency: passive only (maker) — no taker actions added

View File

@@ -397,3 +397,7 @@ class FulfilmentPolicyParams:
# Urgency-driven maker/taker decision (CMA-ES optimizable) # Urgency-driven maker/taker decision (CMA-ES optimizable)
urgency_taker_threshold: float = 0.65 # above this urgency, prefer taker urgency_taker_threshold: float = 0.65 # above this urgency, prefer taker
urgency_taker_penalty_bps: float = 2.0 # penalty for taker at low urgency urgency_taker_penalty_bps: float = 2.0 # penalty for taker at low urgency
# Fee+slippage execution threshold (movable, CMA-ES optimizable)
# If (fee + slippage) < threshold → system tends to EXECUTE (pay the friction)
execution_friction_threshold_bps: float = 3.0 # per leg, test 2-3 bps

View File

@@ -107,6 +107,7 @@ def _params() -> FulfilmentPolicyParams:
low_liquidity_weight=2.0, latency_stress_weight=1.0, low_liquidity_weight=2.0, latency_stress_weight=1.0,
wait_to_retry_ms=0, chase_enabled=False, chase_offset_ticks=1, chase_max_retries=0, wait_to_retry_ms=0, chase_enabled=False, chase_offset_ticks=1, chase_max_retries=0,
urgency_taker_threshold=0.65, urgency_taker_penalty_bps=2.0, urgency_taker_threshold=0.65, urgency_taker_penalty_bps=2.0,
execution_friction_threshold_bps=3.0,
) )
def _place(side: Side = Side.BUY, price_ticks: int = 0, qty: float = 0.10, def _place(side: Side = Side.BUY, price_ticks: int = 0, qty: float = 0.10,

View File

@@ -95,6 +95,7 @@ class CMAParameterCodec:
ParamSpec("chase_max_retries", "int", 0, 5), ParamSpec("chase_max_retries", "int", 0, 5),
ParamSpec("urgency_taker_threshold", "float", 0.1, 0.9), ParamSpec("urgency_taker_threshold", "float", 0.1, 0.9),
ParamSpec("urgency_taker_penalty_bps", "float", 0.0, 10.0), ParamSpec("urgency_taker_penalty_bps", "float", 0.0, 10.0),
ParamSpec("execution_friction_threshold_bps", "float", 0.5, 10.0),
) )
def initial_vector(self, baseline: FulfilmentPolicyParams) -> list[float]: def initial_vector(self, baseline: FulfilmentPolicyParams) -> list[float]:
@@ -157,6 +158,7 @@ class CMAParameterCodec:
chase_max_retries=vals.get("chase_max_retries", 0), chase_max_retries=vals.get("chase_max_retries", 0),
urgency_taker_threshold=vals.get("urgency_taker_threshold", 0.65), urgency_taker_threshold=vals.get("urgency_taker_threshold", 0.65),
urgency_taker_penalty_bps=vals.get("urgency_taker_penalty_bps", 2.0), urgency_taker_penalty_bps=vals.get("urgency_taker_penalty_bps", 2.0),
execution_friction_threshold_bps=vals.get("execution_friction_threshold_bps", 3.0),
) )