3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 估波曲线 (Coppock Curve) 的长线量化交易策略。
估波曲线(Coppock Curve)是一种用于识别股市长期底部买入机会的动量指标。它通过计算两个不同周期的变动率(ROC)之和,再对其进行加权移动平均(WMA)得出。
经典参数:
交易信号逻辑:
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
'''
策略名称:估波曲线 (Coppock Curve) 长线策略
策略周期:建议在 日线 (1d) 周期上运行,但在内部调用 月线 (1mon) 数据计算指标
'''
def init(ContextInfo):
# 1. 设置资金账号
# 请替换为您自己的资金账号
ContextInfo.account_id = '6000000000'
ContextInfo.account_type = 'STOCK'
ContextInfo.set_account(ContextInfo.account_id)
# 2. 设置股票池 (示例使用 沪深300成分股,可根据需要修改)
# 为了演示方便,这里只选取几个代表性标的,实际使用可使用 get_sector 获取板块
ContextInfo.target_list = ['600000.SH', '000001.SZ', '600519.SH', '000858.SZ']
ContextInfo.set_universe(ContextInfo.target_list)
# 3. 策略参数设置 (经典Coppock参数:14, 11, 10)
ContextInfo.roc_long_period = 14 # 长周期 ROC (月)
ContextInfo.roc_short_period = 11 # 短周期 ROC (月)
ContextInfo.wma_period = 10 # WMA 平滑周期 (月)
# 每次下单金额占总资产的比例
ContextInfo.trade_ratio = 0.1
def wma(series, window):
'''
计算加权移动平均 (Weighted Moving Average)
公式: (P1*1 + P2*2 + ... + Pn*n) / (1 + 2 + ... + n)
'''
weights = np.arange(1, window + 1)
# 使用 rolling apply 计算 WMA
return series.rolling(window).apply(lambda x: np.dot(x, weights) / weights.sum(), raw=True)
def calculate_coppock(close_series, roc_long, roc_short, wma_p):
'''
计算估波曲线值
'''
# 1. 计算长周期 ROC: (当前价 - N前价) / N前价 * 100
roc_1 = close_series.pct_change(periods=roc_long) * 100
# 2. 计算短周期 ROC
roc_2 = close_series.pct_change(periods=roc_short) * 100
# 3. 两者相加
roc_sum = roc_1 + roc_2
# 4. 计算 WMA
coppock = wma(roc_sum, wma_p)
return coppock
def handlebar(ContextInfo):
# 获取当前K线位置,避免在历史数据不足时计算报错
if ContextInfo.barpos < 30:
return
# 获取当前时间
current_date = timetag_to_datetime(ContextInfo.get_bar_timetag(ContextInfo.barpos), '%Y%m%d')
# 获取股票池
stock_list = ContextInfo.get_universe()
# 获取历史行情数据
# 注意:Coppock是基于月线的指标,所以这里强制取 '1mon' 数据
# 需要的数据长度 = 长ROC周期 + WMA周期 + 安全余量
data_count = ContextInfo.roc_long_period + ContextInfo.wma_period + 20
market_data = ContextInfo.get_market_data_ex(
['close'],
stock_list,
period='1mon',
count=data_count,
dividend_type='front' # 前复权
)
# 获取账户持仓信息
positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
holding_stocks = [pos.m_strInstrumentID for pos in positions if pos.m_nVolume > 0]
for stock in stock_list:
if stock not in market_data:
continue
df = market_data[stock]
# 数据清洗,去除空值
df.dropna(inplace=True)
# 数据长度不足无法计算
if len(df) < (ContextInfo.roc_long_period + ContextInfo.wma_period):
continue
# 计算指标
df['coppock'] = calculate_coppock(
df['close'],
ContextInfo.roc_long_period,
ContextInfo.roc_short_period,
ContextInfo.wma_period
)
# 获取最近两个月的指标值
# iloc[-1] 是当前月(可能是未走完的),iloc[-2] 是上个月
# 为了信号稳定,通常建议使用已完成的月份数据,或者在月末最后一天交易
# 这里取最后两个有效值进行比较
curr_coppock = df['coppock'].iloc[-1]
prev_coppock = df['coppock'].iloc[-2]
# ---------------- 交易逻辑 ----------------
# 1. 买入逻辑:
# 条件A: 曲线位于零轴下方 (prev_coppock < 0)
# 条件B: 曲线拐头向上 (curr_coppock > prev_coppock)
# 条件C: 当前没有持仓
if prev_coppock < 0 and curr_coppock > prev_coppock and stock not in holding_stocks:
print(f"[{current_date}] {stock} 触发买入信号: 估波曲线底部拐头 (前值:{prev_coppock:.2f}, 现值:{curr_coppock:.2f})")
# 资金管理:按比例下单
passorder(23, 1113, ContextInfo.account_id, stock, 5, -1, ContextInfo.trade_ratio, ContextInfo)
# 2. 卖出逻辑:
# 估波曲线主要用于买入,卖出通常结合趋势反转或止损
# 简单逻辑:当曲线数值开始下降时卖出 (curr_coppock < prev_coppock)
elif stock in holding_stocks:
if curr_coppock < prev_coppock:
print(f"[{current_date}] {stock} 触发卖出信号: 估波曲线下降")
passorder(24, 1101, ContextInfo.account_id, stock, 5, -1, 1, ContextInfo) # 1代表卖出全部持仓
# 也可以加入止损逻辑,例如:
# pos = next((p for p in positions if p.m_strInstrumentID == stock), None)
# if pos and (current_price - pos.m_dOpenPrice) / pos.m_dOpenPrice < -0.10:
# passorder(24, 1101, ContextInfo.account_id, stock, 5, -1, 1, ContextInfo)
数据频率转换:
1d)上回测或运行,但代码中使用了 ContextInfo.get_market_data_ex(..., period='1mon') 强制获取月线数据。这是因为估波曲线本质上是一个长线月度指标。WMA 计算:
pandas 库默认没有直接的 WMA 函数,代码中自定义了 wma 函数,利用 numpy 的点积(dot product)来实现加权平均。信号稳定性:
iloc[-1](当前月)和 iloc[-2](上个月)。iloc[-1] 的数据是会随着每天行情的波动而变化的(即信号可能会“闪烁”)。对于长线策略,这通常是可以接受的,或者你可以修改逻辑为只在月末最后一天交易。买卖条件:
init 函数中的 ContextInfo.account_id 为你的实际账号。ContextInfo.target_list 为你关注的股票列表(建议选择大盘蓝筹股或ETF,因为估波曲线对波动较大的小盘股可能产生滞后)。Q: 为什么使用月线数据而不是日线数据?
A: 估波曲线的设计初衷就是为了过滤短期市场噪音,捕捉长达数年或数月的市场底部。使用日线计算会导致信号过于频繁,失去长线指标的意义。
Q: 如何调整策略的灵敏度?
A: 可以调整 roc_long_period (14), roc_short_period (11), wma_period (10) 这三个参数。减小数值会使指标更灵敏,但虚假信号也会增加。
Q: 可以在实盘中自动下单吗?
A: 可以。代码中使用了 passorder 函数。在实盘模式下,只要账号绑定正确且资金充足,满足条件时会自动发出委托。请务必先在模拟盘充分测试。