K 线走 Channel、策略吐买卖、回测吐 HTML:cinar/indicator 三层怎么接

K 线走 Channel、策略吐买卖、回测吐 HTML:cinar/indicator 三层怎么接

K 线走 Channel、策略吐买卖、回测吐 HTML:cinar/indicator 三层怎么接

源微信页触发了验证码拦截,正文以 cinar/indicator 官方 README、asset / strategy / backtest 包文档、cmd/indicator-backtest 源码和 v2.1.44(2026-09-14 发布)为准,不臆造未公开能力。仓库当前约 1755 Star / 266 Fork,协议是 AGPLv3(v1 仍是 MIT)。作者 Onur Cinar 把定位写得很直:这是一套 技术分析指标 + 可配置策略 + 回测框架,不是投顾,也不是实盘撮合引擎。

很多 Go 量化原型卡在同一处:TA-Lib 要 cgo,pandas 要出进程,自己手搓均线又很快长成一坨切片函数。cinar/indicator 的增量不在「指标数量够不够」,而在 同一套 Channel 流水线把三件事接起来:指标吃数字流,策略吐 Buy / Hold / Sell,回测把动作兑成 Outcome 曲线和 HTML 报告。

封面:Channel 上流过 K 线接到回测


一、别把它当成又一个指标清单

仓库首页确实列了八十多个指标:趋势侧有 SMA、EMA、MACD、DEMA、KAMA、HMA;动量侧有 RSI、随机 RSI、一目均衡、威廉 %R;波动侧有布林带、ATR、超级趋势、肯特纳通道;成交量侧有 OBV、MFI、VWAP。这些名字你在任何技术分析教科书里都能碰到。真正值得单独写一篇的,是 v2 把输入输出都改成了 Go channel。

v2 的主线改动官方写得很清楚:代码覆盖率目标至少 90%;每个指标和策略都有 CSV 测试数据;所有指标、策略都可配置,不藏死参数;用泛型吃多种数值类型;切片爱好者可以走 helper.SliceToChan / helper.ChanToSlice。旧的切片 API 还在 v1 分支。同作者还有 TypeScript 实现 cinar/indicatorts,以及 Alpaca 行情适配 cinar/indicatoralpaca。

安装仍然是标准模块:

go get github.com/cinar/indicator/v2

业务代码按层 import,不要指望一个根包把 SMA 和回测全导出:

import (
"github.com/cinar/indicator/v2/asset"
"github.com/cinar/indicator/v2/backtest"
"github.com/cinar/indicator/v2/helper"
"github.com/cinar/indicator/v2/momentum"
"github.com/cinar/indicator/v2/strategy"
"github.com/cinar/indicator/v2/trend"
)

README 里那句 "AI integration via MCP" 还在项目介绍里出现,但 v2.1.44 的仓库根目录已经没有 mcp/ 包。以当前树为准:能稳定讲的是指标、策略、仓库、回测、CLI 和 Docker;MCP 服务端不要当成开箱即用的交付物。

Mermaid Diagram


二、第一层:数字流上的指标,不是切片函数

最小例子是简单移动平均。默认周期是 50(DefaultSmaPeriod),也可以 NewSmaWithPeriod 或事后改 Period。Compute 吃 <-chan T,吐 <-chan T;新代码应走 ComputeWithContext,无 context 的版本已标 Deprecated。

sma := trend.NewSma[float64]()
sma.Period = 10

closes := helper.SliceToChan([]float64{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})
result := helper.ChanToSlice(sma.Compute(closes))

这里有两个容易踩的点。第一,空闲期(IdlePeriod)。SMA 在攒够窗口之前不会吐数;策略层必须用 helper.Shift 把前面补成 Hold,否则买卖通道和收盘价通道对不齐。官方 RSI 策略就是这么做的。第二,多路输出必须并发排空。v2.1.44 新增的 helper.ChanToSlices 就是为这个场景:DuplicateWithContext 一类函数会同时往多个无缓冲 channel 写,你若按顺序 ChanToSlice(c1) 再 ChanToSlice(c2),生产者会在内部缓冲耗尽后永久阻塞。

