1、信号处理基础:量化交易中的信号概念、信号类型、信号处理流程总览

各位同学,咱们今天聊聊量化交易里最基础、也最容易被忽视的东西——信号。

说实话,我刚开始做量化那会儿,觉得信号就是「金叉买、死叉卖」这么简单。后来在实盘里被市场狠狠教育了几次,才明白信号处理才是整个策略的命门。你想想看,如果连输入的数据都是脏的、乱的,后面再漂亮的模型也是白搭。

1.1 什么是量化交易中的「信号」?

信号,说白了就是市场里传递出来的信息。它告诉你:现在该买、该卖,还是该观望。

我个人习惯把信号分成两类:

  • 原始信号:直接从市场拿到的数据,比如价格、成交量。这些是原材料。
  • 加工信号:经过算法处理后的结果,比如均线金叉、RSI超买超卖。这些是半成品或成品。

嗯,这里要注意:原始信号里藏着大量噪声。我在项目中遇到过,有人直接用Tick数据做高频策略,结果被交易所的撮合延迟和网络抖动搞得一塌糊涂。所以信号处理的第一步,往往是「去噪」。

核心观点:信号 = 信息 + 噪声。我们的工作就是尽可能保留信息,剔除噪声。

1.2 三大信号类型:价格、成交量、波动率

做量化交易,你绕不开这三类信号。我按重要程度排个序:

1.2.1 价格信号

这是最直接的信号。开盘价、收盘价、最高价、最低价,也就是我们常说的OHLC。为什么这四个价格这么重要?

  • 收盘价:市场经过一天博弈后的共识。我个人觉得,收盘价是所有价格里信息量最大的。
  • 开盘价:隔夜信息的集中反映。经常有跳空缺口,这里藏着套利机会。
  • 最高/最低价:多空双方当天打到的最极端位置。做突破策略的人特别看重这个。

我曾经犯过一个低级错误:用复权后的价格做回测,结果信号全乱了。后来才明白,复权会改变价格序列的统计特性,尤其是做均值回归策略时,复权数据会让你误以为有套利空间。

避坑指南:做回测时,尽量用原始价格数据。如果需要复权,请务必搞清楚前复权和后复权的区别。我曾经因为用错复权方式,白亏了三个月的研发时间。

1.2.2 成交量信号

成交量是价格的「佐证」。光看价格不看量,就像只看结果不看过程。

我常用的成交量信号有:

  • 成交量加权平均价(VWAP):机构交易者最爱用的参考线。说白了就是「今天大家平均花了多少钱买的」。
  • 成交量分布:哪个价格区间成交最多,哪里就是多空争夺的「主战场」。
  • 量价背离:价格创新高但成交量萎缩,这往往是趋势衰竭的信号。

举个例子:某只股票连续三天上涨,但成交量一天比一天小。你想想看,这说明什么?说明追高的人越来越少,上涨动力不足。这时候再追进去,大概率要接盘。

1.2.3 波动率信号

波动率是市场的「情绪指标」。它告诉你市场现在有多「激动」。

我个人习惯把波动率分成两种:

类型 计算方法 用途
历史波动率 过去N天的收益率标准差 衡量已发生的波动
隐含波动率 从期权价格反推 预测未来波动

做CTA策略的人,特别喜欢用波动率来调整仓位。波动率高了,仓位降一点;波动率低了,仓位加一点。这叫「波动率平价」,说白了就是让每笔交易承担差不多的风险。

小技巧:计算波动率时,我建议用对数收益率而不是简单收益率。为什么?因为对数收益率在时间序列上可加,而且更符合正态分布假设。这是我在做波动率建模时踩过的坑,分享给大家。

1.3 信号处理流程总览

好了,现在我们知道信号是什么、有哪些类型。接下来看看整个处理流程长什么样。

我把它总结成五个步骤:

  1. 数据采集:从交易所、数据商拿到原始数据。这一步要小心数据缺失、跳变、停牌等问题。
  2. 数据清洗:处理缺失值、异常值、复权调整。嗯,这一步最枯燥,但也最重要。
  3. 信号生成:用算法把原始数据变成交易信号。比如计算均线、MACD、布林带等。
  4. 信号评估:用回测来检验信号的有效性。看夏普比率、最大回撤、胜率等指标。
  5. 信号执行:把信号转化成实际交易指令。这里要考虑滑点、手续费、市场冲击。

你可能会问:这五个步骤哪个最重要?

我的答案是:数据清洗。为什么?因为「垃圾进,垃圾出」。你模型再牛,数据是脏的,结果就是错的。我在项目中遇到过,因为某天的数据里混了一个「价格跳空到0」的异常值,导致整个回测结果失真。排查了整整两天才找到原因。

一句话总结:信号处理不是「锦上添花」,而是「雪中送炭」。没有好的信号处理,就没有好的量化策略。

1.4 一个简单的信号处理示例

光说不练假把式。我给大家看一段简单的Python代码,演示如何计算一个最基本的信号——移动平均线交叉信号。

import pandas as pd
import numpy as np

# 假设我们有一组收盘价数据
prices = [100, 102, 101, 105, 107, 106, 108, 110, 109, 111]

# 计算5日均线和10日均线
def moving_average(data, window):
    return pd.Series(data).rolling(window=window).mean().values

ma5 = moving_average(prices, 5)
ma10 = moving_average(prices, 10)

# 生成信号:当5日均线上穿10日均线时买入,下穿时卖出
signals = []
for i in range(1, len(prices)):
    if ma5[i] > ma10[i] and ma5[i-1] <= ma10[i-1]:
        signals.append('买入')
    elif ma5[i] < ma10[i] and ma5[i-1] >= ma10[i-1]:
        signals.append('卖出')
    else:
        signals.append('持有')

print('信号序列:', signals)

这段代码很简单,但背后藏着很多细节。比如:

  • 为什么用5日和10日?换成其他参数会怎样?
  • 信号出现后,是立即执行还是等收盘确认?
  • 如果连续出现多个信号,怎么处理?

这些问题,咱们后面的章节会一一解答。今天先把基础打牢。

课后思考:如果你拿到一组价格数据,第一件事会做什么?我的习惯是先画个图,看看有没有明显的异常值。视觉检查虽然不严谨,但往往能发现程序发现不了的问题。

好了,信号处理的基础就讲到这里。下一章咱们聊聊「数据清洗」这个看似枯燥、实则关键的话题。到时候我会分享一些我在实战中踩过的坑,保证让你少走弯路。