量化交易系统指标集成后信号始终为0,无法触发交易
量化交易系统Signal字段始终为0的排查与解决
我的量化交易系统已完成指标集成,能正常运行,但Signal字段始终为0,无法生成买入(1)或卖出(-1)信号,导致没有交易订单执行。但相同标的在TradingView平台上能正常给出对应信号。
核心代码
indicators.py
import pandas as pd import numpy as np import ta def lsma(data, period=14, regression=True): size = len(data) out = np.full(size, np.nan) w = np.arange(1, period + 1, dtype=np.float64) if regression: for i in range(period - 1, size): e = i + 1 s = e - period intercept, slope = np.dot(np.linalg.pinv(np.vstack((np.ones(period), w)).T), data[s:e]) out[i] = slope * period + intercept else: for i in range(period - 1, size): e = i + 1 s = e - period out[i] = np.dot(data[s:e], w) / np.sum(w) return out def zlsma(data, period=14, regression=True): size = len(data) sum_w = np.sum(np.arange(1, period + 1, dtype=np.float64)) lsma_v = lsma(data, period, regression) out = np.full(size, np.nan) w = sum_w / (2 * np.sum(np.arange(1, period))) for i in range(period - 1, size): out[i] = lsma_v[i] + (data[i] - lsma_v[i]) * w return out def add_indicators(df): df['FastEMA'] = ta.trend.EMAIndicator(df['Close'], window=5).ema_indicator() df['SlowEMA'] = ta.trend.EMAIndicator(df['Close'], window=15).ema_indicator() df['LongEMA'] = ta.trend.EMAIndicator(df['Close'], window=50).ema_indicator() df['VeryLongEMA'] = ta.trend.EMAIndicator(df['Close'], window=200).ema_indicator() df['RSI'] = ta.momentum.RSIIndicator(df['Close'], window=5).rsi() bb_bands = ta.volatility.BollingerBands(df['Close'], window=20, window_dev=2) df['BB_Lower'] = bb_bands.bollinger_lband() df['BB_Upper'] = bb_bands.bollinger_hband() df['VolumeAvg'] = ta.trend.SMAIndicator(df['Volume'], window=20).sma_indicator() df['ZLSMA'] = zlsma(df['Close'].values, 32) df['ATR'] = ta.volatility.AverageTrueRange(df['High'], df['Low'], df['Close'], window=1).average_true_range() df['LongExitCE'] = df['High'].rolling(window=1).max() - df['ATR'] * 2 df['ShortExitCE'] = df['Low'].rolling(window=1).min() + df['ATR'] * 2 return df def heikin_ashi(df): df['HA_Close'] = (df['Open'] + df['High'] + df['Low'] + df['Close']) / 4 idx = df.index.name df.reset_index(inplace=True) for i in range(0, len(df)): if i == 0: df.at[i, 'HA_Open'] = (df.at[i, 'Open'] + df.at[i, 'Close']) / 2 else: df.at[i, 'HA_Open'] = (df.at[i - 1, 'HA_Open'] + df.at[i - 1, 'HA_Close']) / 2 if idx: df.set_index(idx, inplace=True) df['HA_High'] = df[['HA_Open', 'HA_Close', 'High']].max(axis=1) df['HA_Low'] = df[['HA_Open', 'HA_Close', 'Low']].min(axis=1) return df def generate_signals(df, predicted_prices): df['Signal'] = 0 df['Predicted_Close'] = predicted_prices[:len(df)] df.loc[(df['Close'] > df['FastEMA']) & (df['FastEMA'] > df['ZLSMA']) & (df['Close'] > df['BB_Upper']) & (df['Volume'] > df['VolumeAvg'] * 1.5) & (df['RSI'] > 55) & (df['Predicted_Close'] > df['Close']), 'Signal'] = 1 df.loc[(df['Close'] < df['FastEMA']) & (df['FastEMA'] < df['ZLSMA']) & (df['Close'] < df['BB_Lower']) & (df['Volume'] > df['VolumeAvg'] * 1.5) & (df['RSI'] < 45) & (df['Predicted_Close'] < df['Close']), 'Signal'] = -1 return df
main.py 调用代码
if __name__ == "__main__": exchange = BybitExchange() max_pos = 50 # 最大持仓数 symbols = exchange.get_tickers() # 获取Bybit衍生品所有标的 # 无限循环 while True: balance = exchange.get_balance() if balance is None: print('无法连接到API') else: balance = float(balance) print(f'账户余额: {balance}') pos = exchange.get_positions() print(f'当前持仓数: {len(pos)},持仓列表: {pos}') if len(pos) < max_pos: # 遍历所有标的 for elem in symbols: pos = exchange.get_positions() if len(pos) >= max_pos: break # 获取信号 trades = exchange.get_trade(elem) if trades['Signal'].iloc[-1] == 1: print(f'发现{elem}的买入信号') exchange.set_mode(elem) time.sleep(2) exchange.set_leverage(elem, leverage, leverage) sl_atr = sl_coef * trades.ATR.iloc[-1] tp_sl_ratio = tp_sl_ratio sl = trades['Close'].iloc[-1] - sl_atr tp = trades['Close'].iloc[-1] + sl_atr * tp_sl_ratio exchange.place_order_market('Buy', balance*0.99*leverage*0.97, tp, sl) time.sleep(5) elif trades['Signal'].iloc[-1] == -1: print(f'发现{elem}的卖出信号') exchange.set_mode(elem) time.sleep(2) exchange.set_leverage(elem, leverage, leverage) sl_atr = sl_coef * trades.ATR.iloc[-1] tp_sl_ratio = tp_sl_ratio sl = trades['Close'].iloc[-1] + sl_atr tp = trades['Close'].iloc[-1] - sl_atr * tp_sl_ratio exchange.place_order_market('Sell', balance*0.99*leverage*0.97, tp, sl) time.sleep(5) print('等待2分钟') time.sleep(120)
排查方向与解决方法
1. 信号触发条件过于严苛
generate_signals中,买入/卖出信号需要同时满足6个条件,只要有一个不满足就无法生成信号。比如:
- 收盘价同时站上FastEMA、ZLSMA和布林带上轨
- 成交量超过20日均值1.5倍
- RSI处于55以上(买入)或45以下(卖出)
- 预测收盘价还要高于/低于当前收盘价
解决方法:
- 先单独验证每个条件的触发情况,在
generate_signals中添加调试代码,打印每个条件的布尔值统计:# 调试代码示例 print("Close > FastEMA 触发次数:", (df['Close'] > df['FastEMA']).sum()) print("FastEMA > ZLSMA 触发次数:", (df['FastEMA'] > df['ZLSMA']).sum()) print("Close > BB_Upper 触发次数:", (df['Close'] > df['BB_Upper']).sum()) # 其他条件同理 - 适当放宽条件,比如将成交量阈值从1.5倍调整为1.2倍,或者扩大RSI的阈值范围(比如买入RSI>50,卖出RSI<50)。
2. ZLSMA指标实现与TradingView不一致
自己实现的zlsma函数可能和TradingView的算法有差异:
- 检查权重计算逻辑:
w = sum_w / (2 * np.sum(np.arange(1, period))),这里np.arange(1, period)不包含period,而TradingView的ZLSMA可能使用全周期权重。 - 对比TradingView上的ZLSMA输出和本地计算的
df['ZLSMA']值,验证是否存在偏差。
3. 数据长度不足导致指标值为NaN
所有指标都需要足够的历史数据才能计算有效值:
- ZLSMA用了32周期,最长的EMA是200周期,所以
get_trade(elem)返回的K线数据至少需要200条以上,否则指标会出现NaN,导致条件判断失败。 - 检查
predicted_prices是否有效:如果预测值是NaN或者不符合预期,最后一个条件会不成立。
4. 未使用Heikin-Ashi数据
代码中实现了heikin_ashi函数,但指标计算和信号生成都用的是原始K线数据,如果TradingView是基于Heikin-Ashi K线计算的指标,会导致指标值差异。解决方法:将add_indicators和generate_signals中的Close等字段替换为HA字段,比如df['HA_Close']。
5. main.py变量未定义问题
main.py中使用了leverage、sl_coef、tp_sl_ratio三个变量但未定义,虽然不是Signal为0的直接原因,但会导致下单逻辑报错,建议补充定义:
# 在main.py开头添加 leverage = 10 # 杠杆倍数 sl_coef = 2 # 止损ATR系数 tp_sl_ratio = 1.5 # 止盈止损比例
内容的提问来源于stack exchange,提问作者user8357568
相关产品推荐
相关产品推荐

