fix: price_monitor crash when shares is string + type guard in write_holding_strategy

Root cause: holding_strategies.shares field got set to literal string
'write_holding_strategy' for 6 records, causing TypeError at
price_monitor.py line 611 ('>' not supported between str and int).

Fixes:
1. price_monitor.py: Replace set comprehension with safe loop that
   checks isinstance before comparison. Non-numeric shares treated
   as holdings for safety.
2. mofin_db.py write_holding_strategy: Add type guard that resets
   non-numeric shares to 0 with warning.
3. Data fix: Updated 5 corrupted holding_strategies records from
   holdings table (300035/300308/300750/518880/00700).
   Set 002594 (watchlist) shares=0.
This commit is contained in:
知微
2026-07-21 13:47:52 +08:00
parent 91885f7623
commit a245c8b4dd
2 changed files with 17 additions and 2 deletions
+10 -1
View File
@@ -608,7 +608,16 @@ def run_once(round_label=""):
# === 第三步:买入区偏离检测 + 自动重评 ===
reassesed_codes = []
# 先做急跌检测(仅持仓,自选股不推送暴跌告警)
holdings_codes = {d["code"] for d in active if (d.get("shares") or 0) > 0}
holdings_codes = set()
for d in active:
shares = d.get("shares", 0)
if isinstance(shares, (int, float)):
if shares > 0:
holdings_codes.add(d["code"])
else:
# 非数值shares(如被错误写入的字符串),兜底处理
holdings_codes.add(d["code"])
print(f" [WARN] {d.get('code')} shares为非数值({shares!r}),视为持仓处理", flush=True)
for d in active:
code = d["code"]
# 非持仓跳过
+7 -1
View File
@@ -1180,6 +1180,12 @@ def write_holding_strategy(conn, code: str, name: str, data: dict,
except:
pass
# ── 类型守卫:shares 必须是数值,防止字符串写入导致下游崩溃 ──
_shares = data.get('shares', 0)
if not isinstance(_shares, (int, float)):
print(f" [TYPE GUARD] {code} shares类型异常({type(_shares).__name__}={_shares!r}),重置为0", flush=True)
_shares = 0
# DELETE + INSERT
conn.execute("DELETE FROM holding_strategies WHERE code=?", (code,))
conn.execute("""
@@ -1199,7 +1205,7 @@ def write_holding_strategy(conn, code: str, name: str, data: dict,
""", (
code, name,
data.get('version', 1), data.get('price'), data.get('cost'),
data.get('shares', 0), data.get('stop_loss'), data.get('take_profit'),
_shares, data.get('stop_loss'), data.get('take_profit'),
data.get('entry_low'), data.get('entry_high'), currency,
data.get('strategy_type', 'holding'), data.get('action'),
data.get('timing_signal'), data.get('rr_ratio'),