From 49a9fc980f29d897ec9c1f6bee552ae4985aabac Mon Sep 17 00:00:00 2001 From: hmo Date: Fri, 31 Jul 2026 02:30:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=85=B1=E6=8C=AF=E5=B1=82=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E5=9B=9B=E7=BB=B4=E2=80=94=E2=80=94=E8=A1=8C=E4=B8=9A?= =?UTF-8?q?=E6=96=B0=E9=97=BB=E6=83=85=E7=BB=AA(=E4=B8=9C=E6=96=B9?= =?UTF-8?q?=E8=B4=A2=E5=AF=8C=E7=BF=BB=E9=A1=B5=E6=96=B0=E9=97=BB)=20+=20?= =?UTF-8?q?=E6=8A=80=E6=9C=AF=C3=97=E8=B5=84=E9=87=91=C3=97=E5=85=AC?= =?UTF-8?q?=E5=91=8A=E6=B6=88=E6=81=AF=C3=97=E8=A1=8C=E4=B8=9A=E6=96=B0?= =?UTF-8?q?=E9=97=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/profile-scripts/resonance.py | 46 ++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/deploy/profile-scripts/resonance.py b/deploy/profile-scripts/resonance.py index 6106ddbb..b134df8d 100644 --- a/deploy/profile-scripts/resonance.py +++ b/deploy/profile-scripts/resonance.py @@ -51,6 +51,42 @@ def _flow_state(code): 'flow_delta': round(flow_delta, 2) if flow_delta is not None else None} +# ── 行业新闻情绪分析(2026-07-31:东方财富翻页新闻→500条/股)── +_POS_KW = ['大涨','涨停','回暖','反弹','回升','领涨','突破','创新高','资金流入','净流入','加仓','密集调研','增持','回购'] +_NEG_KW = ['大跌','跌停','回落','下跌','下挫','走弱','资金流出','净流出','减持','利空','风险','预警','亏损','预警'] + +def sector_news_sentiment(sector, days=3): + import sqlite3 + conn = sqlite3.connect('/home/hmo/MoFin/data/mofin.db') + try: + stocks = conn.execute("SELECT code FROM stock_sectors_em WHERE sector=?", (sector,)).fetchall() + if not stocks: + return {'state': 'neutral', 'pos': 0, 'neg': 0, 'total': 0} + from datetime import datetime, timedelta + since = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d') + codes = tuple(s[0] for s in stocks) + placeholders = ','.join('?' for _ in codes) + arts = conn.execute(f"SELECT title, content FROM stock_news WHERE code IN ({placeholders}) AND date>=?", codes + (since,)).fetchall() + pos = neg = 0 + for t, c in arts: + text = (t or '') + ' ' + (c or '') + for kw in _POS_KW: + if kw in text: pos += 1; break + for kw in _NEG_KW: + if kw in text: neg += 1; break + total = pos + neg + state = 'neutral' + if total > 0 and pos / max(total, 1) > 0.6: + state = 'positive' + elif total > 0 and neg / max(total, 1) > 0.6: + state = 'negative' + return {'state': state, 'pos': pos, 'neg': neg, 'total': total} + except Exception: + return {'state': 'neutral', 'pos': 0, 'neg': 0, 'total': 0} + finally: + conn.close() + + def _news_state(code, name=None, sector=None): """消息维度: 3日内该股/该板块最新消息情绪""" since = (datetime.now() - timedelta(days=3)).strftime('%Y-%m-%d') @@ -109,7 +145,15 @@ def evaluate_resonance(code, gate, name=None): decision = 'pass' reason = '' - return {'decision': decision, 'reason': reason, 'flow': flow, 'news': news, 'sector': sector} + # ── 第四维:行业新闻情绪叠加(2026-07-31) ── + sns = sector_news_sentiment(sector) if sector else {'state': 'neutral', 'pos': 0, 'neg': 0, 'total': 0} + if decision == 'pass' and sns['state'] == 'positive' and fs in ('positive', 'strong_positive'): + decision = 'resonance' + reason = f"行业新闻确认({sns['pos']}pos/{sns['neg']}neg) + 资金流入 → 共振" + elif decision == 'pass' and sns['state'] == 'negative' and fs == 'negative': + decision = 'downgrade' + reason = f"行业新闻利空({sns['pos']}pos/{sns['neg']}neg) + 资金流出 → 降级" + return {'decision': decision, 'reason': reason, 'flow': flow, 'news': news, 'sector': sector, 'sector_news': sns} def log_resonance(code, name, price, gate, res, signal_before, signal_after):