tianyagk/dsh-tradewatcher

dsh-tradewatcher

DeepSeek Harness (DSH) web plugin: 盯盘 market-dashboard sidebar tab — three quote strips with hover intraday charts, watchlist with industry alpha, ledger-driven portfolio P&L, A-share boards & detail drawer, host-side Eastmoney relay + read-only agent tools.

待分类cordisdeepseek-harnessdsh

dsh-tradewatcher(盯盘)

一个 DeepSeek Harness Web 插件:通过宿主客户端 Slots 服务注册一个全局「盯盘」面板(左侧栏图标 sidebar.panellist + 主面板 main,两者 id/key 同为 tradewatcher),提供 A股/国际/商品行情条 + 悬浮分时图、行业热力图、分组自选、流水驱动的分组持仓账本(市值/浮动盈亏/当日盈亏/已实现),并把持仓记录以只读模型工具 + 明文 JSON 双通道开放给 dsh 会话分析。

界面与数据组织参考浏览器插件「爱盯盘」(52etf.site);行情为免费公开接口的延迟行情(非 L2),仅作盯盘参考。

  • 安装与使用 → 本文档
  • 历次变更、口径修订与实测依据 → CHANGELOG.md
  • 待开发清单(含「动手前必须探活的源」与「明确不做」) → docs/ROADMAP.md

功能

面板由八个页签组成:自选 / 持仓 / 大盘(含护盘信号与底部位置分析)/ 云图 / 日历 / 工具箱 / 复盘 / 棱镜。下面按模块说明。

行情条与详情图

  • 顶部行情条(四行,默认每 10s 自动刷新 + 手动刷新,页签隐藏时自动暂停)
  1. A股指数:上证指数、深证成指、创业板指、科创50、沪深300、中证500
  2. 国际市场:韩国KOSPI200、法国CAC40、英国富时100、欧洲斯托克50、标普500、纳斯达克、德国DAX30、日经225、恒生指数
  3. 国债收益率:美债10Y、日债10Y、德债10Y、英债10Y
  4. 大宗商品:生猪主连、焦煤主连、豆粕主连、螺纹钢主连、布伦特原油当月、COMEX铜、COMEX白银、伦敦金现
  • 每卡片:名称 / 现价 / 当日涨跌值 / 涨跌幅(红涨绿跌;浅色/深色/跟随系统主题可切);右上角五态色点(实时/延迟/定稿/未取到/无行情源,见「数据出处与状态」)
  • hover 悬浮卡:当天分时图(源缺失自动回退近 5 日收盘走势),附昨收基准虚线、最后行情时间与成交额
  • 点击卡片打开右侧详情抽屉(键盘 Enter/Space 亦可)
  • 自选/持仓每行带分时缩略线,hover 叠加均价线与分时首笔 / 分时高 / 分时低 / 分时振幅(口径:取自分时抽样点,不是交易所口径的今开/最高/最低 —— 官方开高低在详情抽屉;图上不加常驻文字:密集布局里加字就是噪音);均价线用与价格同一套 y 映射,缺口不连线
  • 详情抽屉:固定信息头(名称/代码/现价/涨跌幅/所属行业板块及板块涨跌幅/今开/昨收/换手率/最高/最低/成交量/成交额/市盈率/总市值)+ 三窗格专业图:主图 + 成交量(红绿柱、最大量标注)+ MACD(HIST 柱 + DIF/DEA 线,12/26/9,HIST=(DIF−DEA)×2),主图与子图均带纵轴刻度线(1/2/5×10ⁿ 步长);K 线叠加 MA5/10/30/60(橙/蓝/紫/灰,附当前值图例,均线在全量序列上计算后再截取可视区间)
  • 周期:分时 / 五日 / 日K / 周K / 月K / 年K(记住上次选中)
  • 分时主图叠加均价线;五日图为 5 个交易日连续拼接(午休/隔夜已折叠,交易日之间画分隔线)
  • 东财 trends2 的 ndays 参数会被上游忽略(只回当日),因此五日视图改用 5 分钟 K 线拼接:新浪为主源(A股/ETF/指数,一次可取 6–8 个交易日)、腾讯 5 分钟 K 线兜底
  • 本地按日归档 + 拼接(v0.31.0 起):每次成功取到某一日的分时(任何来源,含 LKG 兜底命中那一次)都会按 secid + 交易日 归档;港/美股、国际指数、外盘商品、期货这些市场,五日档改用本地归档拼接——覆盖多少天、缺哪天,写在口径条上(我们的两条多日渠道(新浪 5 分钟线、腾讯 5 分钟线)只覆盖沪/深,其余市场靠本地归档逐日累积;这是「我们没覆盖」,不等于「上游没有」。2026-10-11 实测:东财 trends2 忽略 ndays(ndays=1 与 5 回包逐点相同),腾讯 5 分钟线对港股未产出 ≥2 个交易日)(本地拼接 3/5 天 · 缺 2026-10-07),缺的日子只列不补
  • ⚠ 不得期待历史归档:归档从本版起累积,装好当天最多只有 1 天(界面上会写「仅当日,从本版起累积」),之后每过一天多一天,最多拼到 5 天。过去的日子没有归档过,追不回来——这不是 bug,也不需要"补数"
  • 缩放:日期宽度双滑块 + 近1月/3月/6月/1年/全部 快捷键,图表内滚轮以光标为中心缩放(最少 8 根);键盘:←/→ 平移(Shift 加速 10 根)、+/- 缩放、Home/End 到两端,滑块手柄是标准 slider 语义
  • 买卖点:图上按持仓流水标注 B/S(悬停显示「数量 @ 价格 · 分组/持仓」);周/月/年 K 把同周期多笔归并为 B2/S3;同一根 bar 的多笔合并为一个标记,悬停给当日小结(笔数 · 合计股数 · 均价);图下有区间图例(区间内 B/S 笔数、净买卖股数、买卖均价),缩放把交易移出可视范围时补一句 (区间外另有 N 笔)
  • 读屏摘要:.tw-sr 文本与图同源同一次计算(区间、首末收盘、区间涨跌幅、最高最低、买卖点笔数与净买卖),不会出现"摘要说涨、图上在跌"
  • 顶部口径条:日K · klt 101 · 前复权 · 截至 10-09 14:31(当根未收盘,MA/MACD 已含未收盘当根) —— 复权用宿主回包的实际生效口径;「截至」用本地最近一次成功取数时刻,不拿"现在"顶替

