扩展函数开发

talib 和平台内置的 EsTalib 都满足不了你的需求时,就需要自己写扩展函数。极智量化的扩展函数开发核心只有一句话:NumericSeries 当作指标的「记忆」,逐 Bar 递推。本章讲清封装思路、导入方式和一个完整范例。

什么时候要写扩展函数

  • 指标需要中间状态(上一根的 EMA、SAR 的加速因子等),不能用一次公式算完。
  • 你有一套自己的交易逻辑想复用到多个策略。
  • 想把一段重复的计算抽成函数,让策略主逻辑更清爽。

自定义函数的基本写法

Python 自定义函数遵循标准语法。用 def 定义、圆括号列参数、冒号起函数体、return 返回值:

def my_func(parameters):
    """文档字符串,可选"""
    # 函数体
    return result

无状态的函数最简单,比如一个「阳线实体占整根 K 线的比例」:

def body_ratio(o, c, h, l):
    total = h - l
    if total == 0:
        return 0
    return abs(c - o) / total

handle_data 里直接调用即可。

封装有状态指标

真正的扩展函数往往有状态。秘诀就是用 NumericSeries 保存上一次的值,每根 Bar 调用一次、写回一次。下面把一个自定义的「自适应均线」封装成函数:

from EsSeries import NumericSeries

def U_MyAdaptive(X, data, period):
    """
    自适应均线示例:趋势强时贴近价格,震荡时更平滑
    X   —— 保存历史值的 NumericSeries(外部维护)
    data—— 价格序列,如 Close()
    period —— 平滑周期
    """
    factor = 2 / (period + 1)
    if len(data) == 1:
        ret = data[-1]
    else:
        ret = X[-1] + factor * (data[-1] - X[-1])
    return ret

在策略里这样用它:

from EsSeries import NumericSeries
# 假设上面的函数已放在同目录 mylib.py
from mylib import U_MyAdaptive

ama = NumericSeries()
period = 15

def handle_data(context):
    if len(Close()) == 0:
        return
    ama[-1] = U_MyAdaptive(ama, Close(), period)
    PlotNumeric('ama', ama[-1], RGB_Purple())

这是极智量化扩展函数的通用范式:函数本身无状态,状态全靠外部传入的 NumericSeries 承载EsTalib 里的 U_EMA / U_SMA 都是这么写的。

封装成类:多输出指标

如果指标有多个输出(比如 SAR 同时给出价格和方向),像 EsTaClass.UC_SAR 那样封装成类更清晰:在 __init__ 里为每个输出建一条 NumericSeries,方法内部维护它们并返回结果。详见 EsTalib技术指标库UC_SAR 示例。

导入个人库

把写好的函数文件(如 mylib.py)放到用户策略目录下,在策略里用相对路径导入。假设 mylib.py 和你的策略 test.py 在同级目录:

from mylib import U_MyAdaptive       # 同级目录,直接导入

如果个人库在子目录或上层目录,按相对量化工作路径补全,例如:

from Quant.Strategy.用户策略.ALib import ATalib   # 下级目录
from Quant.Strategy import CTalib                  # 上层模块

经验:在用户策略下新建文件夹单独存放个人库,便于区分和管理。

自定义函数的使用要点

  1. 先判长度:函数开头用 len(data) 检查数据是否就绪,避免回测初期算出异常值。
  2. 状态写回:每根 Bar 一定要把递推结果写回 X[-1],否则下一根读不到。
  3. 越界安全NumericSeries 已做越界保护,但传入的 data(如 Close())取下标前最好确认长度。
  4. 参数优化兼容:若想让参数参与平台参数优化,把可调参数写进 g_params 字典,而不是写成普通全局变量——后者在参数优化时不会随新值更新。

小结

扩展函数开发的核心是「函数无状态 + 外部 NumericSeries 承载状态」;有多个输出就封装成类;个人库放用户策略目录按相对路径导入。写好自己的指标库后,下一步进入实盘核心:账户与下单示例