DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Astock — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-astock

Astock

A股 / 港股量化工作台:自选股、K线图、公司数据、策略配置与回测。 · A-share & Hong Kong stock quant workbench for DeepSeek Harness.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-astock@0.9.0
READMECompatibilityVersions

Compatibility and provenance

Astock is published as dsh-astock and currently resolves to version 0.9.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/20/2026

Versions

0.9.0stable
9/14/2026
0.8.0stable
9/11/2026
0.7.2stable
9/11/2026
Show 13 more versionsCollapse versions
0.7.1stable
9/11/2026
0.7.0stable
9/11/2026
0.6.3stable
9/11/2026
0.6.2stable
9/11/2026
0.6.1stable
9/11/2026
0.6.0stable
9/11/2026
0.5.0stable
9/11/2026
0.4.1stable
9/11/2026
0.4.0stable
9/11/2026
0.3.1stable
9/11/2026
0.3.0stable
9/11/2026
0.2.0stable
9/11/2026
0.1.0stable
9/11/2026
Latest
0.9.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
347 kB
Files
6
Surface
web
License
MIT
Source
npm
GitHub
★ 2
Weekly downloads
295
Security scan
✓ v0.9.0 scan passed
Last push
9/14/2026
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

README

dsh-astock

A股港股量化工作台 —— DeepSeek Harness 插件。

当前版本 0.9.0 · npm · 版本记录 · 提交历史

在侧边栏底部提供独立的「A股港股」整页:A 股与港股的自选股管理、K线图、公司财务数据、策略配置与回测。

包名 dsh-astock 里的 a 是历史遗留(最初只做 A 股),安装命令与 id 都依赖它,因此保持不变;界面与文档里显示的是 A股港股。

⚠️ 免责声明

本插件仅用于技术学习与量化研究,不构成任何投资建议、要约或收益承诺。 不提供选股推荐与买卖时机提示,也不代客理财。任何据此做出的投资决策由使用者自行判断并承担全部后果。

  • 数据:行情、K线、财务数据均来自第三方公开接口,可能存在错误、延迟、缺失或因接口变更而中断,不对准确性、完整性、及时性作任何保证。港股数据来自腾讯且未经复权,除权除息日会出现价格跳空。
  • 回测:基于历史数据,不能代表未来表现。结果受策略过拟合、幸存者偏差、参数与区间选择影响;交易成本、滑点、涨跌停与流动性均为近似模型,与真实成交存在差异。历史收益不预示未来收益。
  • AI 生成:生成的策略代码仅供参考、未经审核,可能有逻辑错误或隐含风险,请自行阅读并验证后再使用。
  • 责任:使用者应自行核实数据与结果,并自行承担使用本插件所产生的任何直接或间接损失。插件作者不对任何投资损失承担责任。
  • 合规:请遵守所在地区法律法规及所使用数据源的服务条款,禁止用于内幕交易、市场操纵等违法用途。

界面里有两处对应措施:首次打开会要求确认完整条款(确认后落盘,条款有实质修改时会重新提示),底部常驻一条精简声明(即使确认弹窗因接口故障没能出现,这条也始终可见)。回测结果与 AI 生成处也各有对应提示。

功能

模块内容
自选股支持 A 股与港股(可混排):按代码 / 名称 / 拼音首字母搜索(600519、茅台、GZMT、00700),增删、切换;落盘保存
K线手写 SVG 蜡烛图(阳线空心红 / 阴线实心绿)、MA5/10/20/60、成交量副图、十字光标逐根读数;日/周/月 × 前/后/不复权 × 1/3/5/10 年;60–500 根缩放 + 平移
公司数据实时快照(现价/涨跌/开高低/成交额/换手/PE/PB/总市值/流通市值/每手股数/币种)+ 16 期财务(EPS/BPS/ROE/毛利率,仅 A 股)+ 公司动态(说明会 / 财报预约披露 / 除权除息 / 自定义事件)+ AI 查动态并自动填入(可接自定义 HTTP 数据源)
策略9 个参数化模板(双均线、MACD、RSI、布林带、唐奇安突破、均线多头、相对强弱 RS、大盘趋势+相对强弱、说明会前后)+ 表达式编辑器 + JavaScript 编辑器 + 和 AI 多轮对话改策略(可出表达式或 JS、可联网查证)
回测按市场自动切换规则(A 股 T+1/涨跌停/100 股一手;港股 T+0/无涨跌停/每手逐股不同/印花税双边);佣金(5元起)/印花税/其他费率/滑点;总收益/年化/最大回撤/夏普/卡玛/胜率/盈亏比;资金曲线 + 沪深300 对比;支持按日期区间回测与年份快捷档位
交易明细点击买入日期向下展开决策证据:逐条条件的 ✓/✗ 与两侧实际数值、实际触发项加重显示、交叉给出前一根、策略自述 why;拿不到证据时如实说明并提供一键 AI 改写
免责首次强制确认完整条款(落盘,版本变更时重新提示)+ 底部常驻精简声明;回测结果与 AI 生成处各有提示

策略:三种入口

策略页顶部可切换 表达式 / JavaScript 两种模式;页面最上方还有一个 用文字描述让 AI 生成 的入口。三者共用同一套指标实现与同一个回测引擎——JS 侧的指标函数只是把值包装成 AST 节点交给表达式求值器,所以同一个策略在两种模式下必然得到完全相同的回测结果(测试里有交叉验证断言)。

入口一:和 AI 多轮对话(推荐)

策略页底部是对话区:写一句话点「发送」,然后一直追问下去。

我:20 日均线上穿 60 日均线时买入,跌破 20 日均线时卖出。 AI:先用双均线金叉做了一版。已更新为表达式策略,已通过试运行校验 我:再加一个放量过滤,成交量要高于 20 日均量。 AI:加上了。已更新为表达式策略,已通过试运行校验 我:如果持有不到 5 天就别卖。 AI:这个需求表达式表达不了,需要 JavaScript 模式,因为要记住持有了几天。

每一轮 AI 都会给出完整的新策略并直接填进编辑器,所以看完就能点回测。要点:

  • 按当前模式产出:你在表达式模式就让它写表达式,在 JS 模式就写 JS。它做不到时会自己换模式并说明原因(比如「需要记住持有天数」只能写 JS)。
  • 对话上下文一起带上:每一轮都把之前的对话与当前策略发给模型,所以可以用「再加个」「改成」「把止损换成」这种自然的追问,不用重复描述。
  • 想改哪一版都能退回去:表达式与 JS 各留一版,「↺ 换回上一版」一键切回。
  • 只回答、不给代码也是合法的一轮:需求不明确时它会反问,编辑器不动,你接着答就行。
  • 发送后立刻试运行。拿到策略就地跑一遍当前 K 线(表达式按表达式解析、JS 按 JS 执行),语法错、运行错、信号长度不对当场写在气泡下面。试运行失败时策略仍会填进去,方便你手动修。
  • 失败不丢输入:请求失败时你那句话会留在输入框里,直接重试即可。

