问题描述
我的思路:
通过收盘价EMA判断市场的趋势。
如果【当前K线的EMA>前1K线的EMA>前2K线的EMA】,
则认为市场处于上涨趋势;
如果【当前K线的EMA< 前1K线的EMA< 前2K线的EMA】,
则认为市场处于下跌趋势。
遇到的困难:
在回测环境中,怎么写代码计算【收盘价】的EMA趋势?
在这里卡住半个月了!
比如,想要写代码判断:
10分钟K线:当前EMA>前1EMA>前2EMA
该写什么代码?
聚宽的EMA函数如下:
EMA(security_list, check_date, timeperiod=30, unit = '1d', include_now = True, fq_ref_date = None)
check_date只能输入特定日期的EMA,要比较前后周期的EMA数值,要如何实现?
注:需要能在回测环境中使用的。
有知道的大佬,麻烦指点一下,不胜感激!!
解决方案
在 JoinQuant(聚宽)的回测环境中,如果你使用 jqlib.technical_analysis 库中的 EMA 函数,确实会遇到需要频繁传入 check_date 的问题,这在获取连续多个周期的 EMA 时非常不方便且运行效率低下。
最佳解决方案是:使用聚宽内置支持的第三方技术分析库 talib,结合 get_bars 函数获取历史 K 线数据,直接计算出一个 EMA 数组,然后通过数组切片轻松获取当前、前1、前2的 EMA 值。
以下是针对你“10分钟K线,判断当前EMA > 前1EMA > 前2EMA”需求的完整代码实现方案:
核心实现代码
# 导入聚宽函数库
import jqdata
# 导入 talib 库用于高效计算技术指标
import talib
def initialize(context):
# 设定要操作的股票
g.security = '000001.XSHE'
# 设定 EMA 的计算周期,例如 30 周期
g.ema_timeperiod = 30
# 开启真实价格模式
set_option('use_real_price', True)
# 每天按分钟运行,这里我们可以在 handle_data 中控制频率,
# 或者直接使用 run_daily 定时运行。为了演示10分钟K线,我们在 handle_data 中处理。
def handle_data(context, data):
# 1. 获取历史 K 线数据
# 获取 10分钟 (10m) 级别的收盘价数据
# 注意:计算 EMA 需要一定的历史数据作为预热(通常是周期的 2-3 倍),所以 count 设大一点,比如 100
bars = get_bars(g.security, count=100, unit='10m', fields=['close'], include_now=True)
# 提取收盘价序列 (numpy.ndarray)
close_prices = bars['close']
# 2. 使用 talib 计算 EMA 序列
# talib.EMA 会返回一个与 close_prices 长度相同的数组
ema_array = talib.EMA(close_prices, timeperiod=g.ema_timeperiod)
# 3. 提取最后 3 个周期的 EMA 值
# 数组最后一位 [-1] 是当前 K 线的 EMA
# [-2] 是前 1 K 线的 EMA
# [-3] 是前 2 K 线的 EMA
current_ema = ema_array[-1]
prev_ema_1 = ema_array[-2]
prev_ema_2 = ema_array[-3]
# 过滤掉 NaN 值(在数据量不足时 talib 会返回 NaN)
if np.isnan(current_ema) or np.isnan(prev_ema_1) or np.isnan(prev_ema_2):
return
# 4. 判断趋势逻辑
if current_ema > prev_ema_1 and prev_ema_1 > prev_ema_2:
# 上涨趋势
log.info(f"【上涨趋势】当前EMA:{current_ema:.2f} > 前1:{prev_ema_1:.2f} > 前2:{prev_ema_2:.2f}")
# 在这里编写买入逻辑
if context.portfolio.positions[g.security].closeable_amount == 0:
order_value(g.security, context.portfolio.available_cash)
elif current_ema < prev_ema_1 and prev_ema_1 < prev_ema_2:
# 下跌趋势
log.info(f"【下跌趋势】当前EMA:{current_ema:.2f} < 前1:{prev_ema_1:.2f} < 前2:{prev_ema_2:.2f}")
# 在这里编写卖出逻辑
if context.portfolio.positions[g.security].closeable_amount > 0:
order_target(g.security, 0)
代码原理解析
-
get_bars函数:unit='10m':直接获取 10 分钟级别的 K 线数据,完美契合你的需求。count=100:EMA 是指数移动平均,它的计算依赖于历史所有的价格数据(越久远的数据权重越小)。为了保证当前 EMA 值的准确性,获取的数据长度(count)建议至少是 EMA 周期(timeperiod)的 3 倍以上。include_now=True:包含当前正在生成的这根 10 分钟 K 线。
-
talib.EMA函数:- 相比于聚宽自带的
jqlib.technical_analysis.EMA,talib是 C 语言底层编写的,计算速度极快,且直接接收一个价格数组,返回一个完整的 EMA 数组。这是量化回测中最主流、最高效的指标计算方式。
- 相比于聚宽自带的
-
数组切片
[-1], [-2], [-3]:- Python 的列表/数组支持负数索引,
-1代表最后一个元素(即当前最新 K 线),-2代表倒数第二个,以此类推。这样就能轻松拿到你需要的“当前”、“前1”、“前2”的数值进行比较。
- Python 的列表/数组支持负数索引,
通过这种方式,你不仅可以判断 10 分钟 K 线的趋势,只需修改 get_bars 中的 unit 参数(如 '1d', '5m', '60m'),就可以无缝切换到任何时间周期的趋势判断中。