资产侧的基本单元是 asset.Snapshot:Date / Open / High / Low / Close / Volume。CSV 读写走反射助手,日期布局固定为 2006-01-02,时分秒会被静默丢掉。文档写明这是库级限制,不是 Snapshot 特例。做日线回测刚好;做分钟线要自己换格式标签,或干脆不要走默认 CSV 仓库。

指标本身不碰买卖。MACD、RSI、布林带都只是把一条或几条数字流变成另一条数字流。想变成交易建议,必须再包一层策略。这是这套库和「把 TA-Lib 绑进业务」最大的差别:计算层保持纯函数流,决策层才出现 Action。

插图:指标、策略、回测三层


三、第二层:策略只允许三种动作

strategy.Action 只有三个值:Hold = 0、Sell = -1、Buy = 1。Annotation() 把它们映射成 "B" / "S" / 空字符串,方便画在 HTML 报告上。所有内置策略都实现同一接口:

type Strategy interface {
Name() string
Compute(snapshots <-chan *asset.Snapshot) <-chan Action
Report(snapshots <-chan *asset.Snapshot) *helper.Report
}

新代码还应该实现 strategy.WithContext,多一个 ComputeWithContext。官方 RSI 示例(examples/momentum/rsi_strategy.go)把整条链路写得很完整:从快照拆收盘价,算 RSI,阈值映射成动作,再按空闲期平移。默认阈值是 买入 30、卖出 70。

const (
DefaultRsiStrategyBuyAt = 30
DefaultRsiStrategySellAt = 70
)

func (r *RsiStrategy) ComputeWithContext(ctx context.Context, snapshots <-chan *asset.Snapshot) <-chan strategy.Action {
closings := asset.SnapshotsAsClosingsWithContext(ctx, snapshots)
rsi := r.Rsi.ComputeWithContext(ctx, closings)

actions := helper.MapWithContext(ctx, rsi, func(value float64) strategy.Action {
if value <= r.BuyAt {
return strategy.Buy
}
if value >= r.SellAt {
return strategy.Sell
}
return strategy.Hold
})

return helper.ShiftWithContext(ctx, actions, r.Rsi.IdlePeriod(), strategy.Hold)
}

内置策略按族分类,不是营销清单,是你可以 AllStrategies() 拉出来交叉回测的实装:

族 代表策略 典型用途
基准 Buy and Hold 对照基线,别让均线策略赢在「牛市躺赚」
趋势 Golden Cross、MACD、APO、DEMA、KAMA、TRIX 均线交叉、动量确认
动量 RSI、Stochastic RSI、Triple RSI、Ichimoku、Williams %R 超买超卖、云图
波动 Bollinger Bands、Super Trend 通道突破、趋势跟随
成交量 OBV、MFI、CMF、Force Index 价量背离
复合 And / Or / Majority / Split / MACD-RSI 多策略投票或买卖分家
装饰 Inverse、Stop Loss、No Loss 反转信号、加止损

复合层值得单独说。AndStrategy 要 所有子策略得出同一可执行结论 才发信号,偏保守。OrStrategy 任一同意就动。MajorityStrategy 多数决。SplitStrategy 更有意思:买信号用一套策略,卖信号用另一套;两边打架时退回 Hold。AllAndStrategies / AllSplitStrategies 会对给定列表做笛卡尔积,CLI 的 -ands / -splits 就是这两套生成器。组合数量会爆炸,只适合小集合对照,不适合把全部趋势策略两两相乘。


四、第三层:回测兑的是曲线,不是成交回报

回测入口是 backtest.NewBacktest(repository, report)。你填 Names(标的)和 Strategies(策略列表),再 Run()。资产没填就扫仓库里全部标的;策略没填就跑全部已注册策略。默认 1 个 worker、回看 365 天。报告接口把 Begin / AssetBegin / Write / AssetEnd / End 串成生命周期;即便 Workers > 1,官方保证 对 Report 的调用是串行化的,实现者不必自己加锁。

