feat: 推荐原因丰富化——因子值→带数字/方向的中文描述
This commit is contained in:
@@ -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), {}
|
||||
Reference in New Issue
Block a user