自选

  • 分组的新建/改名/备注/删除(删除=归档,可恢复)+ 组内添加(名称/代码搜索补全)/移除/移动分组;搜索池覆盖 A股/港股/美股/ETF/基金/指数/期货主连(如 688825、02155)
  • A股行展示所属行业板块名、板块当日涨幅、个股相对板块 alpha(个股涨跌幅 − 板块涨跌幅)(行业归属 10 分钟缓存,板块涨幅随行情轮询同步刷新);板块涨跌缺失时显示 — 并给出原因,禁用 0 代替(0 会被读成"没涨没跌",那是错的信息)
  • 排序:默认顺序 / 当日涨跌 / 总市值(组内生效,记忆在 prefs.json,同键再点切换升降序);排序沿用面板头部的段控(v0.36.0 起不再有列头排序 —— 列表上方那排列头与段控功能重复,已按用户要求删除),任何宽度下都只有这一个入口
  • 年初至今(YTD)列:口径见「口径规范 → 年初至今」;显示 — 时可在 tooltip 看到具体原因
  • 异动提示:放量/价格异动/量价共振的行带左侧竖条 + 缓慢呼吸背景(不是整行变红——整行红会与"跌了"的语义冲突;prefers-reduced-motion 下退化为静态底色),面板头部「异动 N」徽标可展开队列;同一条目 30 分钟静默(记在 localStorage)

持仓

  • 分组 CRUD(同上归档语义)+ 组内证券的「买入/卖出/调整/编辑/移动/明细/移除」
  • 每分组与总览显示总市值、浮动盈亏、当日盈亏、累计已实现;每行含浮动盈亏率与当日盈亏率、可用(可卖)数量、累计费用(含占累计成交额百分比)、标的年初至今(YTD)
  • 排序:默认顺序 / 市值 / 持仓盈亏(随所选成本口径)/ 当日盈亏 / 仓位占比
  • 总额口径:默认只含 A股,港/美股逐项列在「不含 N 项 ▼」里并可下钻看原因;也可切到固定汇率折算(见「折算口径」)
  • 除权提示:复用已同步的日历事件,顶部列出涉及持仓的公司行为与日期,持仓卡片标「N 天后除权」;不自动改账(真实的送转/派息以券商为准,正确动作是在「调整」里按实际到账录入)
  • 成本口径可切换(右上角分段开关,偏好存 prefs.json),切档弹 toast 报差值而不是只改数字

A股大盘

  • 12 栏网格的紧凑布局(v0.33.0 重排:单行 25px 指标条 + 45px 指数卡矩阵,取代原先每个数值一张两行卡):B1 市场宽度(家数/两市成交额/上涨占比 + 历史分位分布条)+ B2 六大指数卡矩阵 + B3 护盘信号(收起态,无数据时塌成一行)+ B4 板块/资金/ETF + B5 搜索与详情
  • 涨跌家数:优先用上游直接给的字段;拿不到时由本插件自行按沪深A股全量统计(口径见「口径规范 → 涨跌家数」)。取不到就显示 `—` 并把每个尝试过的源与各自的原因写在 tooltip 里,不用 0 顶替
  • 涨跌家数历史分位(样本 ≥5 个交易日后显示;样本不足给原因不给 0)
  • 行业/概念板块涨跌排行与主力资金排行(口径行常显:数据时刻 / 来源;15:05 后标「定稿」;金额与占比两种排序可切,占比只在本页 40 条内重排并写明)
  • ETF 排行;个股/基金搜索 + 详情卡(分时大图、换手/量比/市盈率/市值)
  • 缺失时收缩而不是留空:家数缺失时三格合并成一格且原因只出现一次;其余块缺失只影响一格/一行(块高变化 ≤±8px)

