3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个非常经典的量化交易思路。要实现一个“自适应”策略,核心在于市场状态的识别(Market Regime Classification)。
我们需要一个指标来判断当前是“趋势市”还是“震荡市”,然后根据判断结果动态切换交易逻辑。
市场状态识别(核心):
ER = 价格总位移 / 价格总路程。趋势策略(当 ER > 阈值):
震荡/反转策略(当 ER <= 阈值):
以下是完整的策略代码,您可以直接复制到 PTrade 的回测环境中运行。
import numpy as np
import pandas as pd
def initialize(context):
"""
初始化函数,设置参数和股票池
"""
# 1. 设置要操作的标的(这里以沪深300ETF为例,也可以换成具体股票)
g.security = '510300.SS'
set_universe(g.security)
# 2. 市场状态识别参数 (效率系数 ER)
g.er_period = 20 # 计算ER的时间窗口
g.er_threshold = 0.25 # ER阈值,大于此值判断为趋势,小于为震荡
# 3. 趋势策略参数 (双均线)
g.ma_short_len = 10 # 短期均线
g.ma_long_len = 30 # 长期均线
# 4. 震荡策略参数 (RSI)
g.rsi_period = 14 # RSI周期
g.rsi_low = 30 # 超卖阈值(买入)
g.rsi_high = 70 # 超买阈值(卖出)
# 设置手续费(可选,模拟真实交易成本)
set_commission(commission_ratio=0.0003, min_commission=5.0, type="ETF")
def get_efficiency_ratio(close_prices):
"""
计算考夫曼效率系数 (Efficiency Ratio)
ER = |总位移| / 总路程
"""
if len(close_prices) < 2:
return 0
# 计算总位移:终点 - 起点 的绝对值
net_change = abs(close_prices[-1] - close_prices[0])
# 计算总路程:每天价格变化幅度的绝对值之和
diffs = np.diff(close_prices)
sum_of_changes = np.sum(np.abs(diffs))
if sum_of_changes == 0:
return 0
er = net_change / sum_of_changes
return er
def handle_data(context, data):
"""
盘中运行函数,每日或每分钟调用
"""
security = g.security
# -------------------------------------------------------
# 1. 数据获取
# -------------------------------------------------------
# 获取足够长的历史数据以计算指标
# 需要的最大长度是长期均线长度 + 一些缓冲
lookback = max(g.er_period, g.ma_long_len, g.rsi_period) + 5
# 获取历史收盘价
history_df = get_history(lookback, '1d', 'close', security, fq='pre', include=True)
if len(history_df) < lookback:
return # 数据不足,暂不交易
close_prices = history_df['close'].values
# -------------------------------------------------------
# 2. 市场状态识别 (计算ER)
# -------------------------------------------------------
# 取最近 g.er_period 天的数据计算ER
er_data = close_prices[-g.er_period:]
current_er = get_efficiency_ratio(er_data)
# 获取当前持仓
position = get_position(security).amount
cash = context.portfolio.cash
current_price = data[security]['close']
# 记录日志以便调试
# log.info("日期: %s, ER值: %.4f" % (context.blotter.current_dt, current_er))
# -------------------------------------------------------
# 3. 策略分流
# -------------------------------------------------------
if current_er > g.er_threshold:
# === 场景 A: 趋势市场 (动量策略) ===
# 使用双均线逻辑
ma_short = close_prices[-g.ma_short_len:].mean()
ma_long = close_prices[-g.ma_long_len:].mean()
# 趋势策略逻辑:金叉买入,死叉卖出
if ma_short > ma_long:
# 趋势向上,满仓买入
if cash > 0:
order_value(security, cash)
log.info("[趋势模式] 金叉买入: ER=%.2f, MA_S=%.2f, MA_L=%.2f" % (current_er, ma_short, ma_long))
elif ma_short < ma_long:
# 趋势向下,清仓
if position > 0:
order_target(security, 0)
log.info("[趋势模式] 死叉卖出: ER=%.2f" % (current_er))
else:
# === 场景 B: 震荡市场 (反转策略) ===
# 使用 RSI 逻辑
# PTrade 内置 get_RSI 接口,直接调用
# 注意:get_RSI 返回的是 numpy array,取最后一个值
rsi_values = get_RSI(close_prices, g.rsi_period)
current_rsi = rsi_values[-1]
# 震荡策略逻辑:超卖买入,超买卖出
if current_rsi < g.rsi_low:
# 超卖,预期反弹,买入
if cash > 0:
order_value(security, cash)
log.info("[震荡模式] RSI超卖买入: ER=%.2f, RSI=%.2f" % (current_er, current_rsi))
elif current_rsi > g.rsi_high:
# 超买,预期回调,卖出
if position > 0:
order_target(security, 0)
log.info("[震荡模式] RSI超买卖出: ER=%.2f, RSI=%.2f" % (current_er, current_rsi))
市场状态过滤器 (get_efficiency_ratio):
g.er_threshold (0.25) 来划分界限。您可以根据回测结果调整这个值。数据获取 (get_history):
get_history 获取收盘价序列。为了保证计算准确,count (lookback) 设置得比所需周期稍大一些。include=True 确保包含当前周期的最新数据。趋势模块 (Moving Average):
震荡模块 (RSI):
g.er_threshold 是最敏感的参数。对于波动率大的标的(如科技股),可能需要调高阈值;对于大盘股,可能需要调低。Q: 为什么不直接同时使用均线和RSI,而要分状态?
A: 因为指标之间存在互斥性。在强趋势中,RSI会失效(长期超买/超卖);在震荡中,均线会失效(频繁金叉死叉造成磨损)。分状态处理可以扬长避短。
Q: 这个策略适合什么频率?
A: 代码中默认使用的是日线级别 ('1d')。对于自适应策略,日线级别通常比分钟级别更稳定,因为分钟级别的噪音(Noise)更大,ER系数容易失真。
Q: 如何在PTrade中查看ER值的变化情况?
A: 代码中有一行注释掉的 log.info。您可以取消注释,回测时在日志面板中查看每天的ER值,以此来辅助您调整阈值。