第八章 信号生成模块:技术指标计算与信号合成

信号生成模块,说白了就是做市系统的「大脑」。

前面几章我们搞定了数据清洗、订单簿重建、价格计算。现在,我们要把这些原始数据变成真正的交易信号。我个人习惯把这一步叫做「从数据到决策的最后一公里」。

8.1 技术指标计算:三个核心工具

做市系统里,技术指标不需要太多。我见过不少新手,一上来就堆十几个指标,结果信号互相打架。其实,三个经典指标就够用:移动平均线、RSI、布林带。

8.1.1 移动平均线(MA)

移动平均线是最基础的。它帮你滤掉噪音,看清趋势方向。

我在项目中遇到过一个问题:用简单移动平均(SMA)时,价格突然跳空,均线反应太慢。后来我改用指数移动平均(EMA),效果好了不少。EMA对近期价格更敏感,适合高频做市场景。

核心公式:

EMA = (当前价格 × 平滑因子) + (前一日EMA × (1 - 平滑因子))

平滑因子 = 2 / (周期数 + 1)

def calculate_ema(prices, period=20):
    """
    计算指数移动平均线
    prices: 价格序列,最新价格在最后
    period: 周期,默认20
    """
    smoothing_factor = 2 / (period + 1)
    ema = [prices[0]]  # 初始值用第一个价格
    
    for i in range(1, len(prices)):
        ema_value = (prices[i] * smoothing_factor) + (ema[-1] * (1 - smoothing_factor))
        ema.append(ema_value)
    
    return ema[-1]  # 只返回最新值

我的经验:做市系统里,EMA周期别设太大。5-20周期就够了。周期太长,信号滞后严重,等你反应过来,行情早变了。

8.1.2 RSI(相对强弱指标)

RSI用来判断「超买」和「超卖」。说白了,就是看价格涨得太猛还是跌得太狠。

嗯,这里要注意:RSI的计算方式有很多变种。我建议用 Wilder 的原始版本,简单可靠。

def calculate_rsi(prices, period=14):
    """
    计算RSI指标
    prices: 价格序列,至少需要period+1个数据点
    """
    if len(prices) < period + 1:
        return None
    
    # 计算价格变化
    deltas = [prices[i] - prices[i-1] for i in range(1, len(prices))]
    
    # 分离上涨和下跌
    gains = [d if d > 0 else 0 for d in deltas]
    losses = [-d if d < 0 else 0 for d in deltas]
    
    # 计算平均涨幅和平均跌幅
    avg_gain = sum(gains[-period:]) / period
    avg_loss = sum(losses[-period:]) / period
    
    if avg_loss == 0:
        return 100
    
    rs = avg_gain / avg_loss
    rsi = 100 - (100 / (1 + rs))
    
    return rsi

避坑指南:我曾经在RSI计算上栽过跟头。当时用了整个历史数据来计算平均涨幅,结果RSI值一直偏低。后来才发现,应该只用最近period个数据点来计算。记住:RSI是「相对」指标,不是「绝对」指标。

8.1.3 布林带(Bollinger Bands)

布林带告诉你价格「应该」在什么范围内波动。它由三条线组成:中轨(MA)、上轨(中轨+2倍标准差)、下轨(中轨-2倍标准差)。

你想想看,当价格碰到上轨时,说明价格偏离均值太多,大概率会回调。这就是做市系统里很好的「反转信号」。

def calculate_bollinger_bands(prices, period=20, num_std=2):
    """
    计算布林带
    返回: (中轨, 上轨, 下轨)
    """
    if len(prices) < period:
        return None
    
    # 计算中轨(这里用SMA,你也可以用EMA)
    recent_prices = prices[-period:]
    middle = sum(recent_prices) / period
    
    # 计算标准差
    variance = sum((p - middle) ** 2 for p in recent_prices) / period
    std_dev = variance ** 0.5
    
    upper = middle + num_std * std_dev
    lower = middle - num_std * std_dev
    
    return middle, upper, lower

8.2 信号合成:把指标变成决策

单个指标容易误判。比如RSI显示超买,但价格还在涨。这时候就需要信号合成——把多个指标的结果综合起来。

我个人习惯用「投票机制」。每个指标投一票,最后看总票数决定方向。

指标 做多信号 做空信号 中性信号
EMA 价格 > EMA 价格 < EMA 价格 ≈ EMA
RSI RSI < 30 RSI > 70 30 ≤ RSI ≤ 70
布林带 价格 < 下轨 价格 > 上轨 价格在轨内
def synthesize_signals(price, ema, rsi, bb_middle, bb_upper, bb_lower):
    """
    信号合成函数
    返回: 1=做多, -1=做空, 0=观望
    """
    score = 0
    
    # EMA信号
    if price > ema:
        score += 1  # 看多
    elif price < ema:
        score -= 1  # 看空
    
    # RSI信号
    if rsi < 30:
        score += 1  # 超卖,看多
    elif rsi > 70:
        score -= 1  # 超买,看空
    
    # 布林带信号
    if price < bb_lower:
        score += 1  # 跌破下轨,看多
    elif price > bb_upper:
        score -= 1  # 突破上轨,看空
    
    # 最终决策
    if score >= 2:
        return 1   # 强烈做多
    elif score <= -2:
        return -1  # 强烈做空
    else:
        return 0   # 观望

关键点:信号合成不是简单的「多数决」。我建议给不同指标分配不同权重。比如在趋势行情中,EMA的权重可以高一些;在震荡行情中,布林带的权重可以高一些。这个权重可以动态调整。

8.3 阈值设定:别让系统太敏感

阈值设定是信号生成模块里最容易出问题的地方。阈值设得太小,系统频繁开仓,手续费吃掉利润。阈值设得太大,信号出不来,错过行情。

我曾经犯过一个错误:把RSI的阈值设成20/80,结果一天下来一个信号都没有。后来改成25/75,信号多了,但假信号也多了。最后我找到个平衡点:30/70,配合布林带一起用,效果不错。

我的建议:阈值不要固定死。可以根据市场波动率动态调整。波动率大的时候,把阈值放宽;波动率小的时候,把阈值收紧。这样系统能自适应市场环境。

8.4 知识体系总览

下面这张图,把信号生成模块的核心逻辑串起来了。你可以看到:原始价格数据经过三个指标计算,然后进入信号合成器,最后输出交易决策。

信号生成模块架构图 原始价格数据 EMA计算 周期: 5-20 RSI计算 周期: 14 布林带计算 周期: 20, 标准差: 2 信号合成器 投票机制 + 权重分配 阈值判断(动态调整) 交易信号输出

这张图里,我特意把「阈值判断」放在最后一步。为什么?因为先合成信号,再判断阈值,能减少不必要的计算。如果每个指标都单独设阈值,逻辑会变得很复杂。

最后提醒:信号生成模块一定要做回测。我见过太多人,指标算得漂亮,一上实盘就亏钱。原因往往是参数过拟合。记住:回测是检验信号质量的唯一标准。


交易系统化学习资料 微信Strategy888888