表达式模式还有个额外好处:表达式里的比较(C > MA(20))会被系统逐条拆出真假与两侧数值, 交易明细里的证据比 JS 模式更细。所以简单逻辑优先用表达式。

  • 把真实事件日期一并交给模型,必要时还会自己联网查。你自己算不出「哪天开会」「那天是不是交易日」,模型同样算不出,所以宿主会先把该股的真实事件列表(见因子)塞进提示词,并明确要求:只能用这些日期、禁止自己推算日历、禁止写死日期字符串。列表里没有的(比如产品发布会),它可以自己用 web_search 去查,查到的日期要经你确认才会生效。比如直接写:

    公司开业绩说明会的前一个交易日卖出,会后的第二个交易日买入。

    它会生成 sell: EVMEET(-1), buy: EVMEET(2),用哪场会、哪天、隔几个交易日,全由真实数据决定。 生成完成后提示里会写「已把该股 N 条真实事件日期交给模型」——这句话就是「有没有真实依据」的凭证。

模型调用走宿主的 llm 服务,用 agentDefaultModel 的当前选型,因此不需要在插件里配置任何 API Key。若宿主未挂载 llm 服务或没有默认模型,会给出明确提示。 对话只保存在当前页面状态里(不落盘),切换股票时会清空;点「清空对话」可以随时重新开始。

入口二:表达式

买入 / 卖出条件各写一行,例如:

买入:CROSS(MA(5),MA(20)) AND RSI(14)<70
卖出:CROSS(MA(20),MA(5)) OR C>BOLL_UP(20,2)
  • 变量:C O H L V(收/开/高/低/量),别名 CLOSE OPEN HIGH LOW VOL
  • 函数:MA(n) EMA(n) SUM(n) STD(n)、RSI(n)、DIF() DEA() MACD()、BOLL_UP(n,k) BOLL_MID(n) BOLL_LOW(n,k)、HHV(n) LLV(n) REF(x,n) CROSS(a,b) ABS MAX MIN
  • 运算符:+ - * / > < >= <= == != AND OR NOT(或 && || !)、括号
  • 函数名与 AND/OR/NOT 大小写不敏感;MA(5) 等价于 MA(C,5)

表达式由本包自带的词法 / 语法分析器求值,不使用 eval。每个节点求值为整段区间的序列,一次算完全程。

入口三:JavaScript

写任意 JS——循环、变量、状态机、多分支都可以。必须 return { buy, sell },两个数组长度都要等于 C.length:

const fast = MA(C, 5)
const slow = MA(C, 20)
const volUp = GT(V, MA(V, 20))
const buy = new Array(C.length).fill(0)
const sell = new Array(C.length).fill(0)
let inPosition = false
let holdDays = 0
for (let i = 0; i < C.length; i++) {
  if (!inPosition && CROSS(fast, slow)[i] && volUp[i]) { inPosition = true; holdDays = 0; buy[i] = 1; continue }
  if (inPosition) {
    holdDays++
    if (holdDays >= 5 && LT(C, slow)[i]) { inPosition = false; sell[i] = 1 }  // 至少持有 5 日
  }
}
// 可选:自己说明第 i 根为什么买卖,会显示在交易明细最前面
function why(i, side) {
  return side === 'buy' ? '5 日线上穿 20 日线且放量' : '持有满 5 日后收盘跌破 20 日线'
}
return { buy, sell, why }

可用(都是与 K 线等长的数组,索引可直接用):

  • 序列:C O H L V,以及总根数 N
  • 指标:MA(x,n) EMA(x,n) SUM(x,n) STD(x,n) HHV(x,n) LLV(x,n) REF(x,n)、RSI(n)、DIF() DEA() MACD()、BOLL_UP(p,k) BOLL_MID(p) BOLL_LOW(p,k)、ABS/MAX/MIN
  • 布尔组合(返回 1/0 序列,null 当假):CROSS(a,b) GT LT GTE LTE AND OR NOT
  • 也支持 MA(5) 这类省略序列的写法(默认用收盘价;HHV 默认最高价、LLV 默认最低价)

想让交易明细给出证据,买卖条件就用上面这组布尔函数组合(AND(CROSS(fast, slow), volUp)), 系统才能逐条还原「信号日哪一条成立、两侧数值是多少、这次到底踩中了哪几条」; 如果直接写 C[i] > slow[i] 这类原生比较,运行期不留下任何可读的中间结构,界面只能给指标快照 + 一条一键 AI 改写的出路。也可以额外 return 一个 why(i, side),用自己的话补一句原因。

错误会分类提示:语法错误、运行异常、返回值类型不对、信号数组长度不匹配——四种都是可读的具体信息,不是一句「失败」。

⚠️ 策略代码在浏览器里执行。避免死循环(如 while(true)):主线程被占满会让界面卡住,刷新页面即可恢复。 模板按钮在两个模式下都会填入对应写法——JS 模式下填的是等价 JS 代码,可直接改。

因子

策略不只能用 K 线。因子分两类,界面上也明确分区——因为有一类数据只存在于「当下」,拿来回测就是造假。

已接入:市场情绪(可回测)

全部由「个股 K 线 + 沪深300 指数」算出,不依赖任何不稳定的第三方源:

因子含义
BENCH沪深300 收盘价序列(已按日期对齐到当前标的)
RS(n)相对强弱 = 个股 n 日涨幅 ÷ 指数同期涨幅。>1 表示跑赢大盘
IDXRET(n)指数 n 日涨幅
IDXMA(n)指数 n 日均线
IDXDEV(n)指数偏离 n 日均线的比例,正数表示在均线上方
IDXVOL(n)指数年化波动率(越高越不安全)
BETA(n)个股对指数的滚动 Beta,>1 表示比大盘波动更大

表达式模式与 JS 模式都能用(两者共用同一套实现,不会漂移)。策略页会显示这些因子的当前读数。

内置两个模板演示:相对强弱 RS 择时、大盘趋势 + 相对强弱(要求个股与大盘同时处于上升趋势、且个股跑赢大盘才买)。

前视偏差的处理:指数序列只做前向填充,开头没有对应交易日的位置保持 null,刻意不用未来值回填开头——否则早期的因子值会偷偷用上后面的数据。指数取不到时策略会明确报错,而不是静默算出一堆 null。

已接入:公司事件(可回测)

「财报披露后第二个交易日买入」「说明会前一个交易日卖出」这类想法,缺的从来不是写代码的 能力,而是真实日期——「哪天开会」「哪天披露」「那天是不是交易日」,模型凭空算不出来。 所以这三类日期直接从公开数据里取,交易日换算按真实 K 线做:

因子含义日期来源
EV(n)全部事件—
EVMEET(n)业绩说明会 / 股东大会 / 路演公告正文里的「会议召开时间」(公告日在前)
EVREP(n)财报预约披露交易所预约披露时间表
EVDIV(n)除权除息分红实施公告(公告日在前)
EVCUS(n)自定义事件(AI 联网检索 / 手工添加)用户逐个确认,标为「未核实」

