chart

$npx mdskill add kansoku-trade/kansoku/chart

Renders financial charts via a local web app for visual analysis.

  • Solves the problem of interpreting raw financial data visually.
  • Depends on a local Hono server and React frontend on port 5199.
  • Determines chart type and data based on the POST request parameters.
  • Returns a URL to the rendered chart and optional technical indicators.

SKILL.md

.github/skills/chartView on GitHub ↗
---
name: chart
description: >
  Render financial charts via the local chart web app (workspace at the repo
  root — Hono server + React front end, port 5199). Four chart types: intraday capital-flow line
  (`flow`) and cross-symbol signed-bar comparison (`cohort`) — both Recharts —
  plus SEPA strategy dashboard (`sepa`) and short-term multi-timeframe
  prediction dashboard (`intraday`) — both TradingView Lightweight Charts.
  Multi-timeframe K-line review lives inside `intraday` (the standalone kline
  chart type was removed). The server fetches Longbridge data itself
  (kline / capital flow) and computes all indicators (MA, MACD, RS, trend
  template, volume profile, divergence/beichi detection) in TypeScript; the
  caller only POSTs `{type, symbol, ...}` to `/api/charts` and gets back
  `{id, url, technicals?}`. Charts persist as data JSON under
  `journal/charts/data/`. `url` now points at where the chart actually lives:
  sepa/intraday land on the symbol page (`http://localhost:5199/symbol/<SYM>?analysis=<id>`),
  flow/cohort land on the home page for that date (`http://localhost:5199/?date=YYYY-MM-DD`);
  old `http://localhost:5199/charts/<id>` links still work and redirect there.
  Triggers: 出图、生成图表、画 K 线、画资金流曲线、画对比图、SEPA 仪表盘、
  短线预测、多周期K线、MACD、入场判断可视化、可视化、render chart, plot,
  visualise, sepa dashboard, intraday prediction dashboard.
---

# chart

Creates charts through the local chart app so the user can browse them in one
place instead of squinting at tables. The server pulls market data and computes
everything; charts are stored as versioned data JSON and always rendered by the
latest front-end code.

> **Response language**: match the user — 简体 / 繁體 / English.

## When to call

- After running `longbridge capital --flow` context or when the user wants a flow visual ⇒ `flow`
- For K-line review (multi-timeframe candles + MACD + auto signals) ⇒ `intraday`
- After collecting cumulative net inflow across a cohort of symbols ⇒ `cohort`
- After running `sepa-strategy` on a single name ⇒ `sepa`
- When inside `intraday-signal` ⇒ `intraday` (two-call pattern: POST preview → PATCH prediction)
- When inside `capital-rotation` / `market-session-tracker` / `stock-deep-dive`,
  call this as the LAST step and append the chart URL to the markdown journal entry.

Skip when the user only wants a single number or a tiny series — a Unicode
sparkline in the chat reply is faster.

## Data-root scenario (kansoku-cli)

在 Kansoku 数据目录里跑(外部 Claude Code、无本地 dev server),走
`kansoku-cli` 而不是 HTTP。判据:环境变量 `$KANSOKU_CLI` 有值 → 走 CLI;
无 → 回退 HTTP。

CLI 与 HTTP 契约一致——body 就是原本 POST /api/charts 的 body,
返回 `{id, url, technicals?}` 也不变;CLI 侧额外多带一个 `deepLink`
字段(见下方数据目录场景说明)。

先加载 runtime.env(这一步只需做一次):

```sh
set -a
[ -f .kansoku-agent-kit/runtime.env ] && . .kansoku-agent-kit/runtime.env
set +a
```

之后:

| HTTP 版 | CLI 等价 |
|---|---|
| `curl -s http://localhost:5199/api/health` | `"$KANSOKU_CLI" info kit-version` |
| `POST /api/charts` body 为 X | `printf '%s' "$X" \| "$KANSOKU_CLI" chart create --type <T> --symbol <S> --json-input -` |
| `GET /api/charts?type=&symbol=` | `"$KANSOKU_CLI" chart list [--symbol X]` |
| `GET /api/charts/<id>` | `"$KANSOKU_CLI" chart get <id>` |
| `PATCH /api/charts/<id>` | *(暂不支持——PATCH 仍走 HTTP;数据目录场景 PATCH 目前只在 intraday-signal 里出现,届时 fallback HTTP)* |
| 打开 `data.url`(浏览器访问 `http://localhost:5199/...`) | 打开 `data.deepLink`(`kansoku://route/...`,见下) |

