alphax/tests/test_market_regime.py
2026-06-06 17:52:29 +08:00

172 lines
5.9 KiB
Python

from app.core.market_regime import classify_market_regime
from app.core.global_risk import evaluate_global_risk
def _overview(**overrides):
data = {
"sample_count": 200,
"benchmarks": {
"BTC/USDT": {"change_24h": 0.5},
"ETH/USDT": {"change_24h": 0.4},
},
"advance_decline_ratio": 1.0,
"avg_change_24h": 0.1,
"hot_count_5pct": 8,
"crash_count_5pct": 4,
"funding": {"avg_funding_rate": 0.0001, "extreme_positive_count": 2},
}
data.update(overrides)
return data
def test_market_regime_reduces_size_for_clear_risk_off():
result = classify_market_regime(
_overview(
benchmarks={"BTC/USDT": {"change_24h": -3.4}, "ETH/USDT": {"change_24h": -4.2}},
advance_decline_ratio=0.4,
crash_count_5pct=35,
)
)
assert result["regime"] == "risk_off"
assert result["risk_level"] == "critical"
assert result["position_multiplier"] == 0.25
def test_market_regime_detects_altcoin_rotation():
result = classify_market_regime(
_overview(
benchmarks={"BTC/USDT": {"change_24h": 0.6}, "ETH/USDT": {"change_24h": 1.1}},
advance_decline_ratio=1.4,
avg_change_24h=1.2,
hot_count_5pct=22,
crash_count_5pct=3,
)
)
assert result["regime"] == "altcoin_rotation"
assert result["risk_level"] == "medium"
def test_global_risk_blocks_same_sector_concentration(pg_conn, monkeypatch):
monkeypatch.setattr(
"app.core.global_risk.get_crypto_market_overview",
lambda allow_live_fallback=False: _overview(),
)
pg_conn.execute(
"""
INSERT INTO paper_trades (
recommendation_id, symbol, side, status, opened_at, entry_price, qty,
notional_usdt, current_price, pnl_pct, created_at, updated_at
) VALUES
(1, 'DOGE/USDT', 'long', 'open', '2026-05-23T10:00:00', 1, 100, 1000, 1, 0, '2026-05-23T10:00:00', '2026-05-23T10:00:00'),
(2, 'SHIB/USDT', 'long', 'open', '2026-05-23T10:00:00', 1, 100, 1000, 1, 0, '2026-05-23T10:00:00', '2026-05-23T10:00:00')
"""
)
pg_conn.commit()
result = evaluate_global_risk(
conn=pg_conn,
config={
"account_equity_usdt": 20000,
"global_risk_max_same_sector_positions": 2,
"global_risk_max_same_direction_positions": 10,
},
rec={"symbol": "PEPE/USDT", "sector": "MEME"},
additional_notional=1000,
)
assert result["allow_new_entries"] is False
assert result["decision"] == "block_same_sector_concentration"
def test_global_risk_off_is_favorable_for_short_entries(pg_conn, monkeypatch):
monkeypatch.setattr(
"app.core.global_risk.get_crypto_market_overview",
lambda allow_live_fallback=False: _overview(
benchmarks={"BTC/USDT": {"change_24h": -3.4}, "ETH/USDT": {"change_24h": -4.2}},
advance_decline_ratio=0.4,
crash_count_5pct=35,
),
)
result = evaluate_global_risk(
conn=pg_conn,
config={
"account_equity_usdt": 20000,
"global_risk_gate_enabled": True,
"global_risk_block_critical": False,
"global_risk_critical_min_rec_score": 80,
},
rec={"symbol": "SHORT/USDT", "side": "short", "rec_score": 55},
additional_notional=1000,
)
assert result["allow_new_entries"] is True
assert result["side"] == "short"
assert result["risk_level"] == "medium"
assert result["directional_market_bias"]["market_bias"] == "favorable"
assert "risk_off 对空头属于顺风环境" in " ".join(result["reasons"])
def test_intraday_global_risk_softens_risk_off_for_low_score_long(pg_conn, monkeypatch):
monkeypatch.setattr(
"app.core.global_risk.get_crypto_market_overview",
lambda allow_live_fallback=False: _overview(
benchmarks={"BTC/USDT": {"change_24h": -3.4}, "ETH/USDT": {"change_24h": -4.2}},
advance_decline_ratio=0.4,
crash_count_5pct=35,
),
)
result = evaluate_global_risk(
conn=pg_conn,
config={
"trading_mode": "intraday_trading",
"account_equity_usdt": 20000,
"global_risk_gate_enabled": True,
"global_risk_block_critical": False,
"global_risk_score_blocks_intraday": False,
"global_risk_critical_min_rec_score": 80,
"global_risk_high_min_rec_score": 70,
},
rec={"symbol": "LONG/USDT", "side": "long", "rec_score": 28},
additional_notional=1000,
)
assert result["allow_new_entries"] is True
assert result["decision"] == "allow_reduced_size"
assert result["risk_level"] == "critical"
assert result["intraday_soft_risk"] is True
assert result["position_multiplier"] == 0.25
assert "日内模式下 critical 市场风险只做仓位调节" in " ".join(result["reasons"])
def test_altcoin_rotation_is_adverse_for_short_entries(pg_conn, monkeypatch):
monkeypatch.setattr(
"app.core.global_risk.get_crypto_market_overview",
lambda allow_live_fallback=False: _overview(
benchmarks={"BTC/USDT": {"change_24h": 0.6}, "ETH/USDT": {"change_24h": 1.1}},
advance_decline_ratio=1.4,
avg_change_24h=1.2,
hot_count_5pct=22,
crash_count_5pct=3,
),
)
result = evaluate_global_risk(
conn=pg_conn,
config={
"account_equity_usdt": 20000,
"global_risk_gate_enabled": True,
"global_risk_high_min_rec_score": 70,
},
rec={"symbol": "SQUEEZE/USDT", "side": "short", "rec_score": 55},
additional_notional=1000,
)
assert result["allow_new_entries"] is False
assert result["risk_level"] == "high"
assert result["decision"] == "block_high_weak_score"
assert result["directional_market_bias"]["market_bias"] == "adverse"