能力子页 · 扩展与二次开发
tick-stock-panel 的扩展机制:不改核心代码能加什么
大多数开源项目的“扩展”意味着 fork,之后每次升级都要手工合并。本页讲清 tick-stock-panel 把扩展做成了两条互不干扰的链,以及它为此定下的那些硬约定。
tick-stock-panel 的扩展到底是怎么加载进去的?
后端靠目录自发现,前端靠构建时插槽。两条链都不需要你碰核心文件,也都有各自的约定。
| 链路 | 官方机制 | 你需要做的事 |
|---|---|---|
| 后端 | 把包放进 app/custom/<包名>/,启动时自动发现并注册独立路由 | 写一个普通的 Python 包,在 setup 里把路由注册上去 |
| 前端 | 把 src/custom/*/extension.tsx 放入,构建时自动挂载到插槽 | 实现一个前端模块,向插槽暴露组件 |
| 隔离跳过 | 版本不符或 setup 失败时,该扩展被隔离跳过,不影响主程序 | 升级后发现扩展没加载,先看日志里是不是被跳过了 |
| 卸载 | 删除整个扩展目录即整体卸载,零核心文件修改 | 没有注册表、没有配置文件需要同步清理 |
tick-stock-panel 到底能扩展哪些东西?
下表列出六类拓展方式,以及它们各自应该放在哪里。其中两类完全不需要写代码。
| 拓展方式 | 放在哪里 | 适合什么需求 |
|---|---|---|
| 自定义信号(不写代码) | UI 侧搭建条件,没有文件 | 几个阈值条件的组合,改起来快 |
| 自定义策略 | data/strategies/custom/,文件名带 custom_ 前缀 | 有特殊逻辑,需要历史窗口、状态依赖或自定义评分 |
| AI 生成策略 | data/strategies/ai/,文件名带 ai_ 前缀 | 想先拿一个可跑的基线,再逐行改 |
| 内置策略(贡献回上游) | 仓库的内置策略目录,参照现有文件实现接口 | 你的策略通用且愿意提 PR |
| 数据源插件 | 参照仓库内的插件实现写成插件 | 你有一个仓库未支持的数据源,且不想用 YAML 声明式源 |
| 数据扩展(不写代码) | 面板里的 HTTP 拉取 / CSV·Excel 上传 / JSON 写入 | 你有现成数据文件或接口,想当作信号与因子的输入 |
tick-stock-panel 策略文件里到底要写什么?
一个策略文件由五个部分组成,其中有一个容易被忽略的硬约束。本节把它们摆出来,并补上目录扫描的细节。
| 策略文件组成 | 作用 | 编写时的关注点 |
|---|---|---|
META | 定义 UI 上可调的阈值与默认值 | 把可能变的东西都放这里,而不是写死在逻辑里 |
basic_filter | 单日过滤,返回一个表达式 | 适合“当日满足什么条件”这类逻辑 |
filter_history | 历史窗口过滤,需同时提供 LOOKBACK_DAYS | 只要用到回看,就必须点明回看长度 |
scoring | 评分权重,各项权重之和应为 1.0 | 和不为 1 时排序会出现不可预期的结果 |
ENTRY_SIGNALS / EXIT_SIGNALS | 入场与出场信号 | 它们让策略能被监控引用,也是回测与归因的依据 |
.py 文件。这意味着你可以在里面建子目录放文档、快照与证据,不会被当成策略加载;以下划线开头命名的文件也会被跳过。官方在策略迭代文档里正是利用这一点,把每轮的修改与台账保存在子目录里。它同时提供了一个「证据包」思路:每轮修改都留下改了什么、为什么改、结果如何;并且把「什么没用、为什么」的负知识列为最值得保留的部分。tick-stock-panel 哪些能改、哪些不能改?
边界比能力更重要:加错地方,升级时会连带着把你的修改一起覆盖。
| 想加的东西 | 能不能加 | 正确做法 |
|---|---|---|
| 一个新策略 | 能 | 放自定义策略目录,或向上游提 PR |
| 一个新因子 | 能 | 用因子编辑器的 DSL 写,不需要改代码 |
| 一个新数据源 | 能 | YAML 声明式源(六类数据集契约)或写插件 |
| 一个新页面 | 能 | 用前端插槽挂载,不改核心路由 |
| 一个 AI 工具 | 能(只读前提) | 参照助手的扩展实现写自己的只读工具 |
| 改核心的回测口径 | 不建议 | 上游升级会覆盖你的修改,且会让结果不可审计 |
| 一个设计文档里写了但代码里没有的 API | 不能依赖 | 官方明确要求不得据设计示例虚构尚不存在的 API |
写一个 tick-stock-panel 扩展的正确顺序是什么?
下面七步是本站归纳的顺序:先用空扩展验证加载,再往里面填逻辑,最后用删除测试验证卸载干净。
写一个扩展的七步:从空扩展到可用
先确认你要加的东西属于哪一类
策略?因子?数据源?页面?AI 工具?四类扩展路径各自有固定的目录与命名约定,选错了就加载不上。
先找官方已有的参照实现
数据源插件参考仓库内现有插件;AI 工具参考助手的实现;前端插槽参考现有的前端扩展。照着能跑的代码写,不照设计描述写。
用最小可运行版本验证加载
先只做一个空的扩展,确认它能被发现、能注册、能在界面上看到。这一步通过了,再往里面填逻辑。
再把真实逻辑填进去
到这一步才开始写业务代码。每修改一次都重启一次,确认扩展还在正常加载。
记下你用到的接口与版本
扩展依赖的内部接口可能随版本变。记下你基于哪个版本开发,下次升级后就能快速定位。
用删除测试验证卸载干净
把整个扩展目录移走重启,界面与接口都应该恢复到没有它的样子——这是验证“零核心修改”的最直接方法。
tick-stock-panel 升级会不会把我的扩展弄坏?
下表列出升级前后的几类风险与官方机制,并给出每一类对应的核对动作。
| 升级前后的风险 | 官方机制 | 你该做什么 |
|---|---|---|
| 扩展在新版本下加载失败 | 版本不符或 setup 失败会被隔离跳过,不影响主程序 | 不要把它当成“整站挂了”;先看日志确认是不是被跳过了 |
| 前端插槽在新版本下未挂载 | 插槽是构建时挂载的,前端改动后需重新构建 | 重新构建,并检查你用到的插槽名是否变了 |
| 上游修改了你依赖的内部接口 | 内部接口不属于公开契约 | 对关键扩展做一个最小自测,升级后跑一遍 |
| 你改了核心文件才让扩展能用 | 官方设计本意是不需要改 | 改回去,把修改限制在你自己的扩展目录里 |
| 想把扩展分享给其他人 | 仓库欢迎贡献 | 先读官方的贡献指南,再改成符合其目录约定的形式 |
TSP 的目录与命名到底有哪些硬规定?
下表把六条目录与命名约定列出来。它们看上去是细节,但写错任一条都会导致扩展不被加载。
| 目录 / 文件 | 约定 | 它为什么要求这样 |
|---|---|---|
| 后端自定义包目录 | 一个包对应一个扩展,启动时被自动发现 | 让新功能的引入不需要改任何入口文件 |
| 前端扩展目录 | 每个目录一个入口模块,构建时被挂到插槽 | 前端打包阶段就把扩展编进去,运行时不需要动态加载 |
| 自定义策略目录 | 文件名带 custom_、放在顶层、以 .py 结尾 | 引擎只扫顶层,子目录里可以安心放文档与快照 |
| AI 生成策略目录 | 文件名带 ai_ 前缀,与人工策略分开 | 你随时能区分哪些是自己写的、哪些是生成的 |
| 下划线开头的文件 | 被引擎跳过 | 可以把临时脚本、旧版本备份放在同一目录不被加载 |
| 证据与台账子目录 | 不被作为策略加载 | 每轮修改的记录与快照可以与策略放在一起,但不干扰运行 |
TSP 扩展没生效时,应该怎么排查?
下表列出六类最常见现象与处理顺序:先排“有没有被加载”,再排“加载后行不行”。
| 现象 | 最常见的原因 | 处理顺序 |
|---|---|---|
| 后端扩展没被发现 | 包没放在约定的自定义目录,或目录下缺入口文件 | 先对照目录约定表 → 再看启动日志有无跳过记录 |
| 前端插槽上没出现新页面 | 入口模块名不符合约定,或没重新构建 | 确认文件名与位置 → 重新构建 → 清缓存再看 |
| 策略列表里多了不该有的项 | 把临时脚本或旧版本备份放进了顶层 | 把非策略文件移进子目录,或改成下划线开头命名 |
| 扩展在本机好使、到别人机器就没了 | 依赖了本地路径、环境变量或未提交的文件 | 把扩展当独立仓库管理,并检查所有路径都是相对路径 |
| 升级后扩展失效但主程序正常 | 扩展被隔离跳过 | 看日志的跳过原因 → 对照升级说明 → 改适配而不是改核心 |
| 不知道自己改没改到核心文件 | 没有检查过修改范围 | 用一次删除测试验证:移走扩展目录后界面与接口应完全恢复 |
tick-stock-panel 扩展与二次开发常见问题
以下答案基于官方仓库与文档的核验结果;涉及版本、数据源口径与许可条款的内容一律以官方仓库与官方文档为准。tick-stock-panel 扩展真的不用改核心代码吗?
官方的设计目标就是这个:后端把包放进自定义目录就会被自动发现并注册路由,前端把模块放进自定义目录就会在构建时挂到插槽,两边都不需要注册表。删除整个目录就是卸载,也没有残留配置需要清理。它甚至把自己的 AI 助手当作参考实现——就是为了证明这套机制能支撑一个完整功能。换句话说,你可以把它当成一个“可以自己写功能的客户端”,而不是一个只能用现成功能的封闭产品。
为什么文件名要带前缀?
因为引擎靠命名与目录区分策略来源。自定义策略带 custom_ 前缀,AI 生成的带 ai_ 前缀,两者分别落在不同子目录。这不是命名风格问题,而是为了让系统在不读取任何配置的前提下就能判断一个文件是什么、从哪来、能不能被跳过。另外下划线开头的文件会被跳过,别用它命名策略。
我能用自己的数据源插件吗?
可以。仓库里有现成的插件实现可供参照,你按同样的方式写一个就行。不过先判断你的需求属于哪一类:如果你只是想接一个 HTTP 接口,YAML 声明式数据源可能就够了,不必写代码;只有当接口形态特殊、YAML 表达不了时,才值得上插件。另外记住:深度盘口目前没有自定义数据集契约,那一块接不了。
写完扩展怎么验证它真的生效了?
用一个最小可运行版本先验证加载:空扩展能被发现、能注册、界面上能看到。这一步通过再填逻辑。最后还要做一次删除测试:把整个目录移走重启,界面与接口应该恢复到没有它的样子。如果删掉后还有残留行为,说明你不小心改到了核心文件。
上游升级后扩展失效了怎么办?
先确认它是不是被隔离跳过了。官方的行为是:版本不符或 setup 失败时,该扩展会被跳过而不影响主程序。所以“扩展没上线”与“主程序坏了”是两件事,不要把前者当成后者。定位方法是看启动日志里是不是有跳过记录,再对照你开发时用的版本。
能不能把扩展发布出去给别人用?
可以。仓库欢迎贡献,也提供了贡献指南与协作说明。不过官方在协作说明里给了两条铁纪律:一是区分“已实现能力”与“目标契约”,不得根据设计示例虚构尚不存在的 API;二是不得虚构测试或审查结果,以实际验证结果作为完成标准。实际操作上,建议先把扩展当成一个独立项目维护,等它稳定后再考虑合并到上游;这样即使提交被请求修改,你自己的扩展也不会因此停止工作。
启用扩展后启动变慢了怎么办?
先判断慢在哪一段:如果是启动时才慢,大概率是扩展在初始化阶段做了重操作(比如拉远程数据、扫大目录);如果是运行时才慢,则多半是在请求路径上。两者的修法完全不同:前者把重操作改成懒加载,后者去看是否每次请求都在重算。另外一个常见原因是扩展在每次请求里重复初始化,而不是只在启动时初始化一次。把状态放到正确的生命周期里,是写扩展时最容易忽略的一件事。