body/response 完全一致,写入的图表 JSON 落在 `journal/charts/data/<id>.json`
(跟 HTTP 版本相同)。

数据目录场景通常没有本机 dev server(Kit 用户不会跑 `pnpm start`),
`data.url` 里的 `http://localhost:5199/...` 打不开。CLI 的 chart create
响应现在多带一个 `deepLink` 字段(`url` 照旧保留,向后兼容 dev 场景),
指向 `kansoku://route/...` 这个自定义协议。想让用户看到图表时,打开这个
deep link 即可——它会启动 Kansoku.app(若已在运行则直接切到前台)并跳转到
对应图表页面:

```sh
open "$(echo "$response" | jq -r .deepLink)"
```

macOS 用 `open`,Windows 用 `start`,Linux 用 `xdg-open`——三者都认协议处理器,
换平台只需换这一条命令。

## Server lifecycle

The app must be running before any API call:

```bash
curl -s http://localhost:5199/api/health # {"ok":true,...} = up
```

CLI 等价:`"$KANSOKU_CLI" info kit-version`

If it is down, start it (long-running process — use run_in_background):

```bash
pnpm start # serves API + built web UI on :5199
```

First-time setup only: `pnpm install && pnpm build`.

## API

Base URL `http://localhost:5199`. All responses follow the
`{ok, data, meta}` / `{ok:false, error, hint}` contract.

| Endpoint                                                          | Purpose                                                                                       |
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `GET /api/health`                                                 | liveness check                                                                                |
| `GET /api/charts?type=&symbol=&limit=`                            | list chart metas (newest first)                                                               |
| `POST /api/charts`                                                | create a chart; body below                                                                    |
| `GET /api/charts/:id`                                             | full chart doc                                                                                |
| `GET /api/charts/:id/built?count=`                                | ephemeral intraday rebuild with a larger bar window (history view; max 1000, never persisted) |
| `PATCH /api/charts/:id`                                           | merge fields into input and rebuild (e.g. add `prediction`)                                   |
| `DELETE /api/charts/:id`                                          | remove a chart                                                                                |
| `GET /api/legacy`                                                 | list old single-file HTML archives (served at `/legacy/<file>`)                               |
| `GET /api/stream/quotes?extra=`                                   | SSE quote snapshots (watchlist ∪ positions ∪ extra), 10s cadence                              |
| `GET /api/stream/charts/:id`                                      | SSE live rebuilds for flow/intraday charts, 60s cadence                                       |
| `GET /api/symbols/:sym/{flow,benchmark,position,analyses,latest}` | live per-symbol cockpit data (server-computed, never AI)                                      |

The stream endpoints power the web UI's realtime display; the AI workflow never
needs them — created charts update themselves in the browser while open, and
the persisted JSON stays frozen at analysis time.

### Symbol cockpit (`/symbol/<SYM>`)

Every symbol also gets a stable dashboard URL, `http://localhost:5199/symbol/<SYM>`,
that aggregates live data with the symbol's latest `intraday`/`sepa` analysis — it
is the caller-facing counterpart of `GET /api/symbols/:sym/*`. The same page also
serves the frozen per-analysis view: appending `?analysis=<id>` pins it to one
specific chart doc (this is what `data.url` returns for `sepa`/`intraday` charts)
instead of following the latest one live; a banner offers to jump back to latest
if a newer analysis has since landed. Old `/charts/<id>` links still work — they
resolve the chart's type client-side and redirect to this page (or to the home
page for `flow`/`cohort` charts). During regular session the cockpit also carries a live AI comment stream and auto-reassessment (commentator + escalated analyst, gated on the comment/analyst model settings configured at `/settings`) whose output shares the manual `intraday-signal` format. These `/api/symbols/*`
routes are server plumbing for that page — direct callers rarely need them,
listed here only for completeness:

