问题描述
解决方案
三均线交易策略 (Three Moving Averages Strategy)
三均线策略是一种经典的趋势跟踪策略。它利用三条不同周期的移动平均线(例如短期、中期、长期)的排列关系来判断市场趋势。
策略逻辑
-
均线设置:
- 短期均线 (Short MA):反应价格的短期波动(如 5日线)。
- 中期均线 (Medium MA):反应价格的中期趋势(如 10日线)。
- 长期均线 (Long MA):反应价格的长期方向(如 20日线或60日线)。
-
交易信号:
- 买入信号(多头排列):当 短期均线 > 中期均线 > 长期均线 时,视为上涨趋势确立,全仓买入。
- 卖出信号(空头排列或趋势破坏):当 短期均线 < 中期均线 (或者三者呈现空头排列 短<中<长)时,视为趋势结束或回调,清仓卖出。
- 注:本示例代码采用“短期 < 中期”作为止盈/止损信号,反应更灵敏,避免利润回撤过多。
PTrade 策略代码实现
以下是完整的策略代码,您可以直接复制到 PTrade 回测环境中运行。
def initialize(context):
"""
初始化函数,设置股票池和全局变量
"""
# 1. 设置要操作的股票,这里以 恒生电子(600570.SS) 为例
g.security = '600570.SS'
set_universe(g.security)
# 2. 设置均线周期参数
g.short_period = 5 # 短期均线周期
g.mid_period = 10 # 中期均线周期
g.long_period = 20 # 长期均线周期
# 3. 设置滑点和手续费(可选,回测常用设置)
set_slippage(slippage=0.002) # 设置滑点
set_commission(commission_ratio=0.0003, min_commission=5.0) # 设置手续费
def handle_data(context, data):
"""
盘中运行函数,每个单位时间(如每天)运行一次
"""
security = g.security
# 1. 获取历史收盘价数据
# 获取的数量需要足够计算最长周期的均线,这里多取2天以防万一
count = g.long_period + 2
# get_history 返回的是 DataFrame
history = get_history(count, frequency='1d', field='close', security_list=security, fq='pre')
# 检查数据是否获取成功
if history is None or len(history) < g.long_period:
log.info("历史数据不足,跳过本次计算")
return
# 提取收盘价序列 (Series)
close_prices = history['close']
# 2. 计算三条均线的值
# 计算短期均线 (MA5)
ma_short = close_prices[-g.short_period:].mean()
# 计算中期均线 (MA10)
ma_mid = close_prices[-g.mid_period:].mean()
# 计算长期均线 (MA20)
ma_long = close_prices[-g.long_period:].mean()
# 获取当前持仓数量
position = get_position(security).amount
# 获取当前可用现金
cash = context.portfolio.cash
# 3. 生成交易信号并执行
# 买入逻辑:多头排列 (短 > 中 > 长) 且 当前无持仓
if ma_short > ma_mid and ma_mid > ma_long:
if position == 0:
# 全仓买入
order_value(security, cash)
log.info("买入信号触发:多头排列 (MA%s=%.2f > MA%s=%.2f > MA%s=%.2f)" % (
g.short_period, ma_short,
g.mid_period, ma_mid,
g.long_period, ma_long
))
# 卖出逻辑:短期均线下穿中期均线 (趋势转弱) 且 当前有持仓
# 也可以修改为 ma_short < ma_mid < ma_long (完全空头排列才卖)
elif ma_short < ma_mid:
if position > 0:
# 清仓卖出
order_target(security, 0)
log.info("卖出信号触发:趋势转弱 (MA%s=%.2f < MA%s=%.2f)" % (
g.short_period, ma_short,
g.mid_period, ma_mid
))
代码详细解析
1. 初始化 (initialize)
set_universe: 设定策略操作的股票池。- 全局变量 (
g.xxx): 我们将均线的周期(5, 10, 20)定义为全局变量。这样做的好处是,如果您想调整为(10, 30, 60),只需在initialize中修改数字即可,无需改动核心逻辑。
2. 数据获取 (get_history)
- 我们使用
get_history获取过去g.long_period + 2天的收盘价。 - 注意:必须获取足够长度的数据才能计算出长期均线。例如计算20日均线,至少需要过去20天的数据。
fq='pre':使用前复权数据,这在股票回测中非常重要,可以避免分红配股导致的价格跳空影响均线计算。
3. 均线计算
- 利用 Pandas Series 的切片和
mean()方法计算均值。 close_prices[-5:]表示取最后5个数据。
4. 交易逻辑
- 买入:严格遵守
MA_Short > MA_Mid > MA_Long。这代表短期爆发力强,且中长期趋势向上,是最稳健的进场点。 - 卖出:代码中使用了
MA_Short < MA_Mid作为卖出点。- 解释:虽然三均线策略对应的卖点通常是空头排列(短<中<长),但在实际A股交易中,等到三线完全空头排列时,股价往往已经跌去很多。因此,使用短期均线下穿中期均线作为止损/止盈信号,通常能更好地保住利润。
常见问题 Q&A
Q1: 如何修改均线的周期?
A: 在 initialize 函数中,修改 g.short_period、g.mid_period 和 g.long_period 的值即可。例如改为 10, 30, 60:
g.short_period = 10
g.mid_period = 30
g.long_period = 60
Q2: 这个策略适合什么级别的K线?
A: 默认代码中的 get_history(..., frequency='1d') 是基于日线级别的。
如果您想做分钟级别的三均线策略(例如60分钟线),需要:
- 将策略运行频率设置为“分钟”。
- 将代码中的
frequency='1d'改为frequency='60m'。
Q3: 为什么有时候会出现“未来函数”的警告?
A: 在 PTrade 回测中,如果在 handle_data 中直接获取当天的 close 价格并立即成交,可能包含了一点点未来信息(因为实际交易时你无法确切知道收盘价)。
- 解决方法:PTrade 的
handle_data在日线回测时通常是在收盘后或收盘前一刻运行。为了更严谨,可以使用history[:-1]来计算截止到昨天的均线,或者使用分钟回测在盘中实时计算。但在简单的日线趋势策略教学中,上述代码是标准的写法。
Q4: 如何同时操作多只股票?
A: 您需要将 g.security 设置为一个列表,并在 handle_data 中使用 for 循环遍历。
修改示例:
def initialize(context):
g.security = ['600570.SS', '000001.SZ'] # 列表
set_universe(g.security)
# ... 其他参数 ...
def handle_data(context, data):
for stock in g.security:
# 后续逻辑中的 g.security 全部替换为 stock
# get_history 需要单独对 stock 获取,或者批量获取后处理
# ...