From 3ec5460207e795e4fc7fe312357eb7deceea3574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9F=A5=E5=BE=AE?= Date: Wed, 24 Jun 2026 11:01:53 +0800 Subject: [PATCH] =?UTF-8?q?stale=5Fpush=5Fwlin:=2030=E5=88=86=E9=92=9F?= =?UTF-8?q?=E5=90=8C=E8=82=A1=E5=90=8C=E6=93=8D=E4=BD=9C=E5=86=B7=E5=8D=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit push_cooldown.json 记录每只股票每种操作的最后推送时间。 每次推送前检查 (code, action_type) 是否在30分钟内推过。 是 → 跳过该股(不出现在推送中) 全部跳过 → 整条消息静默不推 冷却键: {code}_{action_type}(如 300308_buy、688639_buy) 不同操作不受限:同一只股 买入→止损 隔10分钟也能推 不同股票不受限:华恒的buy不影响中际的buy 同步修复:港股每手股数香港股数(之前patch到旧文件没生效) --- data/decisions.json | 162 ++++++++++++++++++------------------- data/portfolio.json | 80 +++++++++--------- data/price_history.json | 12 +-- scripts/stale_push_wlin.py | 93 +++++++++++++++++---- 4 files changed, 203 insertions(+), 144 deletions(-) diff --git a/data/decisions.json b/data/decisions.json index 6760f81..5a79055 100644 --- a/data/decisions.json +++ b/data/decisions.json @@ -147,7 +147,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" } @@ -226,7 +226,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -494,9 +494,9 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 0, + "trigger_count": 1, "success_rate": null, - "last_triggered": null + "last_triggered": "2026-06-24" } ], "last_evaluated": "2026-06-24T10:23:51.378572" @@ -705,7 +705,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" } @@ -716,17 +716,17 @@ { "code": "002594", "name": "比亚迪", - "price": 82.81, + "price": 82.93, "cost": 0, "shares": 0, "avg_price": 0, - "action": "盈利持有 | 目标92.54 | 止损80.33 | 买入区81.15~84.47 | 信号:观望", - "stop_loss": 80.33, - "entry_low": 81.15, - "entry_high": 84.47, - "tech_snapshot": "形态:光头光脚阴线/bearish 量价:主动卖盘占优 强撑:76.5 弱撑:82.17 弱压:85.0 强压:92.54", + "action": "盈利持有 | 目标92.59 | 止损80.44 | 买入区81.27~84.59 | 信号:观望", + "stop_loss": 80.44, + "entry_low": 81.27, + "entry_high": 84.59, + "tech_snapshot": "形态:光头光脚阴线/bearish 量价:主动卖盘占优 强撑:76.5 弱撑:82.24 弱压:85.0 强压:92.59", "timing_signal": "观望", - "rr_ratio": 3.92, + "rr_ratio": 3.88, "status": "updated", "note": "", "timestamp": "2026-06-24 09:00", @@ -738,7 +738,7 @@ "position_advice": "减仓或观望", "time_horizon": "观望", "created_at": "2026-06-18 17:15", - "take_profit": 92.54, + "take_profit": 92.59, "updated_reason": "技术信号变化: 大盘中性,行业偏弱,蓝筹,放量下跌,等企稳再入: 止损83.36→79.15 | 形态:带上影阴线/bearish 量价:主动卖盘占优 强撑:78.83 弱撑:83.73 弱压:87.59 强压:93.", "changelog": [ { @@ -824,7 +824,7 @@ { "id": "002594_stop_loss", "condition": { - "price": "<80.33" + "price": "<80.44" }, "action": { "type": "sell", @@ -841,13 +841,13 @@ "id": "002594_buy_dip", "condition": { "scenario": "weak_consolidation", - "price": "<=84.47", - "price_lower": ">=81.15" + "price": "<=84.59", + "price_lower": ">=81.27" }, "action": { "type": "buy", "amount": "normal", - "limit": 81.15, + "limit": 81.27, "reason": "回调支撑买入" }, "priority": 1, @@ -860,7 +860,7 @@ "id": "002594_breakout_chase", "condition": { "scenario": "bullish_recovery", - "price": ">=92.54" + "price": ">=92.59" }, "action": { "type": "buy", @@ -894,7 +894,7 @@ { "id": "002594_take_profit", "condition": { - "price": ">=92.54" + "price": ">=92.59" }, "action": { "type": "sell", @@ -4831,7 +4831,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -4906,17 +4906,17 @@ { "code": "300124", "name": "汇川技术", - "price": 65.86, + "price": 66.01, "cost": 0, "shares": 0, "avg_price": 0, - "action": "盈利持有 | 目标72.94 | 止损63.88 | 买入区64.54~67.18 | 信号:观望", - "stop_loss": 63.88, - "entry_low": 64.54, - "entry_high": 67.18, - "tech_snapshot": "形态:带上影阴线/bearish 量价:主动卖盘占优 强撑:59.82 弱撑:65.28 弱压:66.97 强压:72.94", + "action": "盈利持有 | 目标73.03 | 止损64.03 | 买入区64.69~67.33 | 信号:观望", + "stop_loss": 64.03, + "entry_low": 64.69, + "entry_high": 67.33, + "tech_snapshot": "形态:带上影阴线/bearish 量价:主动卖盘占优 强撑:59.79 弱撑:65.34 弱压:67.09 强压:73.03", "timing_signal": "观望", - "rr_ratio": 3.58, + "rr_ratio": 3.55, "status": "updated", "note": "", "timestamp": "2026-06-24 09:01", @@ -4928,7 +4928,7 @@ "position_advice": "减仓或观望", "time_horizon": "观望", "created_at": "2026-06-18 17:15", - "take_profit": 72.94, + "take_profit": 73.03, "updated_reason": "技术面重评: 止损65.78→64.82 | 形态:光头光脚阴线/bearish 量价:主动卖盘占优 强撑:61.61 弱撑:65.99 弱压:68.95 强压:73", "changelog": [ { @@ -5007,7 +5007,7 @@ { "id": "300124_stop_loss", "condition": { - "price": "<63.88" + "price": "<64.03" }, "action": { "type": "sell", @@ -5024,13 +5024,13 @@ "id": "300124_buy_dip", "condition": { "scenario": "weak_consolidation", - "price": "<=67.18", - "price_lower": ">=64.54" + "price": "<=67.33", + "price_lower": ">=64.69" }, "action": { "type": "buy", "amount": "normal", - "limit": 64.54, + "limit": 64.69, "reason": "回调支撑买入" }, "priority": 1, @@ -5043,7 +5043,7 @@ "id": "300124_breakout_chase", "condition": { "scenario": "bullish_recovery", - "price": ">=72.94" + "price": ">=73.03" }, "action": { "type": "buy", @@ -5077,7 +5077,7 @@ { "id": "300124_take_profit", "condition": { - "price": ">=72.94" + "price": ">=73.03" }, "action": { "type": "sell", @@ -5197,7 +5197,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -5382,9 +5382,9 @@ }, "priority": 0, "rationale": "止损保护本金", - "trigger_count": 0, + "trigger_count": 1, "success_rate": null, - "last_triggered": null + "last_triggered": "2026-06-24" }, { "id": "300548_buy_dip", @@ -5655,7 +5655,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 4, + "trigger_count": 5, "success_rate": null, "last_triggered": "2026-06-24" } @@ -5802,7 +5802,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -5978,7 +5978,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -6189,7 +6189,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 2, + "trigger_count": 3, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -6351,7 +6351,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 12, + "trigger_count": 13, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -6606,7 +6606,7 @@ }, "priority": 4, "rationale": "达到目标价,减半仓锁定利润", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -6759,7 +6759,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 2, + "trigger_count": 3, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -6834,17 +6834,17 @@ { "code": "601318", "name": "中国平安", - "price": 49.5, + "price": 49.67, "cost": 0, "shares": 0, "avg_price": 0, - "action": "盈利持有 | 目标53.57 | 止损48.02 | 买入区48.51~50.24 | 信号:观望", - "stop_loss": 48.02, - "entry_low": 48.51, - "entry_high": 50.24, - "tech_snapshot": "形态:光头光脚阴线/bearish 量价:主动卖盘占优 强撑:46.03 弱撑:48.71 弱压:50.56 强压:53.57", + "action": "盈利持有 | 目标53.63 | 止损48.18 | 买入区48.68~50.36 | 信号:观望", + "stop_loss": 48.18, + "entry_low": 48.68, + "entry_high": 50.36, + "tech_snapshot": "形态:带下影阴线/neutral 量价:主动卖盘占优 强撑:46.09 弱撑:48.84 弱压:50.69 强压:53.63", "timing_signal": "观望", - "rr_ratio": 2.75, + "rr_ratio": 2.66, "status": "updated", "note": "", "timestamp": "2026-06-24 09:01", @@ -6856,7 +6856,7 @@ "position_advice": "减仓或观望", "time_horizon": "观望", "created_at": "2026-06-22 11:50", - "take_profit": 53.57, + "take_profit": 53.63, "changelog": [ { "date": "2026-06-22 12:01", @@ -6885,7 +6885,7 @@ { "id": "601318_stop_loss", "condition": { - "price": "<48.02" + "price": "<48.18" }, "action": { "type": "sell", @@ -6902,13 +6902,13 @@ "id": "601318_buy_dip", "condition": { "scenario": "weak_consolidation", - "price": "<=50.24", - "price_lower": ">=48.51" + "price": "<=50.36", + "price_lower": ">=48.68" }, "action": { "type": "buy", "amount": "normal", - "limit": 48.51, + "limit": 48.68, "reason": "回调支撑买入" }, "priority": 1, @@ -6921,7 +6921,7 @@ "id": "601318_breakout_chase", "condition": { "scenario": "bullish_recovery", - "price": ">=53.57" + "price": ">=53.63" }, "action": { "type": "buy", @@ -6955,7 +6955,7 @@ { "id": "601318_take_profit", "condition": { - "price": ">=53.57" + "price": ">=53.63" }, "action": { "type": "sell", @@ -7117,7 +7117,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -7358,7 +7358,7 @@ }, "priority": 4, "rationale": "达到目标价,减半仓锁定利润", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -7505,7 +7505,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" } @@ -7716,7 +7716,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" } @@ -7856,7 +7856,7 @@ }, "priority": 1, "rationale": "价格回调到支撑区,弱势市场低吸", - "trigger_count": 5, + "trigger_count": 6, "success_rate": null, "last_triggered": "2026-06-24" }, @@ -7931,17 +7931,17 @@ { "code": "688795", "name": "摩尔线程-U", - "price": 676.41, + "price": 677.98, "cost": 0, "shares": 0, "avg_price": 0, - "action": "盈利持有 | 目标816.12 | 止损656.12 | 买入区662.88~689.94 | 信号:观望", - "stop_loss": 656.12, - "entry_low": 662.88, - "entry_high": 689.94, - "tech_snapshot": "形态:光头光脚阴线/bearish 量价:主动卖盘占优 强撑:563.22 弱撑:663.94 弱压:704.03 强压:816.12", + "action": "盈利持有 | 目标816.64 | 止损657.64 | 买入区664.42~691.54 | 信号:观望", + "stop_loss": 657.64, + "entry_low": 664.42, + "entry_high": 691.54, + "tech_snapshot": "形态:光头光脚阴线/bearish 量价:主动卖盘占优 强撑:563.22 弱撑:664.99 弱压:704.03 强压:816.64", "timing_signal": "观望", - "rr_ratio": 6.89, + "rr_ratio": 6.82, "status": "updated", "note": "", "timestamp": "2026-06-24 09:01", @@ -7953,7 +7953,7 @@ "position_advice": "正常配置", "time_horizon": "数月~1年", "created_at": "2026-06-18 17:15", - "take_profit": 816.12, + "take_profit": 816.64, "updated_reason": "技术信号变化: 大盘中性,行业中性,高估值,放量下跌,等企稳再入: 止损683.91→660.96 | 形态:带上影阳线/neutral 量价:主动卖盘占优 强撑:568.43 弱撑:660.96 弱压:746.15 强压:", "changelog": [ { @@ -8032,7 +8032,7 @@ { "id": "688795_stop_loss", "condition": { - "price": "<656.12" + "price": "<657.64" }, "action": { "type": "sell", @@ -8049,13 +8049,13 @@ "id": "688795_buy_dip", "condition": { "scenario": "weak_consolidation", - "price": "<=689.94", - "price_lower": ">=662.88" + "price": "<=691.54", + "price_lower": ">=664.42" }, "action": { "type": "buy", "amount": "normal", - "limit": 662.88, + "limit": 664.42, "reason": "回调支撑买入" }, "priority": 1, @@ -8068,7 +8068,7 @@ "id": "688795_breakout_chase", "condition": { "scenario": "bullish_recovery", - "price": ">=816.12" + "price": ">=816.64" }, "action": { "type": "buy", @@ -8102,7 +8102,7 @@ { "id": "688795_take_profit", "condition": { - "price": ">=816.12" + "price": ">=816.64" }, "action": { "type": "sell", @@ -8328,7 +8328,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" } @@ -8518,7 +8518,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" } @@ -8653,7 +8653,7 @@ }, "priority": 99, "rationale": "没有分支匹配时的默认动作", - "trigger_count": 9, + "trigger_count": 10, "success_rate": null, "last_triggered": "2026-06-24" } @@ -8662,5 +8662,5 @@ } ], "total": 43, - "regenerated_at": "2026-06-24 10:55" + "regenerated_at": "2026-06-24 11:01" } \ No newline at end of file diff --git a/data/portfolio.json b/data/portfolio.json index de53217..7f83c78 100644 --- a/data/portfolio.json +++ b/data/portfolio.json @@ -26,8 +26,8 @@ "action_note": "⚠️盈亏比偏低(1:1.2),不建议加仓", "timing_signal": "大盘中性,行业偏弱,蓝筹,持有" }, - "price": 417.8, - "change_pct": 0.72 + "price": 420.6, + "change_pct": 1.21 }, { "code": "00981", @@ -55,8 +55,8 @@ "action_note": "⚠️盈亏比偏低(1:1.3),不建议加仓", "timing_signal": "大盘中性,行业中性,高估值,蓝筹,持有" }, - "price": 83.75, - "change_pct": 7.58 + "price": 83.1, + "change_pct": 6.74 }, { "code": "01088", @@ -84,8 +84,8 @@ "action_note": "⚠️盈亏比偏低(1:1.2),不建议加仓", "timing_signal": "大盘中性,行业中性,蓝筹,持有" }, - "price": 41.4, - "change_pct": -1.47 + "price": 41.54, + "change_pct": -1.24 }, { "code": "01211", @@ -113,8 +113,8 @@ "action_note": "深套持有", "timing_signal": "大盘中性,行业偏弱,蓝筹,持有" }, - "price": 75.15, - "change_pct": -0.92 + "price": 75.05, + "change_pct": -1.05 }, { "code": "01478", @@ -142,8 +142,8 @@ "action_note": "深套持有", "timing_signal": "大盘中性,行业中性,低估值,持有" }, - "price": 7.64, - "change_pct": -3.3 + "price": 7.59, + "change_pct": -3.55 }, { "code": "01888", @@ -171,8 +171,8 @@ "action_note": "短炒强趋势持", "timing_signal": "大盘中性,行业偏弱,高估值,强趋势持" }, - "price": 97.15, - "change_pct": 11.35 + "price": 94.55, + "change_pct": 8.65 }, { "code": "02202", @@ -200,8 +200,8 @@ "action_note": "深套持有", "timing_signal": "大盘中性,行业中性,高估值,持有" }, - "price": 2.32, - "change_pct": -2.92 + "price": 2.35, + "change_pct": -3.33 }, { "code": "02388", @@ -229,8 +229,8 @@ "action_note": "", "timing_signal": "大盘中性,行业偏强,低估值,蓝筹,持有" }, - "price": 46.0, - "change_pct": -2.13 + "price": 45.98, + "change_pct": -2.17 }, { "code": "09988", @@ -258,7 +258,7 @@ "action_note": "深套持有", "timing_signal": "大盘中性,行业偏弱,蓝筹,持有" }, - "price": 98.3, + "price": 98.5, "change_pct": -0.66 }, { @@ -287,8 +287,8 @@ "action_note": "深套持有", "timing_signal": "大盘中性,行业偏弱,持有" }, - "price": 16.07, - "change_pct": -1.77 + "price": 16.1, + "change_pct": -1.41 }, { "code": "300548", @@ -316,8 +316,8 @@ "action_note": "短炒强趋势持", "timing_signal": "大盘中性,行业中性,高估值,强趋势持" }, - "price": 278.0, - "change_pct": -2.8 + "price": 277.13, + "change_pct": -3.21 }, { "code": "300690", @@ -345,8 +345,8 @@ "action_note": "⚠️盈亏比偏低(1:1.5),不建议加仓", "timing_signal": "大盘中性,行业偏弱,持有" }, - "price": 22.76, - "change_pct": -3.68 + "price": 22.75, + "change_pct": -3.72 }, { "code": "300750", @@ -374,8 +374,8 @@ "action_note": "", "timing_signal": "大盘中性,行业偏弱,蓝筹,持有" }, - "price": 389.35, - "change_pct": -0.81 + "price": 391.57, + "change_pct": -0.09 }, { "code": "518880", @@ -404,7 +404,7 @@ "timing_signal": "大盘中性,行业偏弱,持有" }, "price": 8.46, - "change_pct": -0.95 + "change_pct": -1.0 }, { "code": "600036", @@ -432,8 +432,8 @@ "action_note": "⚠️盈亏比偏低(1:1.2),不建议加仓", "timing_signal": "大盘中性,行业偏强,低估值,蓝筹,弱势持有" }, - "price": 37.06, - "change_pct": -0.91 + "price": 37.11, + "change_pct": -0.88 }, { "code": "600563", @@ -461,8 +461,8 @@ "action_note": "", "timing_signal": "大盘中性,行业偏弱,持有" }, - "price": 174.63, - "change_pct": 7.46 + "price": 173.68, + "change_pct": 7.07 }, { "code": "600739", @@ -490,8 +490,8 @@ "action_note": "⚠️盈亏比偏低(1:1.2),不建议加仓", "timing_signal": "大盘中性,行业偏强,持有" }, - "price": 10.49, - "change_pct": -1.5 + "price": 10.51, + "change_pct": -1.41 }, { "code": "601899", @@ -519,8 +519,8 @@ "action_note": "深套持有", "timing_signal": "大盘中性,行业偏弱,低估值,蓝筹,持有" }, - "price": 27.4, - "change_pct": -1.26 + "price": 27.5, + "change_pct": -0.72 }, { "code": "603259", @@ -548,8 +548,8 @@ "action_note": "", "timing_signal": "大盘中性,行业偏强,低估值,持有" }, - "price": 116.0, - "change_pct": 9.11 + "price": 116.94, + "change_pct": 9.49 }, { "code": "688411", @@ -577,8 +577,8 @@ "action_note": "", "timing_signal": "持有" }, - "price": 264.02, - "change_pct": -3.02 + "price": 265.9, + "change_pct": -2.27 }, { "code": "688981", @@ -606,8 +606,8 @@ "action_note": "", "timing_signal": "大盘中性,行业中性,高估值,蓝筹,持有" }, - "price": 149.0, - "change_pct": 5.15 + "price": 149.6, + "change_pct": 5.43 } ] } \ No newline at end of file diff --git a/data/price_history.json b/data/price_history.json index 328c9e9..504c3bd 100644 --- a/data/price_history.json +++ b/data/price_history.json @@ -107,8 +107,8 @@ { "date": "2026-06-24", "high": 88.32, - "low": 82.8, - "close": 82.81 + "low": 82.78, + "close": 82.93 } ], "00700": [ @@ -1283,8 +1283,8 @@ { "date": "2026-06-24", "high": 68.8, - "low": 65.8, - "close": 65.86 + "low": 65.74, + "close": 66.01 } ], "300548": [ @@ -2316,7 +2316,7 @@ "date": "2026-06-24", "high": 745.2, "low": 660.01, - "close": 676.41 + "close": 677.98 } ], "688802": [ @@ -2610,7 +2610,7 @@ "date": "2026-06-24", "high": 52.43, "low": 49.03, - "close": 49.48 + "close": 49.67 } ], "002171": [ diff --git a/scripts/stale_push_wlin.py b/scripts/stale_push_wlin.py index f9ee02e..4497750 100644 --- a/scripts/stale_push_wlin.py +++ b/scripts/stale_push_wlin.py @@ -17,6 +17,7 @@ import re import json import os import threading +import time from datetime import datetime try: from urllib.request import Request, urlopen @@ -33,6 +34,7 @@ REGEN_SCRIPT = "/home/hmo/.hermes/profiles/position-analyst/scripts/per_stock_re REGEN_LOCK = "/tmp/.stale_push_wlin_regen.lock" MACRO_CTX = "/home/hmo/web-dashboard/data/macro_context.json" MARKET_JSON = "/home/hmo/web-dashboard/data/market.json" +COOLDOWN_PATH = "/home/hmo/web-dashboard/data/push_cooldown.json" NON_BUY_SIGNALS = ["观望", "弱势持有", "深套持有"] @@ -156,6 +158,29 @@ def push_to_xmpp(text): print(f"[XMPP推送失败] {e}", file=sys.stderr) +def load_cooldown(): + try: + with open(COOLDOWN_PATH) as f: + return json.load(f) + except Exception: + return {} + + +def save_cooldown(cd): + try: + with open(COOLDOWN_PATH, "w") as f: + json.dump(cd, f, indent=2) + except Exception: + pass + + +def in_cooldown(code, action_type, cooldown_dict, minutes=30): + key = f"{code}_{action_type}" + last = cooldown_dict.get(key, 0) + elapsed = time.time() - last + return elapsed < minutes * 60, elapsed, key + + def main(): r = subprocess.run( ["python3", DETECTOR], capture_output=True, text=True, timeout=60 @@ -178,6 +203,10 @@ def main(): report = {"flagged": []} code_cur = {i["code"]: i.get("current", "") for i in report.get("flagged", [])} + # 加载冷却状态 + cooldown = load_cooldown() + now_ts = time.time() + # 读 decisions.json 获取完整策略数据 code_data = {} try: @@ -358,7 +387,13 @@ def main(): if lots == 0: details = f"预算不足1手({budget:,.0f}/{lot_cost:,.0f}元)" else: - shares = lots * (200 if code.startswith("688") else 100) + if len(str(code)) == 5: + hk_lot = hk_lot_size(code) + shares = lots * hk_lot + elif code.startswith("688"): + shares = lots * 200 + else: + shares = lots * 100 details = f"{lots}手({shares}股,{lot_cost_total:,.0f}元)" return theo_pct, pct_actual, details, lots, lot_cost_total @@ -426,6 +461,26 @@ def main(): ) pfx = "" if len(code) == 6 else "HK$" + + # 取分支动作类型 + branch_action = "hold" + branch_rationale = "" + if st and scenario_id: + try: + results = st.evaluate_branches(code, scenario_id, price, d.get("shares", 0), d.get("cost", 0)) + applicable = [r for r in results if r.get("applicable")] + if applicable: + best = min(applicable, key=lambda r: r.get("priority", 999)) + branch_action = best.get("action_type", "hold") + branch_rationale = best.get("rationale", "") + except Exception: + pass + + # 冷却检查:相同股+相同操作30分钟内不发 + cooled, elapsed, cd_key = in_cooldown(code, branch_action, cooldown) + if cooled: + continue + action_tag = "⚠️" if lots == 0 else "🛒" lines.append( f" {action_tag} {name}({code}) {pfx}{price:.2f} 买区{buy_low}~{buy_high} | " @@ -435,26 +490,30 @@ def main(): f" 仓位:理论{theo_pct}%×总资产 | 建议{actual_pct}%({details})" ) - # 读分支评估 + # 分支描述 branch_line = "" - if st and scenario_id: - try: - results = st.evaluate_branches(code, scenario_id, price, d.get("shares", 0), d.get("cost", 0)) - applicable = [r for r in results if r.get("applicable")] - if applicable: - # 取优先级最高的适用分支 - best = min(applicable, key=lambda r: r.get("priority", 999)) - action = best.get("action_type", "hold") - rationale = best.get("rationale", "") - branch_line = f" 【{scenario_label}→{action}】{rationale}" - else: - branch_line = f" 【{scenario_label}→持有】无匹配分支" - except Exception: - branch_line = "" + if branch_action != "hold": + branch_line = f" 【{scenario_label}→{branch_action}】{branch_rationale}" if branch_line: - # 追加到上一个元素 lines[-1] += f"\n{branch_line}" + # 记录推送时间(冷却计时用) + cooldown[cd_key] = now_ts + + save_cooldown(cooldown) + + # 修正可操作数量(剔除冷却跳过后的实际数量) + actual_n = len(lines) - (1 if macro_line else 0) - 1 # 减去市场背景 + 操作建议标题 + if actual_n != n: + # 更新操作建议行 + for i, ln in enumerate(lines): + if "【💡 操作建议】" in ln: + lines[i] = f"【💡 操作建议】(当前{actual_n}只自选可操作 | 总资产{total_assets:,.0f}元 现金{available_cash:,.0f}元)" + break + + if actual_n <= 0: + return 0 # 全部冷却中 → 静默,不推 + lines.insert(0, f"【知微】自选买入提醒 {now} | 总资产{total_assets:,.0f}元") out = "\n".join(lines) print(out)