For when the user wants visual markup on a chart image — either standalone or as a follow-up to a prior analysis.
- User attached a chart AND explicitly wants drawing: "draw / annotate / mark / highlight / overlay / 标一下 / 画出来 / 标注 / 在图上标 / 出张图 / 帮我画"
- Follow-up after
analyze.mdproduced an analysis withtrade_setupand user says "把这个画在图上" / "重新画一下" / "换个颜色"
- User attached a chart + asked for analysis → use
analyze.md(it auto-annotates as last step) - Pure concept Q&A → use
qna.md - Non-trading images → not this skill
Path A: User already has an analysis JSON (from running analyze.md previously)
→ Use the glue script kb_phase_b_to_c.py directly — don't redo analysis.
Path B: User wants annotation but no analysis has been done yet
→ Run a slimmed version of analyze.md Steps 1-4 to decide what to annotate, then build the annotation JSON manually and call kb_draw_annotation.py.
.venv/bin/python scripts/kb_phase_b_to_c.py \
--input <analysis.json> \
--image <original.png> \
--output <annotated.png>Optional overrides:
--chart-bbox "x,y,w,h"— override bbox from JSON--y-range "top,bottom"— override y_axis_range from JSON--theme dark|light— override theme
The tool reads chart_bbox / y_axis_range / theme from the JSON, maps patterns + trade_setup to annotations, and renders the image. You don't need to write the annotation JSON yourself in this path.
Read the chart inventory; detect multi-panel; assess resolution. If low resolution, downgrade confidence and prefer fewer, broader annotations.
Same as analyze.md Step 1c. For EACH panel:
chart_bbox: pixel position of the plotting area (exclude toolbars, price-label gutters, time scale)y_axis_range: top + bottom prices on the y-axistheme: dark / light
Why: every annotation's pixel position is derived from these. Wrong bbox → annotations drawn outside the chart.
.venv/bin/python scripts/kb_retrieve.py "<keywords>" --top-k 5Use 2-5 candidate keywords from hypothesized patterns.
Based on retrieved cards' identification rules + chart evidence, produce a list of annotations.
Two supported annotation types:
Use for: Entry / Stop Loss / Targets / key Liquidity levels / Mean Threshold
{
"type": "horizontal_line",
"price": 73000,
"label": "Long Entry @ OTE",
"color": "#00ff88",
"style": "solid" | "dashed",
"label_position": "right" | "left"
}Use for: FVG / Order Block / Breaker / Mitigation / Premium-Discount zone / Killzone
{
"type": "rectangle",
"price_top": 74500,
"price_bottom": 73000,
"x_pct_start": 0.6,
"x_pct_end": 1.0,
"label": "FVG",
"fill_color": "#00ff8830",
"border_color": "#00ff88"
}Single panel:
{
"input_image": "<absolute path>",
"output_image": "<absolute path>",
"theme": "dark",
"panels": [
{
"panel_id": "main",
"chart_bbox": {"x": 50, "y": 30, "width": 800, "height": 400},
"y_axis_range": {"top": 96000, "bottom": 70000},
"annotations": [ ... ]
}
]
}Multi-panel: add more entries to panels array, each with its own chart_bbox / y_axis_range / annotations.
Save to a temporary file (e.g. /tmp/annotation.json).
.venv/bin/python scripts/kb_draw_annotation.py --json /tmp/annotation.jsonPrints the output path on success.
Tell the user:
- Original image path
- Annotated image path
- What was annotated (summary list): "Entry at 73000 / SL at 71000 / T1 at 95200 / FVG zone 73000-74500"
- Confidence level + rationale
- If low confidence — what would improve it (better resolution, manual bbox confirmation, etc.)
| Role | Color | Use |
|---|---|---|
| Entry (long) | #00ff88 solid |
bullish entry |
| Entry (short) | #ff4444 solid |
bearish entry |
| Stop Loss | #ff4444 dashed |
risk |
| Target | #4488ff solid |
T1/T2/T3 |
| FVG (bullish) | #00ff88 border + #00ff8830 fill |
bullish FVG |
| FVG (bearish / IFVG) | #ff8844 border + #ff884430 fill |
bearish or inverted |
| Order Block / Breaker | #aa55ff border + #aa55ff30 fill |
OB family |
| Liquidity Sweep level | #ffaa00 dashed |
swept liquidity |
| Discount zone | #00ff88 border + #00ff8820 fill |
below EQ |
| Premium zone | #ff4444 border + #ff444420 fill |
above EQ |
Deviate only if user requests specific colors. Prefer consistency.
- No fabricated levels (shared rule) — every
pricetraces to chart evidence or a retrieved rule - No invented bbox — conservative estimate if unsure; state low confidence
- Respect multi-panel boundaries — annotations for
panel_leftmust NOT extend intopanel_right - Theme matches background —
darkfor most TradingView/Binance defaults - Label limit — ≤ 8 annotations per panel for readability; pick most actionable (entry/SL/T1/T2 + 2-3 most relevant zones)
- Language (shared rule) — Chinese prose / English technical terms; JSON labels default to English unless user requests Chinese
- Resolution-aware — low resolution → fewer, broader annotations + downgraded confidence
User (after running analysis on BTC 1D): "把上面分析的标到图上"
kb_phase_b_to_c.py \
--input /home/Codes/QuantKnowledge/test-charts/IMG_0557.analysis.json \
--image /home/Codes/QuantKnowledge/test-charts/IMG_0557.PNG \
--output /home/Codes/QuantKnowledge/test-charts/IMG_0557.annotated.pngReply: output path + summary of what was annotated.
User: [attaches BTC 1D chart] "把我应该入场的位置标在图上"
- Examine: BTC 1D, price 79K, range 60K-105K, VWAP at 80,388
- Calibrate: bbox: {x: 30, y: 200, w: 580, h: 500}, y_range: {top: 110000, bottom: 60000}, theme: dark
- Retrieve:
kb_retrieve.py "discount zone OTE entry swing low" - Decide:
- Long Entry near 75K (lower third of range, in discount)
- SL below 60K (with caveat: stop too wide for daytrade)
- T1: 82.5K (EQ), T2: 95K (prior swing high), T3: 105K
- Discount zone rectangle 60K-82.5K
- Build JSON → save to
/tmp/btc_annotation.json - Call
kb_draw_annotation.py --json /tmp/btc_annotation.json - Reply: "Annotated chart saved to .../IMG_0557_annotated.png. Marks: Long bias entry zone 75K, SL 60K (wide), T1 82.5K, T2 95K, T3 105K, Discount zone 60K-82.5K shaded. Confidence: low (HTF bias unclear; daily TF stops are very wide)."
User: [attaches dual-panel image] "画一下 short setup"
- Examine + 1a: 2 panels, both ETHUSDT.P, left=5m, right=15m
- Calibrate each:
- panel_left: {x: 20, y: 30, w: 620, h: 400}, y_range: {top: 2280, bottom: 2200}
- panel_right: {x: 680, y: 30, w: 620, h: 400}, y_range: {top: 2300, bottom: 2200}
- Retrieve:
kb_retrieve.py "5m 15m HTF LTF alignment short entry breaker" - Decide: on both panels: 2245 breaker (rectangle), entry 2245 (line), SL 2270 (dashed), T1 2210 / T2 2200 (lines)
- Build JSON with 2 panels
- Call draw tool (handles multi-panel automatically)
- Reply: confirm HTF+LTF alignment; output path
User: "把入场点标成紫色"
Use #aa55ff for entry instead of default green. Document the choice in output summary.