3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 ptrade 量化交易平台中,虽然系统提供了内置的技术指标计算函数(如 get_MACD),但在实际策略开发中,内置函数往往由于历史数据长度不足或平滑基期选择不同,导致计算出的指标数值与券商软件终端存在微小偏差。为了追求极致的信号精准度,量化交易员通常会选择手动编写 EXPMA 与 MACD 的平滑系数计算公式。
本文将为您详细解析如何在 ptrade 中通过 Python 自定义实现这两个核心指标。
EXPMA 的核心在于平滑系数 $\alpha$ 的计算。其公式为:
$$\alpha = \frac{m}{N + 1}$$
其中:
2.0。当日的 EXPMA 值计算公式为:
$$\text{EXPMA}{\text{today}} = \alpha \times \text{Price}{\text{today}} + (1 - \alpha) \times \text{EXPMA}_{\text{yesterday}}$$
MACD 是基于两条不同周期的 EXPMA(EMA)线计算而来的:
以下是一个完整的 ptrade 策略示例,展示了如何手动编写算法函数,并在 handle_data 中进行实时计算与交易信号判断:
# -*- coding: utf-8 -*-
# 1. 指数平滑均线基础函数
def f_expma(N, m, EXPMA_prev, price):
"""
N: 时间周期
m: 平滑因子系数,默认2.0
EXPMA_prev: 前一日的EXPMA值
price: 当日收盘价
"""
alpha = m / (N + 1)
EXPMA_curr = alpha * price + (1 - alpha) * EXPMA_prev
return EXPMA_curr
# 2. 自定义MACD计算函数
def calculate_custom_macd(N1, N2, N3, m, EMA12_prev, EMA26_prev, DEA_prev, current_price):
"""
手动递推计算当日的 EMA12, EMA26, DIF, DEA 和 MACD BAR
"""
# 计算今日的快速与慢速EMA
EMA12_curr = f_expma(N1, m, EMA12_prev, current_price)
EMA26_curr = f_expma(N2, m, EMA26_prev, current_price)
# 计算DIF
DIF_curr = EMA12_curr - EMA26_curr
# 计算DEA (DIF的N3日平滑)
beta = m / (N3 + 1)
DEA_curr = beta * DIF_curr + (1 - beta) * DEA_prev
# 计算MACD柱状值
BAR_curr = 2 * (DIF_curr - DEA_curr)
return EMA12_curr, EMA26_curr, DIF_curr, DEA_curr, BAR_curr
def initialize(context):
# 初始化股票池
g.security = '600570.SS' # 恒生电子
set_universe(g.security)
# 初始化指标全局变量
g.is_initialized = False
g.EMA12 = None
g.EMA26 = None
g.DIF = None
g.DEA = None
def handle_data(context, data):
security = g.security
# 过滤停牌
if data[security].is_open <= 0:
return
# 获取历史收盘价(获取最近2天数据用于递推)
close_data = get_history(2, '1d', field='close', security_list=security)
if close_data is None or len(close_data) < 2:
return
prev_close = close_data[security]['close'][-2]
curr_close = close_data[security]['close'][-1]
# 首次运行初始化基期价格
if not g.is_initialized:
g.EMA12 = prev_close
g.EMA26 = prev_close
g.DIF = 0.0
g.DEA = 0.0
g.is_initialized = True
# 设定标准MACD参数 (12, 26, 9)
N1, N2, N3 = 12, 26, 9
m = 2.0
# 保存昨日值用于金叉死叉对比
DIF_prev = g.DIF
DEA_prev = g.DEA
# 计算今日最新指标值
g.EMA12, g.EMA26, g.DIF, g.DEA, bar = calculate_custom_macd(
N1, N2, N3, m, g.EMA12, g.EMA26, g.DEA, curr_close
)
# 获取当前账户现金与持仓
cash = context.portfolio.cash
position = get_position(security).amount
# 策略逻辑:DIF 向上突破 DEA(金叉),且两者均大于0 -> 买入
if g.DIF > 0 and g.DEA > 0 and DIF_prev < DEA_prev and g.DIF > g.DEA:
if cash > curr_close * 100:
order(security, 100)
log.info(f"【买入信号】DIF金叉DEA,买入 {security} 100股")
# 策略逻辑:DIF 向下突破 DEA(死叉) -> 卖出平仓
elif DIF_prev > DEA_prev and g.DIF < g.DEA and position > 0:
order_target(security, 0)
log.info(f"【卖出信号】DIF死叉DEA,清仓 {security}")
prev_close)直接作为 EMA 的初始值。为了使计算结果与真实行情软件完全一致,建议在回测或实盘初始化时,先拉取至少 100 天以上 的历史数据进行预热计算。round(price, 2) 进行截断,避免因精度问题导致柜台废单。