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
27 changes: 5 additions & 22 deletions application/runtime_strategy_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from dataclasses import dataclass
from typing import Any

from quant_platform_kit.common.runtime_inputs import build_semiconductor_rotation_indicators_from_history
from quant_platform_kit.strategy_contracts import build_account_state_from_portfolio_snapshot


Expand Down Expand Up @@ -119,29 +120,11 @@ def build_semiconductor_indicators(self, market_data_source, *, trend_window: in
if len(soxx_history) < trend_window:
raise RuntimeError(f"SOXX history has {len(soxx_history)} candles; need at least {trend_window}")

soxl_closes = [float(candle["close"]) for candle in soxl_history[-trend_window:]]
soxx_all_closes = [float(candle["close"]) for candle in soxx_history]
soxx_trend_closes = soxx_all_closes[-trend_window:]
soxx_ma20_closes = soxx_all_closes[-20:]
previous_soxx_ma20_closes = soxx_all_closes[-21:-1]
soxx_ma20 = sum(soxx_ma20_closes) / 20
previous_soxx_ma20 = (
sum(previous_soxx_ma20_closes) / 20
if len(previous_soxx_ma20_closes) == 20
else soxx_ma20
return build_semiconductor_rotation_indicators_from_history(
soxl_history=(float(candle["close"]) for candle in soxl_history),
soxx_history=(float(candle["close"]) for candle in soxx_history),
trend_ma_window=trend_window,
)
return {
"soxl": {
"price": soxl_closes[-1],
"ma_trend": sum(soxl_closes) / trend_window,
},
"soxx": {
"price": soxx_all_closes[-1],
"ma_trend": sum(soxx_trend_closes) / trend_window,
"ma20": soxx_ma20,
"ma20_slope": soxx_ma20 - previous_soxx_ma20,
},
}

def build_account_state_from_snapshot(self, snapshot) -> dict[str, object]:
return build_account_state_from_portfolio_snapshot(
Expand Down
10 changes: 10 additions & 0 deletions notifications/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
"market_status_blend_gate_defensive": "🛡️ 降杠杆({asset})",
"signal_blend_gate_risk_on": "{trend_symbol} 站上 {window} 日门槛线,持有 SOXL {soxl_ratio} + SOXX {soxx_ratio}",
"signal_blend_gate_defensive": "{trend_symbol} 跌破门槛线,防守持有 SOXX {soxx_ratio}",
"market_status_blend_gate_overlay_capped": "🧯 过热降档({asset})",
"signal_blend_gate_overlay_capped": "{trend_symbol} 仍在 {window} 日门槛线上方,但触发过热降档({reasons}),目标仓位 {allocation_text}",
"blend_gate_reason_rsi_cap": "RSI 超阈值",
"blend_gate_reason_bollinger_cap": "突破布林上轨",
"blend_gate_reason_volatility_delever": "{symbol} {window} 日年化波动率 {volatility} 高于 {threshold},SOXL 转向 {redirect_symbol}",
"limit_buy": "限价买入",
"market_buy": "市价买入",
"market_sell": "市价卖出",
Expand Down Expand Up @@ -128,6 +133,11 @@
"market_status_blend_gate_defensive": "🛡️ DE-LEVER ({asset})",
"signal_blend_gate_risk_on": "{trend_symbol} above {window}d gated entry, hold SOXL {soxl_ratio} + SOXX {soxx_ratio}",
"signal_blend_gate_defensive": "{trend_symbol} below gated entry, hold defensive SOXX {soxx_ratio}",
"market_status_blend_gate_overlay_capped": "🧯 HEAT-CAP ({asset})",
"signal_blend_gate_overlay_capped": "{trend_symbol} stays above the {window}d gate, but overlay cap ({reasons}) cuts exposure to {allocation_text}",
"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}",
"limit_buy": "Limit Buy",
"market_buy": "Market Buy",
"market_sell": "Market Sell",
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
flask
gunicorn
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@573fc9e9917cf1f2c1acda9232c5a23a8a05d797
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@53911cbe32f6932e759522e54aa38ca5350aa44e
quant-platform-kit @ git+https://github.com/QuantStrategyLab/QuantPlatformKit.git@8769362096227320bc05c791b5244d4b3e88db50
us-equity-strategies @ git+https://github.com/QuantStrategyLab/UsEquityStrategies.git@ed55a6af0245323dbed82060e89be96d8f77f756
pandas
requests
pandas_market_calendars
Expand Down
11 changes: 11 additions & 0 deletions tests/test_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ def test_build_translator_supports_chinese(self):
),
"SOXX 站上 140 日门槛线,持有 SOXL 70.0% + SOXX 20.0%",
)
self.assertEqual(
translate(
"blend_gate_reason_volatility_delever",
symbol="SOXX",
window=20,
volatility="55.0%",
threshold="50.0%",
redirect_symbol="SOXX",
),
"SOXX 20 日年化波动率 55.0% 高于 50.0%,SOXL 转向 SOXX",
)
self.assertEqual(
translate(
"small_account_warning_note",
Expand Down
6 changes: 6 additions & 0 deletions tests/test_request_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@ def fake_history(_client, symbol):
self.assertAlmostEqual(indicators["soxx"]["ma_trend"], sum(210.0 + idx for idx in range(10, 160)) / 150)
self.assertAlmostEqual(indicators["soxx"]["ma20"], sum(210.0 + idx for idx in range(140, 160)) / 20)
self.assertGreater(indicators["soxx"]["ma20_slope"], 0.0)
self.assertEqual(indicators["soxx"]["rsi14"], 100.0)
self.assertIn("realized_volatility_20", indicators["soxx"])
self.assertEqual(
indicators["soxx"]["realized_volatility"],
indicators["soxx"]["realized_volatility_20"],
)


if __name__ == "__main__":
Expand Down