ranranrunforit commited on
Commit
624c93f
·
verified ·
1 Parent(s): c341e23

Upload 22 files

Browse files
Files changed (2) hide show
  1. BLOG_DRAFT.md +79 -48
  2. Dockerfile +21 -0
BLOG_DRAFT.md CHANGED
@@ -1,69 +1,100 @@
1
- # Field Notes: Putting a 20-Year-Old Chinese Trading Theory on a 4B Model
2
 
3
- *Built for the Build Small hackathon — a Gradio Space, a llama.cpp runtime, and zero cloud APIs.*
4
 
5
  ## The problem (a real one)
6
 
7
  My family trades US stocks using 缠论 (Chan theory) — a Chinese technical-analysis
8
  framework built on fractals, strokes, segments and "pivots" (中枢), famous for its
9
  rigor and infamous for its complexity. We had a battle-tested Python engine that
10
- decomposes monthly → weekly → daily → 60m → 30m charts and emits the classic
11
- three buy / three sell points. Two problems: the engine's reasoning logs are
12
- dense Chinese jargon, and someone had to run it by hand every evening.
13
 
14
  **Chan Compass** fixes both: a Gradio Space that auto-updates after the US close
15
  (18:10 ET), answers exactly one question per ticker — *do I buy or sell tomorrow,
16
- in which price zone, and where am I wrong?* — and uses a small local model as the
17
- translator and analyst the rule engine can't be.
18
 
19
- ## Why a small model is the honest fit
20
 
21
- This is the part I want to stress: the LLM is **not** doing the math. Fractal
22
- merging, divergence grading and nested-interval confirmation are deterministic
23
- code — a 32B (or 320B) model would add nothing but hallucination risk. What the
24
- rule engine can't do is *language*: explain a Chinese decision chain in plain
25
- English, brief today's headlines on my holdings, narrate sector rotation, write
26
- a structured research note. That's bounded, evidence-grounded text work — exactly
27
- what Qwen3-4B (Q4_K_M, ~2.5 GB) handles on 8 CPU cores. The constraint wasn't a
28
- limitation; it drew the architecture: **rules compute, the small model speaks.**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  ## What's in the box
31
 
32
- * **Tomorrow's plan** — one row per ticker: BUY/SELL/HOLD/WAIT, entry zone,
33
- invalidation price. Long-hold mode: ride the weekly pivot uplift, exit only on
34
- third-sell / structural stop / an armed nested-interval line.
35
- * **Sector rotation** — flow proxy (Δ% × dollar volume) across the 11 SPDR
36
- sector ETFs vs SPY, 1/5/20-day windows, with an on-demand AI narrative.
37
- * **Auto Research agent** — PLAN five evidence tools (fundamentals, quarterly
38
- financials, price action, *the Chan engine itself*, news) → sectioned report
39
- (valuation · moat & supply-chain position · bull/bear · Chan timing · risks).
40
- Every step is logged to a JSON trace; new tickers entering the pool get a
41
- report generated automatically by the daily pipeline.
42
- * **Spectrum 2 UI** Adobe's design language approximated in Gradio CSS:
43
- pill buttons, `#0265DC`, Source Sans 3.
44
-
45
- ## Three things I learned the hard way
46
-
47
- 1. **HF Spaces build containers are tiny.** `llama-cpp-python` compiling from
48
- source got OOM-killed at build time on a Space with 32 GB of *runtime* RAM.
49
- Fix: install the runtime at first launch instead (prebuilt CPU wheel, with a
50
- memory-capped compile fallback), persisted to the `/data` storage bucket so
51
- it happens exactly once. Also: pin `python_version: 3.11`, because prebuilt
52
- wheels stop at 3.12.
53
- 2. **Don't put the model on the hot path.** My first version generated an AI
54
- rotation narrative inside "Run analysis" 10 tickers took 186 s. Moving all
55
- LLM calls to on-demand buttons and parallelizing the data downloads brought
56
- the rule-engine path to a few seconds. CPU inference is fine for a 4B model;
 
 
57
  it just can't be a synchronous dependency of everything.