n 是相对该事件的第 n 个交易日:-1 = 事件前一个交易日,0 = 事件当日, 2 = 事件后第二个交易日。事件当天不是交易日(公告常在周末或盘后发)时按之后第一个 交易日算。策略只写 n,日历由引擎算。

港股同样可用(EVMEET / EVREP):

港股事件来源因子
董事会会议召开日期港交所公告(提前公布哪天开会审批业绩)EVREP(n)
股东周年大会 / 股东特别大会通告港交所公告EVMEET(n)
业绩公告公告日即业绩日,只能用于 n >= 0EVREP(n)

港股公告是繁体、日期还常写成中文数字(「謹訂於二零二六年五月十三日」),所以日期解析 同时支持阿拉伯数字与中文数字,并覆盖「將於…召開董事會會議」「謹訂於…舉行股東週年大會」 这些写法。

三类事件都是事先公开过的日期,所以「提前于事件」的条件是合规的:

  • 说明会、股东大会、除权除息都有公告日在前;
  • 财报用预约披露日而不是实际披露日——预约时间表是交易所期初公布的,用它做「财报前 卖出」没问题;用实际披露日等于提前知道了财报哪天出。
  • 引擎还有一道硬保护:如果那一根 K 线当天事件还没公告,该条件直接不触发。所以 「当天才公告的说明会」不会被提前埋伏——这一条有测试专门守着。

「公司数据」页有公司动态表,列出该股全部真实事件日期(日期 / 类型 / 内容 / 何时公开), 你能一眼看到策略手里有什么牌。内置模板 说明会前后 演示这套因子。

AI 生成会把该股的真实事件列表直接塞进提示词,并明确要求:只能用这些日期、禁止自己 推算日历、禁止写死日期字符串;生成结果里也会告诉你「已把该股 N 条真实事件日期交给模型」。

数据源里没有的日期:让 AI 自己联网查

产品发布会这类日期,交易所数据里就是没有。这时 AI 会自己联网查证:宿主给它挂了 web_search / web_fetch 两个工具,它可以搜多轮、也可以打开公告页确认,最多四轮 (最后一轮不再给工具,逼它落笔写代码)。

查到之后它不能直接把日期写进策略,而是输出一个 events 区块:

[{"date":"2026-09-09","title":"秋季新品发布会","announcedAt":"2026-08-01","source":"https://…","evidence":"原文写明 9 月 9 日召开"}]

插件解析出来后,在策略页列成候选事件,必须由你点一下「确认加入」才会生效:

  • 自定义事件单独一类,只由 EVCUS(n) 引用,不会悄悄改变 EV / EVMEET 的语义;
  • 表里标成未核实并给出出处链接——交易所数据和模型检索结果永远分得清;
  • 日期不合法(不是 YYYY-MM-DD、或不是真实存在的日期)的条目直接丢掉——宁可少一条,也不让编的日期进来;
  • 公告日未知时按「事先已知」处理,界面会明确写出来:那是个建模假设,不是事实。

两条检索路径(宿主挂了就用宿主的,坏了用内置的)

宿主 web 服务的搜索 provider 可能是坏的——实测本机部署每次调用都报 WEB_PROVIDER_ERROR: DeepSeek returned no web_search_tool_result blocks。所以检索是两级的:

顺序来源覆盖范围
1宿主 web.search(部署配置的搜索提供方)通用网页
2内置财经资讯检索东方财富站内搜索:财经新闻 + 公告

宿主第一次失败后,本轮不再重试它,直接走内置检索;两条路都不通时如实报错,并且 不再继续给模型工具(省掉后面几轮空转)。界面上会写明这次用的是哪条路、宿主报了什么错、 以及去设置 → 插件 → 插件配置 → Web search 改 Endpoint 就能修好宿主搜索。

宿主还会替模型先查一遍:需求里出现「发布会 / 说明会 / 股东大会 / 业绩 / 财报 / 除权」这类 事件词时,宿主先拿股票名 + 需求去检索一次(约 0.5 秒,10 分钟内同查询走缓存), 把结果原样摆进提示词,并要求模型只能从中取真实日期、找不到就说找不到。 这样做是因为「等模型自己决定去搜」不可靠——实测它会直接声称「列表里已经有这个事件」, 然后写出一个指向不存在日期的策略。

内置检索的结果会标注来源(内置财经资讯检索·东方财富站内搜索:媒体新闻与公告), 不冒充通用搜索。对选股策略来说这部分内容恰好最相关——会议、业绩、发布会都在公告与新闻里。 抓网页(web_fetch)同样先走宿主服务,不可用时退回插件直连取正文。

宿主没挂 web 服务时不会假装查过:返回值里写明「未挂载 web 服务,本次没有联网查证」, 界面照原样显示。/astock/api/health 里的 webSearch 字段就是这项能力的状态。

取不到时不会装没事

会议日期只能从公告正文里读,而正文接口(np-cnotice-stock)在密集请求下会直接 ECONNRESET(实测过)。所以:

  • 正文按 art_code 把解析结果落盘缓存(announcements.json):一条公告里的会议日期 不会变,抓过一次就不再打扰上游,上游抖动也不会让已有的事件凭空消失;
  • 拉取改为小批量并发 + 重试 + 批间隔,降低触发限流的概率;
  • 仍然失败的部分会写进 errors 并在界面上说明「部分事件没取到:…」,绝不悄悄变少。 财报预约披露与除权除息走另一个域名,不受影响,所以限流时事件列表不会全空;
  • 失败后 60 秒内不再请求正文(退避):被限流时反复切股票/刷新只会把封禁越敲越久;
  • 界面上有 ↻ 重新加载事件日期 与 手动添加 两条出路,不用干等。

实测该正文接口在密集请求后会按 IP 限流,返回 ECONNRESET,通常几十分钟到几小时恢复; 恢复后解析结果会永久落盘,之后不再请求。

兜底一:自己填

上游读不到、或数据源里根本没有的日期(自家公司发布会、行业展会),「公司数据」页有 手动添加:选日期、写名称,立刻成为自定义事件,策略里用 EVCUS(n) 引用。 它和 AI 检索的结果一起标成「未核实」,来源分列显示。

一只股票如果没有可用事件(例如港股最近 200 条公告里没有会议类文件),界面会说明原因, 用到事件因子的策略会直接报错而不是静默算出「没有信号」。给 AI 的提示词里也会明确写上 「这只股票没有事件数据,禁止使用 EV/EVMEET/EVREP/EVDIV」,免得它生成一个一跑就报错的策略。

公司数据页:让 AI 去查动态,查到就填表

「公司数据」页有独立的 AI 对话区,和策略页那个是两回事:这里不写策略,只查这家公司的动态 (发布会、业绩说明会、股东大会、财报披露、分红除权……),查到的日期直接填进事件表。

