Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions application/signal_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@
"trend_rsi14_dynamic_threshold",
"trend_rsi14_effective_threshold",
"trend_bb_upper",
"blend_gate_volatility_delever_symbol",
"blend_gate_volatility_delever_window",
"blend_gate_volatility_delever_threshold_mode",
"blend_gate_volatility_delever_threshold",
"blend_gate_volatility_delever_dynamic_threshold",
"blend_gate_volatility_delever_dynamic_sample_count",
"blend_gate_volatility_delever_dynamic_lookback",
"blend_gate_volatility_delever_dynamic_percentile",
"blend_gate_volatility_delever_dynamic_min_periods",
"blend_gate_volatility_delever_dynamic_floor",
"blend_gate_volatility_delever_dynamic_cap",
"blend_gate_volatility_delever_metric",
"blend_gate_volatility_delever_triggered",
)
Expand Down
8 changes: 8 additions & 0 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
"blend_gate_reason_rsi_cap": "RSI 超阈值",
"blend_gate_reason_bollinger_cap": "突破布林上轨",
"blend_gate_reason_volatility_delever": "{symbol} {window} 日年化波动率 {volatility} 高于 {threshold},SOXL 转向 {redirect_symbol}",
"blend_gate_reason_volatility_delever_dynamic": "{symbol} {window} 日年化波动率 {volatility} 高于实际阈值 {threshold}({threshold_detail}),SOXL 转向 {redirect_symbol}",
"blend_gate_volatility_threshold_detail_dynamic": "动态 {percentile},{lookback}日窗口,范围 {floor}-{cap},样本 {sample_count}",
"blend_gate_volatility_threshold_detail_dynamic_fallback": "动态样本不足,回退固定 {fixed_threshold}(样本 {sample_count}/{min_periods},{percentile})",
"blend_gate_volatility_threshold_detail_fixed": "固定阈值 {threshold}",
"strategy_plugin_line": "🧩 插件:{plugin} | 状态:{route} | 提醒:{action}",
"strategy_plugin_alert_subject": "🚨 策略插件告警:{plugin} | {route}",
"strategy_plugin_alert_title": "🚨 【策略插件告警】",
Expand Down Expand Up @@ -223,6 +227,10 @@
"blend_gate_reason_rsi_cap": "RSI over threshold",
"blend_gate_reason_bollinger_cap": "price above upper band",
"blend_gate_reason_volatility_delever": "{symbol} {window}d annualized volatility {volatility} is above {threshold}; redirect SOXL to {redirect_symbol}",
"blend_gate_reason_volatility_delever_dynamic": "{symbol} {window}d annualized volatility {volatility} is above effective threshold {threshold} ({threshold_detail}); redirect SOXL to {redirect_symbol}",
"blend_gate_volatility_threshold_detail_dynamic": "dynamic {percentile}, {lookback}d lookback, bounded {floor}-{cap}, samples {sample_count}",
"blend_gate_volatility_threshold_detail_dynamic_fallback": "dynamic warm-up, fallback fixed {fixed_threshold} (samples {sample_count}/{min_periods}, {percentile})",
"blend_gate_volatility_threshold_detail_fixed": "fixed threshold {threshold}",
"strategy_plugin_line": "🧩 Plugin: {plugin} | status: {route} | notice: {action}",
"strategy_plugin_alert_subject": "🚨 Strategy plugin alert: {plugin} | {route}",
"strategy_plugin_alert_title": "🚨 【Strategy Plugin Alert】",
Expand Down
39 changes: 39 additions & 0 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,45 @@ def test_build_translator_supports_chinese():
)
== "SOXX 10 日年化波动率 55.0% 高于 50.0%,SOXL 转向 SOXX"
)
assert (
translate(
"blend_gate_reason_volatility_delever_dynamic",
symbol="SOXX",
window=10,
volatility="61.0%",
threshold="60.0%",
threshold_detail=translate(
"blend_gate_volatility_threshold_detail_dynamic",
percentile="p95",
lookback="252",
floor="50.0%",
cap="75.0%",
sample_count="252",
),
redirect_symbol="SOXX",
)
== "SOXX 10 日年化波动率 61.0% 高于实际阈值 60.0%(动态 p95,252日窗口,范围 50.0%-75.0%,样本 252),SOXL 转向 SOXX"
)
en_translate = build_translator("en")
assert (
en_translate(
"blend_gate_reason_volatility_delever_dynamic",
symbol="SOXX",
window=10,
volatility="61.0%",
threshold="60.0%",
threshold_detail=en_translate(
"blend_gate_volatility_threshold_detail_dynamic",
percentile="p95",
lookback="252",
floor="50.0%",
cap="75.0%",
sample_count="252",
),
redirect_symbol="SOXX",
)
== "SOXX 10d annualized volatility 61.0% is above effective threshold 60.0% (dynamic p95, 252d lookback, bounded 50.0%-75.0%, samples 252); redirect SOXL to SOXX"
)
assert (
translate(
"strategy_plugin_line",
Expand Down
23 changes: 23 additions & 0 deletions tests/test_signal_snapshot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from application.signal_snapshot import build_signal_snapshot


def test_includes_soxl_dynamic_volatility_fields():
snapshot = build_signal_snapshot(
platform="ibkr",
strategy_profile="soxl_soxx_trend_income",
execution={
"blend_gate_volatility_delever_threshold_mode": "rolling_percentile",
"blend_gate_volatility_delever_threshold": 0.60,
"blend_gate_volatility_delever_dynamic_threshold": 0.60,
"blend_gate_volatility_delever_dynamic_sample_count": 252,
"blend_gate_volatility_delever_dynamic_percentile": 0.95,
"blend_gate_volatility_delever_metric": 0.61,
"blend_gate_volatility_delever_triggered": True,
},
)

indicators = snapshot["indicators"]
assert indicators["blend_gate_volatility_delever_threshold_mode"] == "rolling_percentile"
assert indicators["blend_gate_volatility_delever_dynamic_threshold"] == 0.60
assert indicators["blend_gate_volatility_delever_dynamic_sample_count"] == 252
assert indicators["blend_gate_volatility_delever_triggered"] is True
2 changes: 1 addition & 1 deletion tests/test_strategy_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def test_load_strategy_entrypoint_for_profile_resolves_tqqq_growth_income(monkey
assert entrypoint.manifest.default_config["benchmark_symbol"] == "QQQ"
assert entrypoint.manifest.default_config["managed_symbols"] == (
"TQQQ",
"QQQ",
"QQQM",
"BOXX",
"SCHD",
"DGRO",
Expand Down