docs: 更新CHANGELOG + 开发日志记录07/13全部变更

- XMPP Bot非阻塞/本地XMPP/MUC修复
- price_monitor推送冷却持久化
- 深套股规则重构+换股规划swap-plan
- 周月线技术分析增强
- 健康Tab写无读清零
- stale_push_wlin/per_stock_reassess/promote_candidates更新
- static/index.html + mofin_health.json + server.py同步
This commit is contained in:
知微
2026-07-13 12:09:25 +08:00
parent 2109289668
commit 9239ab40c0
9 changed files with 645 additions and 358 deletions
+10 -4
View File
@@ -229,11 +229,11 @@ def main():
continue
entry = decisions_map.get(code)
if not entry:
# 不在 decisions 中的自选股 → 从 DB watchlist_stocks 构建entry
# 不在 decisions 中的自选股 → 从 holding_strategies 构建entry
import sqlite3
_db = sqlite3.connect('/home/hmo/web-dashboard/data/mofin.db')
_db = sqlite3.connect('/home/hmo/MoFin/data/mofin.db')
_db.row_factory = sqlite3.Row
_wl = _db.execute("SELECT * FROM watchlist_stocks WHERE code=? AND is_active=1", (code,)).fetchone()
_wl = _db.execute("SELECT * FROM holding_strategies WHERE code=? AND status='active' AND decision_type='自选策略'", (code,)).fetchone()
_db.close()
if _wl:
entry = {
@@ -299,7 +299,13 @@ def main():
skipped += 1
continue
# 打印参数调试
print(f" DEBUG: code={code} name={entry.get('name','')} price={price} cost={entry.get('cost')} shares={entry.get('shares')} action={entry.get('action','')[:30]} is_wl={entry.get('type','') in ('自选策略','watchlist')}", flush=True)
if entry is None:
print(f" DEBUG: code={code} ENTRY=NONE 跳过")
print(f" [SKIP] {code} 策略数据不存在")
skipped += 1
continue
entry_action = str(entry.get('action') or '')
print(f" DEBUG: code={code} name={entry.get('name','')} price={price} cost={entry.get('cost')} shares={entry.get('shares')} action={entry_action[:30]} is_wl={entry.get('type','') in ('自选策略','watchlist')}", flush=True)
result = reassess_strategy(
code=code,
name=entry.get("name", ""),
+13
View File
@@ -56,6 +56,19 @@ def main():
print(f"{code} {name} 已在自选中,标记promoted")
continue
# 验证实时价格:无有效价格的候选股不入自选(防假数据污染)
try:
import subprocess, json as _jj
_r = subprocess.run(["python3", "/home/hmo/.hermes/profiles/position-analyst/scripts/stock_quote.py", code],
capture_output=True, text=True, timeout=10)
_q = _jj.loads(_r.stdout)
if float(_q.get("price", 0)) <= 0:
print(f"{code} {name} 无实时价格,跳过")
continue
except Exception as _e:
print(f"{code} {name} 价格获取失败({_e}),跳过")
continue
# 构建策略
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
timing_signal = "买入" if score >= 7 else "关注"
+3 -1
View File
@@ -136,7 +136,9 @@ def main():
if not cur_price or cur_price <= 0:
continue
drift = (cur_price / center - 1) * 100
if abs(drift) > 15:
# 触发条件:价格偏离>15% 或 买入区明确错误(价格完全在区间外且偏离>50%)
price_outside = cur_price < wl_el or cur_price > wl_eh
if abs(drift) > 15 or (price_outside and abs(drift) > 50):
reassess_scripts.append(code)
print(f"[AUTO_REASSESS] {name}({code}) 价{cur_price:.2f}偏离买入区中心{center:.2f} {drift:+.0f}% → 触发重评")
if reassess_scripts:
+8 -35
View File
@@ -363,39 +363,6 @@ def main():
dec = read_decisions()
for e in dec.get("decisions", []):
code_data[e["code"]] = e
# 补充watchlist_stocks中不在holding_strategies的自选股
import sqlite3 as _sq3
_wl_db = _sq3.connect('/home/hmo/MoFin/data/mofin.db')
_wl_db.row_factory = _sq3.Row
_wl_rows = _wl_db.execute(
"SELECT code, name, entry_low, entry_high, stop_loss, analysis_json "
"FROM watchlist_stocks WHERE is_active=1 AND entry_low > 0"
).fetchall()
_wl_db.close()
for _w in _wl_rows:
_c = str(_w["code"])
if _c in code_data:
continue
_aj = json.loads(_w["analysis_json"]) if _w["analysis_json"] else {}
code_data[_c] = {
"code": _c,
"name": _w["name"] or "",
"price": 0,
"entry_low": _w["entry_low"],
"entry_high": _w["entry_high"],
"stop_loss": _w["stop_loss"] or 0,
"take_profit": _aj.get("take_profit", 0),
"rr_ratio": _aj.get("rr", 0),
"tech_snapshot": _aj.get("tech_snapshot", ""),
"timing_signal": _aj.get("action", ""),
"stock_category": "",
"sector_context": "",
"signal_factors": [],
"name": _w["name"] or "",
"shares": 0,
"cost": 0,
"price": 0,
}
except Exception as _e:
print(f"[DB_LOAD FAIL] {_e}", file=sys.stderr)
@@ -498,8 +465,8 @@ def main():
eh = row[5] or 0
if price <= 0 or el <= 0 or eh <= 0:
continue
# 价格必须在买入区内或略高于(不超过5%
if price > eh * 1.05:
# 价格必须在买入区内(硬检查,拒绝偏离仍推买入
if price < el or price > eh:
continue
name = row[1] or code
all_candidates.append((name, code, price, el, eh, "", False))
@@ -573,6 +540,12 @@ def main():
# 信号必须含买入/加仓才推荐——其他非操作信号跳过
if not any(kw in sig for kw in ["买入", "加仓"]):
continue
# 价格必须在买入区内(硬检查,拒绝价格偏离仍推买入)
buy_low, buy_high = s[3], s[4]
price_check = s[2]
if buy_low and buy_high and buy_low > 0:
if not (buy_low <= price_check <= buy_high):
continue
# RR完整性检查:买入/加仓信号必须RR>0(策略数据要完整)
cd = code_data.get(s[1], {})
rr = cd.get("rr_ratio", 0) or 0