我:小米近三年的产品发布会都有哪些? AI:查到 2026 年 9 月 7 日有一场秋季旗舰新品发布会…… 已自动填入 1 条事件(标为未核实,可删除)

  • 自动填入:宿主直接从 AI 的输出里解析 events 区块并写进自定义事件(同一天同标题只留一条), 客户端只管把最新表铺上去。表里标未核实、带来源链接、随时可删;策略里用 EVCUS(n) 引用。
  • 只问情况不会乱写:AI 没给出日期时,表里不会多出任何东西。
  • 换了股票就重开对话:对话是跟着股票的。

外部数据源:接你自己的接口

除了联网检索,「外部数据源」区可以配 HTTP 接口,配完 AI 就能把它当工具调用:

字段说明
名称工具名(模型看到的是 ds_<名称>)
URL 模板支持 {code} {name} {query} 占位符,例如 https://api.example.com/ann?code={code}
说明原样注入系统提示词——把某个 MCP / skill 的用法写在这里,AI 就知道该怎么用你的数据源

启用的数据源会作为工具交给模型,调用结果(含失败原因)都会回灌给它;停用的不会出现。

为什么不是「直接调用宿主注册的 MCP 工具」

用运行时探针在真实 Host 进程里查过,结论是做不到:

插件上下文 ctx.get('tools')  →  只有 register / schemas / get,没有 execute
agent 上下文 ctx.get('tools') →  有 execute(但那是 agent 作用域,插件借不到)
ctx.get('skills').list()     →  0 条(skill 注册在 agent 作用域,插件侧看不到)

也就是说,宿主里注册的工具(包括 MCP 服务器提供的)在插件作用域内不可执行,skill 目录 也读不到。这是作用域设计,不是 bug。所以插件这边给的是自己能掌控的两条路: 把数据源配成 HTTP 接口,或把用法写进「说明」(MCP 若同时提供 HTTP 端点,直接填进来即可)。 界面上也照实写明了这一点,不假装支持。

安全:harness 自带的核心工具(bash / 读写文件 / web_* 之外的东西)不会被暴露给这个助手; 插件只把它自己配置的数据源交给模型。

规划中

阶段因子可回测
行业所属行业、成分股自算行业指数、个股 vs 行业相对强度✅
公司动态公告密度序列;最新公告列表密度✅ / 列表仅当下
市场热度人气榜、行业实时排名、当日资金流❌ 仅展示

市场热度这类数据没有历史,所以只能做信息面板并标注「不参与回测」,绝不能当因子用。

港股

搜索、行情、K线、回测都支持港股(代码 5 位,如 00700 腾讯控股、00005 汇丰控股)。A 股与港股可混在同一个自选股列表里。

但港股不是「换个数据源」那么简单——A 股与港股的交易规则不同,直接套用会算错。回测引擎按标的自动切换:

A 股港股
交割T+1(当日买入不可卖)T+0(当日可回转)
涨跌停±10%(创业板/科创板 ±20%,北交所 ±30%)无涨跌停
每手股数恒为 100逐股不同:腾讯 100、小米 200、汇丰 400、长和 500
印花税卖出单边 0.05%买卖双边各 0.1%
币种CNYHKD

每手股数从行情里逐股读取,不写死。策略页会明示当前适用哪套规则,并提供「套用港股默认费率」一键填入。

港股的三个限制

  1. 无复权数据。腾讯对港股不提供复权价(qfq/hfq/不复权返回的数据完全相同),本插件拿到的港股 K 线是不复权的。除权除息日会有价格跳空,长期收益会略被低估。回测结果页会明确提示这一点。
  2. 无财务数据。东方财富那份财务报只覆盖 A 股(港股 SECUCODE=00700.HK 返回「返回数据为空」)。切到港股的公司数据页会给出这句说明,而不是一张空表。
  3. 成交额单位不同。A 股行情接口给的是万元,港股给的是元,已在解析层归一化。同样,港股行情没有换手率与市净率,界面显示 — 而非 0。

回测区间

策略页最上方是一条常驻操作条(滚动时也贴在顶部):

[开始回测]   起始[2023-09-11] ~ 结束[        ]
快捷区间  近1年  近3年  近5年  近10年  全部
          已加载 780 根:2023-08-25 ~ 2026-09-11(选更长的档位会自动多取数据)
          所选区间命中 780 根 K 线。
  • 默认三年:起始日默认为三年前的今天,结束日留空(取到最新)。可以直接改日期,也可以点档位。
  • 年份快捷档位:原生日期选择器只能按月步进,翻到几年前要点很多下。这里的 近1/3/5/10年 是一键跳年。
  • 档位会自动补数据:选了比已加载范围更长的档位(比如只加载了 3 年却点「近10年」),会连带把 K 线年数调大并重新取数,而不是给你一个被静默裁剪的区间。
  • 区间是在已加载的 K 线上按日期裁剪,切换瞬时完成,不会重新取数。
  • 所选区间不足 30 根会直接报错并说明原因;起始日早于已加载数据时会提示需要更多数据,而不会静默算出一段不完整的区间。
  • 结果页会写明实际使用的区间(2026-01-05 ~ 2026-06-30(116 根)),以及是否发生过裁剪。

交易明细:为什么买 / 为什么卖

点击交易明细里的买入日期,会在下方展开这笔交易的决策证据:

▾ 2026-07-15   1204.86   2026-08-20   1298.50   +7.66%   26
    为什么买
      信号日 2026-07-14(收盘决定信号) → 成交日 2026-07-15(开盘 @1204.86)
      策略自述原因(why 钩子返回)
        第 486 根:5 日线上穿 20 日线,成交量高过 20 日均量
      按你代码里的条件函数自动拆解(✓ 成立、✗ 不成立;加重显示的是本次信号的实际触发项)
      ✓  全部条件成立(AND)        下列条件必须同时成立
        ✓  CROSS(MA(C, 5), MA(C, 20))   今 1202.47 vs 1197.29 / 前 1195.80 vs 1197.29
        ✓  V > MA(V, 20)                今 86321.00 vs 41120.00
        ✗  RSI(14) > 200                今 41.8833 vs 200

为什么信号日在成交日前一天:信号在收盘产生、次日开盘成交(无未来函数),所以要解释「为什么」,必须回到信号那一根去看。

证据不是猜的:条件函数会被逐个记录

JS 策略有循环和状态机,静态分析确实给不出可信归因——但它在计算层面是收敛的:每一个买卖条件都是策略库里 GT / LT / GTE / LTE / CROSS / AND / OR / NOT 这些函数的组合。所以库函数在返回时会记下自己的身份、操作数与结果, 信号日就能把整条链路反过来还原出来:

  • 逐条列出每条条件当时成立还是不成立(不成立的一样列出来,不会只挑成立的讲);
  • 每条都比较两侧的实际数值,交叉类条件额外给出前一根(只看当根证明不了上穿);
  • 加重显示本次信号实际触发的那几条:AND 的每个分支都是触发源,OR 里没成立的分支不会被算进去;
  • 缩进表示条件之间的嵌套关系。