状态可见性(侧栏徽标与降级态)

  • 侧栏徽标:左侧栏「盯盘」图标上带一个小徽标,不打开面板也知道发生了什么 —— 内容只有持仓当日盈亏率(带符号短标记,如 -2.3%;0.0% 是真的零;算不出时徽标为空、悬停里给原因,不用 0 冒充);颜色跟随 prefs.redUp(红涨绿跌 ↔ 绿涨红跌);隐身视图下只显示沪深300 点位,不出现任何金额。侧栏标签恒为「盯盘」(不带 · 数据 HH:mm:ss、也不带 · 已收盘 —— 用户明确不要后缀);数据时刻与「已收盘」状态在侧栏条目的悬停 `title`(当日盈亏 -1.6% · 数据 15:05:56 · 已收盘)与面板内,信息没有丢。图标只有 18px、字形最多 4 个字符。徽标数据来自 GET /tradewatcher/badge,只读同一份 rescue 快照与持仓汇总,不触发新的采样 —— 徽标是常驻的,若它自己打一遍上游,等于把"看一眼侧栏"变成取数压力。

⚠ 护盘等级不进这个徽标:v0.25.0 曾有一条"护盘 ≥「疑似护盘」就显示「护」"的优先分支,它顶掉当日涨跌幅;2026-10-16 按用户要求删除(同一个 18px 的位置放两种语义,用户既分不清这个字是"我的"还是"市场的",也分不清它为什么变)。护盘等级有自己的位置(护盘面板 + tradewatcher_rescue 工具);要放回侧栏必须另立入口。回归防线在 src/client/badgeView.test.ts(徽标改成「护」或任何非涨跌幅文本 ⇒ 断言必败)

  • 卡片五态色点与列表头汇总:见「数据出处与状态」
  • 降级态一律显式:护盘暂停时分数位显示 — 而非上次的分数;数据来自备用源/上次成功结果时行上标 source 与「上次数据」;上游熔断时状态条简述 + tooltip 明细(逐主机剩余时间、最后错误),并说明哪种因子"等几分钟能补齐"、哪种"该源根本没有,不是等的问题"
  • 本会话未采样 ≠ 采样缺口:收盘后重启用持久化的上次快照并红标「上次数据」,gap 只反映当日真实失败

备份与迁移

持仓页「备份」按钮:导出把 watch/positions/ledger/prefs 打包成一份带 schemaVersion 与校验和的 JSON;导入是两段式 —— 选文件 → 预览(校验 + 覆盖前后差异)→ 确认覆盖。覆盖前宿主把原文件写成 .bak,导入后立即重读内存(不需要重启)。

校验不通过一律拒绝并逐条给原因:非对象、缺 schemaVersion、版本高于插件支持、缺文件、流水条目无法解析、引用不存在的持仓/分组 id、重放出现负持仓、校验和不匹配。最后一条是硬约束:宁可不导入,也不导入一份算不平的账 —— 一旦写进去,之后所有成本、盈亏、已实现都建立在一个错的账本上,而用户没有任何手段看出"从哪一天开始不对"。

大盘云图

只保留第三方站点(自绘云图已于 v0.62.0 删除,见 CHANGELOG.md 的对应条目):

  • 第三方站点:内嵌 iframe 到第三方热力图站点(地址见 src/client/CloudMap.tsx 的 CLOUD_MAP_URL;可重新加载/新窗口打开)。信息量更全(钻取、K 线、复盘),但面积与颜色的口径由站点决定,本插件无法保证

本插件不抓取该站内容,iframe 只做展示与降级说明。

iframe 有三态降级:加载中 / 已加载 / 超时(8 秒)。超时显示占位(域名 + 最后成功加载时间 + 一句"本插件无法区分是本机网络还是该站点的问题")并给一次「重试」(重建 iframe 并重新计时);最后成功时间记在 localStorage,跨会话可见;状态徽标常驻显示当前处于哪一态。

护盘信号(A股大盘页内)