58
- 3. **Global CSS is a loaded gun.** A single `button { border-radius: 999px }`
59
- for Spectrum-style pills turned Gradio Dataframe's internal sort/fullscreen
60
- icons into giant ovals floating over the data. Scope your selectors.
 
 
 
61
 
62
  ## What's next
63
 
64
- A LoRA fine-tune of Qwen3-1.7B on pairs of (Chan decision chain plain-English
65
- explanation) mined from the app's own logs making the tiniest model the best
66
- Chan translator on the Hub — and publishing the agent traces as a dataset.
67
 
68
  *Not investment advice. Engine logic unchanged from the original; the app around
69
- it is what this hackathon built.*
 
1
+ # Field Notes: Putting a 20-Year-Old Chinese Trading Theory on a Fine-Tuned 1.7B
2
 
3
+ *Built for the Build Small hackathon — a Gradio Space, a local llama.cpp sub-agent pool, a model I fine-tuned myself, and zero cloud APIs.*
4
 
5
  ## The problem (a real one)
6
 
7
  My family trades US stocks using 缠论 (Chan theory) — a Chinese technical-analysis
8
  framework built on fractals, strokes, segments and "pivots" (中枢), famous for its
9
  rigor and infamous for its complexity. We had a battle-tested Python engine that
10
+ decomposes monthly → weekly → daily → 60m → 30m → 15m → 5m charts and emits the
11
+ classic three buy / three sell points. Two problems: the engine's reasoning logs
12
+ are dense Chinese jargon, and someone had to run it by hand every evening.
13
 
14
  **Chan Compass** fixes both: a Gradio Space that auto-updates after the US close
15
  (18:10 ET), answers exactly one question per ticker — *do I buy or sell tomorrow,
16
+ at what buy point, in which zone, and where am I wrong?* — and uses a pool of small
17
+ local models as the translators and analysts the rule engine can't be.
18
 
19
+ ## Why small models are the honest fit
20
 
21
+ The LLMs are **not** doing the math. Fractal merging, divergence grading and
22
+ nested-interval confirmation are deterministic code — a 32B (or 320B) model would
23
+ add nothing but hallucination risk and latency. What the rule engine can't do is
24
+ *language*: turn a Chinese decision chain into a plain-English summary, brief
25
+ today's headlines on my holdings, narrate sector rotation, write a structured
26
+ research note. That's bounded, evidence-grounded text work — exactly what 1.7B–4B
27
+ models handle on 8 CPU cores. The constraint drew the architecture: **rules
28
+ compute, small models speak.**
29
+
30
+ ## A pool of sub-agents, not one model
31
+
32
+ Early versions shared a single model behind one lock, so the moment two features
33
+ ran at once you'd get "model busy." The fix was a **sub-agent pool** — four small
34
+ models, each with its own lock, running through llama.cpp:
35
+
36
+ * **Summary** (Signals → AI Summary) — my **fine-tuned Chan-Tuned Qwen3-1.7B**
37
+ * **Narrator** (sector rotation) — Qwen3-1.7B
38
+ * **Reporter** (watchlist news + research support) — Qwen3-1.7B
39
+ * **Analyst** (Auto Research) — Qwen3-4B
40
+
41
+ They genuinely run in parallel: you can stream a research report while the Signals
42
+ summary writes, with no collision.
43
+
44
+ ## The fine-tune (the part I'm proudest of)
45
+
46
+ The Summary sub-agent runs a model I trained myself. The app captures every
47
+ (raw read → English summary) pair it produces into a dataset on the `/data`
48
+ bucket; a couple hundred focused pairs later, I exported the JSONL straight from
49
+ the app's Model tab, LoRA-tuned **Qwen3-1.7B** on a free Colab T4 with Unsloth,
50
+ converted to GGUF, and published it to the Hub
51
+ (`ranranrunforit/chan-compass-qwen3-1.7b-gguf`). One line in `MODEL_ZOO` wires it
52
+ back in. The loop closes: the app generated its own training data, and now runs on
53
+ the model that data produced — a 1.7B doing one job well instead of a giant model
54
+ doing everything adequately.
55
 