report := backtest.NewHTMLReport(outputDir)
bt := backtest.NewBacktest(repository, report)
bt.Names = append(bt.Names, "brk-b")
bt.Strategies = append(bt.Strategies, trend.NewApoStrategy())
if err := bt.Run(); err != nil {
log.Fatal(err)
}

HTMLReport 给每个「策略 × 标的」出可视化页面;DataReport 把结果收成可程序访问的 DataStrategyResult:最终 Outcome、最后一次 Action、全程交易动作列表。CLI 比这段 API 更适合批量对照,但 v2.1.44 起必须显式传 -strategies,不再默认跑全库:

indicator-backtest -list-strategies

indicator-backtest \
-repository-name filesystem \
-repository-config /home/user/assets \
-report-config /home/user/reports \
-strategies apo,macd,rsi \
-workers 1

大批次回测可以丢一份 JSON,-config 会覆盖除 -list-strategies 以外的其它 flag。config 对象按字段叠到策略默认实例上,连嵌套指标都能改,例如把 RSI 的 RMA 周期改成 10:

{
"repository": { "name": "filesystem", "config": "/home/user/assets" },
"report": { "name": "html", "config": "/home/user/reports" },
"symbols": ["aapl", "msft"],
"workers": 4,
"lastDays": 365,
"addSplits": false,
"addAnds": false,
"strategies": [
{ "name": "macd" },
{
"name": "rsi",
"config": {
"BuyAt": 20,
"SellAt": 80,
"Rsi": { "Rma": { "Period": 10 } }
}
}
]
}

Outcome 是累计收益曲线。v2.1.44 又补了两个风险调整指标:Sharpe Ratio 和 Sortino Ratio,默认按 252 个交易日 年化,无风险利率按 0。样本不足两期、或波动小到像噪声时,比率返回 0,避免除零。只看累计收益很容易被「偶尔一把大赚」骗到;这两个数至少能把波动和回撤拉进对照表。

K 线走 Channel、策略吐买卖、回测吐 HTML:cinar/indicator 三层怎么接

插图:K 线 Channel 接到买卖动作


五、数据从哪来:仓库、同步、Docker 一条龙

asset.Repository 抽象了「按名字取 Snapshot 流」。研究代码里你几乎不会直接打开 CSV 文件:策略的 Compute 只要一条 <-chan *asset.Snapshot,仓库负责按标的名把历史灌进这条通道。官方实现有三套,外加独立仓库 Alpaca。选哪一套取决于你是在写单测、在笔记本里对照,还是要把日线缓存到磁盘反复跑:

实现 适用 注意
File System 本地 CSV 目录 Get 返回全部历史,无日期地板
In Memory 单测、小样本 同上,无地板
Tiingo 远程日线 Get 只返回 2000-01-01 之后
indicatoralpaca Alpaca 行情 另仓维护,要 API Key / Secret

文件系统仓库的用法很直:asset.NewFileSystemRepository("/home/user/assets"),目录里每个标的一个 CSV。Get(name) 返回全历史;GetSince 从某天切;Append 把新快照接到文件末尾。同步器 asset.Sync 用多 worker 把源仓库灌到目标仓库,并在两次远程拉取之间插入 delay,避免把行情 API 打爆。典型路径是 Tiingo → 本地文件系统:

indicator-sync \
-source-name tiingo \
-source-config "$TIINGO_KEY" \
-target-name filesystem \
-target-config /home/user/assets \
-days 30

本地文件若是空的,会按 -days 往回拉;已有数据则从最后日期接着补。Docker 镜像 ghcr.io/cinar/indicator:latest 把这两步收成一条命令:先 sync,再 backtest。入口脚本强制要 --api-key 和 --strategies:

docker run -it --rm \
-v "$(pwd)/output:/app/output" \
ghcr.io/cinar/indicator:latest \
--api-key YOUR_TIINGO_API_KEY \
--days 365 \
--last 30 \
--assets aapl msft googl \
--strategies apo,macd,rsi

镜像里看策略名:

docker run --rm --entrypoint ./indicator-backtest \
ghcr.io/cinar/indicator:latest -list-strategies