识别「符合国家队历史行为模式的宽基 ETF 护盘行为」。常驻状态条(等级/评分/归因)+ 六通道标的卡 + 因子明细表(含贡献度列)+ 分时量能图 + 今日信号时间线与近 60 日历史回看。信号达「疑似护盘」时面板自动展开。

  • 监测通道:默认核心 6 只宽基(沪深300ETF华泰柏瑞 510300 / 上证50ETF华夏 510050 / 中证500ETF南方 510500 / 中证1000ETF华夏 512100 / 科创50ETF华夏 588000 / 创业板ETF易方达 159915),可在设置里追加 510310 / 510330 / 159919 / 588080;共振按指数去重
  • 六因子加权:量能 0.22 / 超大单 0.26 / 脉冲 0.18 / 持续性 0.12 / 量价背离 0.14 / 共振 0.08,乘时点系数(早盘 0.4 → 尾盘 1.1)得 0–100 评分;等级 ≥75 强护盘信号 / 55–74 疑似护盘 / 35–54 资金异动 / <35 平静
  • 因子语义:F2 以核心通道(沪深300/上证50)为主,仅外围通道净流入时打 0.7 折,核心通道超大单净流出达成交额 −15% 时封顶为「资金异动」;F3 区分盘中脉冲(14:30 前,打 0.6 折)与尾盘突袭(满分权重),命中线为该时段 P90;F4 用「时间 + 幅度」(最近 5 分钟超大单净增 ÷ 该窗口成交额,锚点 5%/12%/25%);F6 共振列出标的名并分层,核心 0 只时不得给「强护盘信号」
  • 阈值来源全部标注:量能倍数用历史分位数标定(腾讯日K 500 根 × 6 只 = 2886 样本,P75/P90/P95 = 1.19/1.57/1.92x,对应 40/70/100 分);日内进度曲线用新浪 5 分钟线 126 个交易日标定(10:00 已占全天 29.6%、11:30 60.9%、14:30 86.0%),因此「同时点量能倍数」天然按时间进度归一;超大单强度因免费源已无日频资金流历史暂用经验锚点,host 采样器自建样本满 20 个交易日后自动改用自建分位数(面板显示当前来源与样本天数)
  • 防误报约束(每条都写进归因,不做静默降级):指数明显上涨时封顶(+1.0% 以上最多「资金异动」;+0.3% 以上不得为「强护盘」,因为放量上涨更可能是追涨);「强护盘」要求超大单强度达高门槛;无有效超大单且无脉冲时最多「资金异动」
  • 采样:host 侧常驻采样器,仅工作日 09:25–11:35 / 12:55–15:05 活跃,常态 30s、尾盘(默认 14:30 起)自动切 15s(可在面板设置里改),每次采样 1 个批量请求(约 2 请求/分钟),页面关闭也持续记录
  • 非活跃时段:分数位显示 —(不把上次的分数留在那里假装是当前分),状态行 采样暂停 · 下次 10-09 09:25(已收盘)(跨周末指向下周一);暂停时段一律不出现「采样缺口」字样——那时的缺口不是正在发生的事
  • 数据:rescue-log.json(60 天滚动)保存每日信号事件、5 分钟抽样、20 日均额基准、自建样本与出分日志(各因子原始值 + 当次生效阈值,粒度 5 分钟刻度 + 等级变化);⚠ 免费源无 ETF 资金流历史,历史回看只能从本模块上线日起算

交易日历维护(每月一次,5 分钟)

护盘模块按交易日历判断"今天是否交易":休市日不采样、不出等级、不写当日分(否则假日的"量能平稳"会被 算成一份平静的当日分 —— 那就是假信号)。判定优先级:外部日历文件 > 内置假日表 > 周末规则。

  • 文件位置(用户自己的状态目录,升级不会覆盖):~/.dsh/dsh-tradewatcher/trading-calendar.json
  • 格式:按月列出休市日(只列公告里的法定休市,周末不用写 —— 周末由星期判定)。

没有法定休市的月份写 "2026-11": [] 即可 —— 这条空数组同时表示"本月已覆盖"(缺键 = 未覆盖 ⇒ 会告警并退回内置表)。 为什么列休市日而不是列交易日:一个月里法定休市只有 0–5 天,交易日有 18–23 天,前者写得更少、更不容易抄错。

  • 样例(2026 年 10 月,来源:上交所《关于上海证券交易所2026年部分节假日休市安排的通知》上证公告〔2025〕45号):
{
  "v": 1,
  "source": "上交所 2026 年部分节假日休市安排",
  "updatedAt": "2026-10-08",
  "months": {
    "2026-10": ["2026-10-01", "2026-10-02", "2026-10-05", "2026-10-06", "2026-10-07"],
    "2026-11": []
  }
}
  • 数据从哪来:交易所每年 12 月发布次年安排(上交所「休市安排」页 ),

每月初扫一眼该页有没有新的节假日公告即可(年中通常只有"中秋/国庆"这类补充公告)。

  • 改完自查:npm run calendar:check(只读)—— 打印文件路径、是否覆盖当月、本月休市日、被忽略的周末条目、

损坏文件的隔离去向,以及未来 10 天的交易日判定。也可在护盘面板上看:未覆盖当月时面板与 agent 工具输出 都会显示 ⚠ 交易日历未更新到本月(YYYY-MM)…。

  • 文件写坏了怎么办:schema 不合法(版本不对、日期格式错、日期不在所属月份、重复)或 JSON 解析失败时,

