6.9 KiB
知行指标移植文档(通达信 → 任意平台)
供后续导入到其他项目/平台使用的完整规格:公式原文、参数、数值口径、参考实现、 校验向量、显示规范。框架无关部分可直接拷贝;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] + (N−1)·E[i−1]) / (N+1),首根以自身为种子
(E[0] = X[0])。等价于系数 k = 2/(N+1) 的 E[i] = k·X[i] + (1−k)·E[i−1]。
无限记忆,但衰减因子 (N−1)/(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 根后残差 < 1e−5)。
- 建议 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收窄。 createTooltipDataSource的legends会整体替换默认图例行,线值图例须自己拼回;calcParams: DKX_PERIODS让图例显示「知行(14,28,57,114)」(通达信式)。- 长周期指标 + 分页窗口的完整坑位说明见
memory/custom-indicator-framework.md。
九、移植检查清单
- M1~M4 = 14/28/57/114(不是 BBI 的 3/6/12/24)
- EMA 首根种子=自身;MA 窗口不满=null(两条都与常见库默认不同)
- 计算输入与显示用同一复权基准的收盘价
- 预热 ≥113 根覆盖到可视区最左端之外
- 跑第六节校验向量,逐位一致
- 颜色:趋势线 #E61851、多空线 #F5C518、板块文本 #00C0C0