# 配置说明 > 配置以 **Host 文件为准**(`~/.dsh/dsh-stock-leek/config.json`),浏览器 `localStorage` 仅作首屏缓存;因此同一台机器多标签页共享一份自选/持仓。 ## 字段 | 字段 | 类型 | 默认 | 说明 | |---|---|---|---| | `version` | number | `1` | 配置格式版本 | | `indices` | `[{code,name}]` | 12 个常见指数 | 大盘候选列表(可增删) | | `barIndices` | `string[]` | `["sh000001","sz399001"]` | 显示在对话左下角的指数代码(有序) | | `watchlist` | `[{code,name,addedAt}]` | 茅台 / 宁德时代 | 自选股 | | `positions` | `[持仓]` | `[]` | 持仓明细,见下 | | `pollMs` | number | `5000` | 行情刷新间隔(最小 2000,上限 120000) | | `riseColor` / `fallColor` | string | `#f5455c` / `#1eb980` | 涨/跌配色(A 股惯例:红涨绿跌) | | `barStyle` | `"compact"` \| `"full"` | `"full"` | 指数栏样式:仅涨跌 / 点位+涨跌 | | `barAlign` | `"left"` \| `"center"` \| `"right"` | `"left"` | 指数栏水平对齐 | | `barPlacement` | `"floating"` \| `"dock"` | `"floating"` | 悬浮锚定 / 嵌入输入框 | | `barVisible` | boolean | `true` | 是否显示指数栏 | | `remind` | boolean | `true` | **预警总开关**:关闭后规则保留但不评估(`cfg.alerts` 的开关,见下) | | `alerts` | `[预警规则]` | `[]` | 预警规则,上限 50 条,见下 | | `pnlCurve` | boolean | `true` | 持仓页「今日盈亏走势」曲线是否展开 | | `ma` | `number[]` | `[5,10,20]` | K 线均线周期,白名单 `[5,10,20,60]`,去重保序,允许空数组 | | `pausedMarkets` | `string[]` | `[]` | **已暂停的市场**(可多选:`cn`=A股、`hk`=港股、`us`=美股)。被暂停的市场:不刷新行情、不评估预警、指数栏不因它展开。收盘的市场**自动停**(无需开关) | | `__rev` | number | — | **内部字段**:每次成功写入 +1,供多标签页冲突检测,见下 | ### 持仓结构 ``` { code, name, cost, qty, txns: [{ id, date, time, price, qty }] } ``` - `cost` 成本价(元/股),`qty` 当前持仓股数 - `txns` 买卖变动流水:**买入 `qty>0`、卖出 `qty<0`**,可多条 - 买入按加权平均摊薄 `cost`,卖出减持仓;`qty` 始终是当前持仓 - 今日收益按当日 `txns` 现金流计算,**跨日自动失效**(次日无当日变动即回到 `(现价−昨收)×qty`) ### 预警规则 ``` { id, code, name?, type, value, enabled, createdAt? } ``` - `id`:`[A-Za-z0-9_-]{1,32}`(**`config.json.alerts` 的 `states` 以它为键**,字符集守卫防原型污染键) - `type`:8 种——`price_above` / `price_below` / `cost_above` / `cost_below` / `pct_up` / `pct_down` / `limit_near` / `speed_up` - `value`:阈值(非负)。比率类(`pct_*` / `limit_near` / `speed_up`)单位是 %;`cost_*` 忽略该字段(阈值=持仓成本价) - `limit_near` **仅 A 股/北交所**:港/美/指数没有涨跌停概念。⚠️ 实测其 `limitUp` **不是 `-1` 哨兵**而是无意义值(`usAAPL.limitUp=8.72`、`hk00700.limitUp=1.27`),所以防护按**市场前缀拒收**而不是判哨兵值 —— 若放行会算出荒谬阈值、`armed` 立即穿越、必然误触发 - 触发判定:**每个交易日每条规则只提示一次**(不是"穿越+滞回重复报")。判据是行情时间戳的**市场本地日**,次日重新生效;评估在 Host 独立循环,见 [docs/alerts-plan.md](alerts-plan.md) ### 预警状态文件 `config.json.alerts` ```json { "version": 1, "states": { "": { "phase": "armed|fired", "day": "YYYYMMDD" } } } ``` - **只存状态、不存触发历史**:`states` 是「今日是否已提示过」的唯一依据,丢了会在 Host 重启后重复播报 - 路径**派生自配置路径**(`configPath() + ".alerts"`)而非 `dirname()` 拼接 —— 后者会丢掉测试的 pid 隔离 - 客户端只读(`GET /alerts` 仅返回 `states`),只有 Host 写 ### 环境变量 `DSH_STOCK_LEEK_CONFIG` 可覆盖配置路径(测试用)。设置后**不做旧路径搬迁**——显式指定路径视为「我知道我要写哪」。 > 旧名 `DSH_LEEK_FUND_CONFIG` 仍兼容:新名为空时回退读它,老脚本不会因为改名而失效。 --- ## 配置安全 | 机制 | 说明 | |---|---| | **写入备份** | 每次写配置前先把旧文件复制为 `config.json.bak`;写入本身走 `tmp + rename` 原子替换,崩溃也至少留一份上一版 | | **损坏保护** | 解析失败时**不再静默回落默认值**(那会吞掉持仓):损坏原文另存 `config.json.corrupt` 供人工找回 → 尝试回退 `.bak` → 才用默认值,并通过 `GET /config` 的 `warning` 字段在设置页顶部显示**常驻告警条**(保存成功后自动解除) | | **多标签页同步** | 保存成功后经 `BroadcastChannel` 广播,其他标签页立即采用同一份配置,不再各写各的后写覆盖先写 | | **冲突检测** | 配置带 `__rev` 版本号,每次写入 +1;客户端带上自己那份的版本号,若落盘时版本已变(即期间有别的标签页改过),Host 返回 `conflict`,客户端弹出告警要求核对,**不假装无事发生** | | **旧路径搬迁** | 插件改过名,配置落盘位置跟着变过(见下方迁移链)。启动时若「新位置无文件」,按新→旧顺序找第一个**能解析**的旧文件搬过来;旧文件保留为 `.migrated.bak` **不删除**;新位置已有文件时不会被旧文件覆盖;旧文件本身损坏则跳过它继续试下一个 | | **测试隔离** | 需要写配置的两个测试统一走 `test/config-guard.mjs`:未指定 `DSH_STOCK_LEEK_CONFIG` → 落到系统临时目录并在退出时清理;若该变量指向真实配置路径(**新旧三代默认路径都识别**)→ **直接拒绝启动**,除非显式设 `SL_ALLOW_REAL_CONFIG=1` | ### 配置路径迁移链 插件改名过,落盘位置也随之变化。每次改名都留了自动搬迁,**用户无需手动搬文件**: ``` ~/.dsh-leek-fund/config.json (最早) ↓ ~/.dsh/dsh-leek-fund/config.json (改名前) ↓ ~/.dsh/dsh-stock-leek/config.json (当前) ``` 每次搬迁都遵循同样的规则:新位置有文件就不动;旧文件解析不了就跳过;搬完把旧文件复制成 `.migrated.bak` 而**不是删除**——万一出问题还能手工捞回。 ### 同目录文件一览 ``` ~/.dsh/dsh-stock-leek/ ├── config.json # 当前配置 ├── config.json.bak # 上一次写入前的备份(每次写前轮换) └── config.json.corrupt # 仅在解析失败时出现:损坏原文,供人工找回 ``` --- ## 代码归一化 `normalizeApiCode` 接受并自动补全市场前缀: | 输入 | 归一 | 说明 | |---|---|---| | `sh000001` / `600519` / `510300` | `sh000001` / `sh600519` / `sh510300` | 沪(60/68/5x 开头) | | `300750` / `159915` | `sz300750` / `sz159915` | 深 | | `899050` / `430047` | `bj899050` / `bj430047` | 北交所 | | `00700` / `hk00700` / `hkHSI` | `hk00700` / `hk00700` / `hkHSI` | 港股 / 恒指 | | `AAPL` / `us.AAPL` / `usr_ixic` | `usAAPL` / `usAAPL` / `usIXIC` | 美股(`usr_` 为兼容别名写法) |