均线走势(60日线从下降,到走平,到掉头向上)如何用策略代码怎么出来?
均线走势(60日线从下降,到走平,到掉头向上)如何用策略代码怎么出来?
问题描述
解决方案
在量化交易中,识别均线(如60日均线)从“下降 -> 走平 -> 掉头向上”的形态,是一个非常经典的寻找底部反转信号的策略。在 JoinQuant(聚宽)平台上,我们可以通过获取历史收盘价,计算出连续多日的 MA60 序列,然后通过比较这几天 MA60 的数值变化来实现这个逻辑。
实现思路
- 获取足够长的数据:要计算最近几天的 60 日均线,我们需要获取过去 60 天加上观察天数(例如 5 天)的数据,总共约 65 天的收盘价。
- 计算 MA60 序列:利用
pandas的rolling(window=60).mean()方法,计算出每日的 60 日均线值。 - 形态判断:
- 下降:前期的 MA60 呈递减趋势(如
MA60[-5] > MA60[-4] > MA60[-3])。 - 走平:中期的 MA60 变化极小,设定一个极小的阈值(如
abs(MA60[-2] - MA60[-3]) / MA60[-3] < 0.001)。 - 向上:最新的 MA60 呈递增趋势(如
MA60[-1] > MA60[-2])。
- 下降:前期的 MA60 呈递减趋势(如
完整策略代码示例
以下是一个在 JoinQuant 平台上可以直接运行的策略代码示例:
# 导入聚宽函数库
import jqdata
import pandas as pd
# 初始化函数,设定要操作的股票、基准等等
def initialize(context):
# 设定要操作的股票,这里以平安银行(000001.XSHE)为例
g.security = '000001.XSHE'
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 每天开盘时运行
run_daily(market_open, time='09:30')
def market_open(context):
security = g.security
# 1. 获取过去 65 天的收盘价数据
# 65天足以让我们计算出最近 6 天的 60日均线值
close_data = attribute_history(security, 65, '1d', ['close'])
if len(close_data) < 65:
return # 数据不足,跳过
# 2. 计算 MA60 序列
# 使用 pandas 的 rolling 函数计算移动平均
ma60_series = close_data['close'].rolling(window=60).mean().dropna()
if len(ma60_series) < 5:
return
# 3. 提取最近 5 天的 MA60 值
# ma1 为 5天前,ma5 为昨天(最新)
ma1 = ma60_series.iloc[-5]
ma2 = ma60_series.iloc[-4]
ma3 = ma60_series.iloc[-3]
ma4 = ma60_series.iloc[-2]
ma5 = ma60_series.iloc[-1]
# 4. 逻辑判断
# 判断下降:前三天均线依次递减
is_falling = (ma1 > ma2) and (ma2 > ma3)
# 判断走平:第3天和第4天的均线差值绝对值非常小(这里设定阈值为 0.1%)
# 阈值可以根据具体标的的波动特性进行调整
is_flat = abs(ma4 - ma3) / ma3 < 0.001
# 判断向上:最新一天的均线大于前一天
is_rising = ma5 > ma4
# 取得当前的现金
cash = context.portfolio.available_cash
# 5. 交易执行
# 如果同时满足 下降 -> 走平 -> 向上
if is_falling and is_flat and is_rising:
log.info(f"[{context.current_dt}] {security} 60日均线出现 下降->走平->向上 形态!")
# 如果当前没有持仓,则全仓买入
if context.portfolio.positions[security].closeable_amount == 0:
order_value(security, cash)
log.info(f"买入 {security}")
# 简单的止损/平仓逻辑:如果价格跌破60日均线,卖出
current_price = close_data['close'].iloc[-1]
if current_price < ma5 and context.portfolio.positions[security].closeable_amount > 0:
order_target(security, 0)
log.info(f"价格跌破60日均线,卖出 {security}")
代码细节解析与优化建议
- 数据获取长度:
attribute_history(security, 65, '1d', ['close'])获取了 65 天的数据。因为计算 60 日均线需要 60 天的数据,所以第 60 天产生第一个 MA60 值,65 天的数据刚好可以产生 6 个 MA60 值,足够我们提取最近 5 天的均线进行形态对比。 - “走平”的定义:在数学上,两条均线完全相等(
ma3 == ma4)的概率极低。因此,我们引入了一个阈值(Threshold)。代码中abs(ma4 - ma3) / ma3 < 0.001表示均线变化率小于千分之一即视为走平。在实际策略中,你可以根据股票的活跃度将这个阈值调大或调小。 - 观察窗口期:示例代码中使用了 5 天的窗口(2天下降,1天走平,1天向上)。如果你希望形态更加稳固,可以扩大获取的数据量(例如 70 天),并要求连续 3 天下降、连续 2 天走平、连续 2 天向上,只需相应增加
ma_series的提取和判断条件即可。