{"slug":"chart","title":"chart","summary":"Render financial charts via the local chart web app (workspace at the repo root — Hono server + React front end, port 1792). Four chart types: intraday capital-flow line (`flow`) and cross-symbol signed-bar comparison (`cohort`) — both Recharts — plus SEPA strategy dashboard (`se","platform":"Claude","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-09-01T17:41:55.972677Z","repo":{"url":"https://github.com/kansoku-trade/kansoku","stars":319,"forks":38,"license":null,"updatedAt":"2026-09-19T13:43:53Z"},"bodyHtml":"<hr>\n<h2>name: chart\ndescription: &gt;\nRender financial charts via the local chart web app (workspace at the repo\nroot — Hono server + React front end, port 1792). Four chart types: intraday capital-flow line\n(<code>flow</code>) and cross-symbol signed-bar comparison (<code>cohort</code>) — both Recharts —\nplus SEPA strategy dashboard (<code>sepa</code>) and short-term multi-timeframe\nprediction dashboard (<code>intraday</code>) — both TradingView Lightweight Charts.\nMulti-timeframe K-line review lives inside <code>intraday</code> (the standalone kline\nchart type was removed). The server fetches Longbridge data itself\n(kline / capital flow) and computes all indicators (MA, MACD, RS, trend\ntemplate, volume profile, divergence/beichi detection) in TypeScript; the\ncaller only POSTs <code>{type, symbol, ...}</code> to <code>/api/charts</code> and gets back\n<code>{id, url, technicals?}</code>. Charts persist as data JSON under\n<code>journal/charts/data/</code>. <code>url</code> now points at where the chart actually lives:\nsepa/intraday land on the symbol page (<code>http://localhost:1792/symbol/&lt;SYM&gt;?analysis=&lt;id&gt;</code>),\nflow/cohort land on the home page for that date (<code>http://localhost:1792/?date=YYYY-MM-DD</code>);\nold <code>http://localhost:1792/charts/&lt;id&gt;</code> links still work and redirect there.\nTriggers: 出图、生成图表、画 K 线、画资金流曲线、画对比图、SEPA 仪表盘、\n短线预测、多周期K线、MACD、入场判断可视化、可视化、render chart, plot,\nvisualise, sepa dashboard, intraday prediction dashboard.</h2>\n<h1>chart</h1>\n<p>Creates charts through the local chart app so the user can browse them in one\nplace instead of squinting at tables. The server pulls market data and computes\neverything; charts are stored as versioned data JSON and always rendered by the\nlatest front-end code.</p>\n<blockquote>\n<p><strong>Response language</strong>: match the user — 简体 / 繁體 / English.</p>\n</blockquote>\n<h2>When to call</h2>\n<ul>\n<li>After running <code>longbridge capital --flow</code> context or when the user wants a flow visual ⇒ <code>flow</code></li>\n<li>For K-line review (multi-timeframe candles + MACD + auto signals) ⇒ <code>intraday</code></li>\n<li>After collecting cumulative net inflow across a cohort of symbols ⇒ <code>cohort</code></li>\n<li>After running <code>sepa-strategy</code> on a single name ⇒ <code>sepa</code></li>\n<li>When inside <code>intraday-signal</code> ⇒ <code>intraday</code> (two-call pattern: POST preview → PATCH prediction)</li>\n<li>When inside <code>capital-rotation</code> / <code>market-session-tracker</code> / <code>stock-deep-dive</code>,\ncall this as the LAST step and append the chart URL to the markdown journal entry.</li>\n</ul>\n<p>Skip when the user only wants a single number or a tiny series — a Unicode\nsparkline in the chat reply is faster.</p>\n<h2>Data-root scenario (kansoku-cli)</h2>\n<p>在 Kansoku 数据目录里跑（外部 Claude Code、无本地 dev server），走\n<code>kansoku-cli</code> 而不是 HTTP。判据：环境变量 <code>$KANSOKU_CLI</code> 有值 → 走 CLI；\n无 → 回退 HTTP。</p>\n<p>CLI 与 HTTP 契约一致——body 就是原本 POST /api/charts 的 body，\n返回 <code>{id, url, technicals?}</code> 也不变；CLI 侧额外多带一个 <code>deepLink</code>\n字段（见下方数据目录场景说明）。</p>\n<p>先加载 runtime.env（这一步只需做一次）：</p>\n<pre><code>set -a\n[ -f .kansoku-agent-kit/runtime.env ] &amp;&amp; . .kansoku-agent-kit/runtime.env\nset +a\n</code></pre>\n<p>之后：</p>\n<table>\n<thead>\n<tr>\n<th>HTTP 版</th>\n<th>CLI 等价</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>curl -s http://localhost:1792/api/health</code></td>\n<td><code>\"$KANSOKU_CLI\" info kit-version</code></td>\n</tr>\n<tr>\n<td><code>POST /api/charts</code> body 为 X</td>\n<td><code>printf '%s' \"$X\" \\| \"$KANSOKU_CLI\" chart create --type &lt;T&gt; --symbol &lt;S&gt; --json-input -</code></td>\n</tr>\n<tr>\n<td><code>GET /api/charts?type=&amp;symbol=</code></td>\n<td><code>\"$KANSOKU_CLI\" chart list [--symbol X]</code></td>\n</tr>\n<tr>\n<td><code>GET /api/charts/&lt;id&gt;</code></td>\n<td><code>\"$KANSOKU_CLI\" chart get &lt;id&gt;</code></td>\n</tr>\n<tr>\n<td><code>PATCH /api/charts/&lt;id&gt;</code></td>\n<td><em>(暂不支持——PATCH 仍走 HTTP；数据目录场景 PATCH 目前只在 intraday-signal 里出现，届时 fallback HTTP)</em></td>\n</tr>\n<tr>\n<td>打开 <code>data.url</code>（浏览器访问 <code>http://localhost:1792/...</code>）</td>\n<td>打开 <code>data.deepLink</code>（<code>kansoku://route/...</code>，见下）</td>\n</tr>\n</tbody>\n</table>\n<p>body/response 完全一致，写入的图表 JSON 落在 <code>journal/charts/data/&lt;id&gt;.json</code>\n（跟 HTTP 版本相同）。</p>\n<p>数据目录场景通常没有本机 dev server（Kit 用户不会跑 <code>pnpm start</code>），\n<code>data.url</code> 里的 <code>http://localhost:1792/...</code> 打不开。CLI 的 chart create\n响应现在多带一个 <code>deepLink</code> 字段（<code>url</code> 照旧保留，向后兼容 dev 场景），\n指向 <code>kansoku://route/...</code> 这个自定义协议。想让用户看到图表时，打开这个\ndeep link 即可——它会启动 Kansoku.app（若已在运行则直接切到前台）并跳转到\n对应图表页面：</p>\n<pre><code>open \"$(echo \"$response\" | jq -r .deepLink)\"\n</code></pre>\n<p>macOS 用 <code>open</code>，Windows 用 <code>start</code>，Linux 用 <code>xdg-open</code>——三者都认协议处理器，\n换平台只需换这一条命令。</p>\n<h2>Server lifecycle</h2>\n<p>The app must be running before any API call:</p>\n<pre><code>curl -s http://localhost:1792/api/health # {\"ok\":true,...} = up\n</code></pre>\n<p>CLI 等价：<code>\"$KANSOKU_CLI\" info kit-version</code></p>\n<p>If it is down, start it (long-running process — use run_in_background):</p>\n<pre><code>pnpm start # serves API + built web UI on :1792\n</code></pre>\n<p>First-time setup only: <code>pnpm install &amp;&amp; pnpm build</code>.</p>\n<h2>API</h2>\n<p>Base URL <code>http://localhost:1792</code>. All responses follow the\n<code>{ok, data, meta}</code> / <code>{ok:false, error, hint}</code> contract.</p>\n<table>\n<thead>\n<tr>\n<th>Endpoint</th>\n<th>Purpose</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>GET /api/health</code></td>\n<td>liveness check</td>\n</tr>\n<tr>\n<td><code>GET /api/charts?type=&amp;symbol=&amp;limit=</code></td>\n<td>list chart metas (newest first)</td>\n</tr>\n<tr>\n<td><code>POST /api/charts</code></td>\n<td>create a chart; body below</td>\n</tr>\n<tr>\n<td><code>GET /api/charts/:id</code></td>\n<td>full chart doc</td>\n</tr>\n<tr>\n<td><code>GET /api/charts/:id/built?count=</code></td>\n<td>ephemeral intraday rebuild with a larger bar window (history view; max 1000, never persisted)</td>\n</tr>\n<tr>\n<td><code>PATCH /api/charts/:id</code></td>\n<td>merge fields into input and rebuild (e.g. add <code>prediction</code>)</td>\n</tr>\n<tr>\n<td><code>DELETE /api/charts/:id</code></td>\n<td>remove a chart</td>\n</tr>\n<tr>\n<td><code>GET /api/legacy</code></td>\n<td>list old single-file HTML archives (served at <code>/legacy/&lt;file&gt;</code>)</td>\n</tr>\n<tr>\n<td><code>GET /api/stream/quotes?extra=</code></td>\n<td>SSE quote snapshots (watchlist ∪ positions ∪ extra), 10s cadence</td>\n</tr>\n<tr>\n<td><code>GET /api/stream/charts/:id</code></td>\n<td>SSE live rebuilds for flow/intraday charts, 60s cadence</td>\n</tr>\n<tr>\n<td><code>GET /api/symbols/:sym/{flow,benchmark,position,analyses,latest}</code></td>\n<td>live per-symbol cockpit data (server-computed, never AI)</td>\n</tr>\n</tbody>\n</table>\n<p>The stream endpoints power the web UI's realtime display; the AI workflow never\nneeds them — created charts update themselves in the browser while open, and\nthe persisted JSON stays frozen at analysis time.</p>\n<h3>Symbol cockpit (<code>/symbol/&lt;SYM&gt;</code>)</h3>\n<p>Every symbol also gets a stable dashboard URL, <code>http://localhost:1792/symbol/&lt;SYM&gt;</code>,\nthat aggregates live data with the symbol's latest <code>intraday</code>/<code>sepa</code> analysis — it\nis the caller-facing counterpart of <code>GET /api/symbols/:sym/*</code>. The same page also\nserves the frozen per-analysis view: appending <code>?analysis=&lt;id&gt;</code> pins it to one\nspecific chart doc (this is what <code>data.url</code> returns for <code>sepa</code>/<code>intraday</code> charts)\ninstead of following the latest one live; a banner offers to jump back to latest\nif a newer analysis has since landed. Old <code>/charts/&lt;id&gt;</code> links still work — they\nresolve the chart's type client-side and redirect to this page (or to the home\npage for <code>flow</code>/<code>cohort</code> 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 <code>/settings</code>) whose output shares the manual <code>intraday-signal</code> format. These <code>/api/symbols/*</code>\nroutes are server plumbing for that page — direct callers rarely need them,\nlisted here only for completeness:</p>\n<ul>\n<li><code>GET /api/symbols/:sym/flow</code> — today's capital-flow curve + large/medium/small distribution (live, via <code>longbridge capital</code>)</li>\n<li><code>GET /api/symbols/:sym/benchmark</code> — SMH/QQQ normalized same-session comparison (live, via <code>longbridge kline</code>)</li>\n<li><code>GET /api/symbols/:sym/position</code> — shares/cost/unrealized + distance to stop/target from the latest analysis's entry plan (live)</li>\n<li><code>GET /api/symbols/:sym/analyses</code> — past <code>intraday</code> analyses for this symbol with mechanical outcome judgments (<code>hit_target</code> / <code>hit_stop</code> / <code>open</code>, computed server-side from post-anchor bars — never AI recall)</li>\n<li><code>GET /api/symbols/:sym/latest</code> — the latest <code>intraday</code> chart doc in full, plus <code>prediction_stale</code></li>\n</ul>\n<p>The client-side indicator toggle bar (show/hide 金叉死叉、自动背离、自动背驰、123\n结构、SB 结构、K线形态、AI 标注、价位线、EMA 均线; state in localStorage) has no API\nsurface — it's a pure front-end feature on both the cockpit and archive pages.\nSwing 高低点 are not one of the toggles — they're baked into the\ndivergence/beichi/pattern123/SB detectors as the underlying pivot data, not a\nstandalone overlay (deliberate deviation from the earlier spec draft). SB（第二次\n突破/跌破，对应 Al Brooks 的 High 2 / Low 2）标注顺势回调后第二次尝试冲破前高/前低\n的结构：图上灰色 H1/L1 是失败的第一次尝试，金色 H2/L2 箭头是确认成功的第二次突破；\n<code>technicals</code> 里对应 <code>second_breakouts</code> 这一行。</p>\n<h3>POST body per type</h3>\n<p>The server fetches Longbridge data itself when <code>symbol</code> is given; pass <code>data</code>\n(or <code>kline</code> / <code>timeframes</code>) only to override with hand-assembled rows.</p>\n<pre><code>// flow — server runs `longbridge capital &lt;SYM&gt; --flow`\n{ \"type\": \"flow\", \"symbol\": \"MU.US\", \"subtitle\": \"单位推断为千 USD · 仅供参考\" }\n\n// cohort — data is always caller-assembled\n{ \"type\": \"cohort\", \"title\": \"存储 vs Mag 7 主力净流\",\n  \"data\": [{ \"symbol\": \"MU\", \"value\": -17087 }, { \"symbol\": \"NVDA\", \"value\": 9540 }] }\n\n// sepa — server pulls 260 day bars + SPY.US automatically\n{ \"type\": \"sepa\", \"symbol\": \"MRVL.US\", \"name\": \"Marvell Technology\",\n  \"position\": { \"shares\": 1, \"cost\": 100.00 },       // optional\n  \"context\": { /* see sepa context schema below */ } }\n\n// intraday — server pulls 5m/15m/1h × 1000 bars automatically (--session all:\n// pre/post-market bars included by default; pass \"session\": \"intraday\" to exclude)\n{ \"type\": \"intraday\", \"symbol\": \"MU.US\", \"name\": \"Micron Technology\",\n  \"ema_periods\": [9, 21, 55],                        // optional, fast/mid/slow EMA overlay (default 9/21/55, max 4)\n  \"position\": { \"shares\": 1, \"cost\": 100.00 },       // optional\n  \"prediction\": null }                                // omit for preview mode\n</code></pre>\n<p>CLI 等价（body 走 stdin，<code>--json-input -</code>）：</p>\n<ul>\n<li>flow → <code>\"$KANSOKU_CLI\" chart create --type flow --symbol MU.US --json-input -</code></li>\n<li>cohort → <code>\"$KANSOKU_CLI\" chart create --type cohort --json-input -</code>（无单一 symbol，省略 <code>--symbol</code>）</li>\n<li>sepa → <code>\"$KANSOKU_CLI\" chart create --type sepa --symbol MRVL.US --json-input -</code></li>\n<li>intraday → <code>\"$KANSOKU_CLI\" chart create --type intraday --symbol MU.US --json-input -</code></li>\n</ul>\n<p>Success returns <code>data.id</code>, <code>data.url</code> (paste this into journal entries), plus\ntype-specific meta: sepa → <code>verdict_tier / passes / fails / bars</code>; intraday →\n<code>mode / bars / technicals</code>.</p>\n<h3>sepa <code>context</code> schema</h3>\n<p>All fields optional:</p>\n<pre><code>{\n  \"earnings_dates\": [\"2026-05-29\"], // E markers on those bars\n  \"stage\": \"Stage 2 末期\", // 阶段判断 sidebar card\n  \"stage_note\": \"Stage 3 顶部嫌疑\",\n  \"base_count\": \"3-4 (减半仓)\",\n  \"pattern\": \"无可买（扩张振幅）\",\n  \"verdict\": {\n    // override the auto verdict\n    \"tier\": \"watch\", // pass / watch / buy\n    \"label\": \"\uD83D\uDC40 WATCH LIST\",\n    \"color\": \"#ffc107\",\n    \"reason\": \"...\",\n  },\n  \"entry_plan\": {\n    // 入场计划 card + price lines\n    \"pivot\": 260.0, // required: consolidation-range high\n    \"stop\": 241.8, // default pivot × 0.93 (-7%)\n    \"target1_pct\": 8, // default 8 (Phase 2: 卖一半 + 移至本钱)\n    \"target2_pct\": 15, // default 15 (Phase 3: 再卖 25% + 沿 20MA 跟踪)\n    \"note\": \"...\",\n    \"hypothetical\": true, // 标注 \"假设性\" 徽章\n  },\n  \"support_zones\": [\n    // omit → auto zones (MA50 / MA200 / volume cluster)\n    {\n      \"low\": 217,\n      \"high\": 226,\n      \"tier\": \"watch\", // warning / watch / buy / value\n      \"label\": \"MA50 关注区\",\n      \"note\": \"...\",\n      \"sources\": [\"MA50 $221.75\"],\n    },\n  ],\n  \"auto_support_zones\": true, // false disables the auto fallback\n  \"volume_profile\": { \"lookback_days\": 120, \"bins\": 30 },\n}\n</code></pre>\n<p>Derived values (auto-computed server-side): <code>buy_zone_high = pivot × 1.05</code>,\n<code>target1/2 = pivot × (1 + pct/100)</code>, <code>R/R = (target2 − pivot) / (pivot − stop)</code>\n— based on T2, not T1, because T1 is the SEPA Phase-2 partial exit. R/R &lt; 2:1\nrenders a red warning.</p>\n<p><strong>Verdict auto-detection</strong> (when <code>context.verdict</code> omitted): any trend-template\nfail → <code>PASS</code> \uD83D\uDEAB; all 8 pass + price ≥ 25% above MA50 → <code>WATCH · Extended</code> \uD83D\uDC40;\nall 8 pass otherwise → <code>WATCH · No pattern detected</code> \uD83D\uDC40. <code>STRONG BUY</code> ✅ is never\nauto-emitted — pass <code>context.verdict</code> after manually confirming a valid pattern</p>\n<ul>\n<li>pivot ±5% buy zone.</li>\n</ul>\n<p><strong>Auto markers on the main K-line</strong>: earnings (<code>context.earnings_dates</code>),\nclimax top (volume ≥ 2.5×20MA + red close + local high), MA50/MA200 breakdowns,\n52w high. Hardcoded lines: 52w high/low, MA50 × 1.25 extended warning.</p>\n<h3>intraday two-call pattern</h3>\n<ol>\n<li><strong>POST without <code>prediction</code></strong> → preview. Read <code>data.technicals</code> from the\nresponse: per timeframe <code>last_dif / last_dea / last_hist</code>, <code>last_vwap</code>\n(当日 session VWAP，m5/m15), <code>emas</code> (latest\nfast/mid/slow EMA values — price vs EMA stack tells the short-term trend\nposture), recent swing highs/lows, <code>last_cross</code> (金叉/死叉),\n<code>divergence_candidates</code>, <code>beichi_candidates</code>, <code>second_breakouts</code> (SB 结构，\nH2/L2). Also read <code>meta.day_context</code>:\n<code>daily_trend</code> (up/down/range vs 日线 MA20/MA50), <code>daily_ma20</code>/<code>daily_ma50</code>,\n<code>high_20d</code>/<code>low_20d</code>, <code>prev_day</code> (昨日高/低/收), <code>pre_market</code> 区间,\n<code>opening_range</code> (开盘前 30 分钟), <code>vwap</code> — the server draws these as the\nVWAP line and 日内参照位 price lines on the chart. Read these numbers —\ndon't eyeball candles.</li>\n<li><strong>PATCH <code>/api/charts/:id</code> with <code>{\"prediction\": {...}}</code></strong> → final dashboard.\nAdd <code>\"refresh\": true</code> to any PATCH to refetch the latest bars (incl. pre/post\nmarket) and recompute everything before rebuilding — same id, same URL.</li>\n</ol>\n<p>CLI 等价：第 1 步（POST 预览）可用\n<code>\"$KANSOKU_CLI\" chart create --type intraday --symbol MU.US --json-input -</code>；\n第 2 步（PATCH 写入 prediction）目前无 CLI 等价，仍走 HTTP。</p>\n<p><code>prediction</code> schema:</p>\n<pre><code>{\n  \"direction\": \"short\", // long | short | neutral\n  \"anchor\": { \"timeframe\": \"m15\", \"time\": \"2026-07-01T17:00:00Z\", \"price\": 1049.81 },\n  \"scenarios\": [\n    // ≥ 2, probabilities ≈ 100\n    { \"label\": \"继续探底\", \"probability\": 45, \"path\": \"...\", \"trigger\": \"...\" },\n  ],\n  \"range_bound_plan\": {\n    \"condition\": \"...\",\n    \"long_tactic\": \"...\",\n    \"short_tactic\": \"...\",\n    \"low\": 1020.0,\n    \"high\": 1060.0,\n  },\n  // low/high = 箱体下沿/上沿；neutral 必填（观望按守住/破位对账入记分板），方向单可选\n  \"entry_plan\": {\n    \"entry\": 1049.81,\n    \"stop\": 1030.0,\n    \"target1_pct\": 3,\n    \"target2_pct\": 6,\n    \"note\": \"...\",\n  }, // 仅 long/short；neutral（观望）省略整个 entry_plan，条件应对写进 range_bound_plan\n  \"price_zones\": [\n    // only real resistance/pressure zones drawn on chart\n    {\n      \"kind\": \"resistance\",\n      \"label\": \"反弹压力带\",\n      \"low\": 60.9,\n      \"high\": 61.35,\n      \"note\": \"短线均线和第一修复位重合\",\n      \"sources\": [\"5m EMA9/21\", \"第一修复位\"],\n    },\n  ],\n  \"signals\": [\n    // 可选；背离/背驰/K线形态/123 结构/SB 结构均由服务端自动检测绘制，无需在此重复\n    {\n      \"type\": \"other\",\n      \"timeframe\": \"m5\",\n      \"time\": \"...\",\n      \"price\": 1032.28,\n      \"bias\": \"bearish\",\n      \"label\": \"尾盘放量长阴收在最低——摆动点未确认前的人工备注\",\n    },\n  ],\n}\n</code></pre>\n<p>R/R is direction-aware (<code>long</code>: risk = entry−stop; <code>short</code>: risk = stop−entry);\nthe sidebar flags rr &lt; 2:1 in red. <code>entry_plan</code> can carry structured level\ncontext so the chart explains why a point was selected instead of hiding the\nreason in prose:</p>\n<pre><code>{\n  \"entry\": 61.1,\n  \"stop\": 62.52,\n  \"target1\": 60.0, // optional explicit target price; overrides pct-derived price\n  \"target2\": 57.92,\n  \"rationale\": \"反弹到 60.90-61.35 压力带后受阻才入场。\",\n  \"stop_note\": \"站回上一段反弹高点，空头计划失效。\",\n  \"entry_zone\": { \"kind\": \"resistance\", \"label\": \"反弹压力带\", \"low\": 60.9, \"high\": 61.35 },\n  \"target1_label\": \"T1 · 日内低点\",\n  \"target1_note\": \"整数位和日内低点，首次触及先看是否止跌。\",\n  \"target1_zone\": { \"kind\": \"support\", \"label\": \"日内低点\", \"low\": 60.0, \"high\": 60.0 },\n  \"target2_label\": \"T2 · 深一档支撑\",\n  \"target2_condition\": \"60.00 跌破并反抽失败后才成立。\",\n  \"target2_zone\": { \"kind\": \"support\", \"label\": \"深一档支撑\", \"low\": 57.9, \"high\": 58.0 },\n}\n</code></pre>\n<p><code>entry_plan.entry_zone</code> and <code>target1_zone</code> / <code>target2_zone</code> are explanation\ncontext for the right panel only; they are not drawn as chart zones and should\nnot be named <code>入场区</code>, <code>T1 区域</code>, or <code>T2 区域</code>. Put only genuine upper supply\nareas in top-level <code>price_zones</code> with <code>kind: \"resistance\"</code>; those are rendered\nas chart boundaries and in the sidebar's key-zone section.</p>\n<p>Supported zone kinds remain <code>entry</code>, <code>stop</code>, <code>target</code>, <code>support</code>, <code>resistance</code>,\n<code>invalidation</code>, <code>watch</code>, but the intraday chart-zone overlay intentionally\nfilters to explicit <code>resistance</code> zones. MACD structure signals + simplified 背离/背驰\nare auto-detected and drawn on every render regardless of <code>prediction</code>. Every\nDIF/DEA cross is classified by zero-line position（零上/零下金叉、零上/零下死叉）\nplus structural patterns: 二次金叉（零下双金叉且低点抬高 → 底部确认）、空中加油\n（零上二次金叉 → 强势延续）、二次死叉（顶部确认 / 空头中继）、上穿/下穿零轴\n（趋势确认，last 2 bars marked 待确认 with a <code>?</code>）. Each marker's tooltip carries\nthe implication text; <code>technicals.&lt;tf&gt;.structure_signals</code> (last 6) and\n<code>zero_tangle</code>（DIF 贴零轴缠绕 = 震荡市，交叉信号失效）expose the same data to the\nanalysis workflow — read them in the preview step. The swing-based divergence\nauto-detectors only fire on confirmed swing pivots — the last 1-2 bars can never\nbe flagged; read <code>last_dif/last_dea/last_hist</code> directly for the newest bar.</p>\n<p>14 classic K-line patterns are also auto-detected on the main pane (arrow\nmarkers, tooltip carries the implication): 单根——锤子线/上吊线/倒锤子/射击之星;\n双根——看涨吞没/看跌吞没/乌云盖顶/刺透形态/看涨孕线/看跌孕线; 三根——启明星/\n黄昏星/红三兵/三只乌鸦. All require a trend-context filter (4-bar net move into\nthe pattern) plus a body-size filter vs the trailing 14-bar average, so quiet\nchop produces few marks. One pattern max per bar (stars &gt; soldiers/crows &gt;\ntwo-bar &gt; single-bar). <code>technicals.&lt;tf&gt;.candle_patterns</code> (last 6) exposes them\nto the analysis workflow. Caveat: the newest bar may still be forming intraday —\na pattern on it can repaint until the bar closes.</p>\n<p>123 reversal structures (Sperandeo 1-2-3) are also auto-detected per timeframe\nfrom confirmed swing pivots: ① a ~20-bar extreme → ② the reaction pivot → ③ a\nhigher low (bullish) / lower high (bearish). The price pane gets ①②③ markers, a\n①→②→③ connector, and a dashed trigger line at the ② price running from ③ to the\nlatest bar; a close beyond ② flips the structure to confirmed (<code>123✓</code> marker on\nthe breakout bar), while a break of ① drops the structure silently. The ③ marker\nshows <code>③?</code> until confirmation. <code>technicals.&lt;tf&gt;.pattern_123</code> (last 2, each with\n<code>status: forming|confirmed</code>, <code>trigger</code>, <code>invalidation</code>, <code>p1/p2/p3</code>) exposes them\nto the analysis workflow — a <code>forming</code> structure is a ready-made entry setup\n(enter on the ② break, stop beyond ①). The sidebar's 自动信号 section lists them\nwith an 酝酿中/已确认 badge.</p>\n<p>Off-session bars (盘前/盘后浅蓝、夜盘深蓝) get a full-height backdrop on both\npanes — thin-volume price action outside regular hours is visually discounted at\na glance. Regular hours = 09:30-16:00 ET (DST-aware via America/New_York).</p>\n<h3><code>context</code> — AI-classified news + conclusion (optional, schema_version 2)</h3>\n<p>Both <code>POST /api/charts</code> (type <code>intraday</code>) and <code>PATCH /api/charts/:id</code> accept an\noptional <code>context</code> field alongside <code>prediction</code>. It's frozen at write time like\n<code>prediction</code> — the server never generates or judges it. <code>schema_version</code> is now\n<code>2</code>; older (<code>v1</code>) chart docs without <code>context</code> still load and render fine.</p>\n<pre><code>\"context\": {\n  \"generated_at\": \"2026-07-06T14:30:00Z\",         // ISO timestamp\n  \"conclusion\": {\n    \"stance\": \"short\",                            // long | short | neutral\n    \"summary\": \"一句话综合判断\",\n    \"action\": \"现在该做什么（挂单/等待/减仓）\"\n  },\n  \"news\": [\n    { \"time\": \"2026-07-06T13:10:00Z\",\n      \"source\": \"longbridge\",                     // longbridge | x | trump | sec | gdelt\n      \"tag\": \"catalyst\",                          // catalyst | regulatory | sentiment | macro\n      \"title\": \"...\", \"note\": \"AI 一句话解读\", \"url\": \"可选\" }\n  ],\n  \"sources_used\": [\"longbridge-news\", \"twitter-reader\"]\n}\n</code></pre>\n<p>The dashboard shows <code>context.generated_at</code>'s age and a stale badge, sharing the\nsame ~15-min staleness rule as <code>prediction</code> (<code>prediction_updated_at</code> /\n<code>prediction_stale</code> on chart metas cover both).</p>\n<h3>Realtime prediction upkeep</h3>\n<p>Once the US cash session is open, intraday charts must be maintained under\nthese rules:</p>\n<ul>\n<li><strong>Cash-session rebuilds drop off-session bars.</strong> Any PATCH after 09:30 ET\npasses <code>{\"session\": \"intraday\", \"refresh\": true}</code> — the prediction\ndashboard must not render pre-market / overnight bars intraday. The\ndefault <code>--session all</code> is for pre-market analysis only.</li>\n<li><strong>Volume calls align to prior sessions' same-time window.</strong> Never compare\ntoday's running volume against full-day totals. Pull <code>longbridge kline --period 5m</code> (regular-session bars), sum today's bars, and compare against\nthe same number of opening bars averaged over the prior ~5-8 sessions.\nPair the ratio with per-bar direction before calling a move confirmed — a\nlevel break on ~0.6x same-period volume is not a confirmed breakout.\nCaveat: Longbridge daily-K volume includes extended hours; 5m-K volume\ndoes not — never mix the two.</li>\n<li><strong>Stale predictions get refreshed on a ~15 min loop.</strong> The server marks an\nintraday chart's prediction stale when it is &gt;15 min old during regular\nhours (<code>GET /api/charts?stale=true</code> lists them; the SSE envelope and chart\nmetas carry <code>prediction_updated_at</code> / <code>prediction_stale</code>). Each loop\nround: fetch the stale list → re-pull quote / capital flow / klines →\nPATCH <code>prediction</code> with scenarios revised only on material change, but\n<strong>always move <code>anchor</code> to the newest m5 bar time + latest price</strong> — the\nanchor marker must track the live tape, never sit minutes behind it →\nappend a timestamped journal note on material revisions (revision\ndiscipline) → stop the loop after 16:00 ET close.</li>\n</ul>\n<h2>桌面版模式</h2>\n<p>打包的桌面版（<code>Kansoku.app</code>）不监听任何本机端口，全部走 <code>app://</code> 内部协议 + IPC，不提供 HTTP 接口。要用这个 skill 的 curl 命令，单独起 server 进程即可：<code>pnpm start</code>（或开发模式 <code>pnpm dev</code>），API 照常在 <code>http://localhost:1792</code>。</p>\n<h2>Storage</h2>\n<ul>\n<li>Chart docs: <code>journal/charts/data/&lt;YYYY-MM-DD&gt;-&lt;slug&gt;.json</code> — gitignored,\n<code>schema_version</code> field for forward compatibility. Date = US session date\n(derived from the data, not local clock).</li>\n<li>Old single-file HTML archives stay in <code>journal/charts/*.html</code>, listed in the\napp under 旧版存档 and served at <code>/legacy/&lt;file&gt;</code>.</li>\n<li>The app itself: the pnpm workspace at the repo root (<code>apps/server/</code> Hono +\nTS, <code>apps/web/</code> Vite + React). Analysis parity with the retired Python\nimplementation is locked by vitest golden tests: <code>pnpm test</code>.</li>\n</ul>\n<h2>Sparkline alternative (no API)</h2>\n<p>For tiny in-chat previews render Unicode sparklines directly: <code>▁▂▄▆█</code> plus ANSI\ngreen/red. Use for 5-20-point series where a full chart is overkill.</p>\n<h2>Related skills</h2>\n<ul>\n<li><code>longbridge-capital-flow</code> / <code>longbridge-kline</code> — same data the server pulls; call directly only for in-chat analysis</li>\n<li><code>capital-rotation</code> — should end with a <code>cohort</code> chart</li>\n<li><code>market-session-tracker</code> — may create <code>flow</code> charts</li>\n<li><code>sepa-strategy</code> — calls <code>sepa</code> as the last step of its Step 10</li>\n<li><code>intraday-signal</code> — calls <code>intraday</code> twice (POST preview, then PATCH prediction)</li>\n</ul>\n","files":[{"path":"SKILL.md","sizeBytes":25792,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"trusted-source-unreviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"trusted-source-unreviewed","screen":{"ran":true,"outcome":"clean","suspicious":0,"notes":0,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-09-01T17:42:04.442326Z","sha256":"90C591AB9DD91798A8455EE302B0F5E1C2011159A2C5EBC41F76E84D4DF460F1","sizeBytes":11966},"review":null,"source":{"repositoryUrl":"https://github.com/kansoku-trade/kansoku","path":".claude/skills/chart","license":null,"commit":"9f4f3a4498a132f38b54354de04335e0e5439dee","subtreeSha":"464CC5388A3FC2D4766F8CB42AFAAD5508D8E6E915B4B209C359F54656C29165","lastSyncedAt":"2026-09-25T23:11:53.908188Z"},"reviewedAt":"2026-09-01T17:42:43.31268Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/kansoku-trade/kansoku/tree/main/.claude/skills/chart"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install kansoku-trade-kansoku@llmmart"},{"target":"git","command":"git clone https://github.com/kansoku-trade/kansoku.git"}]}