Files
codex_jxs_code/strategy/strategy_signal.py
2026-02-23 04:09:34 +08:00

126 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
信号生成模块 - 多指标加权投票 + 多时间框架过滤
"""
import numpy as np
import pandas as pd
def generate_indicator_signals(df: pd.DataFrame, params: dict) -> pd.DataFrame:
"""
根据指标值生成每个指标的独立信号 (+1 做多 / -1 做空 / 0 中性)
df 必须已经包含 compute_all_indicators 计算出的列
"""
out = df.copy()
# --- 布林带 %B ---
out['sig_bb'] = 0
out.loc[out['bb_pct'] < params.get('bb_oversold', 0.0), 'sig_bb'] = 1
out.loc[out['bb_pct'] > params.get('bb_overbought', 1.0), 'sig_bb'] = -1
# --- 肯特纳通道 ---
out['sig_kc'] = 0
out.loc[out['kc_pct'] < params.get('kc_oversold', 0.0), 'sig_kc'] = 1
out.loc[out['kc_pct'] > params.get('kc_overbought', 1.0), 'sig_kc'] = -1
# --- 唐奇安通道 ---
out['sig_dc'] = 0
out.loc[out['dc_pct'] < params.get('dc_oversold', 0.2), 'sig_dc'] = 1
out.loc[out['dc_pct'] > params.get('dc_overbought', 0.8), 'sig_dc'] = -1
# --- EMA 交叉 ---
out['sig_ema'] = 0
out.loc[out['ema_diff'] > 0, 'sig_ema'] = 1
out.loc[out['ema_diff'] < 0, 'sig_ema'] = -1
# --- MACD ---
out['sig_macd'] = 0
out.loc[out['macd_hist'] > 0, 'sig_macd'] = 1
out.loc[out['macd_hist'] < 0, 'sig_macd'] = -1
# --- ADX + DI ---
adx_thresh = params.get('adx_threshold', 25)
out['sig_adx'] = 0
out.loc[(out['adx'] > adx_thresh) & (out['di_diff'] > 0), 'sig_adx'] = 1
out.loc[(out['adx'] > adx_thresh) & (out['di_diff'] < 0), 'sig_adx'] = -1
# --- Supertrend ---
out['sig_st'] = out['st_dir']
# --- RSI ---
rsi_ob = params.get('rsi_overbought', 70)
rsi_os = params.get('rsi_oversold', 30)
out['sig_rsi'] = 0
out.loc[out['rsi'] < rsi_os, 'sig_rsi'] = 1
out.loc[out['rsi'] > rsi_ob, 'sig_rsi'] = -1
# --- Stochastic ---
stoch_ob = params.get('stoch_overbought', 80)
stoch_os = params.get('stoch_oversold', 20)
out['sig_stoch'] = 0
out.loc[(out['stoch_k'] < stoch_os) & (out['stoch_k'] > out['stoch_d']), 'sig_stoch'] = 1
out.loc[(out['stoch_k'] > stoch_ob) & (out['stoch_k'] < out['stoch_d']), 'sig_stoch'] = -1
# --- CCI ---
cci_ob = params.get('cci_overbought', 100)
cci_os = params.get('cci_oversold', -100)
out['sig_cci'] = 0
out.loc[out['cci'] < cci_os, 'sig_cci'] = 1
out.loc[out['cci'] > cci_ob, 'sig_cci'] = -1
# --- Williams %R ---
wr_ob = params.get('wr_overbought', -20)
wr_os = params.get('wr_oversold', -80)
out['sig_wr'] = 0
out.loc[out['wr'] < wr_os, 'sig_wr'] = 1
out.loc[out['wr'] > wr_ob, 'sig_wr'] = -1
# --- WMA ---
out['sig_wma'] = 0
out.loc[out['wma_diff'] > 0, 'sig_wma'] = 1
out.loc[out['wma_diff'] < 0, 'sig_wma'] = -1
return out
SIGNAL_COLS = [
'sig_bb', 'sig_kc', 'sig_dc', 'sig_ema', 'sig_macd',
'sig_adx', 'sig_st', 'sig_rsi', 'sig_stoch', 'sig_cci',
'sig_wr', 'sig_wma',
]
WEIGHT_KEYS = [
'w_bb', 'w_kc', 'w_dc', 'w_ema', 'w_macd',
'w_adx', 'w_st', 'w_rsi', 'w_stoch', 'w_cci',
'w_wr', 'w_wma',
]
def compute_composite_score(df: pd.DataFrame, params: dict) -> pd.Series:
"""
加权投票计算综合得分 (-1 ~ +1)
"""
weights = np.array([params.get(k, 1.0) for k in WEIGHT_KEYS])
total_w = weights.sum()
if total_w == 0:
total_w = 1.0
signals = df[SIGNAL_COLS].values # (N, 12)
score = (signals * weights).sum(axis=1) / total_w
return pd.Series(score, index=df.index, name='score')
def apply_htf_filter(score: pd.Series, htf_df: pd.DataFrame, params: dict) -> pd.Series:
"""
用高时间框架如1h的趋势方向过滤信号
htf_df 需要包含 'ema_diff'
只允许与大趋势同向的信号通过
"""
# 将 htf 的 ema_diff reindex 到主时间框架
htf_trend = htf_df['ema_diff'].reindex(score.index, method='ffill')
filtered = score.copy()
# 大趋势向上时,屏蔽做空信号
filtered.loc[(htf_trend > 0) & (filtered < 0)] = 0
# 大趋势向下时,屏蔽做多信号
filtered.loc[(htf_trend < 0) & (filtered > 0)] = 0
return filtered