Files
stock/frontend/src/indicators/zhixing.md
2026-08-17 00:47:13 +08:00

6.9 KiB
Raw Blame History

知行指标移植文档(通达信 → 任意平台)

供后续导入到其他项目/平台使用的完整规格:公式原文、参数、数值口径、参考实现、 校验向量、显示规范。框架无关部分可直接拷贝klinecharts v10 集成见第八节。 本仓库实现:zhixing.ts(算法+模板)/ index.ts(注册表)/ DetailKLine.vue(数据管道)。

一、原始通达信公式

知行短期趋势线:EMA(EMA(C,10),10),COLORE61851,LINETHICK1;
MA1:=MA(CLOSE,60);
MA2:=EMA(CLOSE,13);
Z1:=STRCAT(HYBLOCK,' ');
Z2:=STRCAT(Z1,DYBLOCK);
Z3:=STRCAT(Z2,' ');
DRAWTEXT_FIX(ISLASTBAR,0,0,0,STRCAT(Z3,GNBLOCK)),COLOR00C0C0;
知行多空线:(MA(CLOSE,M1)+MA(CLOSE,M2)+MA(CLOSE,M3)+MA(CLOSE,M4))/4;

参数表(通达信公式管理器里配置,公式文本不带——移植时最容易丢的就是这个):

参数 缺省值
M1 14
M2 28
M3 57
M4 114

二、逐行语义

作用 移植处理
知行短期趋势线 EMA 嵌套两层,主图线 画线,#E61851
MA1 / MA2 := 隐藏赋值,且未被后续引用 → 死代码 不画
Z1~Z3 + DRAWTEXT_FIX 左上角固定文本:行业板块+地域板块+概念板块(通达信本地板块数据) 无本地板块数据源,用「行业+地域」近似做成图例行;概念板块缺失
知行多空线 4 条 MA 的等权平均,主图线 画线,周期 14/28/57/114

三、数值口径(与通达信逐位一致)

EMA通达信式E[i] = (2·X[i] + (N1)·E[i1]) / (N+1),首根以自身为种子 E[0] = X[0])。等价于系数 k = 2/(N+1)E[i] = k·X[i] + (1k)·E[i1]。 无限记忆,但衰减因子 (N1)/(N+1)N=10 时 ≈0.82/根),截断起点的影响几十根后可忽略。

MA通达信式严格窗口窗口不满输出空值null/NaN不是 min_periods=1 的渐进均值—— 很多图表库内置 MA 是渐进口径,直接用会整条线偏掉。

多空线dkx[i] = (MA14[i] + MA28[i] + MA57[i] + MA114[i]) / 4,四个 MA 任一为空则为空。 即前 113 根没有多空线(通达信从上市日起算,同样如此)。

复权口径:序列必须与图表展示用同一复权基准(前复权/不复权)的收盘价计算,否则数值对不上。

