4.1 指标的三种形态:overlays、markers、bands


4.1 指标的三种形态:overlays、markers、bands

本节摘要:QuantDinger 用 Python 写指标,形态收敛为三种(官方口径):overlay——与价格同坐标的连续叠加线;marker——落在特定 K 线上的离散事件点;band——上下轨夹出的区间带。本节先逐一给出定义、输出结构与典型用例;再用一张对照 ASCII 图把三者放回同一张 K 线图,建立直觉;然后给一段 API 形态示意代码,展示三种输出各自长什么样(类名与方法签名以官方文档为准);接着讲本章最重要的工程原则「一处定义、两处使用」——图表上画的和回测里算的是同一个类的同一次计算,杜绝「图上好看、回测对不上」;最后给选型方法:按输出的时间语义(连续区间、离散时刻、成对边界)对号入座。

学习目标

  • 说出三种形态的定义、输出结构与典型用例。
  • 用输出语义给一个新指标想法选定形态。
  • 读懂 API 形态示意代码并区分三种返回结构。
  • 解释「一处定义、两处使用」的工程价值。

一、三种形态逐个拆

形态 输出结构 时间语义 典型用例(示意)
overlay 与 K 线等长的数值序列 每根 K 线一个值,连续 均线类、ATR 类、动量类
marker (时间/序号, 标签) 的稀疏列表 只在事件发生处有值 交叉触发、突破确认、缺口标记
band 上下轨(可加中轨)的成对序列 每根 K 线一对边界 波动通道、超买超卖区间带

选型的唯一依据是你想要的输出在说什么:说「这根 K 线上某个量是多少」用 overlay;说「这件事在这根 K 线上发生了」用 marker;说「此刻的合理区间在哪儿」用 band。三种可以组合:一个波动率指标可以同时产出 band(通道)与 marker(收缩触发点),4.2 节正是这么做的。

三种形态同图(放大版) 价格 │ ● │ ● ● ╭ ─ ─ band 上轨 ─ ─ ╮ │ ● ● ┈┈┈┈ ● ┈ overlay:均线 ┈┈ ● │● ● ╰ ─ ─ band 下轨 ─ ─ ╯ │ ▲ ▲ │ └─ marker:事件点 └─ marker:事件点 └───────────────────────────────▶ 时间 overlay 每根 K 线都有值;marker 只在事件处;band 上下成对 ​

二、API 形态示意

# indicator_forms_demo.py —— 三种形态的 API 形态示意(教学示意,以官方文档为准) class SmaOverlay: """overlay:简单移动平均,返回与 K 线等长的序列(前段不足为 None)""" def __init__(self, period=20): self.period = period def compute(self, closes): values = [None] * len(closes) for i in range(len(closes)): if i + 1 >= self.period: window = closes[i + 1 - self.period : i + 1] values[i] = sum(window) / self.period return {"form": "overlay", "name": "SMA" + str(self.period), "values": values} class CrossMarker: """marker:快慢线交叉事件,返回稀疏的事件点列表""" def __init__(self, fast=10, slow=30): self.fast, self.slow = fast, slow def compute(self, closes): events = [] for i in range(self.slow, len(closes)): f_now = sum(closes[i + 1 - self.fast : i + 1]) / self.fast f_prev = sum(closes[i - self.fast : i]) / self.fast s_now = sum(closes[i + 1 - self.slow : i + 1]) / self.slow s_prev = sum(closes[i - self.slow : i]) / self.slow if f_prev <= s_prev and f_now > s_now: events.append({"index": i, "kind": "golden_cross"}) if f_prev >= s_prev and f_now < s_now: events.append({"index": i, "kind": "death_cross"}) return {"form": "marker", "name": "MA-Cross", "events": events} if __name__ == "__main__": demo = [float(x) for x in range(1, 41)] # 单调上升的演示序列 ov = SmaOverlay(5).compute(demo) mk = CrossMarker(3, 8).compute(demo) print(ov["form"], "末值:", round(ov["values"][-1], 2)) print(mk["form"], "事件数:", len(mk["events"]), mk["events"][:2]) ​

读这段示意的三个观察点:第一,overlay 的序列长度恒等于输入长度、前段用 None 占位——下游永远知道「第几根 K 线对应什么」;第二,marker 是稀疏的,只携带发生位置与事件种类,不携带仓位含义;第三,两种形态互不越界——交叉marker不负责「该买多少」,那是第 5 章 sizing 的职责。

三、一处定义,两处使用

同一指标实现同时服务两个消费者:图表(人看)与回测(机器算)。这是平台级的一致性保障:

┌──▶ 图表渲染:画在 K 线图上,供人复盘 同一个指标类 ────┤ (同一份代码) └──▶ 回测引擎:逐根喂给策略,供机器计算 ​

反例是散件时代的常见病:图表软件里拖出来的「SMA(20)」和回测脚本里手写的「SMA(20)」,参数同名、实现对不齐(前复权口径、闭合判定差一点),复盘结论与回测结论各自为政。「一处定义、两处使用」从机制上消灭这类分歧——你在图上看到的每一个 marker,回测里策略也能在同位置看到;策略在回测里踩过的每一个信号,图上也能指给你看。

四、形态选型练习

三个想法,三个答案(自测后再对):

想法 输出在说什么 形态
「每根 K 线的真实波幅」 每根一个值 overlay
「价格突破近 20 根高点这件事」 发生/未发生 marker
「按波幅画出的正常波动范围」 一对边界 band

选错的代价:把事件写成 overlay,序列里塞满「0 和 1」,图上难看、回测里还得再做一次判断;把边界写成 overlay,上下轨的对齐关系丢失。形态选对了,下游的一切消费都顺理成章。

本节要点回顾

  • 三形态:overlay 连续值、marker 离散事件、band 成对边界;选型看输出语义。
  • overlay 等长占位、marker 稀疏携带位置与种类,互不越界到仓位领域。
  • 一处定义、两处使用:图表与回测共用同一实现,机制性保证一致性。
  • 组合是常态:一个指标可以同时产出 band 与 marker。
  • 指标不表达仓位与方向决策,那是策略层的职责。

词汇表齐了,该造一个真正的词。下一节从「波动率收缩后往往有行情展开」这个想法出发,写出规格、实现三件套(ATR、带宽分位、收缩事件)、跑通自测,再接入图表与回测。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U