feat: 推荐原因丰富化——因子值→带数字/方向的中文描述

This commit is contained in:
lookt
2026-09-16 14:27:56 +08:00
parent 93ea5037ce
commit 42e1e68e26
5 changed files with 251 additions and 3 deletions
+71
View File
@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
"""
推荐原因生成器:因子截面值 → 带具体数字和方向的中文推荐理由。
"""
import numpy as np
import pandas as pd
def build_reason(code, kline_df, weights):
"""
从单股日K线(时间升序,≥30行)生成多维度推荐原因。
返回 (reason_str, factor_detail_dict)
"""
if kline_df is None or len(kline_df) < 30:
return '', {}
close = kline_df['close'].reset_index(drop=True)
vol = kline_df['volume'].reset_index(drop=True)
high = kline_df['high'].reset_index(drop=True)
low = kline_df['low'].reset_index(drop=True)
n = len(close)
c = close.iloc[-1]
parts = []
# 动量
if n > 21:
mom = (c / close.iloc[-21] - 1) * 100
tag = '' if mom > 5 else ('偏强' if mom > 0 else '偏弱' if mom > -5 else '')
parts.append(f"20日动量{mom:+.1f}%{tag}")
# 趋势(MA20 偏离)
ma20 = close.rolling(20).mean().iloc[-1]
if ma20 and ma20 > 0:
dev = (c - ma20) / ma20 * 100
tag = '强势区' if dev > 3 else ('偏高水平' if dev > 0 else '偏低水平' if dev > -3 else '弱势区')
parts.append(f"距MA20 {dev:+.1f}%{tag}")
# 量能
v20 = vol.rolling(20).mean().iloc[-1]
if v20 and v20 > 0:
vr = vol.iloc[-1] / v20
if vr > 1.5:
parts.append(f"量比{vr:.1f}(放量)")
elif vr < 0.5:
parts.append(f"量比{vr:.1f}(极度缩量)")
# RSI
close_s = close
delta = close_s.diff()
gain = delta.clip(lower=0).rolling(14).mean()
loss = (-delta.clip(upper=0)).rolling(14).mean()
rs = gain / loss.replace(0, np.nan)
rsi = (100 - 100 / (1 + rs)).iloc[-1]
if rsi == rsi:
if rsi > 70:
parts.append(f"RSI={rsi:.0f}(超买)")
elif rsi < 30:
parts.append(f"RSI={rsi:.0f}(超卖)")
# MACD
ema12 = close.ewm(span=12, adjust=False).mean()
ema26 = close.ewm(span=26, adjust=False).mean()
dif = ema12 - ema26
dea = dif.ewm(span=9, adjust=False).mean()
hist = (dif - dea).iloc[-1]
if hist > 0:
parts.append("MACD多头")
else:
parts.append("MACD空头")
return ''.join(parts), {}