问题描述
解决方案
移动平均价(MA)在PTrade中的计算方法
在量化交易中,移动平均价(Moving Average, MA)是最基础且最常用的技术指标之一。在PTrade量化平台中,计算移动平均价主要依赖于获取历史行情数据的API:get_history 或 get_price。结合Python强大的数据处理库(如Pandas和Numpy),我们可以非常方便地计算出各种周期的均线。
以下是几种在PTrade中计算移动平均价的常用方法:
方法一:使用 get_history 和 Pandas 计算(最常用)
这是最直接的方法,适用于日线或分钟级别的策略。通过 get_history 获取过去N根K线的收盘价,然后使用Pandas的 .mean() 方法求平均值。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
security = g.security
# 取得过去5天的历史价格数据(不包含当前周期)
# fq=None 表示不复权,实盘中通常建议使用前复权 fq='pre'
df = get_history(5, '1d', 'close', security, fq='pre', include=False)
# 计算5日均线价格,并保留3位小数
ma5 = round(df['close'].mean(), 3)
# 取得过去10天的历史价格数据
df10 = get_history(10, '1d', 'close', security, fq='pre', include=False)
ma10 = round(df10['close'].mean(), 3)
log.info(f"当前5日均线: {ma5}, 10日均线: {ma10}")
方法二:结合实时最新价计算动态均线(适用于Tick级别)
如果你在做Tick级别的交易(使用 tick_data 或 run_interval),你可能需要将过去N-1天的历史收盘价与当前的最新价结合起来,计算出实时的动态均线。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
run_interval(context, func, seconds=3)
# 盘前准备历史数据,避免盘中频繁调用长周期历史数据
def before_trading_start(context, data):
# 获取过去10天的历史收盘价
history = get_history(10, '1d', 'close', g.security, fq='pre', include=False)
g.close_array = history['close'].values
# 自定义计算实时均线的函数
def get_MA_day(days, close_array, current_price):
# 取过去 days-1 天的收盘价之和
close_sum = close_array[-(days-1):].sum()
# 加上当前最新价,除以 days
MA = (current_price + close_sum) / days
return MA
def func(context):
stock = g.security
# 获取最新价
snapshot = get_snapshot(stock)
if not snapshot or stock not in snapshot:
return
current_price = snapshot[stock]['last_px']
# 计算实时的5日和10日均线
ma5 = get_MA_day(5, g.close_array, current_price)
ma10 = get_MA_day(10, g.close_array, current_price)
log.info(f"实时最新价: {current_price}, 动态MA5: {ma5}, 动态MA10: {ma10}")
完整策略示例:经典双均线策略
基于上述计算方法,我们可以轻松实现一个经典的双均线策略:当短期均线(5日)上穿长期均线(10日)时买入,下穿时卖出。
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
def handle_data(context, data):
security = g.security
# 得到十日历史价格
df = get_history(10, '1d', 'close', security, fq='pre', include=False)
# 得到五日均线价格
ma5 = round(df['close'][-5:].mean(), 3)
# 得到十日均线价格
ma10 = round(df['close'][-10:].mean(), 3)
# 取得当前资金余额
cash = context.portfolio.cash
# 如果五日均线大于十日均线(金叉)
if ma5 > ma10:
# 用所有 cash 买入股票
order_value(security, cash)
log.info("买入 %s" % security)
# 如果五日均线小于十日均线(死叉),并且目前有头寸
elif ma5 < ma10 and get_position(security).amount > 0:
# 全部卖出
order_target(security, 0)
log.info("卖出 %s" % security)
💡 关键注意事项
- 复权处理 (
fq):在计算均线等技术指标时,强烈建议使用前复权 (fq='pre')。如果不复权,当股票发生分红派息或送转股时,价格会出现跳空缺口,导致均线计算严重失真,从而触发错误的交易信号。 - 包含当前周期 (
include):get_history的include参数默认为False。在handle_data中,如果include=False,获取的是昨天及以前的数据;如果include=True,则包含当天的未走完的K线数据。通常计算传统日均线时使用include=False。 - 性能优化:如果策略需要计算长周期均线(如MA60、MA120),尽量在
before_trading_start中获取历史数据并缓存到全局变量g中,避免在handle_data或tick_data中高频调用长周期历史数据接口,以提升策略运行效率。