问题描述
解决方案
佳庆指标(Chaikin Oscillator,简称 CHO)是由马克·佳庆(Marc Chaikin)发明的,它本质上是累积/派发线(Accumulation/Distribution Line, ADL)的移动平均线差值。
CHO 结合了价格和成交量,用于衡量资金流入(累积)和流出(派发)的动量。它类似于 MACD,但应用于 ADL 指标而非价格本身。
1. 佳庆指标 (CHO) 的计算原理
CHO 的计算步骤如下:
- 计算资金流量乘数 (CLV):
$$CLV = \frac{(收盘价 - 最低价) - (最高价 - 收盘价)}{最高价 - 最低价}$$ - 计算资金流量 (Money Flow Volume):
$$Money Flow Volume = CLV \times 成交量$$ - 计算累积/派发线 (ADL):
$$ADL_{今日} = ADL_{昨日} + Money Flow Volume_{今日}$$ - 计算 CHO:
$$CHO = EMA(ADL, 3) - EMA(ADL, 10)$$
(通常使用 3日 EMA 和 10日 EMA)
2. 交易策略逻辑
在本示例策略中,我们将采用经典的零轴交叉策略:
- 买入信号:CHO 线由下向上穿过零轴(金叉)。这表明短期资金流入动能强于长期,市场进入累积阶段。
- 卖出信号:CHO 线由上向下穿过零轴(死叉)。这表明短期资金流出动能增强,市场进入派发阶段。
3. 聚宽 (JoinQuant) 策略代码实现
以下是一个完整的策略代码,您可以直接复制到聚宽的回测环境中运行。代码使用了 talib 库来计算 CHO,以确保计算的高效和准确。
# -*- coding: utf-8 -*-
import jqdata
import talib
import numpy as np
def initialize(context):
"""
初始化函数,设定基准、手续费、滑点等
"""
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定操作的股票(示例:平安银行)
g.security = '000001.XSHE'
# CHO指标参数
g.fast_period = 3 # 短周期
g.slow_period = 10 # 长周期
# 设定交易费用
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
def handle_data(context, data):
"""
按天运行的策略函数
"""
security = g.security
# 1. 获取历史数据
# 获取足够长的数据以确保EMA计算稳定,通常取 slow_period 的 3-4 倍以上
# 这里获取过去 60 天的 High, Low, Close, Volume
h_data = attribute_history(security, 60, '1d', ['high', 'low', 'close', 'volume'])
# 如果数据不足(例如停牌或刚上市),则跳过
if len(h_data) < 40:
return
# 2. 提取数据为 numpy 数组,供 talib 使用
high = h_data['high'].values
low = h_data['low'].values
close = h_data['close'].values
volume = h_data['volume'].values
# 3. 计算 CHO 指标
# talib.ADOSC(high, low, close, volume, fastperiod=3, slowperiod=10)
# 注意:talib计算的是 Chaikin Oscillator
cho = talib.ADOSC(high, low, close, volume, fastperiod=g.fast_period, slowperiod=g.slow_period)
# 获取当前和前一天的 CHO 值
current_cho = cho[-1]
prev_cho = cho[-2]
# 检查是否计算出有效值(剔除 NaN)
if np.isnan(current_cho) or np.isnan(prev_cho):
return
# 4. 获取当前账户资金和持仓
cash = context.portfolio.available_cash
curr_position = context.portfolio.positions[security].closeable_amount
# 5. 生成交易信号
# 买入信号:CHO 上穿 0 轴
if prev_cho < 0 and current_cho > 0:
if cash > 0:
# 全仓买入
order_value(security, cash)
log.info(f"买入信号: CHO上穿0轴 (前值:{prev_cho:.2f}, 现值:{current_cho:.2f})")
# 卖出信号:CHO 下穿 0 轴
elif prev_cho > 0 and current_cho < 0:
if curr_position > 0:
# 清仓卖出
order_target(security, 0)
log.info(f"卖出信号: CHO下穿0轴 (前值:{prev_cho:.2f}, 现值:{current_cho:.2f})")
# 6. 绘制图表(可选)
record(CHO=current_cho)
4. 策略优化建议
单纯使用 CHO 进行零轴交叉交易可能会在震荡市中产生较多虚假信号。在实际量化研究中,通常会结合以下方法进行优化:
- 结合趋势过滤器:
- 引入移动平均线(如 MA60 或 MA200)。只有当价格位于均线之上(趋势向上)时,才执行 CHO 的买入信号;当价格位于均线之下时,忽略买入信号或仅执行卖出信号。
- 背离分析:
- 底背离:股价创新低,但 CHO 没有创新低(底部抬高),通常是强烈的买入信号。
- 顶背离:股价创新高,但 CHO 没有创新高(顶部降低),通常是强烈的卖出信号。
- 注:编写背离策略需要识别局部极值点,逻辑比零轴交叉复杂。
- 阈值调整:
- 不使用 0 作为界限,而是设定一个缓冲区。例如:CHO > 5000 买入,CHO < -5000 卖出(具体数值取决于成交量级,或者对 CHO 进行标准化处理)。
Q&A
Q1: 为什么代码中要使用 talib.ADOSC 而不是自己写公式计算?
A1: talib 是底层的 C 语言库,计算速度极快且经过了广泛验证。自己编写公式容易在 EMA 初始化或数据对齐上出错。在量化平台中,优先使用标准库是最佳实践。
Q2: CHO 指标和 MACD 有什么区别?
A2: MACD 是基于价格的 EMA 差值,反映价格趋势;CHO 是基于**ADL(累积/派发线)**的 EMA 差值,反映资金流向(成交量)的动量。CHO 通常能比单纯的价格指标更早发现趋势的反转,因为“量在价先”。
Q3: 这个策略适合什么类型的股票?
A3: CHO 严重依赖成交量数据,因此它更适合成交量活跃、流动性好的个股(如沪深300成分股)。对于成交量极不规则或经常停牌的股票,CHO 可能会产生剧烈波动和误导性信号。