两种模式能给出的东西不一样

模式能给出的解释
表达式逐条件拆解:把顶层的 AND / OR 摊平成一条条条件,各自标注 ✓/✗ 并附上比较两侧的具体数值。不成立的条件也会如实列出。
JavaScript(用条件函数组合)与表达式模式同一套证据:逐条真假 + 两侧数值 + 实际触发项,还能额外显示策略自己写的 why(i, side) 说明。
JavaScript(直接写 C[i] > MA(C, 20)[i] 等原生比较)无法自动归因——系统拿不到条件函数留下的标记。界面会如实说明这一点并给出信号日的指标快照(C / MA5 / MA20 / MA60 / RSI14 / MACD / 有指数时的 RS、IDXDEV),同时提供一键让 AI 改写成可归因版本(保持买卖逻辑不变,只换成条件函数 + why),原代码留在「策略配置」页可随时换回。

这个区别是本质的:原生 JS 比较在运行期不留下任何可读取的中间结构,静态分析也给不出可信的归因。 与其编一个看起来像原因的理由,不如说清「这里只能给快照」并给出一条能真正拿到证据的路。

why(i, side):让策略自己说话

条件函数的证据链说明「哪些条件成立了」,但这条策略为什么要看这几个条件只有写代码的人说得准。 所以代码可以额外 return 一个 why 函数,它返回的一句话会显示在明细最前面:

function why(i, side) {
  if (side === 'buy') return '5 日线上穿 20 日线,成交量高过 20 日均量,且大盘在 60 日线上方'
  return '5 日线下穿 20 日线,或收盘跌破 20 日线'
}
return { buy, sell, why }

AI 生成的策略会被要求同时给出条件函数组合与 why 说明,所以生成的策略开箱就有完整证据。

回测的真实性约定

按 A 股口径(港股按上表切换):

  • 无未来函数:信号在收盘产生,在次日开盘成交。
  • T+1:买入当日不可卖出。因卖出也走次日开盘,实际最短持有为 2 个交易日,比真实 T+1 略保守。
  • 涨跌停:按板块推断限幅(主板 10% / 创业板·科创板 20% / 北交所 30%)。开盘处于涨停价则买不进,跌停价则卖不出。ST 股的 ±5% 无法从代码推断,未建模,会对 ST 偏乐观。港股无此限制。
  • 成本:佣金费率可调、5 元起收;印花税买卖费率分开设置(A 股卖出单边、港股双边);其他费率(过户费等)可调;滑点默认千分之一。
  • 整手:委托量按该股的每手股数取整(A 股 100,港股逐股不同)。资金不足 1 手时不会建仓,界面会明确提示原因。
  • 前复权口径:A 股默认使用前复权价,收益连续性正确,但绝对价位与历史成交价不一致。
  • 回测结束仍有持仓时不强制平仓,按最后一根收盘价计入权益(界面会提示)。

数据源

默认全部免密钥。K线与行情以腾讯为主源、新浪为备源,搜索与财务用东方财富。

  • K线:web.ifzq.gtimg.cn(按年区间分页)→ 备源 money.finance.sina.com.cn
  • 行情:qt.gtimg.cn(GBK 编码,按响应头 charset 解码)
  • 搜索:searchapi.eastmoney.com;失败时回退为纯代码录入
  • 财务:datacenter-web.eastmoney.com
  • 事件:港交所/交易所公告(正文日期)、预约披露时间表、分红实施公告
  • 资讯检索(AI 联网查证的兜底):search-api-web.eastmoney.com

同花顺官方数据(可选,需要自己的 API Key)

同花顺官方有一套面向 AI Agent 的 A 股数据服务:同一个 API Key,提供 MCP 与 REST 两套入口。

项值
官网 / 文档https://fuyao.aicubes.cn/ · https://fuyao.aicubes.cn/docs/
API Keyhttps://fuyao.aicubes.cn/admin/ 免费签发
RESThttps://fuyao.aicubes.cn/api/...,请求头 X-api-key
托管 MCP(HTTP)https://fuyao.aicubes.cn/mcp/a-share、/mcp/a-share-index、/mcp/meta 等 6 个
限流不限制累计调用次数(异常并发会 429 / code=4001)

在「公司数据」页填入 Key 之后:

  • AI 助手会多出 ths_corporate_actions(除权除息 / 分红送股)、ths_prices_snapshot(行情)、 ths_hot_stocks(热榜)、ths_dragon_tiger(龙虎榜)四个工具;
  • 除权除息事件在东方财富那份表为空时,自动改用同花顺官方复权事件兜底;
  • Key 只存在本地($DSH_ASTOCK_HOME/hithink.json),接口里只回掩码,不回明文。

为什么插件走 REST 而不是直接连 MCP:宿主里注册的 MCP 工具在插件作用域内不可执行 (插件拿到的 tools 服务只有 register/schemas/get,没有 execute,见下文实测)。 好在这套服务两套入口共用同一个 Key、同一批数据,走 REST 等价且更简单。 当前覆盖 A 股,港股不在它的范围内。

配置

环境变量作用默认
DSH_ASTOCK_HOME状态落盘目录$DSH_HOME/astock,再退回 ~/.dsh/astock

目录里有四个 JSON:watchlist.json(自选股)、disclaimer.json(免责声明确认)、 events.json(自定义事件)、announcements.json(公告正文解析缓存,可随时删除,删了会重新抓)。

结构