文件会被改名隔离成 trading-calendar.json.invalid-(旁边留一份 .reason.txt 说明原因), 并退回内置假日表;面板与工具输出都会显示这次隔离。不会静默按空表跑。

  • 失败方向:日历过期的后果只是多采一天(把假期当交易日),不会把真交易日误判成休市 —— 后者会漏掉

真实信号,是更糟的失败。所以判定顺序把"确定性的日历"放在"上游行情推断"之前。

底部位置 / 形态 / 概率(与护盘并列,不进入护盘评分)

回答"当前位置是否具备底部特征",避免把两件事混成一个数:

  • 位置:距 60/250 日最高回撤、近 60 日收盘分位、距 60 日最低、连续下跌天数、是否创 60 日新低 → 位置分(0–100,低位高分)
  • 日内形态:现价相对当日最低的回升幅度、下影线占振幅比例、当日最低点出现的时刻、是否"跌破前 20 日低后收回"、是否"创 60 日新低后收回" → 形态分
  • 底部概率(历史频率):把当前状态与历史同类日类比(近 60 日收盘分位 ≤ 25% 且 当日量能 ≥ 前 20 日均量 × 1),统计其后 5 日内最高价达到当日收盘 ×(1+目标) 的频率,同时给出无条件基线与样本量,并附 Wilson 95% 区间;样本 N < 30 标「样本少」
  • 诚实边界:① 概率是历史同类情形的频率,不是预测,必须与 N 和基线一起读;② 日内形态不进入概率(没有可回算的历史分钟数据,混进去就是伪精确),它只作实时修正参考;③ 位置低 ≠ 见底,护盘也可能发生在下跌半程

日历

财经日历模块。月历网格按重要性三档语义色标记(高 / 中 / 低):颜色是独立语义色阶(--tw-imp-1/2/3),不复用涨跌色、不随红涨绿跌翻转,隐身视图下统一灰化。格子里只显示事件名,点日期弹出当天事件详情卡(公布时刻、类别、重要度、来源、关联标的、备注),支持手动事件的增/删/改与自动事件的隐藏。

  • 自动同步(东财数据中心,6 小时缓存):新股申购/上市日历(全市场);自选 + 持仓标的的财报预约披露日期、分红除权除息/股权登记日;国际/国内宏观(东财 H5 财经日历,覆盖窗口过去 7 天 ~ 未来 92 天,分页 50 条/页、4 并发,约 1–2 秒),含美联储议息会议、联邦基金利率目标、各国央行利率决议、非农、失业率、PCE、PPI、GDP、ISM、零售、初请失业金,以及中国 CPI/PPI/社融/进出口等;每条带北京时间公布时刻(00:00 视为未定时刻不显示)
  • 归类与重要度由名称启发式推导(数据源本身不含重要度字段):国家前缀 → 中国/中国香港/中国台湾/中国澳门 归国内宏观,其余核心经济体归国际宏观,无前缀的会议/行业事件归其他;非核心经济体(泰国、土耳其)不入库。重要度:议息/利率决议/联邦基金利率/LPR/非农/CPI/PCE/GDP/两会/关税 → 高;PPI/PMI/零售/社融/失业金/库存等 → 中;其余 → 低(港口/保税区高频库存分项降为低)
  • 改期留痕与勾稽:上游会悄悄改期,因此按 autoKey 对比上一条,日期/结束日/标题变化即记 from → to(最多 5 条),事件卡标 可能变更 ×N,悬停给出历次变更的时刻与前后值(手动事件不受影响);格点与事件卡上 实心 ●=有持仓 / 空心 ○=仅自选 / 无标记=无关(用字形而非颜色——颜色已被重要度占用),当天事件列表默认按勾稽排序(持仓 → 自选 → 其他,组内按重要度与时刻)
  • 手动维护:源里没有的事件(美国 CPI(BLS)不在东财免费源内)、未上市公司 IPO 与上市日期、自定义提醒——可在页面新增,也可以直接让会话里的 agent 用 tradewatcher_calendar_add 写入

视图与隐私

  • 三档视图(Alt+M 轮换,持久化):完整(默认)/ 紧凑(隐藏说明文字与脚注)/ 隐身(金额模糊为 ¥••••、盈亏保留正负号、涨跌色转灰阶)
  • 金额遮罩做在格式化出口内部,因此"新增一处显示金额忘了判断"不会漏出真实数字;只影响显示,取数、告警、agent 工具返回完全不受影响。价格与点位不属于"金额",照常显示
  • 动效纪律(v0.87.0,参考竞品做法后自定):常驻/循环动画只动 `transform`/`opacity`;关闭态 display:none(不留透明层吃点击);面板不可见或页面切后台 ⇒ 根节点 data-idle=true 暂停全部动画;尊重 prefers-reduced-motion。细则与阈值见 docs/DESIGN-UIUX-ADOPT.md
  • 截图 / 录屏保护(行情条右侧「▣」):面板不透明度 35%–100%(只作用于本插件面板);数字模糊(把价格/涨跌/盈亏/成交额糊住,鼠标移到某一行或某张卡上时该行临时显形)。模糊目标是"所有使用 --tw-mono 的数字面"清单,界面上写明边界:只覆盖本插件渲染的数字,整屏不可读请配合隐身视图

