stock-html:一遍看懂的手繪圖解頁
把材料做成一個單檔 HTML 頁面:方格紙 / 黑板兩套手繪主題,固定角色的兩格漫畫,全部數字可複算。兩種用法:
- 股票報告(
kind="stock",預設):一隻股票、一份財報、一條併購或重大新聞 → 一份完整的圖解報告。 - 通用學習頁(
kind="general"):文章、論文、技術文件、課程筆記 → 主線 + 概念依賴鏈 + 漫畫卡片 + 學習路線。
本目錄自帶工具箱,不要從零手寫 HTML:
| 檔案 | 作用 |
|---|---|
scripts/sketch.py | 畫布、兩格漫畫、現成圖表、整頁拼裝;save() 時自動做離線版面檢查 |
scripts/blocks.py | 半成品積木:主線圖、護城河、遠期對帳圖、三種兩格漫畫版式、股價推演表——一次做多份報告時用 |
scripts/verify.py | 用無頭 Chrome 真實渲染,讀頁面內建自檢結果,分段截圖 |
assets/template.html | 頁面模板:兩套主題、抖動濾鏡、印章進度、內建自檢腳本 |
examples/boba_merger.py | 完整參考寫法(虛構公司的個股報告),開工前先讀一遍 |
references/stock-report.md | 股票報告每一節怎麼寫、數據紀律 |
references/visual-style.md | 視覺規範、畫布座標、手寫 SVG 的規矩 |
references/qa.md | 三層自檢、看圖要點、沒有 Chrome 時的備用辦法 |
三條不可妥協
- 讀者零基礎。 每個術語第一次出現時用一句話解釋,括號裡給英文原詞。禁止「如你所知」「顯而易見」「不難理解」。
- 先說結論,再說原理。 每一節第一句必須是結論,不是背景鋪墊。
- 數字不能憑印象。 所有數字先核實、先用腳本算平,再畫圖。推算值標「示意」,機率標「主觀估計,不是預測」。
工作流程
- 讀完全部材料——使用者給的檔案、截圖、連結,一個不落。
- 連網核實——一手來源優先(公司公告、8-K、新聞稿、財報),把每個要用的數字落地。細則見
references/stock-report.md的「數據紀律」。 - 寫 build 腳本,數字放最上面——所有輸入和推算寫成變數,用
assert互相對帳(漲跌幅分解、價差、增厚/攤薄、倍數 × EPS)。算不平不許往下畫。 - 排概念依賴鏈(8–13 個概念)——按「後一個概念是為了解決前一個概念帶來的問題」排,不按材料原順序。某個概念說不出它在解決上一個的什麼問題,就是排錯了。
- 拼頁面——照
examples/boba_merger.py的寫法:import sys; sys.path.insert(0, "<本 skill 目錄>/scripts") from sketch import * p = Page("標題", "副標題") # 預設 kind="stock" p.mainline(...); p.checkup(...); p.section(..., role="moat"); p.chain(...); p.card(...) # … p.save("out.html") # 寫檔案 + 離線預檢,有 ERROR 就改到沒有 - 真實渲染檢查——
python3 scripts/verify.py out.html --shots shots/。必須看到[CHECK light] PASS和[CHECK dark] PASS,然後逐張看截圖(淺色、深色至少各看兩段)。細則見references/qa.md。 - 交付——環境裡有 Artifact 發佈工具就發佈(發佈後讀控制台,確認兩個主題都是 PASS);沒有就把 HTML 檔案交給使用者。
- 回覆使用者——先用 2–3 句直接回答他的問題(比如「基本面變了嗎」),再用 5–8 個要點說明頁面裡有什麼,註明和預期不同的地方(日期未確認、反推的數字、字型回退),最後列來源。
股票報告的預設結構
下面每一節預設都要有(Page.save() 會對缺失的節報警)。這是「至少要有」,不是「只能有」:材料裡還有別的重點(估值與同行對比、管理層與資本配置、現金流與負債、客戶集中度……)就再加 section()。每節正文 ≤ 4 句,以圖為主。
| # | 小節 | 怎麼呼叫 | 必須回答的問題 | 用什麼圖 |
|---|---|---|---|---|
| 1 | 主線 | mainline() | 這件事到底在幹什麼?(主循環 / 生產線 / 核心矛盾 三選一) | 一句話 + 一張圖 |
| 2 | 體檢單 | checkup() | 基本面變了嗎?每行帶數字和口徑 | ✓ 綠勾 / — 橙橫 / ✗ 紅叉 |
| 3 | 核心競爭力 | section(role="moat") | 哪 2–3 件事別人真的抄不走?證據是哪個數?弱點在哪? | 護城河圖 + tiles |
| 4 | 概念依賴鏈 | chain() | 看懂這家公司 / 這條新聞要先懂哪 8–13 個概念? | 蛇形流程圖 |
| 5 | 概念卡片 | card() × N | 每個概念:沒有它時的煩惱 → 它的辦法 → 解決了什麼、代價是什麼 | 兩格漫畫 |
| 6 | 技術規劃路線 | section(role="roadmap") | 現在做到哪、下一步是什麼、哪些只是願景? | roadmap() 台階圖 |
| 7 | 遠期規劃 | section(role="vision") | 管理層 3–5 年要去哪?按現在的速度到得了嗎,差多少? | 目標 vs 現速對比圖 |
| 8 | 隱藏危機 | section(role="risks") | 公告和多頭敘事裡沒寫的 4–6 件事;各自的預警訊號是哪個數? | risk_matrix() + 預警表 |
| 9 | 關鍵時間節點 | section(role="timeline") | 未來 6–12 個月哪幾天會出結果?哪些日期還沒確認? | timeline() + 日程表 |
| 10 | 股價推演 | section(role="paths") | 2–3 條路各需要發生什麼、落在什麼價位、主觀機率多少? | paths_chart() + 推演表 |
| 11 | 尺子 | section(role="ruler") | 衡量好壞的 2–3 個指標;每個辦法改善哪個、犧牲哪個? | ruler_chart() + 對照表 |
| 12 | 零基礎版(按需) | section(role="eli5") | 最反直覺的那個機制,一步一步帶算式 | 瀑布圖 + 步驟 + 對比表 |
| 13 | 學習路線 | route() | 3–4 站:為什麼去、去多久、連結 | 地鐵線路圖 |
| — | 頁腳 | sources() | 全部來源 + 「僅作學習用途,不構成投資建議」 | — |
每一節的寫法、常見空話和反例見 references/stock-report.md(寫股票報告前必讀)。
通用學習頁的結構
Page(..., kind="general"):主線 → 概念依賴鏈 → 概念卡片 → 尺子(這個領域衡量好壞的 2–3 個指標畫在同一張圖上)→ 零基礎版(按需)→ 學習路線。沒有體檢單、股價推演和免責聲明。
貫穿全頁的規矩
- 固定角色。 全頁所有圖用同一組角色,不同概念裡不換人。股票類預設:A、B、C 三位老股東 + D 一位新股東;餅 = 股份,幣 = 利潤。在主線圖下面用一行小字交代角色。
- 數字縮小版。 把 9.21 億股畫成 6 塊餅、把 $10 億利潤畫成 10 枚幣;比例必須和真實數據一致,圖上標「示意值」。
- 概念卡片只寫兩行:「解決了什麼」和「代價是什麼」。代價不許留空、不許寫「基本沒有代價」——找不到代價就是沒想清楚。
- 固定顏色語義(全頁一致):綠 = 正在進行的(業務、利潤);橙 = 新來的(新事件、新股東);藍 = 存起來的(股份、現金、價值);紅色虛線 = 作廢 / 被釋放的(損失)。印章用紫色。
硬性要求(發佈前逐條過)
- 每格漫畫說明文字 ≤ 15 個字(連數字和符號一起數;英文頁 ≤ 32 字元)。
- 文字絕不壓邊框、絕不互相重疊。
- 以圖為主,正文每節 ≤ 4 句。
- 所有圖是手寫的內聯 SVG(用
sketch.py產生)。不用 Chart.js / D3 / Mermaid。 - CSS、JS、SVG 全部內聯在一個 HTML 檔案裡;不加任何外鏈(包括 Google Fonts——部分 Artifact 環境的 CSP 會攔)。
- 文字不進抖動濾鏡、不加 transform(
Canvas.text()已經保證;手寫 SVG 時自己注意)。 - 學習路線的連結必須用抓取工具打開核實,內容對得上才寫
verified=True。被攔截或打不開就換一個,或不給url(頁面會顯示「需自行搜尋」)。編造連結是這個技能最嚴重的失敗。 - 不提使用者的持倉和期權,只分析股票本身;不給買賣指令。
verify.py兩個主題都 PASS,並且看過截圖。
工具箱速查
# 畫布:顏色只用語義名 ink / ink2 / green / orange / blue / red / purple
c = Canvas(760, 300, "名字") # 大圖 760 寬,字號 ≥ 12
c.rect / line / arrow / curve / circle / path / poly / bar # fill="green" 淺色,"green!" 實心
c.text(x, y, "文字", size=14, anchor="middle", color="ink", bold=False)
c.person(cx, top, "A", "blue", mood="happy") # 固定角色小人(約 30×60)
c.pie(cx, cy, r, ["blue"]*6 + ["orange"]*2, labels) c.coins(x, y, 12, "green", cols=4)
c.shop(cx, base, label="BOBA") c.doc(x, y) c.bubble(x, y, w, h) c.tick / cross / minus
# 兩格漫畫:560×232;左格中心 x=140,右格中心 x=420;你的繪圖區 y 44–188
k = Comic("左格說明 ≤15 字", "右格說明 ≤15 字")
# 現成圖表(都回傳 Canvas)
snake(nodes) metro(stations) timeline(events) roadmap(stages) risk_matrix(items)
paths_chart(history, scenarios) ruler_chart(points, xr, yr, iso, gauge) waterfall(steps)
# 頁面
p = Page(title, subtitle, kind="stock", notice=None)
p.mainline(一句話, canvas, kind="核心矛盾", note="固定角色:…")
p.checkup([("ok" | "mid" | "bad", "帶數字的一行"), ...])
p.chain([(概念名, 它帶來的新問題), ...])
p.card(name, en, definition, comic, solves, cost, stamp="next" | "redo" | "done")
p.section(title, prose, canvas=, table=(表頭, 行), steps=[…], tiles=[…], after=, note=, role=)
p.route([Stop(name, why, time, url, link_text, verified=True), ...])
p.sources([(標題, url), ...]); p.save("out.html")
英文頁面:在建立任何 Comic / Page 之前呼叫 set_lang("en")。每個函式的參數細節直接看 scripts/sketch.py 裡的 docstring。
一次做多份報告(比如一個 ETF 的前十大成分股)時,用 scripts/blocks.py 的積木,每份報告只需寫數字和文案:
from blocks import * # 同時匯入 sketch 的全部工具
m = mainline_tug(左標題, [(標籤, 值, 是否指引)×3], 單位註, 問題, 副問題, [(力量, 顏色)×3], 右標題, [(日期, 股價), ...], "−6%")
mo = moat(["① 最深", "② 次之", "③ 最淺"], "TICK")
vi = vision([(值, 標籤1, 標籤2, 顏色, 虛線)×3], gap_between=(1, 2), note="演算法…")
c1 = C_bars(左說明, 右說明, [(標籤, 值, 顏色)], [(標籤, 值, 顏色)], lnote=, rnote=, fmt="%g") # 前後對比柱
c2 = C_talk(左說明, 右說明, "A", "氣泡裡的話", "煩惱物件", "D", "辦法物件", "一行註") # 角色 + 物件
c3 = C_flow(左說明, 右說明, ["框", "框"], ["框", "框", "框"], rnote="一行註") # 流程框
sc = [scen("路徑", 機率, 示意EPS, 低倍數, 高倍數, "green"), ...]; expect(sc); scen_table(sc, 需要發生什麼)
p = Page(..., notice=disclaimer("2026-11-11"))
積木畫出來的圖偏「標準件」;單份報告想畫得更講究,仍用 Canvas / Comic 手畫,兩者可以混用。
現成圖表不夠用時,直接用 Canvas 的基礎圖形自己畫——工具箱是起點不是籠子;只要文字都走 c.text(),檢查照樣生效。
不能跑 Python 的時候
複製 assets/template.html,把 {{BODY}} 換成手寫的 HTML + 內聯 SVG,其餘佔位符({{TITLE}} {{LANG}} {{CAPMAX}} {{PAGE_KEY}} {{LABELS}})照 sketch.py 裡 Page.html() 的值填。手寫 SVG 必須遵守 references/visual-style.md 的畫布座標和 class 約定(svg.chk、rect.panel、text.cap),內建自檢才認得出來。在瀏覽器裡打開 頁面.html?check=1,底部檢查條必須是綠色 PASS。
常見失敗模式
- ❌ 概念按材料原順序排 → 依賴鏈沒有資訊量,重排
- ❌ 「代價是什麼」寫成「幾乎沒有代價」 → 沒想清楚,再想
- ❌ 不同概念的圖裡換了角色 → 讀者要重新認人,統一
- ❌ 核心競爭力只有形容詞(「品牌強大」「技術領先」),沒有數字和口徑 → 換成證據
- ❌ 把管理層的願景當成效指引導寫進遠期規劃 → 標清楚是目標,並和現在的速度對帳
- ❌ 隱藏危機寫成「宏觀不確定性」「競爭加劇」這種套話 → 寫具體的傳導路徑和要盯的數
- ❌ 把沒公告的日期寫死 → 寫「預計 12 月初(去年為 12/2,以公司公告為準)」
- ❌ 機率和價位不標「主觀估計 / 示意」 → 讀者會當成預測
- ❌ 二手媒體說「沒有新消息」就信了 → 先查公司公告和 SEC 文件
- ❌ 學習路線的連結沒打開核實 → 最嚴重
- ❌ 正文寫成長篇大論 → 每節 ≤ 4 句
- ❌ 沒跑
verify.py、沒看截圖就交付 → 文字重疊的頁面發出去了