- `GET /api/symbols/:sym/flow` — today's capital-flow curve + large/medium/small distribution (live, via `longbridge capital`)
- `GET /api/symbols/:sym/benchmark` — SMH/QQQ normalized same-session comparison (live, via `longbridge kline`)
- `GET /api/symbols/:sym/position` — shares/cost/unrealized + distance to stop/target from the latest analysis's entry plan (live)
- `GET /api/symbols/:sym/analyses` — past `intraday` analyses for this symbol with mechanical outcome judgments (`hit_target` / `hit_stop` / `open`, computed server-side from post-anchor bars — never AI recall)
- `GET /api/symbols/:sym/latest` — the latest `intraday` chart doc in full, plus `prediction_stale`

The client-side indicator toggle bar (show/hide 金叉死叉、自动背离、自动背驰、123
结构、SB 结构、K线形态、AI 标注、价位线、EMA 均线; state in localStorage) has no API
surface — it's a pure front-end feature on both the cockpit and archive pages.
Swing 高低点 are not one of the toggles — they're baked into the
divergence/beichi/pattern123/SB detectors as the underlying pivot data, not a
standalone overlay (deliberate deviation from the earlier spec draft). SB(第二次
突破/跌破,对应 Al Brooks 的 High 2 / Low 2)标注顺势回调后第二次尝试冲破前高/前低
的结构:图上灰色 H1/L1 是失败的第一次尝试,金色 H2/L2 箭头是确认成功的第二次突破;
`technicals` 里对应 `second_breakouts` 这一行。

### POST body per type

The server fetches Longbridge data itself when `symbol` is given; pass `data`
(or `kline` / `timeframes`) only to override with hand-assembled rows.

```jsonc
// flow — server runs `longbridge capital <SYM> --flow`
{ "type": "flow", "symbol": "MU.US", "subtitle": "单位推断为千 USD · 仅供参考" }

// cohort — data is always caller-assembled
{ "type": "cohort", "title": "存储 vs Mag 7 主力净流",
  "data": [{ "symbol": "MU", "value": -17087 }, { "symbol": "NVDA", "value": 9540 }] }

// sepa — server pulls 260 day bars + SPY.US automatically
{ "type": "sepa", "symbol": "MRVL.US", "name": "Marvell Technology",
  "position": { "shares": 1, "cost": 100.00 },       // optional
  "context": { /* see sepa context schema below */ } }

// intraday — server pulls 5m/15m/1h × 1000 bars automatically (--session all:
// pre/post-market bars included by default; pass "session": "intraday" to exclude)
{ "type": "intraday", "symbol": "MU.US", "name": "Micron Technology",
  "ema_periods": [9, 21, 55],                        // optional, fast/mid/slow EMA overlay (default 9/21/55, max 4)
  "position": { "shares": 1, "cost": 100.00 },       // optional
  "prediction": null }                                // omit for preview mode
```

CLI 等价(body 走 stdin,`--json-input -`):

- flow → `"$KANSOKU_CLI" chart create --type flow --symbol MU.US --json-input -`
- cohort → `"$KANSOKU_CLI" chart create --type cohort --json-input -`(无单一 symbol,省略 `--symbol`)
- sepa → `"$KANSOKU_CLI" chart create --type sepa --symbol MRVL.US --json-input -`
- intraday → `"$KANSOKU_CLI" chart create --type intraday --symbol MU.US --json-input -`

Success returns `data.id`, `data.url` (paste this into journal entries), plus
type-specific meta: sepa → `verdict_tier / passes / fails / bars`; intraday →
`mode / bars / technicals`.

### sepa `context` schema

All fields optional:

```jsonc
{
  "earnings_dates": ["2026-05-29"], // E markers on those bars
  "stage": "Stage 2 末期", // 阶段判断 sidebar card
  "stage_note": "Stage 3 顶部嫌疑",
  "base_count": "3-4 (减半仓)",
  "pattern": "无可买(扩张振幅)",
  "verdict": {
    // override the auto verdict
    "tier": "watch", // pass / watch / buy
    "label": "👀 WATCH LIST",
    "color": "#ffc107",
    "reason": "...",
  },
  "entry_plan": {
    // 入场计划 card + price lines
    "pivot": 260.0, // required: consolidation-range high
    "stop": 241.8, // default pivot × 0.93 (-7%)
    "target1_pct": 8, // default 8 (Phase 2: 卖一半 + 移至本钱)
    "target2_pct": 15, // default 15 (Phase 3: 再卖 25% + 沿 20MA 跟踪)
    "note": "...",
    "hypothetical": true, // 标注 "假设性" 徽章
  },
  "support_zones": [
    // omit → auto zones (MA50 / MA200 / volume cluster)
    {
      "low": 217,
      "high": 226,
      "tier": "watch", // warning / watch / buy / value
      "label": "MA50 关注区",
      "note": "...",
      "sources": ["MA50 $221.75"],
    },
  ],
  "auto_support_zones": true, // false disables the auto fallback
  "volume_profile": { "lookback_days": 120, "bins": 30 },
}
```

Derived values (auto-computed server-side): `buy_zone_high = pivot × 1.05`,
`target1/2 = pivot × (1 + pct/100)`, `R/R = (target2 − pivot) / (pivot − stop)`
— based on T2, not T1, because T1 is the SEPA Phase-2 partial exit. R/R < 2:1
renders a red warning.

**Verdict auto-detection** (when `context.verdict` omitted): any trend-template
fail → `PASS` 🚫; all 8 pass + price ≥ 25% above MA50 → `WATCH · Extended` 👀;
all 8 pass otherwise → `WATCH · No pattern detected` 👀. `STRONG BUY` ✅ is never
auto-emitted — pass `context.verdict` after manually confirming a valid pattern

- pivot ±5% buy zone.

**Auto markers on the main K-line**: earnings (`context.earnings_dates`),
climax top (volume ≥ 2.5×20MA + red close + local high), MA50/MA200 breakdowns,
52w high. Hardcoded lines: 52w high/low, MA50 × 1.25 extended warning.

### intraday two-call pattern

1. **POST without `prediction`** → preview. Read `data.technicals` from the
   response: per timeframe `last_dif / last_dea / last_hist`, `last_vwap`
   (当日 session VWAP,m5/m15), `emas` (latest
   fast/mid/slow EMA values — price vs EMA stack tells the short-term trend
   posture), recent swing highs/lows, `last_cross` (金叉/死叉),
   `divergence_candidates`, `beichi_candidates`, `second_breakouts` (SB 结构,
   H2/L2). Also read `meta.day_context`:
   `daily_trend` (up/down/range vs 日线 MA20/MA50), `daily_ma20`/`daily_ma50`,
   `high_20d`/`low_20d`, `prev_day` (昨日高/低/收), `pre_market` 区间,
   `opening_range` (开盘前 30 分钟), `vwap` — the server draws these as the
   VWAP line and 日内参照位 price lines on the chart. Read these numbers —
   don't eyeball candles.
2. **PATCH `/api/charts/:id` with `{"prediction": {...}}`** → final dashboard.
   Add `"refresh": true` to any PATCH to refetch the latest bars (incl. pre/post
   market) and recompute everything before rebuilding — same id, same URL.

CLI 等价:第 1 步(POST 预览)可用
`"$KANSOKU_CLI" chart create --type intraday --symbol MU.US --json-input -`;
第 2 步(PATCH 写入 prediction)目前无 CLI 等价,仍走 HTTP。

`prediction` schema:

```jsonc
{
  "direction": "short", // long | short | neutral
  "anchor": { "timeframe": "m15", "time": "2026-07-01T17:00:00Z", "price": 1049.81 },
  "scenarios": [
    // ≥ 2, probabilities ≈ 100
    { "label": "继续探底", "probability": 45, "path": "...", "trigger": "..." },
  ],
  "range_bound_plan": {
    "condition": "...",
    "long_tactic": "...",
    "short_tactic": "...",
    "low": 1020.0,
    "high": 1060.0,
  },
  // low/high = 箱体下沿/上沿;neutral 必填(观望按守住/破位对账入记分板),方向单可选
  "entry_plan": {
    "entry": 1049.81,
    "stop": 1030.0,
    "target1_pct": 3,
    "target2_pct": 6,
    "note": "...",
  }, // 仅 long/short;neutral(观望)省略整个 entry_plan,条件应对写进 range_bound_plan
  "price_zones": [
    // only real resistance/pressure zones drawn on chart
    {
      "kind": "resistance",
      "label": "反弹压力带",
      "low": 60.9,
      "high": 61.35,
      "note": "短线均线和第一修复位重合",
      "sources": ["5m EMA9/21", "第一修复位"],
    },
  ],
  "signals": [
    // 可选;背离/背驰/K线形态/123 结构/SB 结构均由服务端自动检测绘制,无需在此重复
    {
      "type": "other",
      "timeframe": "m5",
      "time": "...",
      "price": 1032.28,
      "bias": "bearish",
      "label": "尾盘放量长阴收在最低——摆动点未确认前的人工备注",
    },
  ],
}
```

R/R is direction-aware (`long`: risk = entry−stop; `short`: risk = stop−entry);
the sidebar flags rr < 2:1 in red. `entry_plan` can carry structured level
context so the chart explains why a point was selected instead of hiding the
reason in prose:

```jsonc
{
  "entry": 61.1,
  "stop": 62.52,
  "target1": 60.0, // optional explicit target price; overrides pct-derived price
  "target2": 57.92,
  "rationale": "反弹到 60.90-61.35 压力带后受阻才入场。",
  "stop_note": "站回上一段反弹高点,空头计划失效。",
  "entry_zone": { "kind": "resistance", "label": "反弹压力带", "low": 60.9, "high": 61.35 },
  "target1_label": "T1 · 日内低点",
  "target1_note": "整数位和日内低点,首次触及先看是否止跌。",
  "target1_zone": { "kind": "support", "label": "日内低点", "low": 60.0, "high": 60.0 },
  "target2_label": "T2 · 深一档支撑",
  "target2_condition": "60.00 跌破并反抽失败后才成立。",
  "target2_zone": { "kind": "support", "label": "深一档支撑", "low": 57.9, "high": 58.0 },
}
```

`entry_plan.entry_zone` and `target1_zone` / `target2_zone` are explanation
context for the right panel only; they are not drawn as chart zones and should
not be named `入场区`, `T1 区域`, or `T2 区域`. Put only genuine upper supply
areas in top-level `price_zones` with `kind: "resistance"`; those are rendered
as chart boundaries and in the sidebar's key-zone section.

Supported zone kinds remain `entry`, `stop`, `target`, `support`, `resistance`,
`invalidation`, `watch`, but the intraday chart-zone overlay intentionally
filters to explicit `resistance` zones. MACD structure signals + simplified 背离/背驰
are auto-detected and drawn on every render regardless of `prediction`. Every
DIF/DEA cross is classified by zero-line position(零上/零下金叉、零上/零下死叉)
plus structural patterns: 二次金叉(零下双金叉且低点抬高 → 底部确认)、空中加油
(零上二次金叉 → 强势延续)、二次死叉(顶部确认 / 空头中继)、上穿/下穿零轴
(趋势确认,last 2 bars marked 待确认 with a `?`). Each marker's tooltip carries
the implication text; `technicals.<tf>.structure_signals` (last 6) and
`zero_tangle`(DIF 贴零轴缠绕 = 震荡市,交叉信号失效)expose the same data to the
analysis workflow — read them in the preview step. The swing-based divergence
auto-detectors only fire on confirmed swing pivots — the last 1-2 bars can never
be flagged; read `last_dif/last_dea/last_hist` directly for the newest bar.

