| --- |
| title: Chan Compass · US Stocks |
| emoji: 🧭 |
| colorFrom: blue |
| colorTo: purple |
| sdk: docker |
| app_port: 7860 |
| pinned: false |
| license: mit |
| short_description: Local Chan-theory US stock signals, fine-tuned 1.7B |
| tags: |
| - build-small-hackathon |
| - track:backyard |
| - achievement:offgrid |
| - achievement:welltuned |
| - achievement:offbrand |
| - achievement:llama |
| - achievement:sharing |
| - achievement:fieldnotes |
| --- |
| |
| # 🧭 Chan Compass — US Stocks |
|
|
| Multi-timeframe **缠论 (Chan theory)** signal engine for US stocks — monthly → weekly → |
| daily → 60m → 30m → 15m → 5m → 1m **nested-interval (区间套) confirmation** — plus a |
| **sector capital-rotation monitor**, a **today-only watchlist news desk**, a |
| **multi-agent research desk**, and a **fully local llama.cpp brain** (Qwen3 GGUF + |
| a **published fine-tune**, all ≤ 32B parameters, no cloud APIs). |
|
|
| UI design language: **Adobe Spectrum 2** (pill buttons, Spectrum blue `#0265DC`, |
| Source Sans 3 — Adobe's open font), served from `ui_kits/chan-compass/` by |
| `gradio.Server`. |
|
|
| > **Backyard AI** — this solves a real problem for real people: my family trades |
| > US stocks with a Chan-theory engine whose reasoning is dense Chinese jargon and |
| > which had to be run by hand every night. Chan Compass runs it automatically and |
| > turns each verdict into a plain-English summary they actually read. |
|
|
| ## 🔗 Links |
|
|
| - 🎬 **Demo video:** https://www.youtube.com/watch?v=Ynwdzsf_KBA |
| - 📓 **Blog / Field Notes:** https://huggingface.co/blog/build-small-hackathon/chan-compass |
| - 🎯 **Fine-tuned model:** https://huggingface.co/ranranrunforit/chan-compass-qwen3-1.7b-gguf |
| - 📡 **Agent-trace dataset:** https://huggingface.co/datasets/ranranrunforit/chan-compass-agent-traces |
| - 📣 **Social posts:** [post 1](https://x.com/ranranrunforit/status/2066096644135764377) · [post 2](https://x.com/ranranrunforit/status/2066217978773782669) |
| |
| ## The local sub-agent pool |
| |
| All language work runs on a pool of small local models through llama.cpp — each |
| sub-agent has its own lock, so features never block one another: |
| |
| | Sub-agent | Model | Used by | |
| |---|---|---| |
| | **Interpreter** | **Chan-Tuned Qwen3-1.7B** (my published fine-tune) | Signals → AI Interpret | |
| | **Narrator** | Qwen3-1.7B | Sector Rotation narrative | |
| | **Reporter** | Qwen3-1.7B | Watchlist News briefs + research support | |
| | **Analyst** | Qwen3-4B | Auto Research report writing | |
| |
| The Interpreter sub-agent uses a **fine-tuned** Qwen3-1.7B |
| (`ranranrunforit/chan-compass-qwen3-1.7b-gguf`, Q8_0), LoRA-trained on |
| (raw read → English summary) pairs captured from the app's own usage — a small |
| model doing one focused job well. |
|
|
| ## Tabs |
|
|
| | Tab | What it does | |
| |---|---| |
| | 📈 Signals | Runs the unchanged Chan engine over your ticker pool (pure rule engine, no LLM on this path): next-session BUY / SELL / HOLD / WAIT with an explicit **buy point**, entry zone, invalidation price, confidence and suggested weight. Pick a ticker for a plain-English raw read, then **AI Interpret** — the Interpreter sub-agent references the multi-timeframe ruling chain (kept backstage) and writes an English-only interpretation. | |
| | 🔄 Sector Rotation | Where capital is flowing: 11 SPDR sector ETFs (full S&P 500), flow proxy = change% × dollar volume + relative strength vs SPY, over 1/5/20 days, tables instant + an on-demand AI narrative. | |
| | 📰 Watchlist News | For each holding, checks **today's** news only, streaming each ticker / headline / AI brief as it arrives; quiet tickers are grouped. | |
| | 🧪 Auto Research | Multi-agent: PLAN → 6 evidence tools in parallel (fundamentals, quarterly financials, price action, the Chan engine itself, money-flow proxy, news) → Analyst (4B) streams valuation · tech moat · supply-chain map (with tickers) · bull/bear while the Reporter (1.7B) writes money-flow · Chan timing · risks in parallel. Every run saves a JSON **agent trace**; new pool tickers get a report **auto-generated** by the daily pipeline. | |
| | ⏰ Automation | Daily pipeline at **18:10 America/New_York**, with a live Pipeline Log and auto-refreshing trace list. Manual "Run now" too, plus a one-click **Publish traces as a Hub dataset** button (uses your `HF_TOKEN`, no command line). | |
| | 🧠 Model | Live sub-agent status (auto-refresh), one-click self-test, model picker, and a **fine-tuning dataset export** (download the JSONL the app captured). | |
|
|
| ## Email any result |
|
|
| Each of the four result tabs has an **email box + ✉ Send Email** button — send the |
| current AI result to any address. Delivery uses the **Resend HTTPS API** (works on |
| HF Spaces, which block outbound SMTP), with SMTP as an off-HF fallback. Set a Space |
| secret `RESEND_API_KEY` to enable it. Both HTML and clean plain-text are rendered |
| from the markdown, so reports arrive properly formatted. |
|
|
| ## Data |
|
|
| Yahoo Finance via `yfinance`: 10y daily (weekly/monthly resampled), 60m (730d), |
| 30m/15m/5m (60d), 1m (7d). Downloads are parallel with a time budget; whatever |
| isn't fetched in time is skipped and picked up next run. Cached to parquet. |
|
|
| ## Persistent storage (`/data` bucket) |
|
|
| With a storage bucket attached, the app keeps everything across restarts: |
| `/data/cache_us` market data · `/data/output` signals + holdings + **the last |
| pipeline results** (`last_results.json`) and **last-run time** (`last_run.txt`) · |
| `/data/reports` research reports · `/data/traces` agent traces · `/data/dataset` |
| captured fine-tuning pairs · `/data/hf_cache` GGUF models · `/data/pylibs` the |
| llama.cpp runtime (installed once, persisted). |
|
|
| **Results survive restarts and page reloads.** When the daily pipeline runs (or |
| you press Run now), the signals table, sector-rotation tables, and watchlist-news |
| briefs are written to `/data`. Open the app later — even after a restart — and it |
| loads those last results immediately, no recompute. So if the 18:10 ET schedule |
| ran at 6 pm, opening the page at 7 pm shows the finished results right away. |
| (Re-running with a different ticker pool in Signals / News / Auto Research |
| recomputes just that view.) |
|
|
| ## Fine-tuning kit (🎯 Well-Tuned) |
|
|
| `finetune/` contains a ready-to-run Colab notebook and guide: export the captured |
| (raw read → summary) pairs from the Model tab, LoRA-tune Qwen3-1.7B on a free T4, |
| convert to GGUF, push to the Hub, and point `MODEL_ZOO` at it. The published |
| result is already wired in as the **Interpreter sub-agent**. |
|
|
| ## Hackathon track & badges |
|
|
| **Track — 🏡 Backyard AI.** A real tool for real people: my family's nightly |
| Chan-theory routine, automated and made readable. |
|
|
| Bonus badges this build targets: |
|
|
| 🎨 **Off Brand** — a hand-built **React + Spectrum 2** frontend served by |
| `gradio.Server` (the app's own HTML/CSS/JS, not the default Gradio component |
| render). · 🐜 **Tiny Titan** — the everyday language work (Signals interpret, |
| rotation narrative, news briefs) all runs on **1.7B** models, and the Interpreter |
| sub-agent is a **fine-tuned 1.7B** (≤ 4B). · 🤖 **Best Agent** — the multi-agent |
| Auto Research desk: PLAN → parallel evidence tools → Analyst + Reporter writing |
| different sections at once, every step logged. · 🎬 **Best Demo** — app + demo |
| video + social posts (links below). · 🏆 **Bonus Quest Champion** — stacking the |
| above plus the extras below. |
|
|
| Extra credentials (beyond the current badge list): all inference is **local via |
| llama.cpp**, zero cloud APIs; a **published fine-tuned model** |
| (`ranranrunforit/chan-compass-qwen3-1.7b-gguf`) the app actually uses; and each |
| research run writes a full JSON agent trace, **published as a Hub dataset** |
| ([`ranranrunforit/chan-compass-agent-traces`](https://huggingface.co/datasets/ranranrunforit/chan-compass-agent-traces), |
| one click from the Automation tab); plus a build write-up |
| ([blog post](https://huggingface.co/blog/build-small-hackathon/chan-compass)). |
|
|
| > Show, Don't Tell: 🎬 [demo video](https://www.youtube.com/watch?v=Ynwdzsf_KBA) · |
| > 📣 social posts [1](https://x.com/ranranrunforit/status/2066096644135764377), |
| > [2](https://x.com/ranranrunforit/status/2066217978773782669). |
|
|
| ## Architecture (🎨 Off-Brand) |
|
|
| This is not the default Gradio component UI. `server.py` builds a |
| **`gradio.Server`** (Gradio's FastAPI-based server) that: |
|
|
| - serves the hand-built **React + Spectrum 2 frontend** (`ui_kits/chan-compass/`) |
| as static files at `/`, and |
| - exposes the unchanged Python backend as JSON + Server-Sent-Events endpoints |
| under `/api/*` (signals, rotation, news, research, automation, model, email). |
|
|
| So the whole look-and-feel is the app's own HTML/CSS/JS — a real custom frontend — |
| while still being a Gradio app (`gradio.Server`) running through llama.cpp. |
|
|
| ## Deploy on Hugging Face Spaces |
|
|
| 1. Create a Space → SDK **Docker**, hardware **CPU upgrade** (8 vCPU/32GB recommended). |
| The included `Dockerfile` runs `uvicorn server:app` on port 7860. |
| 2. Upload every file in this folder (keep names + the `ui_kits/chan-compass/` |
| folder structure unchanged); overwrite-upload as a full set each time. |
| 3. First launch installs the llama.cpp runtime once (prebuilt CPU wheel, with a |
| compile fallback) into `/data/pylibs`. |
| 4. **Model** tab — sub-agents auto-load; watch the live status until each shows ✅. |
| 5. Optional secrets: `RESEND_API_KEY` (email), `HF_TOKEN` (faster model downloads |
| + the one-click trace publisher, silences the unauthenticated-Hub warning). |
| 6. ⚠️ Free Spaces sleep when idle, so the 18:10 ET timer can't fire unattended — |
| use "Run now", or pick always-on hardware. Last-run time is persisted to |
| `/data`, so it survives restarts. |
|
|
| ## Design system |
|
|
| UI follows the **Adobe Spectrum 2** design system. The live frontend is |
| served from `ui_kits/chan-compass/` by `gradio.Server`; the source |
| tokens/components are under `design_system/` for reference. |
|
|
| ## Files |
|
|
| `chan_engine.py` / `chan_multilevel.py` / `chan_enhance.py` — the original Chan |
| analysis engine, **verbatim, logic untouched** · `chan_glue.py` — runtime wiring + |
| analyzer cache · `data_us.py` — yfinance loader · `signal_runner.py` · `rotation.py` · |
| `news_watch.py` · `research.py` · `research_agent.py` · `automation.py` · |
| `llm_local.py` · `emailer.py` · `finetune_data.py` · `trace_publish.py` · `server.py` (the gr.Server entry) · `ui_kits/chan-compass/` (the React frontend) · |
| `finetune/` — the fine-tuning notebook + guide. |
|
|
| *Built with Love for My Family.* |
|
|