π‘οΈ What the market thermometer is
We collapse valuation, sentiment, and liquidity indicators onto a single 0β100 relative scale. 0 = the coldest the market has ever been within its lookback; 100 = the hottest ever. GitHub Actions recomputes on weekdays at 09:30 UTC for post-CN/HK close and daily at 22:00 UTC for post-US close; all numbers come from the silver layer and are reproducible from git history.
Step 1: convert each indicator to its historical percentile
Each indicator (CAPE, VIX, social financing, DXY β¦) is converted to its trailing 10-year rolling percentile. Monthly series (CAPE, M2, social financing) are forward-filled to daily first so the window has enough data points.
Step 2: direction determines hot or cold
Each indicator carries a direction in weights.yaml: + means high percentile β high temperature (e.g. high CAPE = expensive = hot); - means high percentile β low temperature (e.g. high VIX = fear = cold; strong DXY = tight global liquidity = cold).
Step 3: combine into sub-temperatures
Within each sub-temperature (valuation / sentiment / liquidity) we take a weighted average across the available indicators. Missing indicators auto-renormalise β e.g. when HK options PCR has no free source, HK sentiment falls back to 100% on southbound 5d instead of going blank.
Step 4: combine into overall temperature
The three sub-temperatures are combined per-market into the overall temperature (0β100). Bands: < 30 Cold Β· 30β70 Neutral Β· β₯ 70 Hot.
function Formula at a glance
tune Per-market weights
Loaded live from config/weights.yaml β edit and rerun finsynapse transform run --layer temperature to apply.
| Sub-temperature | Weight | Indicator | Ind. weight | Direction |
|---|---|---|---|---|
| Valuation | 65% | CSI 300 trailing P/E csi300_pe_ttm |
50% | + high pct β hot |
CSI 300 P/B csi300_pb |
50% | + high pct β hot | ||
| Sentiment | 20% | cn_north_5d cn_north_5d |
25% | + high pct β hot |
A-share 5-day turnover cn_a_turnover_5d |
25% | + high pct β hot | ||
cn_margin_balance cn_margin_balance |
35% | + high pct β hot | ||
cn_usdcny_pressure cn_usdcny_pressure |
15% | β high pct β cold | ||
| Liquidity | 15% | cn_m2_yoy cn_m2_yoy |
25% | + high pct β hot |
CN social financing (12M) cn_social_financing_12m |
25% | + high pct β hot | ||
cn_credit_impulse cn_credit_impulse |
25% | + high pct β hot | ||
cn_dr007 cn_dr007 |
25% | β high pct β cold |
| Sub-temperature | Weight | Indicator | Ind. weight | Direction |
|---|---|---|---|---|
| Valuation | 60% | HK ETF TTM dividend yield hk_ewh_yield_ttm |
100% | β high pct β cold |
| Sentiment | 25% | Southbound flow (5D) cn_south_5d |
60% | + high pct β hot |
hk_vhsi hk_vhsi |
40% | β high pct β cold | ||
| Liquidity | 15% | us10y_real_yield us10y_real_yield |
30% | β high pct β cold |
DXY dxy |
20% | β high pct β cold | ||
hk_hibor_1m hk_hibor_1m |
50% | β high pct β cold |
| Sub-temperature | Weight | Indicator | Ind. weight | Direction |
|---|---|---|---|---|
| Valuation | 35% | US trailing P/E us_pe_ttm |
35% | + high pct β hot |
US CAPE (Shiller P/E) us_cape |
35% | + high pct β hot | ||
us_erp us_erp |
30% | β high pct β cold | ||
| Sentiment | 45% | VIX vix |
40% | β high pct β cold |
us_hy_oas us_hy_oas |
35% | β high pct β cold | ||
us_umich_sentiment us_umich_sentiment |
25% | + high pct β hot | ||
| Liquidity | 20% | us10y_real_yield us10y_real_yield |
25% | β high pct β cold |
DXY dxy |
15% | β high pct β cold | ||
us_nfci us_nfci |
35% | β high pct β cold | ||
us_walcl us_walcl |
25% | + high pct β hot |
history Historical extremes & matched events
Below are the all-time hottest and coldest readings for each market's overall temperature, matched to the dominant macro event around that date. Today's "historical percentile" is where the current reading sits on this timeline.
"Historical percentile" = where today's overall temperature ranks against every trading day since data started. 99% means hotter than 99% of historical days.
| Market | Type | Date | Temp | Matched event |
|---|---|---|---|---|
| π¨π³ CN China A-share | π Today | 2026-05-14 | 79Β° (P79) | (no labelled event in window) |
| π¨π³ CN China A-share | π₯ All-time hot | 2013-01-16 | 100Β° | (no labelled event in window) |
| π¨π³ CN China A-share | π§ All-time cold | 2014-05-19 | 0Β° | (no labelled event in window) |
| ππ° HK Hong Kong | π Today | 2026-05-14 | 14Β° (P15) | (no labelled event in window) |
| ππ° HK Hong Kong | π₯ All-time hot | 2021-02-23 | 97Β° | 2021 southbound surge + tech mania peak |
| ππ° HK Hong Kong | π§ All-time cold | 2018-04-06 | 1Β° | (no labelled event in window) |
| πΊπΈ US United States | π Today | 2026-05-14 | 87Β° (P70) | (no labelled event in window) |
| πΊπΈ US United States | π₯ All-time hot | 2018-01-30 | 100Β° | (no labelled event in window) |
| πΊπΈ US United States | π§ All-time cold | 2022-03-07 | 2Β° | 2022 Fed aggressive hiking cycle |
info A few things worth knowing
- Weights are frozen once set β no curve fitting. Weekly attribution uses the same fixed weights.
- The 10-year rolling window means truly unprecedented extremes get clipped at 0 or 100. By design β the thermometer measures "position relative to history", not absolute level.
- The data_quality field tags rows as
ok(all three sub-temps produced) or<sub>_unavailable(e.g.liquidity_unavailablewhen every input in that sub-temp was missing for the day). Single-indicator gaps inside a sub-temp auto-renormalize on the available weights and don't surface in this field. - The daily brief in gold/ is just narrative β LLM or template stitches these silver numbers into prose, no new calculations.