模型,评分,修复网格策略市场状态监听
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
负向指标 (5维) — calculate_negative_features(df)
|
||||
注意: #53 trend_consistency_20d 与 #39 同名不同义,更新字典时会覆盖 #39
|
||||
"""
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def calculate_negative_features(ctx) -> pd.DataFrame:
|
||||
"""计算负向指标 (5维)"""
|
||||
kline = ctx.kline.copy()
|
||||
if kline.empty:
|
||||
return pd.DataFrame()
|
||||
|
||||
kline = kline.sort_values(['stock_code', 'trade_date'])
|
||||
candidates = ctx.candidates
|
||||
|
||||
features = {}
|
||||
grouped = kline.groupby('stock_code')
|
||||
|
||||
for code, group in grouped:
|
||||
if code not in candidates:
|
||||
continue
|
||||
g = group.tail(120)
|
||||
if len(g) < 20:
|
||||
continue
|
||||
|
||||
closes = g['close'].values
|
||||
opens = g['open'].values
|
||||
highs = g['high'].values
|
||||
lows = g['low'].values
|
||||
volumes = g['volume'].values
|
||||
|
||||
feat = {}
|
||||
|
||||
# 53. trend_consistency_20d (负向版本): |mean(return>0) - 0.5| × 100
|
||||
# 衡量偏离均衡的程度,越接近50%越弱
|
||||
rets_20 = np.diff(closes[-21:]) / np.where(closes[-21:-1] > 0, closes[-21:-1], 1)
|
||||
feat['trend_consistency_20d'] = abs(np.mean(rets_20 > 0) - 0.5) * 100
|
||||
|
||||
# 54. max_consecutive_direction_20d: 最大连续同向天数
|
||||
rets_sign = np.sign(np.diff(closes[-21:]))
|
||||
max_consec = 0
|
||||
curr_consec = 0
|
||||
curr_sign = 0
|
||||
for s in rets_sign:
|
||||
if s != 0 and s == curr_sign:
|
||||
curr_consec += 1
|
||||
elif s != 0:
|
||||
curr_sign = s
|
||||
curr_consec = 1
|
||||
else:
|
||||
curr_consec = 0
|
||||
max_consec = max(max_consec, curr_consec)
|
||||
feat['max_consecutive_direction_20d'] = max_consec
|
||||
|
||||
# 55. gap_risk_20d: mean(|open_t - close_{t-1}|/close_{t-1} > 0.02) × 100
|
||||
gap_count = 0
|
||||
n = 0
|
||||
for i in range(max(0, len(g) - 20), len(g)):
|
||||
if i > 0 and closes[i - 1] > 0:
|
||||
gap_pct = abs(opens[i] - closes[i - 1]) / closes[i - 1]
|
||||
if gap_pct > 0.02:
|
||||
gap_count += 1
|
||||
n += 1
|
||||
feat['gap_risk_20d'] = gap_count / n * 100 if n > 0 else 0
|
||||
|
||||
# 56. liquidity_drying_up_20d: min(vol_20d)/mean(vol_60d)
|
||||
vol_20 = volumes[-20:]
|
||||
vol_60 = volumes[-60:] if len(volumes) >= 60 else volumes
|
||||
feat['liquidity_drying_up_20d'] = (
|
||||
np.min(vol_20) / np.mean(vol_60) if np.mean(vol_60) > 0 else 1
|
||||
)
|
||||
|
||||
# 57. price_stagnation_20d: (max(high_20d)-min(low_20d))/close × 100
|
||||
h20 = np.max(highs[-20:])
|
||||
l20 = np.min(lows[-20:])
|
||||
feat['price_stagnation_20d'] = (
|
||||
(h20 - l20) / closes[-1] * 100 if closes[-1] > 0 else 0
|
||||
)
|
||||
|
||||
features[code] = feat
|
||||
|
||||
return pd.DataFrame.from_dict(features, orient='index')
|
||||
Reference in New Issue
Block a user