宽屏布局

面板在宽屏下用宽度装更多内容而不是把内容拉长:行情条是自动填充网格(宽屏多列、窄屏换行,没有内容被藏进横向滚动);自选与持仓列表在 ≥1080px 时铺成多列(按列竖向填充,名次自上而下读是 1/2/3,同高度约两倍条目;窗口变窄自动退回单列);提示文案限宽 96ch。

安装

前置:插件按 dsh 0.2.x 的客户端 Slots 契约注册面板(ctx.slots.inject('sidebar.panellist' | 'main', …)),不依赖任何第三方侧边栏插件;宿主侧只需 webServer + webRuntime 两个服务(由 dsh web 提供)。旧版 ctx.betterSidebar 已在 0.2 移除。

# 1) 构建(lib/index.js + lib/client.js)
cd dsh-tradewatcher && npm install && npm run build   # 或 npm run check(含类型检查/测试/自检)

# 2) 注册进 web profile(默认 ~/.dsh/profiles/web,可用 DSH_PROFILE_DIR 覆盖)
bash scripts/install.sh

# 3) 重启 dsh web 进程(必须:宿主半区改动只有重启后才生效)
#    重启后点左侧栏「盯盘」图标(走势线)打开主面板

卸载:bash scripts/uninstall.sh,然后同样重启 web。