四、参考实现(框架无关 TypeScript可直接拷贝

export const DKX_PERIODS = [14, 28, 57, 114];

function ema(src: number[], n: number): number[] {
  const out = new Array<number>(src.length);
  const k = 2 / (n + 1);
  let prev = NaN;
  for (let i = 0; i < src.length; i++) {
    prev = Number.isNaN(prev) ? src[i] : src[i] * k + prev * (1 - k);
    out[i] = prev;
  }
  return out;
}

function sma(src: number[], n: number): (number | null)[] {
  const out = new Array<number | null>(src.length).fill(null);
  let sum = 0;
  for (let i = 0; i < src.length; i++) {
    sum += src[i];
    if (i >= n) sum -= src[i - n];
    if (i >= n - 1) out[i] = sum / n;
  }
  return out;
}

/** closes 为整段历史收盘价(建议从上市日或至少 ≥ 需求长度+114 根起) */
export function computeZhixingSeries(closes: number[]) {
  const trend = ema(ema(closes, 10), 10);
  const mas = DKX_PERIODS.map((p) => sma(closes, p));
  const dkx = new Array<number | null>(closes.length).fill(null);
  for (let i = 0; i < closes.length; i++) {
    const m = mas.map((a) => a[i]);
    if (m.every((v) => v != null)) dkx[i] = m.reduce((s, v) => s + (v as number), 0) / m.length;
  }
  return { trend, dkx };
}

五、参考实现Python / numpy

import numpy as np

DKX_PERIODS = (14, 28, 57, 114)

def ema_tdx(x: np.ndarray, n: int) -> np.ndarray:
    out = np.empty(len(x))
    k = 2.0 / (n + 1)
    prev = np.nan
    for i, v in enumerate(x):
        prev = v if np.isnan(prev) else v * k + prev * (1 - k)
        out[i] = prev
    return out
    # pandas 等价写法adjust=False 且首根种子=自身,与通达信一致):
    # s.ewm(span=n, adjust=False).mean()

def sma_tdx(x: np.ndarray, n: int) -> np.ndarray:
    c = np.concatenate(([0.0], np.cumsum(x)))
    out = np.full(len(x), np.nan)
    out[n - 1:] = (c[n:] - c[:-n]) / n   # 窗口不满保持 NaN
    return out

def zhixing(close: np.ndarray):
    trend = ema_tdx(ema_tdx(close.astype(float), 10), 10)
    stack = np.vstack([sma_tdx(close.astype(float), p) for p in DKX_PERIODS])
    dkx = np.full(len(close), np.nan)
    ok = ~np.isnan(stack).any(axis=0)
    dkx[ok] = stack[:, ok].mean(axis=0)
    return trend, dkx

六、校验向量(移植后跑一遍,全对即口径正确)

趋势线 closes = [10,11,12,13,14,15]

EMA(C,10)          = 10.000000, 10.181818, 10.512397, 10.964688, 11.516563, 12.149915
EMA(EMA(C,10),10)  = 10.000000, 10.033058, 10.120210, 10.273752, 10.499717, 10.799753

MA 严格窗口 sma([1,2,3,4,5,6], 3)

null, null, 2.000000, 3.000000, 4.000000, 5.000000

多空线预热 closes[i] = i+1线性爬坡116 根):索引 0~112 全为 null 索引 113 起有值,闭式解 dkx[i] = (i+1) (13+27+56+113)/8 = i+1 26.125

dkx[113] = 87.875000   dkx[114] = 88.875000   dkx[115] = 89.875000

七、数据与预热要求

  • MA114 需预热 113 根:喂给算法的历史长度 = 可视区最左端再往左 ≥113 根。 分页加载的图表不要只算当前窗口(首屏窗口常见 240 根,左边会缺一大段), 应在「全部已加载历史」上整段计算,左滑前插后整体重算。
  • EMA 理论上要上市日起算;实际截断到几百根即可(衰减 0.82/根60 根后残差 < 1e5
  • 建议 closes 传入前先按 timestamp 升序、剔除停牌空K。

八、klinecharts v10 集成要点(本仓库方案)

  • 注册:registerIndicator(makeZhixingIndicator(get)),模板工厂注入「(key, timestamp) → 预计算值」 访问器;序列由 DetailKLine 在 allData 上预计算写入 PV['zx_trend']/PV['zx_dkx'] calc 里按 bar.timestamp 取值(不要用图表相对索引,翻页后会错位)。
  • 回调参数的 Indicator<D> 不带 E 泛型,extendData 是 unknown取值需 as 收窄。
  • createTooltipDataSourcelegends 会整体替换默认图例行,线值图例须自己拼回; calcParams: DKX_PERIODS 让图例显示「知行(14,28,57,114)」(通达信式)。
  • 长周期指标 + 分页窗口的完整坑位说明见 memory/custom-indicator-framework.md

九、移植检查清单

  1. M1~M4 = 14/28/57/114(不是 BBI 的 3/6/12/24
  2. EMA 首根种子=自身MA 窗口不满=null两条都与常见库默认不同
  3. 计算输入与显示用同一复权基准的收盘价
  4. 预热 ≥113 根覆盖到可视区最左端之外
  5. 跑第六节校验向量,逐位一致
  6. 颜色:趋势线 #E61851、多空线 #F5C518、板块文本 #00C0C0