Tiingo 免费 Key 在 tiingo.com 申请。这是行情源,不是交易所;同步下来的是历史快照,回测仍然是纸面上的 Outcome。


六、排坑:同根成交、许可证、以及它不是交易系统

文档把最大的回测陷阱写进了 OutcomeWithContext:默认按位置对齐,动作用同一根 K 线的收盘价成交。信号是看完这根收盘才产生的,实盘不可能用同一口价成交。这个假设会系统性抬高回测成绩。更接近现实的路径是 ComputeWithOutcomeAndTimingWithContext,把 ExecutionTiming 设成 NextOpen 或 NextClose。这时 outcomes 通道会比 actions 少一个值(最后一根没有下一根可成交),做报表列对齐时要自己补偏移;若你只取 helper.Last(outcomes, 1) 看最终收益,则不受影响。

许可证是第二条红线。v2 起双许可:AGPLv3 + 商用授权。网络服务一旦改了这套库并对外提供,AGPL 会要求提供对应源码。v1 仍是 MIT,但没有 v2 的 Channel 重写、泛型和 JSON 回测配置。闭源产品接入前先找维护者谈商用条款,别默认「开源就能塞进私有量化平台」。

第三条是产品边界。仓库免责声明写得很硬:技术指标基于历史,不保证未来;覆盖率再高也可能有 bug;作者不是财务顾问。回测没有滑点、没有手续费、没有涨跌停、没有流动性。BuyAndHoldStrategy 存在的意义就是给你一条笨基准——如果你的 MACD 策略在牛市里还跑不赢它,先别急着上实盘。

和常见方案怎么选,可以压成一张表:

方案 语言/绑定 策略层 回测报告 适合
cinar/indicator v2 纯 Go,零依赖 一等公民 HTML / Data + Sharpe/Sortino Go 服务里做研究与对照
TA-Lib C + 多语言绑定 无 无 只要指标数字
pandas-ta / vectorbt Python 生态丰富 强 研究笔记本、向量化回测
cinar/indicatorts TypeScript 同源指标/策略 浏览器侧 前端演示、Node 原型

选型建议很具体:你的运行时已经是 Go(行情网关、内部研究 CLI、要编译进同一个二进制),这套库能少一次跨语言。你要分钟级撮合、组合保证金、实盘风控,它不够,也不该硬拧。Channel 模型适合 按根推流;若你手里是超大矩阵、只想一次 numpy 算完,Python 仍然更省事。


七、最小可跑路径

本地没有 Tiingo Key 时,先用文件系统仓库喂 CSV,再在代码里跑单策略。目录里每个标的一个 CSV,列对应 Snapshot 字段,日期用 YYYY-MM-DD。配套练习见 practice/sma_channel.go:把收盘价推进 SMA Channel,打印空闲期之后的均线。下一步再把同一条收盘流交给 momentum 的 RSI 策略,用 strategy.ComputeWithOutcome 看 Outcome。最后才上 indicator-backtest -strategies rsi,macd -- aapl。

完整链路可以记成五步:

1. 准备 Snapshot 流(内存切片、本地 CSV 或 Tiingo)。

2. 用指标 Channel 算出 RSI / MACD / 均线,处理 IdlePeriod。

3. 策略把数字映射成 Buy / Hold / Sell;需要时用 And / Split / Stop Loss 组合。

4. ComputeWithOutcomeAndTiming 指定下一根开盘或收盘成交,避免同根幻觉。

5. HTML 报告看图,Sharpe / Sortino 看表;对照 Buy and Hold。

源文标题把「指标、策略、回测」说成塞在一起。读完官方文档会发现:它们是 三层接口,靠 Channel 对齐,而不是一个大泥球函数。Go 量化入门如果只抄 SMA 公式,抄完仍然没有买卖语义,也没有可复现的对照报告。这套库把后两步补上了——前提是你把它当成研究框架,而不是印钞机。

💻 配套实训环境与动手练习

本文涉及的相关技术指令、开发环境与工具链已内置在边学边练在线实验室中,无需繁琐安装配置,随时在浏览器中实践体验:

文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有

最新文章

热门文章

本栏目文章