|
|
@@ -713,11 +713,23 @@ def _grid_switch_tradeoff(*,
|
|
|
trend: dict[str, Any] | None,
|
|
|
) -> dict[str, Any]:
|
|
|
inventory_state = _inventory_state_label(wallet_state.get("inventory_state"))
|
|
|
+ supervision = current_primary.get("supervision") if isinstance(current_primary.get("supervision"), dict) else {}
|
|
|
open_order_count = int(current_primary.get("open_order_count") or 0)
|
|
|
if not open_order_count:
|
|
|
state = current_primary.get("state") if isinstance(current_primary.get("state"), dict) else {}
|
|
|
open_order_count = int(state.get("open_order_count") or len(state.get("orders") or []) or 0)
|
|
|
|
|
|
+ adverse_side = str(supervision.get("adverse_side") or "unknown")
|
|
|
+ adverse_count = int(supervision.get("adverse_side_open_order_count") or 0)
|
|
|
+ adverse_notional = float(supervision.get("adverse_side_open_order_notional_quote") or 0.0)
|
|
|
+ adverse_distance = _safe_float(supervision.get("adverse_side_nearest_distance_pct"))
|
|
|
+ base_order_notional = 1.0
|
|
|
+ config = current_primary.get("config") if isinstance(current_primary.get("config"), dict) else {}
|
|
|
+ for candidate in (config.get("order_notional_quote"), config.get("max_order_notional_quote")):
|
|
|
+ candidate_value = _safe_float(candidate)
|
|
|
+ if candidate_value and candidate_value > base_order_notional:
|
|
|
+ base_order_notional = candidate_value
|
|
|
+
|
|
|
trend_score = float(trend.get("score") or 0.0) if trend else 0.0
|
|
|
breakout_score = float(breakout.get("score") or 0.0)
|
|
|
levels = float(grid_pressure.get("levels") or 0.0)
|
|
|
@@ -726,6 +738,7 @@ def _grid_switch_tradeoff(*,
|
|
|
persistent = bool(breakout.get("persistent"))
|
|
|
trend_ready = trend_score > 0.45 and directional_micro_clear
|
|
|
|
|
|
+ stay_cost = 0.0
|
|
|
switch_benefit = 0.0
|
|
|
if persistent:
|
|
|
switch_benefit += 0.28
|
|
|
@@ -738,7 +751,15 @@ def _grid_switch_tradeoff(*,
|
|
|
switch_benefit += min(trend_score, 2.5) * 0.18
|
|
|
switch_benefit += min(breakout_score, 5.0) * 0.04
|
|
|
|
|
|
- stay_cost = 0.0
|
|
|
+ if adverse_side in {"buy", "sell"} and adverse_count > 0:
|
|
|
+ adverse_notional_ratio = adverse_notional / max(base_order_notional, 1.0)
|
|
|
+ switch_benefit += min(adverse_count, 8) * 0.02
|
|
|
+ if adverse_distance is not None and adverse_distance <= 1.25:
|
|
|
+ switch_benefit += 0.08
|
|
|
+ stay_cost += min(adverse_notional_ratio, 4.0) * 0.07
|
|
|
+ else:
|
|
|
+ adverse_notional_ratio = 0.0
|
|
|
+
|
|
|
if inventory_state == "balanced":
|
|
|
stay_cost += 0.06
|
|
|
elif inventory_state in {"base_heavy", "quote_heavy"}:
|
|
|
@@ -755,6 +776,8 @@ def _grid_switch_tradeoff(*,
|
|
|
stay_cost += 0.18
|
|
|
if not persistent:
|
|
|
stay_cost += 0.12
|
|
|
+ if adverse_notional_ratio >= 1.0:
|
|
|
+ stay_cost += 0.08
|
|
|
|
|
|
margin = round(switch_benefit - stay_cost, 4)
|
|
|
should_switch = persistent and trend_ready and margin > 0.0
|
|
|
@@ -771,6 +794,10 @@ def _grid_switch_tradeoff(*,
|
|
|
"open_order_count": open_order_count,
|
|
|
"near_fill": near_fill,
|
|
|
"fill_fights": fill_fights,
|
|
|
+ "adverse_side": adverse_side,
|
|
|
+ "adverse_side_open_order_count": adverse_count,
|
|
|
+ "adverse_side_open_order_notional_quote": round(adverse_notional, 4),
|
|
|
+ "adverse_side_nearest_distance_pct": round(adverse_distance, 4) if adverse_distance is not None else None,
|
|
|
"inventory_state": inventory_state,
|
|
|
}
|
|
|
|
|
|
@@ -895,6 +922,10 @@ def _decide_for_grid(*,
|
|
|
action = "replace_with_trend_follower"
|
|
|
target_strategy = trend["strategy_id"]
|
|
|
mode = "act"
|
|
|
+ if switch_tradeoff.get("adverse_side_open_order_count", 0) > 0:
|
|
|
+ reasons.append(
|
|
|
+ f"{switch_tradeoff.get('adverse_side')} ladder is exposed near market"
|
|
|
+ )
|
|
|
if directional_inventory:
|
|
|
reasons.append("inventory posture can be absorbed by the directional handoff")
|
|
|
reasons.append(
|
|
|
@@ -917,6 +948,10 @@ def _decide_for_grid(*,
|
|
|
reasons.append(
|
|
|
f"breakout is persistent, but staying in grid still looks cheaper than switching (benefit {switch_tradeoff['switch_benefit']:.2f} vs cost {switch_tradeoff['stay_cost']:.2f})"
|
|
|
)
|
|
|
+ if switch_tradeoff.get("adverse_side_open_order_count", 0) > 0:
|
|
|
+ reasons.append(
|
|
|
+ f"{switch_tradeoff.get('adverse_side')} ladder exposure is not yet costly enough to justify the handoff"
|
|
|
+ )
|
|
|
if grid_fill.get("near_fill") and fill_fights_breakout:
|
|
|
reasons.append("nearby opposing fill is only a warning here, not enough on its own to justify the handoff")
|
|
|
else:
|