56
  ## What's in the box
57
 
58
+ * **Tomorrow's plan** — one row per ticker: BUY/SELL/HOLD/WAIT, explicit **buy
59
+ point**, entry zone, invalidation price. Long-hold mode: ride the weekly pivot
60
+ uplift, exit only on third-sell / structural stop / an armed nested-interval line.
61
+ * **Sector rotation** — flow proxy (Δ% × dollar volume) across the 11 SPDR sector
62
+ ETFs vs SPY, 1/5/20-day windows, instant tables + on-demand AI narrative.
63
+ * **Watchlist news** — today-only headlines per holding, streamed as they arrive,
64
+ each with an AI brief.
65
+ * **Multi-agent Auto Research** PLAN six evidence tools in parallel
66
+ (fundamentals, financials, price, *the Chan engine itself*, money-flow proxy,
67
+ news) Analyst and Reporter writing different sections **simultaneously**:
68
+ valuation · tech moat · supply-chain map with tickers · bull/bear · money flow ·
69
+ Chan timing · risks. Every run writes a full JSON trace — the plan, each tool
70
+ call and its result, each sub-agent's request and response — **published as a Hub
71
+ dataset** so anyone can see how the agent actually reasoned.
72
+ * **Email any result** — each tab can email its output; on HF (where SMTP is
73
+ blocked) delivery goes over the Resend HTTPS API, markdown rendered to clean HTML.
74
+ * **Spectrum 2 UI**Adobe's design language in Gradio.
75
+
76
+ ## Four things I learned the hard way
77
+
78
+ 1. **HF build containers are tiny.** `llama-cpp-python` got OOM-killed compiling at
79
+ *build* time on a Space with 32 GB of *runtime* RAM. Fix: install the runtime at
80
+ first launch (prebuilt CPU wheel, capped-compile fallback), persisted to `/data`
81
+ so it happens once. Pin `python_version: 3.11` prebuilt wheels stop at 3.12.
82
+ 2. **Don't put the model on the hot path.** My first "Run analysis" generated an AI
83
+ narrative inline — 10 tickers took 186 s. Moving all LLM calls off the rule path
84
+ and parallelizing downloads brought it to a few seconds. CPU inference is fine;
85
  it just can't be a synchronous dependency of everything.
86
+ 3. **One lock per model.** A shared lock turns concurrent features into "model
87
+ busy." A sub-agent pool one instance and lock per job — fixed it and made the
88
+ fine-tune swappable for just the one agent that needed it.
89
+ 4. **Platforms block SMTP; ship HTTPS email.** Outbound mail ports are closed on
90
+ Spaces, so email failed with "network unreachable." The Resend REST API over
91
+ 443 works — and it needs a `User-Agent` header or Cloudflare 403s you.
92
 
93
  ## What's next
94
 
95
+ The agent traces are already public as a Hub dataset; next I want to grow the
96
+ fine-tune set so the Summary model keeps sharpening on exactly the phrasing this
97
+ task needs, and feed real family usage back into that loop.
98
 
99
  *Not investment advice. Engine logic unchanged from the original; the app around
100
+ it — and the model that explains it — is what this hackathon built.*
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ RUN useradd -m -u 1000 user
4
+ WORKDIR /app
5
+
6
+ # system deps for building wheels if needed
7
+ RUN apt-get update && apt-get install -y --no-install-recommends \
8
+ build-essential git curl && rm -rf /var/lib/apt/lists/*
9
+
10
+ COPY --chown=user requirements.txt requirements.txt
11
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
12
+
13
+ COPY --chown=user . /app
14
+ USER user
15
+
16
+ ENV HOME=/home/user \
17
+ PATH=/home/user/.local/bin:$PATH \
18
+ AUTO_LOAD_MODEL=1
19
+
20
+ EXPOSE 7860
21
+ CMD ["python", "app.py"]