问题描述
解决方案
这是一个基于 TRIX(Triple Exponential Average,三重指数平滑移动平均) 指标的 PTrade 量化交易策略。
策略原理
TRIX 是一种动量指标,通过对收盘价进行三次指数平滑处理,过滤掉频繁的短期波动,从而反映股价的长期趋势。
- TRIX 线:收盘价的三重指数移动平均线(EMA3)的变化率。
- MATRIX 线:TRIX 线的 M 日简单移动平均线(信号线)。
交易信号:
- 金叉买入:当 TRIX 线由下向上穿过 MATRIX 线时,视为买入信号。
- 死叉卖出:当 TRIX 线由上向下穿过 MATRIX 线时,视为卖出信号。
策略代码
import pandas as pd
import numpy as np
def initialize(context):
"""
初始化函数,设置股票池和参数
"""
# 设置要操作的股票,这里以恒生电子为例
g.security = '600570.SS'
set_universe(g.security)
# TRIX 指标参数
g.N = 12 # 计算 EMA 的周期
g.M = 9 # 计算 MATRIX(信号线)的周期
# 设置滑点和佣金(回测常用设置)
set_commission(commission_ratio=0.0003, min_commission=5.0)
set_slippage(slippage=0.002)
def handle_data(context, data):
"""
按周期运行的策略逻辑
"""
security = g.security
# 1. 获取历史收盘价数据
# TRIX 需要三次平滑,建议获取足够长的数据以消除初始值的偏差
# N=12, M=9,获取 100 条数据通常足够稳定
hist_data = get_history(100, frequency='1d', field='close', security_list=security, fq='pre')
if hist_data is None or len(hist_data) < 50:
log.info("数据不足,跳过计算")
return
# 2. 计算 TRIX 指标
# 将数据转换为 Series 方便计算
close_prices = hist_data['close']
# 计算 TRIX 和 MATRIX
trix, matrix = calculate_trix(close_prices, g.N, g.M)
# 确保指标数据有效(去除 NaN)
if np.isnan(trix.iloc[-1]) or np.isnan(matrix.iloc[-1]) or \
np.isnan(trix.iloc[-2]) or np.isnan(matrix.iloc[-2]):
return
# 获取当前和前一时刻的指标值
current_trix = trix.iloc[-1]
current_matrix = matrix.iloc[-1]
prev_trix = trix.iloc[-2]
prev_matrix = matrix.iloc[-2]
# 3. 获取账户持仓和资金情况
position = get_position(security)
cash = context.portfolio.cash
current_price = data[security]['close']
# 4. 生成交易信号
# 金叉:上个周期 TRIX < MATRIX,当前周期 TRIX > MATRIX
golden_cross = (prev_trix < prev_matrix) and (current_trix > current_matrix)
# 死叉:上个周期 TRIX > MATRIX,当前周期 TRIX < MATRIX
death_cross = (prev_trix > prev_matrix) and (current_trix < current_matrix)
# 5. 执行交易
# 买入逻辑:金叉且当前无持仓
if golden_cross and position.amount == 0:
log.info("TRIX 金叉形成 (TRIX: %.3f, MATRIX: %.3f),买入 %s" % (current_trix, current_matrix, security))
order_value(security, cash)
# 卖出逻辑:死叉且有持仓
elif death_cross and position.amount > 0:
log.info("TRIX 死叉形成 (TRIX: %.3f, MATRIX: %.3f),卖出 %s" % (current_trix, current_matrix, security))
order_target(security, 0)
def calculate_trix(series, n, m):
"""
手动计算 TRIX 指标
:param series: 收盘价序列 (pandas Series)
:param n: EMA 周期
:param m: 信号线周期
:return: trix, matrix (pandas Series)
"""
# 1. 计算第一次 EMA (EMA1)
ema1 = series.ewm(span=n, adjust=False).mean()
# 2. 计算第二次 EMA (EMA2)
ema2 = ema1.ewm(span=n, adjust=False).mean()
# 3. 计算第三次 EMA (EMA3)
ema3 = ema2.ewm(span=n, adjust=False).mean()
# 4. 计算 TRIX: (EMA3 - 昨日EMA3) / 昨日EMA3 * 100
# pct_change() 计算的是 (curr - prev) / prev,默认不乘 100,所以手动乘以 100
trix = ema3.pct_change() * 100
# 5. 计算 MATRIX (TRIX 的 m 日简单移动平均)
matrix = trix.rolling(window=m).mean()
return trix, matrix
代码说明
-
数据获取 (
get_history):- TRIX 指标涉及三次指数平滑,对历史数据的依赖性较强。为了保证计算结果的准确性,我们获取了 100 天的历史数据。如果数据量太少,早期的 EMA 值会不稳定。
- 使用
fq='pre'(前复权)数据,以避免分红派息导致的价格跳空影响指标计算。
-
指标计算 (
calculate_trix):- PTrade 的 API 文档中没有直接提供
get_TRIX函数,因此我们使用pandas库手动实现。 ewm(span=n, adjust=False).mean()用于计算指数移动平均(EMA)。pct_change()用于计算变化率。rolling(window=m).mean()用于计算简单移动平均(MA),即 MATRIX 线。
- PTrade 的 API 文档中没有直接提供
-
交易逻辑:
- 金叉:
prev_trix < prev_matrix且current_trix > current_matrix。 - 死叉:
prev_trix > prev_matrix且current_trix < current_matrix。 - 使用
order_value全仓买入,使用order_target清仓卖出。
- 金叉:
-
兼容性:
- 代码避免了 Python 3.6+ 的 f-string 语法,使用了
%格式化字符串,确保在 PTrade 的 Python 3.5 环境中也能正常运行。
- 代码避免了 Python 3.6+ 的 f-string 语法,使用了
Q&A
Q: 为什么 TRIX 指标适合中长期趋势?
A: 因为 TRIX 对价格进行了三次平滑处理,极大地过滤了短期的高频噪音。这使得它对价格变化的反应比 MACD 或 RSI 更滞后,但也更稳定,不容易产生虚假信号,因此更适合捕捉中长期的主要趋势。
Q: 如何调整策略的灵敏度?
A: 修改 initialize 函数中的 g.N 和 g.M。
- 减小
g.N(例如改为 5 或 9):指标会更敏感,信号更多,但假信号风险增加。 - 增大
g.N(例如改为 20 或 30):指标更平滑,信号更少,适合捕捉大趋势,但滞后性会增强。
Q: 可以在分钟级别回测吗?
A: 可以。只需在回测设置界面将频率选为“分钟”,并将 get_history 中的 frequency 参数改为 '1m', '5m', '30m' 等即可。代码逻辑无需修改。