malkhut: fee+slippage execution threshold
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user