14 classic K-line patterns are also auto-detected on the main pane (arrow
markers, tooltip carries the implication): 单根——锤子线/上吊线/倒锤子/射击之星;
双根——看涨吞没/看跌吞没/乌云盖顶/刺透形态/看涨孕线/看跌孕线; 三根——启明星/
黄昏星/红三兵/三只乌鸦. All require a trend-context filter (4-bar net move into
the pattern) plus a body-size filter vs the trailing 14-bar average, so quiet
chop produces few marks. One pattern max per bar (stars > soldiers/crows >
two-bar > single-bar). `technicals.<tf>.candle_patterns` (last 6) exposes them
to the analysis workflow. Caveat: the newest bar may still be forming intraday —
a pattern on it can repaint until the bar closes.

123 reversal structures (Sperandeo 1-2-3) are also auto-detected per timeframe
from confirmed swing pivots: ① a ~20-bar extreme → ② the reaction pivot → ③ a
higher low (bullish) / lower high (bearish). The price pane gets ①②③ markers, a
①→②→③ connector, and a dashed trigger line at the ② price running from ③ to the
latest bar; a close beyond ② flips the structure to confirmed (`123✓` marker on
the breakout bar), while a break of ① drops the structure silently. The ③ marker
shows `③?` until confirmation. `technicals.<tf>.pattern_123` (last 2, each with
`status: forming|confirmed`, `trigger`, `invalidation`, `p1/p2/p3`) exposes them
to the analysis workflow — a `forming` structure is a ready-made entry setup
(enter on the ② break, stop beyond ①). The sidebar's 自动信号 section lists them
with an 酝酿中/已确认 badge.

Off-session bars (盘前/盘后浅蓝、夜盘深蓝) get a full-height backdrop on both
panes — thin-volume price action outside regular hours is visually discounted at
a glance. Regular hours = 09:30-16:00 ET (DST-aware via America/New_York).

### `context` — AI-classified news + conclusion (optional, schema_version 2)

Both `POST /api/charts` (type `intraday`) and `PATCH /api/charts/:id` accept an
optional `context` field alongside `prediction`. It's frozen at write time like
`prediction` — the server never generates or judges it. `schema_version` is now
`2`; older (`v1`) chart docs without `context` still load and render fine.

```jsonc
"context": {
  "generated_at": "2026-07-06T14:30:00Z",         // ISO timestamp
  "conclusion": {
    "stance": "short",                            // long | short | neutral
    "summary": "一句话综合判断",
    "action": "现在该做什么(挂单/等待/减仓)"
  },
  "news": [
    { "time": "2026-07-06T13:10:00Z",
      "source": "longbridge",                     // longbridge | x | trump | sec | gdelt
      "tag": "catalyst",                          // catalyst | regulatory | sentiment | macro
      "title": "...", "note": "AI 一句话解读", "url": "可选" }
  ],
  "sources_used": ["longbridge-news", "twitter-reader"]
}
```

The dashboard shows `context.generated_at`'s age and a stale badge, sharing the
same ~15-min staleness rule as `prediction` (`prediction_updated_at` /
`prediction_stale` on chart metas cover both).

### Realtime prediction upkeep

Once the US cash session is open, intraday charts must be maintained under
these rules:

- **Cash-session rebuilds drop off-session bars.** Any PATCH after 09:30 ET
  passes `{"session": "intraday", "refresh": true}` — the prediction
  dashboard must not render pre-market / overnight bars intraday. The
  default `--session all` is for pre-market analysis only.
- **Volume calls align to prior sessions' same-time window.** Never compare
  today's running volume against full-day totals. Pull `longbridge kline