package.json             dsh.bundle.patch + dsh.client.platform,exports["./client"]
cordis.patch.yml         插入 id=astock name=dsh-astock
lib/index.js             Host 半边:10 条 /astock/api/* 路由 + 自选股/免责/自定义事件落盘 + 事件抓取 + 联网查证工具循环
client/client.js         客户端 bundle:__ModuleLoader__ 工厂块,仅 require('react')
tests/
  engine.test.mjs        表达式引擎 + 回测引擎(纯离线,读 fixtures)
  host.test.mjs          Host 路由(真实上游 + mock llm)
  client.test.mjs        客户端 bundle(真实执行组件 + 数据流)
  fixtures/              两份真实日线数据,供离线测试使用

客户端与 Host 通过 HTTP 路由通信(host.call 是动态插件专有机制,正式 bundle 不可用)。

测试

pnpm test                 # 三套全跑
node tests/engine.test.mjs   # 策略与回测引擎(纯离线,43 项)
node tests/host.test.mjs     # Host 半边:真实上游 + mock llm + 港股 + 自选股混排 + 免责声明 + 事件路由 + 港股事件解析 + 联网查证工具循环 + 多轮对话与表达式输出 + 检索兜底与预查 + 公司数据对话 + 同花顺数据(280 项)
node tests/client.test.mjs   # 客户端 bundle:真实执行组件 + 数据流 + 策略模式 + AI 入口 + 港股规则 + 回测区间与档位 + 免责弹窗 + 情绪因子 + 事件因子与自定义事件 + 交易证据链 + AI 对话与表达式模式 + 公司数据对话与数据源管理 + 同花顺 Key(274 项)

host.test.mjs 与 client.test.mjs 需要网络(要打腾讯/东财的真实接口)。engine.test.mjs 完全离线,只读 tests/fixtures/。

client.test.mjs 用自建 hook 运行时而非 react-dom:宿主里 react 是 18、react-dom 是 19,版本不匹配;本插件只用到 createElement / useState / useEffect,足以模拟。

安装

dsh plugin --profile web add -w <本目录绝对路径>

-w 是必需的:profile 自身的 pnpm-workspace.yaml 把它标记为 workspace root。

首次安装后需重启 dsh web(bundle 列表只在启动时读取)。

改代码后要不要重启?

分两半,结论不同:

改动的文件生效方式
client/client.js热更新,不用重启。harness 的 @deepseek-ai/dsh-client-hmr 会轮询 bundle 文件,内容变了就通过 /plugins/events SSE 推送新版本,页面自动换掉旧 bundle(必要时刷新一次页面)。
lib/index.js(Host 半边)需要重启 dsh web。Host 插件在启动时装载。

判断某次改动是否已经被服务:从 /plugins/events 取当前图,找到本包条目的 url,抓下来 grep 新代码即可:

curl -s --max-time 5 http://127.0.0.1:3080/plugins/events \
  | sed -n 's/^data: //p' | head -1 \
  | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const g=JSON.parse(s).graph;console.log(g.entries.find(e=>e.id==='dsh-astock').url)})"

版本记录

每个版本对应一次 GitHub 提交与一次 npm 发布。完整提交历史见 commits。

0.9.0

接入同花顺官方数据(REST API,凭一个 Key)

调研确认:同花顺官方(HiThink-Tech)发布了面向 AI Agent 的金融数据服务 HiThink-Tech/Financial-API,同一个 API Key 同时提供 MCP 与 REST 两套入口: 6 个托管 MCP 端点(https://fuyao.aicubes.cn/mcp/*,HTTP 传输)与一组 REST 接口 (https://fuyao.aicubes.cn/api/...,请求头 X-api-key),不限制累计调用次数。

由于插件作用域执行不了宿主注册的 MCP 工具(实测),插件改走同一份数据的 REST 入口:

  • 「公司数据」页新增「同花顺官方数据」:粘贴 Key → 保存 / 清除 / 测试连接;Key 本地落盘、只回掩码。
  • 配好后 AI 助手多出四个工具:ths_corporate_actions(除权除息/分红送股)、 ths_prices_snapshot、ths_hot_stocks、ths_dragon_tiger。
  • 除权除息事件在东方财富为空时用同花顺官方复权事件兜底(A 股)。
  • 代码 → thscode 的交易所后缀映射(沪/深/北),港股明确报「不在覆盖范围」。

测试:host 262 → 280 项(后缀映射、Key 掩码与清除、未配置不暴露工具、配置后注入工具、 假 Key 被如实拒绝、除权兜底),client 264 → 274 项(Key 表单、掩码、测试连接、清除)。 合计 597 项全通过。

0.8.0

公司数据页接入 AI 对话:查到动态直接填进表;并接自定义数据源

  • 「公司数据」页新增 AI 对话区:查发布会 / 说明会 / 股东大会 / 财报 / 分红等公司动态, 查到的事件由宿主直接写进事件表(标未核实、带来源、可删除,同日同标题去重), 策略里用 EVCUS(n) 引用。只问情况、没给出日期时不会往表里塞东西;换股票自动重开对话。
  • 新增「外部数据源」:可配 HTTP 接口(URL 模板支持 {code} {name} {query}), 启用的数据源会作为工具交给模型,调用结果(含失败原因)回灌;「说明」字段原样注入提示词。
  • 实测结论(运行时探针):插件上下文里的 tools 服务只有 register/schemas/get, 没有 execute;skills.list() 在插件侧返回 0 条——也就是说插件无法调用宿主注册的 工具(含 MCP 服务器)或读取 skill 目录,这是作用域设计。因此走「HTTP 数据源 + 说明文本」 这条自己能掌控的路,界面上也照实写明,不假装支持。
  • 安全:只把插件自己配置的数据源交给模型,harness 自带核心工具不暴露。

测试:host 238 → 262 项(数据源增删改查、模板替换、数据源当工具调用并回灌、说明注入、 自动填表与去重、停用不暴露、只问答不写表),client 241 → 264 项(对话区、自动填表提示、 数据源增删、注册表限制说明)。合计 569 项全通过。

0.7.2

修「小米产品发布会之前卖出」这类需求跑不通

拿线上真实请求复现过,两头都出了问题:

  1. 模型根本没搜(searched=false、suggestedEvents=[]),却在说明里声称 「列表里已经有 2026-09-07「小米产品发布会」,已登记为自定义事件」,然后写了 EVCUS(-1)——策略指向一个不存在的日期。原因是提示词只说「列表里没有的事件才需要联网查」, 没写「不许假设它已经存在」。
  2. 即使它真的写错了,也没有任何机制拦住。

三处修复:

  • 提示词加硬规则:EVCUS 只能引用用户已确认的自定义事件;事件列表里没有的, 不许假设存在、不许跳过检索;绝不允许声称「列表里已经有某个事件」,除非它真的在列表里。
  • 输出后校验 + 强制补一轮:策略里用到了 EVMEET/EVREP/EVDIV/EVCUS(或事件全空的 EV) 而对应事件不存在时,宿主不采信,补一轮带明确指令的对话(「先联网查证并输出 events 区块, 查不到就明说」)。只有既给出候选事件、又确实搜过才算合规——凭记忆写的日期一样不可信。
  • 宿主替模型先查一遍:事件类需求先自己做一次新闻检索(内置财经资讯检索), 把结果摆进提示词。不再把可靠性押在「模型会不会去调工具」上。
  • 兜底也给足出路:确实查不到时,界面上写明三条路——再追问一次 / 公司数据页手动添加 / 改成不依赖事件因子;候选事件区也标注「不点确认就直接回测会报错」。

测试:host 218 → 238 项(假设事件的检测、强制补一轮、预查块与命中缓存、非事件需求不预查), client 240 → 241 项(查不到事件时的三条出路)。合计 522 项全通过。

0.7.1

修「AI 的 web_search 用不了」:检索加了一层内置兜底

用运行时探针在真实 Host 进程里查过,结论很明确:

  • llm 的工具调用完全正常——模型会正确发出 web_search 的流式工具调用;
  • 坏的是宿主 web.search:每次调用都返回 WEB_PROVIDER_ERROR: DeepSeek returned no web_search_tool_result blocks, 它配的搜索 Endpoint(open.feedcoopapi.com/search_api/global_search/messages)没返回原生搜索结果。

插件这边能做的是不把整件事卡在宿主的配置上:

  • 宿主搜索失败后自动改用内置财经资讯检索(东方财富站内搜索,覆盖财经新闻与公告), 实测能搜到「贵州茅台召开半年度业绩说明会」这类带日期的新闻,正是策略需要的东西;
  • 宿主 provider 失败一次后本轮不再重试;两条路都不通就如实报错并停止再给工具;
  • 界面写明这次用的是哪条路、宿主的原始报错,以及修好宿主搜索的路径 (设置 → 插件 → 插件配置 → Web search → Endpoint);
  • web_fetch 同样加了插件直连的兜底。

测试:host 208 → 218 项(内置检索结构、宿主可用时走宿主、provider 报错时退回内置、 本轮不再重试、两条路都不通),client 237 → 240 项(检索来源与修复路径提示)。合计 501 项全通过。

0.7.0

AI 改成多轮对话,并且能产出表达式策略

原来只有「一句话 → 一次生成 → 填进编辑器」,想再改只能重说一遍;而且只出 JS。 现在策略页底部是对话区:

  • 多轮对话:每一轮都把之前的对话与当前策略一起发给模型,所以「再加个放量过滤」 「把止损换成跌破 30 日线」这样追问就行。AI 每轮给出完整的新策略并直接填进编辑器。
  • 支持表达式模式:按你当前的模式产出——表达式模式要求输出 {"buy":"…","sell":"…"},JS 模式要求输出函数体。需求确实表达不了时(要记持有天数、 多步状态),它会改用另一种模式并说明原因,返回值和界面都如实显示实际产出的是哪种。
  • 只回答不给代码也是合法一轮:需求不明确时它会反问,编辑器不动。
  • 两模式各留一版可回退:↺ 换回上一版表达式 / ↺ 换回上一版代码。
  • 失败不丢输入:请求失败时那句话回到输入框,并在对话里留一条失败气泡。
  • 表达式模式下的事件因子(EVCUS(-1))也能用;交易明细里同样写明命中的真实事件—— 这一条原来只对 JS 生效,现在表达式模式也补上了。

注意:AI 产出的策略每一轮都会覆盖编辑器(旧版可回退)。模型偶尔忘记加围栏代码块时, 只要整段看着就是函数体也会被认成代码。

测试:host 187 → 208 项(表达式块解析、对话历史传递与裁剪、反问轮、模型换模式时如实回报、 无围栏纯代码识别),client 211 → 237 项(多轮历史、表达式应用与试运行校验、反问不改编辑器、 清空对话、回退上一版、表达式模式的事件因子证据)。合计 488 项全通过。

0.6.3

限流退避 + 手动添加事件(上游靠不住时的两条出路)

东财的公告正文接口(np-cnotice-stock)在密集请求后会按 IP 限流,返回 ECONNRESET。 实测该接口没有可替代的镜像域名(np-anotice-stock 的 content 路径返回空 body),所以:

  • 失败后 60 秒内不再请求正文——被限流时反复切股票/刷新只会把封禁越敲越久;
  • 「公司数据」页新增手动添加事件:选日期、写名称,即时成为自定义事件(标为手工来源、 未核实),与 AI 检索走同一条保存路径;
  • 配合 0.6.2 的「取数出错不写缓存」与「↻ 重新加载」,限流期间不再被锁死。

测试:host 185 → 187 项,client 206 → 211 项。合计 441 项全通过。

0.6.2

修「限流后要等 30 分钟才恢复」

事件列表有 30 分钟进程内缓存,但取数出错时也写了缓存——于是上游限流一次, 「缺了会议事件」的结果就被锁住半小时,上游恢复了用户也看不到。改成只有成功才进缓存。

同时「公司数据」页新增 ↻ 重新加载事件日期 按钮,取数失败会直接显示原因, 不用切股票来触发重取。

测试:client 204 → 206 项。合计 434 项全通过。

0.6.1

港股也能用事件因子了(修「港股没事件数据」)

0.6.0 上线后实测:港股股票的事件列表是空的,AI 生成的事件策略一跑就报 「事件因子需要公司事件数据」。原因是港股公告的标题写法、日期写法都与 A 股不同, 原来的解析一条都没匹配上:

  • 新增港股来源:「董事会会议召开日期」公告=提前公布的业绩日(港股版的预约披露), 归到 EVREP(n);股东周年大会 / 股东特别大会通告归到 EVMEET(n); 业绩公告作为兜底(公告日即业绩日,只能用于 n >= 0,不会变成未来函数)。
  • 日期解析支持中文数字(「謹訂於二零二六年五月十三日」→ 2026-05-13), 并覆盖「將於…召開董事會會議」这类港式写法。
  • 同一天的财报事件去重时优先保留更早公布的那条(预告日), 这样 EVREP(-1) 这种提前量才是有依据的。

修「上游限流导致事件悄悄变少」

公告正文接口在密集请求下会直接 ECONNRESET。原来的代码把它 .catch(() => null) 吞掉了, 表现就是「事件列表莫名变少、界面还说一切正常」。现在:

  • 正文解析结果按 art_code 落盘缓存(announcements.json),抓过就不再请求;
  • 小批量并发 + 重试 + 批间隔,降低触发限流的概率;
  • 失败的部分写进 errors 并在界面说明「部分事件没取到:…」,绝不静默变少。

修「模型不知道没有事件数据」

原来没有事件时只回报一个 0,模型照样按常识写 EVMEET(-1)。现在这种情况会在提示词里 明确写上「这只股票没有事件数据,禁止使用 EV/EVMEET/EVREP/EVDIV」,并给出两条出路 (联网查到就用 EVCUS、否则生成不依赖事件的替代策略)。客户端的试运行也会把 待确认的候选事件一并算进去,不再出现「明明确认后能用、却先报一次错」。

测试:host 158 → 185 项(中文数字与繁体日期提取、港股真实事件、候选事件校验、无事件提示词), client 201 → 204 项(无事件时的原因显示与预警、试运行带上候选事件)。合计 432 项全通过。 新增测试钩子 __test(仅供离线测试调用纯函数,不是公开 API)。

0.6.0

AI 可以自己联网查资料了(发布会这类交易所数据里没有的日期)

0.5.0 给了模型真实的交易所事件日期,但那里面没有「产品发布会」。0.6.0 让模型自己上网查:

  • 宿主给模型挂 web_search / web_fetch 两个工具,最多四轮工具调用(最后一轮不给工具, 逼它落笔写代码)。工具调用是流式分片给出的,插件按 index 拼回完整参数。
  • 模型查到的日期不能直接写进策略,必须输出 events 区块;插件解析后列成候选事件, 由用户点「确认加入」才成为自定义事件。日期不合法的条目直接丢弃。
  • 自定义事件单独一类,只由 EVCUS(n) 引用,不会悄悄改变 EV/EVMEET 的语义; 表中标注未核实并附出处链接,与交易所数据严格分开。
  • 宿主没挂 web 服务时静默降级,但会如实回报「未挂载 web 服务,本次没有联网查证」; health.webSearch 暴露这项能力的状态。
  • 新增 /astock/api/custom-events(覆盖式保存)与 events.json 落盘;事件表支持逐条删除。

测试:host 127 → 158 项(多轮工具调用、分片参数拼接、候选事件解析与非法日期丢弃、搜索失败的降级、 没有 web 服务时的降级、自定义事件的去重与来源区分),client 181 → 201 项(自定义事件渲染与删除、 EVCUS 语义、自定义事件不混进 EVMEET、候选事件的确认流程)。合计 401 项全通过。

0.5.0

交易明细的「为什么买 / 为什么卖」改为真正的证据链(针对「还是没给出实际证明」的反馈)

之前 JS 模式的交易明细只能给一张指标快照,没有任何东西能证明「这笔交易到底踩中了哪一条条件」—— 信号日的 MA5 甚至可能是向下的,快照本身无法解释信号。0.5.0 把这件事做实:

  • JS 策略库现在会记录触发链路:每个条件函数(GT / LT / GTE / LTE / CROSS / AND / OR / NOT) 返回时都会记下自己的身份、操作数与结果(标记不可枚举,不影响任何计算结果,两种模式的指标仍然同源)。 信号日据此把整条链路反向还原:
    • 逐条列出每条条件当时成立还是不成立(不成立的照样列,不挑着说);
    • 每条附两侧实际数值,交叉类条件额外给出前一根(只看当根证明不了上穿);
    • 加重显示本次信号实际触发的那几条:AND 的每个分支都是触发源,OR 里没成立的分支不算;
    • 缩进表示嵌套关系。
  • 新增 why(i, side) 钩子:策略可以自己 return 一个函数说明第 i 根为什么买卖, 这段话显示在明细最前面——「为什么要看这几个条件」只有写代码的人说得准。
  • 原生比较(C[i] > slow[i])仍然无法归因,此时界面明确说「无法自动归因」并给出三条出路, 其中一条是新增的一键让 AI 改写成可归因版本(保持买卖逻辑不变,改成条件函数组合 + why)。 改写会覆盖编辑器内容,因此旧代码自动留档,「策略配置」页可一键换回。
  • AI 生成的策略被要求必须用条件函数组合并附 why 说明,开箱即有完整证据。
  • 策略编辑页与 README 都写清了「怎么写才有证据」。

新增:公司事件因子(真实日期,可回测)

  • 新增 /astock/api/events:抓三类事先公开的真实日期——说明会 / 股东大会(逐条去公告正文里 提取「会议召开时间」,提取不到或日期不合常理就宁可漏掉也不编)、财报预约披露日、 除权除息日(带公告日)。
  • 新增 EV(n) / EVMEET(n) / EVREP(n) / EVDIV(n):n 是相对该事件的第 n 个交易日, 交易日换算按真实 K 线做(事件日不是交易日就顺延到之后第一个交易日)。
  • 硬保护:那一根 K 线当天事件还没公告时,条件直接不触发——「当天才公告的说明会」不会被提前埋伏。
  • 「公司数据」页新增公司动态表;新增模板说明会前后;交易明细里会写明「命中 2026-08-21 说明会」。
  • AI 生成把该股真实事件列表塞进提示词,并要求只能用这些日期、禁止推算日历;返回值里带 events 条数,界面显示「已把该股 N 条真实事件日期交给模型」。

测试:client 139 → 181 项(证据链、AND/OR/NOT 节点、实际触发项、OR 假分支不误标、原生比较兜底、 一键改写与换回;事件日映射、非交易日顺延、当天公告不许提前埋伏、事件缺失时的可读错误), host 103 → 127 项(AI 提示词要求条件函数与 why、要求用事件因子且不许编日期、事件路由的真实性与日期合理性)。 合计 351 项全通过。

0.4.1

文档发布:让 npm 页面同步 README

  • 纯文档版本,无代码变更。npm 上已发布的版本不能修改,0.4.0 的 README 里没有版本记录, 这个版本只为把最新文档同步到 npm 页面。
  • 之所以单独发一版而不是等下次代码改动:npm 页面的 README 是给使用者看的第一手材料, 版本记录留在那里才有意义。

0.4.0

交易明细说明「为什么买 / 为什么卖」

  • 点击交易行向下展开决策证据。表达式模式把顶层 AND / OR 摊平成一条条条件,各自标注 ✓ / ✗ 并附上比较两侧的具体数值;不成立的条件也如实列出,不挑着说。
  • 引擎开始记录信号发生的 bar(成交在次日开盘,所以信号在前一根),解释回到信号那一根而不是成交那一根。
  • JS 模式无法定位到具体语句,界面如实说明并改为给出信号日的指标快照——与其编一个像原因的理由,不如说清这里只能给快照。

0.3.1

修复:AI 生成策略总是报「模型没有返回任何内容」

  • 根因:思考 token 与正文 token 共用 maxTokens。默认选型带 reasoningEffort: high,2048 的预算被思考全部吃掉,模型还没开始写代码就被截断(实测 reasoningTokens=2048、text-delta=0、finish=max-tokens)。
  • 不再透传 reasoningEffort;maxTokens 2048 → 16384。
  • 错误信息改为说清「为什么没有内容」,区分截断 / 其他 finish 原因 / 流意外结束,并给出可操作建议。

0.3.0

市场情绪因子(第一阶段)

  • 新增 BENCH、RS(n)、IDXRET(n)、IDXMA(n)、IDXDEV(n)、IDXVOL(n)、BETA(n),全部由「个股 K 线 + 沪深300」算出,完全可回测。
  • 表达式与 JS 两种模式共用同一套实现(只在求值器里写一次),不会漂移。
  • 指数序列只做前向填充,开头保持 null,不用未来值回填——避免前视偏差。
  • 策略页新增因子读数面板;新增「相对强弱 RS 择时」「大盘趋势 + 相对强弱」两个模板。

0.2.0

免责声明 + 改名 + 首次发布到 npm

  • 首次打开强制确认完整条款(落盘,条款版本变更时重新提示)+ 底部常驻声明;回测结果与 AI 生成处各有提示。
  • 显示名从「A股量化工作台」改为「A股港股量化工作台」,侧边栏标签改为「A股港股」——此前已支持港股,旧名字不再准确。
  • 移除 private,补 publishConfig(本机默认 registry 是只读镜像,不显式指定会发布失败)。

0.1.0

首个版本

  • A 股与港股:自选股(可混排、落盘)、手写 SVG K 线图、公司财务数据。
  • 三种策略入口:6 个参数化模板 / 表达式(手写词法 + 语法分析,不使用 eval)/ JavaScript(new Function,支持循环与状态机)。
  • 回测引擎:按市场自动切换规则(A 股 T+1、涨跌停、100 股一手、印花税卖出单边;港股 T+0、无涨跌停、每手逐股读取、印花税双边),支持按日期区间回测。
  • 无未来函数(信号收盘产生、次日开盘成交)、佣金/印花税/过户费/滑点、整手约束。

说明:0.1.0 发布时显示名仍是「A股量化工作台」,改名的提交(42f99d4)随 0.2.0 一起发布。