插件为「双面」结构:主机半区(quote 中继、文件存储、/tradewatcher/* 路由、agent 工具)+ 浏览器半区(Tab UI),通过 dsh.bundle.patch(cordis.patch.yml 的 insert 行)随 bundle 自动挂载,无需手改 profile 的 cordis 配置。

快速上手

  1. 左侧栏点「盯盘」图标打开主面板;顶部三行行情条是 A股指数 / 国际市场 / 大宗商品,点任意卡片打开右侧详情抽屉(分时/五日/日K/周K/月K/年K)。
  2. 「自选」里新建分组 → 添加证券(可搜代码或名称)→ 行上可移除/移动分组;排序开关在面板右上。
  3. 「持仓」里新建分组 → +持仓 添加标的 → 行上「买/卖」录入流水(数量/价格/费用)→ 分组与总览自动核算。数量与成本不落盘,全部由流水推导,所以请始终用买/卖/调整录入,而不是直接改数字。
  4. 想离线复盘或让会话分析:数据都在 ~/.dsh/dsh-tradewatcher/*.json(明文),也可以直接用 tradewatcher_portfolio 等模型工具问。

数据与接口

数据文件(DSH_HOME 默认 ~/.dsh)

文件 · 内容 ~/.dsh/dsh-tradewatcher/watch.json · 自选:{ groups: [{id,name,order,archived?,note?}], items: [{id,groupId,secid,name,note?,createdAt}] } ~/.dsh/dsh-tradewatcher/positions.json · 持仓:{ groups:[…], items:[{id,groupId,secid,name,note?,createdAt}] } —— 数量/成本不落盘,全部由流水推导 ~/.dsh/dsh-tradewatcher/ledger.json · 逐笔流水/审计(append-only):{v, entries:[{id,ts,actor,verb,groupId?,posId?,secid?,qty?,price?,fee?,note?,meta?}]} ~/.dsh/dsh-tradewatcher/prefs.json · 主题/刷新间隔/配色/排序/视图/折算口径/截图保护等偏好 ~/.dsh/dsh-tradewatcher/quotes-lkg.json · 行情 last-known-good 快照(每只证券最近一次有效读数,进程重启后仍可兜底,非账本数据) ~/.dsh/dsh-tradewatcher/trends-lkg.json · 分时序列 last-known-good(上游失败时返回上一份好图并标 staleAt) ~/.dsh/dsh-tradewatcher/trends//.json · 按日归档的分时(本地拼接五日的原料)。保留最近 12 个交易日;单日 >512KB 或单标的总量 >8MB 时不写并在界面提示「本次未归档」;清理只删本目录里的日期文件。可在设置里用 trendArchive 关闭 ~/.dsh/dsh-tradewatcher/board-lkg.json · 板块/资金/ETF 排行的 last-known-good(全部上游不可用时显示上次成功结果并标注时间) ~/.dsh/dsh-tradewatcher/klines/__.json · K 线本地缓存:首次查看一次性拉全量(日 800 / 周 400 / 月 240 根),之后每次只增量拉最新几根并合并;上游不可用时直接回退缓存。复权口径进文件名(_0/_1/_2),不同口径互不顶替 ~/.dsh/dsh-tradewatcher/breadth.json · 涨跌家数每日快照:收盘后(15:05 起,15:30 后定稿)记录当日涨/跌/平家数与两市成交额,保留 60 日窗口 + 30 天余量 ~/.dsh/dsh-tradewatcher/calendar.json · 财经日历事件库(自动同步 + 手动维护,含改期留痕) ~/.dsh/dsh-tradewatcher/trading-calendar.json · 交易日历缓存(npm run calendar:check 与跨市场休市判断用;按年缓存,缺失时按规则推算并标注) ~/.dsh/dsh-tradewatcher/prism-settings.json · 棱镜(第 9 行):研判时点(HH:MM,默认 09:35 / 11:20 / 13:10 / 14:40,可增删)+ 当日已触发水位;写入走 updateJsonLocked,读不到不覆写 ~/.dsh/dsh-tradewatcher/prism-skeleton.md · 棱镜的研判骨架(页面可编辑的多行文本,≤20 000 字);首次打开写默认值 ~/.dsh/dsh-tradewatcher/prism-news.json · 金十快讯(24h):{status, items};首次回填 ≤10 页/批、页间 ≥3s,之后按 lastSeenId 增量;只保留 24 小时 ~/.dsh/dsh-tradewatcher/prism-runs.json · 棱镜研判结果(4 路分析 + 1 次汇总,保留最近 20 次);失败留痕、不自动重试 ~/.dsh/dsh-tradewatcher/prism-account.json · 棱镜模拟盘账户:资金上限(初始 150 万,可入金)、现金、持仓与成本、已实现盈亏、复制留痕;复制按真实成本价(只读真实持仓) ~/.dsh/dsh-tradewatcher/prism-orders.json · 棱镜挂单/成交:{orders, fills};挂单当日有效,跨日失效;撤销/不可成交(T+1/涨跌停/停牌/整手)都留原因 ~/.dsh/dsh-tradewatcher/prism-equity.json · 棱镜每日净值曲线(一天一点):{points:[{day,equity,cash,positionsValue,realized,unrealized,at}]} ~/.dsh/dsh-tradewatcher/fupan.json · 复盘笔记(第 8 行 fupan):{ v:1, notes:[{id,date,text,pinnedTo?,source,at}] },at = 最后一次写入时刻。有界:单条正文 ≤4000 字、≤2000 条、序列化后 ≤512 KB;条数/体积超限时按「最久未更新」丢弃并在回包 dropped 段逐条留痕(置顶的最后才丢),单条超长直接 400 不截断。读不到(权限/磁盘)≠ 没有笔记 ⇒ 本次启动拒绝写回并如实披露;坏 JSON 先隔离保留原字节再从容开始 ~/.dsh/dsh-tradewatcher/global-flow.json · 工具箱「全球资金流蛋糕模型」的每日份额快照:一天一条、保留 90 天(一天 ≈ 0.9KB);成分一变,旧快照整份作废并留痕,不与新成分混用 ~/.dsh/dsh-tradewatcher/macro-log.json · 工具箱「全球资金流蛋糕模型」的宏观两档自采样:每个交易日一条(广义美元指数 / 美国 10Y 收益率)+ 每源诊断留痕(diag:本次各源是否可用、值、原因 —— 真机排障的现场证据),保留 120 天。用途:两个源都没有可无歧义解读的"昨收"字段 ⇒ 「较上日」与「5 日变化」只由本插件自采样算,绝不用来源不明的字段充当变化量;不足 ⇒ 界面显示「未取到」+ 原因,不写 0 ~/.dsh/dsh-tradewatcher/market-extras.json · 大宗商品/债券等扩展行情缓存(last-known-good;上游失败时回退上次成功结果并标注时间) ~/.dsh/dsh-tradewatcher/leverage.json · 工具箱「杠杆温度计」的两融历史:{ v:1, lastFetchDay, lastAttemptAt, cross, rows:[{d,rzye,rqye,ltsz,rzyezb,rzjme}] }(单位:元 / %)。每天最多取一次上游(两融 T+1,当天数据不会中途变);首次 6 页回填 4018 个交易日(2010-03-31 起,≈610 KB),之后每天追加一行;上限 4500 行 / 1 MB(丢最旧的并留痕)。读不到 ≠ 没有(坏 JSON 先隔离保留原字节,不覆写);cross 只内部记录深交所单市与合计的量级校验,不进回包 ~/.dsh/dsh-tradewatcher/rescue-log.json · 护盘信号:每日信号事件、5 分钟抽样、20 日均额基准、自建样本、出分日志(60 天滚动) ~/.dsh/dsh-tradewatcher/macro-archive.json · 宏观后台归档(npm run macro:archive):BIS 等官方长期序列(单次约 25 秒 ⇒ 只允许后台跑,不进交互路径),带抓取时间与来源;同样走 robots.txt 门禁与「每主机 ≤5 次/小时」预算 ~/.dsh/dsh-tradewatcher/write-log.json · 写操作日志(目前只覆盖插件代写的日历事件新增:tradewatcher_calendar_add 这类;持仓/流水的写入由侧边栏自己维护、不经这里):每条记 by(会话 id)/反向操作/是否已撤销。撤销不删历史(撤销本身也留痕),保留最近 500 条。真机上若从未用工具写过日历,这个文件不会存在(不是漏了) ~/.dsh/dsh-tradewatcher/*.json.bak · 导入备份前自动留下的原文件副本,用于人工回滚

  • verb:buy买入 / sell卖出 / adjust调整 / add新建持仓 / remove移除持仓 / gcreate新建分组 / grename改名 / gdelete归档 / grestore还原 / gmove移动或编辑 / pnote备注
  • secid 为东财代码,格式 市场.代码:1.600519(沪A)、1.688825(科创板)、0.300750(深A)、1.510300(沪ETF)、116.02155/116.00700(港股)、100.KOSPI200(全球指数)、114.lhm(生猪主连)等

会话内分析(双通道)

  1. 模型工具(只读,重启后对所有会话可见)
  • tradewatcher_portfolio — 分组汇总 + 每只持仓(数量/成本/现价/市值/浮盈/当日/已实现/可用数量/费用)
  • tradewatcher_ledger — 逐笔流水,可按 posId/groupId 过滤(追溯完整交易过程)
  • tradewatcher_watchlist / tradewatcher_quotes / tradewatcher_search — 自选、实时行情、证券搜索(cn/intl/commodity/bond/all 预设组)
  • tradewatcher_calendar / tradewatcher_calendar_add — 财经日历读取与手动事件写入(唯一的写工具,带节流与反向操作登记)
  • tradewatcher_undo — 撤销本插件的写入(按 id 或 last=N;listOnly=true 只列出可撤销项)
  • tradewatcher_rescue — 护盘信号(六因子 + 贡献度 + 出分日志 + 采样窗口)
  • tradewatcher_ytd — 年初至今(前复权口径,含基准说明与缺失明细)
  • 每个读数都带数据出处:asOf / stale / source / missing[](见「数据出处与状态」)
  • 系统提示词已注册引导段落(插件在会话工具列表即显形,如出现工具名即说明挂载成功)
  1. 明文 JSON 文件:上述数据文件路径固定、格式如上,任何会话可用文件工具直接读取做离线分析/回溯校验

HTTP 路由(同源,浏览器信任围栏保护,POST 校验 Origin)

GET /tradewatcher/health|badge|quotes?ids=|trend?secid=|kline?secid=|detail?secid=|auction?secid=|suggest?q=|board?scope=&sort=&pn=&pz=|anomaly?ids=|ytd?ids=|breadth、GET|POST /tradewatcher/watch|portfolio|prefs|calendar、GET /tradewatcher/ledger、GET /tradewatcher/trades?secid=、GET /tradewatcher/industry|industries、GET|POST /tradewatcher/backup(导出/导入备份;POST body {mode:'preview'|'apply', bundle})

  • /tradewatcher/kline 的 fqt:0=不复权 1=前复权(默认)2=后复权;回包 kline.fqt 是实际生效口径(指数/期货恒为 0 并置 fqSupported:false),kline.asOf/barOpen 供口径条显示"数据截至几点、当根是否已收盘"
  • /tradewatcher/auction?secid=:竞价四项(价/量/占比/溢价)+ 09:15–09:25 采样序列。唯一一条不依赖东财的详情类出口:只读本地 auction/.json 与腾讯 m1(同包 qt 里的昨收),东财熔断也照给;永远 200,不可用时 auction.state='unavailable' + missing[](沪深 transient / 非沪深 no-source)
  • /tradewatcher/detail 除 detail 外同时返回顶层 auction(与 /auction 同一份);detail.auction 保留只为兼容旧客户端
  • /tradewatcher/badge 只读同一份 rescue 快照与持仓汇总,不触发新采样
  • /tradewatcher/anomaly 用 K 线本地缓存 + 行情涨跌幅判定自选异动,不额外打上游

口径规范

以下为当前生效的规则。每条改动的来龙去脉与实测依据见 CHANGELOG.md。

时间口径

全插件的时间标签只有一套口径:`Asia/Shanghai`(src/host/time.ts)。hhmmOf / dayOf / weekdayOf / calToday / shanghaiDayStart 全部来自同一实现,并在 4 个时区(Asia/Shanghai、UTC、America/New_York、Australia/Sydney)下断言一致;npm test 会把这套断言跑两遍(宿主 TZ 与 TZ=UTC),因为只有显式切 TZ 才锁得住时区回归。

注意 inTradingWindow 里的星期也必须按北京时间——北京时间周一 10:00 在 TZ=America/New_York 下是周日 22:00,用宿主星期会把真实交易日判成休市。收盘后是否"定稿"同样按北京时间 15:05 判定(不用浏览器本地时区,否则容器里的 UTC 浏览器会把收盘后判成盘中)。

排序

选择存进 prefs.json,同键再点一次切换升降序。两条硬约定(src/client/sort.ts,8 组断言锁死):