|
|
@@ -588,6 +588,82 @@ def test_make_decision_argus_compression_stays_context_only():
|
|
|
assert decision.payload["argus_decision_context"]["compression_active"] is True
|
|
|
|
|
|
|
|
|
+def test_make_decision_keeps_grid_when_1m_and_5m_trend_is_only_partial_confirmation():
|
|
|
+ concern = {"id": "c1", "account_id": "a1", "market_symbol": "xrpusd", "base_currency": "XRP", "quote_currency": "USD"}
|
|
|
+ narrative = {
|
|
|
+ "stance": "constructive_bullish",
|
|
|
+ "confidence": 0.91,
|
|
|
+ "opportunity_map": {"continuation": 0.9, "mean_reversion": 0.03, "reversal": 0.02, "wait": 0.05},
|
|
|
+ "features_by_timeframe": {
|
|
|
+ "1m": {
|
|
|
+ "raw": {"price": 1.4334},
|
|
|
+ "trend": {"alignment": "mixed", "strength": 0.12, "bias_score": 0.49},
|
|
|
+ "momentum": {"impulse": "high"},
|
|
|
+ },
|
|
|
+ "5m": {
|
|
|
+ "raw": {"price": 1.4334},
|
|
|
+ "trend": {"alignment": "bullish_pullback", "strength": 0.32, "bias_score": 1.30},
|
|
|
+ "momentum": {"impulse": "medium"},
|
|
|
+ },
|
|
|
+ "15m": {
|
|
|
+ "raw": {"price": 1.4334},
|
|
|
+ "trend": {"alignment": "bullish_pullback", "strength": 0.38, "bias_score": 1.51},
|
|
|
+ "momentum": {"impulse": "medium"},
|
|
|
+ },
|
|
|
+ "1h": {
|
|
|
+ "raw": {"price": 1.4312},
|
|
|
+ "trend": {"alignment": "fully_bullish", "strength": 0.71, "bias_score": 2.83},
|
|
|
+ "momentum": {"impulse": "medium"},
|
|
|
+ },
|
|
|
+ "4h": {
|
|
|
+ "raw": {"price": 1.4308},
|
|
|
+ "trend": {"alignment": "fully_bullish", "strength": 1.0, "bias_score": 4.64},
|
|
|
+ "momentum": {"impulse": "low"},
|
|
|
+ },
|
|
|
+ "1d": {
|
|
|
+ "raw": {"price": 1.4311},
|
|
|
+ "trend": {"alignment": "bearish_pullback", "strength": 0.28, "bias_score": -1.13},
|
|
|
+ "momentum": {"impulse": "medium"},
|
|
|
+ },
|
|
|
+ },
|
|
|
+ "scoped_state": {
|
|
|
+ "micro": {"impulse": "mixed", "trend_bias": "bullish", "location": "upper_half", "reversal_risk": "low"},
|
|
|
+ "meso": {"structure": "trend_continuation", "momentum_bias": "bullish"},
|
|
|
+ "macro": {"bias": "bullish"},
|
|
|
+ },
|
|
|
+ "cross_scope_summary": {"alignment": "micro_meso_macro_aligned", "friction": "low"},
|
|
|
+ "decision_inputs": {
|
|
|
+ "structural_direction": "bullish",
|
|
|
+ "structural_trend_strength": 0.9,
|
|
|
+ "tactical_direction": "bullish",
|
|
|
+ "tactical_trend_strength": 0.55,
|
|
|
+ "tactical_range_quality": 0.0,
|
|
|
+ "tactical_easing": False,
|
|
|
+ "micro_location": "upper_half",
|
|
|
+ "micro_atr_percent": 0.0606,
|
|
|
+ "micro_bollinger_width_pct": 0.2976,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ wallet_state = {
|
|
|
+ "inventory_state": "base_heavy",
|
|
|
+ "rebalance_needed": True,
|
|
|
+ "grid_ready": False,
|
|
|
+ "base_ratio": 0.7481,
|
|
|
+ "quote_ratio": 0.2519,
|
|
|
+ }
|
|
|
+ strategies = [
|
|
|
+ {"id": "grid-1", "strategy_type": "grid_trader", "mode": "active", "account_id": "a1", "state": {"center_price": 1.4293}, "config": {"grid_step_pct": 0.0125}},
|
|
|
+ {"id": "trend-1", "strategy_type": "trend_follower", "mode": "off", "account_id": "a1", "state": {}, "config": {}},
|
|
|
+ {"id": "protect-1", "strategy_type": "exposure_protector", "mode": "off", "account_id": "a1", "state": {}, "config": {}},
|
|
|
+ ]
|
|
|
+
|
|
|
+ decision = make_decision(concern=concern, narrative_payload=narrative, wallet_state=wallet_state, strategies=strategies)
|
|
|
+
|
|
|
+ assert decision.action == "keep_grid"
|
|
|
+ assert decision.target_strategy == "grid-1"
|
|
|
+ assert decision.payload["grid_switch_tradeoff"]["short_term_trend_score"] < 0.68
|
|
|
+
|
|
|
+
|
|
|
def test_make_decision_promotes_developing_breakout_from_time_window_memory():
|
|
|
concern = {"id": "c1", "account_id": "a1", "market_symbol": "xrpusd", "base_currency": "XRP", "quote_currency": "USD"}
|
|
|
narrative = {
|
|
|
@@ -934,6 +1010,78 @@ def test_make_decision_replaces_trend_with_rebalancer_on_edge_cooling_even_befor
|
|
|
assert decision.target_strategy == "protect-1"
|
|
|
|
|
|
|
|
|
+def test_make_decision_replaces_trend_with_rebalancer_when_1m_and_5m_dislocate_from_higher_trends():
|
|
|
+ concern = {"id": "c1", "account_id": "a1", "market_symbol": "xrpusd", "base_currency": "XRP", "quote_currency": "USD"}
|
|
|
+ narrative = {
|
|
|
+ "stance": "constructive_bullish",
|
|
|
+ "confidence": 0.76,
|
|
|
+ "opportunity_map": {"continuation": 0.6, "mean_reversion": 0.12, "reversal": 0.08, "wait": 0.2},
|
|
|
+ "scoped_state": {
|
|
|
+ "micro": {"impulse": "up", "trend_bias": "bullish", "location": "near_upper_band", "reversal_risk": "low"},
|
|
|
+ "meso": {"structure": "trend_continuation", "momentum_bias": "bullish"},
|
|
|
+ "macro": {"bias": "bullish"},
|
|
|
+ },
|
|
|
+ "cross_scope_summary": {"alignment": "partial_alignment", "friction": "medium"},
|
|
|
+ "features_by_timeframe": {
|
|
|
+ "1m": {"trend": {"bias_score": 0.82, "alignment": "fully_bullish"}, "momentum": {"impulse": "up"}},
|
|
|
+ "5m": {"trend": {"bias_score": -0.74, "alignment": "fully_bearish"}, "momentum": {"impulse": "down"}},
|
|
|
+ "15m": {"trend": {"bias_score": 0.66, "alignment": "fully_bullish"}, "momentum": {"impulse": "up"}},
|
|
|
+ "1h": {"trend": {"bias_score": 0.7, "alignment": "fully_bullish"}, "momentum": {"impulse": "up"}},
|
|
|
+ },
|
|
|
+ }
|
|
|
+ wallet_state = {
|
|
|
+ "inventory_state": "base_heavy",
|
|
|
+ "rebalance_needed": True,
|
|
|
+ "grid_ready": False,
|
|
|
+ "base_ratio": 0.74,
|
|
|
+ "quote_ratio": 0.26,
|
|
|
+ }
|
|
|
+ strategies = [
|
|
|
+ {"id": "trend-1", "strategy_type": "trend_follower", "mode": "active", "account_id": "a1", "state": {}, "config": {}},
|
|
|
+ {"id": "protect-1", "strategy_type": "exposure_protector", "mode": "off", "account_id": "a1", "state": {}, "config": {}},
|
|
|
+ ]
|
|
|
+ decision = make_decision(concern=concern, narrative_payload=narrative, wallet_state=wallet_state, strategies=strategies)
|
|
|
+ assert decision.mode == "act"
|
|
|
+ assert decision.action == "replace_with_exposure_protector"
|
|
|
+ assert decision.target_strategy == "protect-1"
|
|
|
+
|
|
|
+
|
|
|
+def test_make_decision_replaces_trend_with_rebalancer_when_short_tape_is_mixed_and_inventory_is_base_heavy():
|
|
|
+ concern = {"id": "c1", "account_id": "a1", "market_symbol": "xrpusd", "base_currency": "XRP", "quote_currency": "USD"}
|
|
|
+ narrative = {
|
|
|
+ "stance": "constructive_bullish",
|
|
|
+ "confidence": 0.77,
|
|
|
+ "opportunity_map": {"continuation": 0.61, "mean_reversion": 0.12, "reversal": 0.08, "wait": 0.19},
|
|
|
+ "scoped_state": {
|
|
|
+ "micro": {"impulse": "mixed", "trend_bias": "mixed", "location": "lower_half", "reversal_risk": "low"},
|
|
|
+ "meso": {"structure": "trend_continuation", "momentum_bias": "bullish"},
|
|
|
+ "macro": {"bias": "bullish"},
|
|
|
+ },
|
|
|
+ "cross_scope_summary": {"alignment": "micro_meso_macro_aligned", "friction": "low"},
|
|
|
+ "features_by_timeframe": {
|
|
|
+ "1m": {"trend": {"bias_score": -0.12, "alignment": "mixed"}, "momentum": {"impulse": "medium"}},
|
|
|
+ "5m": {"trend": {"bias_score": 0.88, "alignment": "bullish_pullback"}, "momentum": {"impulse": "low"}},
|
|
|
+ "15m": {"trend": {"bias_score": 0.95, "alignment": "bullish_pullback"}, "momentum": {"impulse": "low"}},
|
|
|
+ "1h": {"trend": {"bias_score": 2.6, "alignment": "fully_bullish"}, "momentum": {"impulse": "medium"}},
|
|
|
+ },
|
|
|
+ }
|
|
|
+ wallet_state = {
|
|
|
+ "inventory_state": "depleted_quote_side",
|
|
|
+ "rebalance_needed": True,
|
|
|
+ "grid_ready": False,
|
|
|
+ "base_ratio": 0.99,
|
|
|
+ "quote_ratio": 0.01,
|
|
|
+ }
|
|
|
+ strategies = [
|
|
|
+ {"id": "trend-1", "strategy_type": "trend_follower", "mode": "active", "account_id": "a1", "state": {}, "config": {}},
|
|
|
+ {"id": "protect-1", "strategy_type": "exposure_protector", "mode": "off", "account_id": "a1", "state": {}, "config": {}},
|
|
|
+ ]
|
|
|
+ decision = make_decision(concern=concern, narrative_payload=narrative, wallet_state=wallet_state, strategies=strategies)
|
|
|
+ assert decision.mode == "act"
|
|
|
+ assert decision.action == "replace_with_exposure_protector"
|
|
|
+ assert decision.target_strategy == "protect-1"
|
|
|
+
|
|
|
+
|
|
|
def test_make_decision_replaces_trend_with_rebalancer_when_micro_reversal_risk_spikes():
|
|
|
concern = {"id": "c1", "account_id": "a1", "market_symbol": "xrpusd", "base_currency": "XRP", "quote_currency": "USD"}
|
|
|
narrative = {
|
|
|
@@ -988,6 +1136,40 @@ def test_make_decision_replaces_rebalancer_with_grid_when_balanced_and_rotationa
|
|
|
assert decision.target_strategy == "grid-1"
|
|
|
|
|
|
|
|
|
+def test_make_decision_replaces_rebalancer_with_grid_when_wallet_is_rebalanced_even_if_trend_is_still_hot():
|
|
|
+ concern = {"id": "c1", "account_id": "a1", "market_symbol": "xrpusd", "base_currency": "XRP", "quote_currency": "USD"}
|
|
|
+ narrative = {
|
|
|
+ "stance": "constructive_bullish",
|
|
|
+ "confidence": 0.84,
|
|
|
+ "opportunity_map": {"continuation": 0.82, "mean_reversion": 0.08, "reversal": 0.03, "wait": 0.07},
|
|
|
+ "scoped_state": {
|
|
|
+ "micro": {"impulse": "up", "trend_bias": "bullish", "location": "near_upper_band", "reversal_risk": "low"},
|
|
|
+ "meso": {"structure": "trend_continuation", "momentum_bias": "bullish"},
|
|
|
+ "macro": {"bias": "bullish"},
|
|
|
+ },
|
|
|
+ "cross_scope_summary": {"alignment": "micro_meso_macro_aligned", "friction": "low"},
|
|
|
+ }
|
|
|
+ wallet_state = {
|
|
|
+ "inventory_state": "balanced",
|
|
|
+ "rebalance_needed": False,
|
|
|
+ "grid_ready": True,
|
|
|
+ "base_ratio": 0.61,
|
|
|
+ "quote_ratio": 0.39,
|
|
|
+ }
|
|
|
+ strategies = [
|
|
|
+ {"id": "protect-1", "strategy_type": "exposure_protector", "mode": "active", "account_id": "a1", "state": {}, "config": {}},
|
|
|
+ {"id": "grid-1", "strategy_type": "grid_trader", "mode": "off", "account_id": "a1", "state": {}, "config": {}, "report": {"supervision": {"capacity_available": True, "side_capacity": {"buy": True, "sell": True}, "inventory_pressure": "balanced", "degraded": False}}},
|
|
|
+ {"id": "trend-1", "strategy_type": "trend_follower", "mode": "off", "account_id": "a1", "state": {}, "config": {}, "report": {"supervision": {"capacity_available": True, "trend_strength": 0.94, "inventory_pressure": "balanced", "degraded": False}}},
|
|
|
+ ]
|
|
|
+
|
|
|
+ decision = make_decision(concern=concern, narrative_payload=narrative, wallet_state=wallet_state, strategies=strategies)
|
|
|
+
|
|
|
+ assert decision.mode == "act"
|
|
|
+ assert decision.action == "replace_with_grid"
|
|
|
+ assert decision.target_strategy == "grid-1"
|
|
|
+ assert "rebalanced" in decision.reason_summary
|
|
|
+
|
|
|
+
|
|
|
def test_make_decision_replaces_rebalancer_with_grid_when_within_tolerance_even_before_perfect_balance():
|
|
|
concern = {"id": "c1", "account_id": "a1", "market_symbol": "xrpusd", "base_currency": "XRP", "quote_currency": "USD"}
|
|
|
narrative = {
|