--period 5m` (regular-session bars), sum today's bars, and compare against
  the same number of opening bars averaged over the prior ~5-8 sessions.
  Pair the ratio with per-bar direction before calling a move confirmed — a
  level break on ~0.6x same-period volume is not a confirmed breakout.
  Caveat: Longbridge daily-K volume includes extended hours; 5m-K volume
  does not — never mix the two.
- **Stale predictions get refreshed on a ~15 min loop.** The server marks an
  intraday chart's prediction stale when it is >15 min old during regular
  hours (`GET /api/charts?stale=true` lists them; the SSE envelope and chart
  metas carry `prediction_updated_at` / `prediction_stale`). Each loop
  round: fetch the stale list → re-pull quote / capital flow / klines →
  PATCH `prediction` with scenarios revised only on material change, but
  **always move `anchor` to the newest m5 bar time + latest price** — the
  anchor marker must track the live tape, never sit minutes behind it →
  append a timestamped journal note on material revisions (revision
  discipline) → stop the loop after 16:00 ET close.

## 桌面版模式

打包的桌面版(`Kansoku.app`)不监听任何本机端口,全部走 `app://` 内部协议 + IPC,不提供 HTTP 接口。要用这个 skill 的 curl 命令,单独起 server 进程即可:`pnpm start`(或开发模式 `pnpm dev`),API 照常在 `http://localhost:5199`。

## Storage

- Chart docs: `journal/charts/data/<YYYY-MM-DD>-<slug>.json` — gitignored,
  `schema_version` field for forward compatibility. Date = US session date
  (derived from the data, not local clock).
- Old single-file HTML archives stay in `journal/charts/*.html`, listed in the
  app under 旧版存档 and served at `/legacy/<file>`.
- The app itself: the pnpm workspace at the repo root (`apps/server/` Hono +
  TS, `apps/web/` Vite + React). Analysis parity with the retired Python
  implementation is locked by vitest golden tests: `pnpm test`.

## Sparkline alternative (no API)

For tiny in-chat previews render Unicode sparklines directly: `▁▂▄▆█` plus ANSI
green/red. Use for 5-20-point series where a full chart is overkill.

## Related skills

- `longbridge-capital-flow` / `longbridge-kline` — same data the server pulls; call directly only for in-chat analysis
- `capital-rotation` — should end with a `cohort` chart
- `market-session-tracker` — may create `flow` charts
- `sepa-strategy` — calls `sepa` as the last step of its Step 10
- `intraday-signal` — calls `intraday` twice (POST preview, then PATCH prediction)

More from kansoku-trade/kansoku

SkillDescription
capital-rotationUse when reading today's US-market capital flow across multiple sectors to identify rotation direction — e.g. "今天资金流向", "板块强弱", "rotation map", "卖芯买云", "where is money moving today", "scan flows across sectors". Produces a cross-section snapshot of net inflows by cohort (indices / semis / software-cloud / mega-tech / AI applications), names the dominant narrative, and writes a dated journal file. Different from `market-session-tracker` (intraday live monitoring of a single watchlist) — this is a one-shot end-of-session rotation read.
fredUS/global macro time series from St. Louis Fed FRED — CPI, GDP, Fed funds, yields, M2, DXY, etc.
gdeltGlobal multilingual news event stream with tone scoring via GDELT 2.0 Doc API.
hithink-a-shareA 股官方数据,来自同花顺(HiThink)官方 API——涨停股票池、连板天梯、龙虎榜、个股异动原因、热榜、A 股官方口径财报(利润表/资产负债表/现金流量表/财务指标)、行情快照与日 K。
intraday-signal>
korea-market>
market-session-trackerUse when monitoring stocks/ETFs/indices across pre-market, open, intraday, or close — especially when the user is reading session action live and may revise their take as it unfolds. Triggers include 盘前/盘中/收盘 sessions, multi-symbol watchlists (e.g. MU/TSM/SMH semi tracking), user observations like "突破"/"冲高"/"回调"/"假突破", capital flow checks, market temperature checks, semi/AI/memory plays, and any request that bundles a position context with a live read.
sec-edgarUS SEC EDGAR filings — list 10-K/10-Q/8-K/Form 4/S-1, fetch filing text, parse insider Form 4 transactions.
stock-deep-diveUse when the user asks for an end-to-end orientation on a listed company they don't yet understand, especially when the request combines two or more dimensions in one ask. Triggers on "X 是干什么的", "帮我了解 X", "X 主营 + 同行", "盘前为什么涨", "本周趋势 + 阻力支撑", "X 和其他公司的关系", "first time looking at X", "full brief on X". Skip when the user wants only a single lens — use the targeted Longbridge sub-skill instead.
trade-gate>