问题描述
解决方案
在 QMT 中获取行情数据后,利用 Pandas 计算移动平均线(Moving Average, MA)是非常常见的操作。主要步骤包括:使用 ContextInfo.get_market_data_ex 获取 DataFrame 格式的数据,然后调用 Pandas 的 rolling().mean() 方法进行计算。
以下是完整的策略代码示例及详细说明。
策略代码示例
# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
# 1. 设置股票池,这里以浦发银行为例
ContextInfo.set_universe(['600000.SH'])
# 2. 定义需要计算的均线周期,例如 5日均线 和 20日均线
ContextInfo.ma_short = 5
ContextInfo.ma_long = 20
def handlebar(ContextInfo):
# 仅在最后一根K线处理,避免历史回测时重复打印大量日志(视需求而定)
if not ContextInfo.is_last_bar():
return
# 获取当前主图周期
period = ContextInfo.period
stock_list = ContextInfo.get_universe()
# 3. 获取历史行情数据
# 注意:count 必须大于最大的均线周期,否则数据不足以计算
# 这里取 100 根 K 线以确保有足够的数据计算 MA20
data_dict = ContextInfo.get_market_data_ex(
fields=['close'], # 只需要收盘价
stock_code=stock_list,
period=period,
count=100, # 数据长度
dividend_type='follow' # 复权方式跟随主图
)
for stock in stock_list:
if stock in data_dict:
# 获取该股票的 DataFrame
df = data_dict[stock]
# 4. 使用 Pandas 计算移动平均线
# rolling(window=N): 创建一个 N 周期的滑动窗口
# mean(): 计算窗口内的平均值
df['MA5'] = df['close'].rolling(window=ContextInfo.ma_short).mean()
df['MA20'] = df['close'].rolling(window=ContextInfo.ma_long).mean()
# 5. 处理 NaN 值(可选)
# 刚开始的 N-1 个数据因为窗口未满会产生 NaN,可以使用 dropna() 去除或 fillna() 填充
# df.dropna(inplace=True)
# 打印结果验证
print(f"====== {stock} 均线计算结果 (最后5行) ======")
print(df.tail())
# 获取最新的均线值
last_ma5 = df['MA5'].iloc[-1]
last_ma20 = df['MA20'].iloc[-1]
print(f"最新 MA5: {last_ma5}, 最新 MA20: {last_ma20}")
关键步骤解析
-
获取数据 (
get_market_data_ex):- 推荐使用
ContextInfo.get_market_data_ex,因为它直接返回{stock_code: DataFrame}的字典结构,非常适合 Pandas 处理。 - 重要参数
count: 获取的数据长度必须大于你要计算的均线周期。例如计算 MA20,count至少要设为 20,通常建议设得更大(如 100),以确保均线数据的连续性。
- 推荐使用
-
计算均线 (
rolling().mean()):df['close']: 提取收盘价列(Series)。.rolling(window=N): Pandas 的核心函数,用于创建一个大小为 N 的滚动窗口。.mean(): 对窗口内的数据求平均值。- 结果会自动对齐索引,赋值回 DataFrame 的新列(如
df['MA5'])。
-
数据访问:
- 计算完成后,可以通过
df['MA5'].iloc[-1]获取最新一根 K 线的均线值,或者df['MA5'].iloc[-2]获取上一根 K 线的值(常用于判断金叉死叉)。
- 计算完成后,可以通过
常见问题 (Q&A)
Q: 为什么计算出来的均线前几行是 NaN (Not a Number)?
A: 这是正常的。例如计算 5 日均线,前 4 天的数据不足以凑齐 5 个数据点来计算平均值,因此 Pandas 会填充为 NaN。如果需要处理,可以使用 df.dropna() 删除这些行,或者在逻辑判断时忽略它们。
Q: 如何计算加权移动平均线 (WMA) 或指数移动平均线 (EMA)?
A:
- EMA: Pandas 提供了直接的方法
df['close'].ewm(span=N, adjust=False).mean()。 - WMA: Pandas 没有直接的 WMA 函数,通常需要自定义函数或使用
apply配合权重计算,或者直接调用talib库(QMT 内置了TA_Lib)来计算,例如talib.WMA。
Q: get_market_data_ex 返回的数据包含哪些列?
A: 返回的 DataFrame 的列名取决于你在 fields 参数中传入的列表。通常包括 'open', 'high', 'low', 'close', 'volume', 'amount' 等。在计算均线时,通常只使用 'close' 列。