feedback
← 回到目錄

指標建議做法:標準化

原始數值很難設門檻。標準化後的數值告訴你當前讀數有多不尋常——這才是真正重要的事。

原始指標值的問題

假設你想建一個「買盤強勁時做多」的策略。你用淨市價買量作為訊號。在平靜的一週這個數值可能是 8,420 BTC,在劇烈波動的時期可能是 85,000 BTC。門檻要設多少?任何固定數字,一半的時候太敏感,另一半的時候又太遲鈍。

價格衍生的指標也有同樣問題:BTC 在 2 萬美元時,SMA 差值 500 USDT 代表一回事;在 9 萬美元時,完全是另一回事。

標準化把原始數值轉換成一個問題:「這個讀數距離正常值有幾個標準差?」 這讓讀數在不同市場環境和不同標的之間都有可比性。

滾動 Z-score:最實用的方法

Z-score 衡量當前值距離近期均值有幾個標準差:

z = (當前值 - 滾動均值) / 滾動標準差

用 30 天的滾動窗口,Z-score +2.0 代表當前讀數比過去一個月的平均高了 2 個標準差——不尋常,但不算極端。+3.5 就是近期標準來看非常高了。

Z-score 有個很好的特性:它大致上是無量綱的,可以跨標的比較。BTCUSDT 的 TI Z-score +2.0 和 ETHUSDT 的 TI Z-score +2.0 代表大致相同的意義——兩者相對於各自的近期歷史都是異常偏高。

在策略裡實作滾動 Z-score:

window = 720  # 30 天 × 24h,適用於 1h 週期
df['z'] = (
    (df['raw_indicator'] - df['raw_indicator'].rolling(window).mean())
    / df['raw_indicator'].rolling(window).std()
)

Blave Alpha 指標已經完成標準化

你不需要自己標準化 Blave 的獨家指標。它們已經以標準化的分數交付,可以跨標的和時間段比較:

指標已標準化?說明
多空力道(TI)相對於滾動近期歷史標準化;可跨標的比較
籌碼集中度(HC)標準化;正值代表多頭集中,負值代表空頭集中
巨鯨警報(WH)OI 和成交量變化各自標準化
爆倉(LQ)標準化的爆倉強度
市場情緒(MS)現貨合約價差,標準化
資金稀缺(CS)穩定幣利用率,標準化
市場方向(MD)全市場 BTC 方向訊號,標準化
擠壓動能(SM)固定 1d 週期;附 scolor 方向標籤

這就是為什麼使用 Blave 指標的門檻策略用的是 ENTRY_TH = 1.693 這樣的數字,而不是原始的成交量數字——那個門檻有一致的意義:「當 TI 高於近期平均 1.7 個標準差時進場。」

標準化數值會隨 lookback 窗口衰退。 因為這些指標是相對於滾動窗口標準化的,同樣的絕對讀數在低波動和高波動的市場環境下可能代表不同的原始值。TI +2.0 在低波動月份代表的原始買盤力道,可能遠小於高波動月份的 TI +2.0。解讀 Blave 指標讀數時,要結合當前的市場環境。

什麼時候你需要自己標準化

不是所有指標都需要標準化。SMA 交叉訊號(SMA_fast > SMA_slow)本身已經是二元的——沒有什麼需要標準化。問題出現在你把指標的大小當作門檻的時候。

範例 1 — SMA 差值作為門檻

直接用價格減 SMA 的原始值設門檻,跨價格環境就會失效:

# ✗ BTC 從 2 萬漲到 9 萬之後,這個門檻就失準了
signal[df['Close'] - df['SMA_50'] > 500] = 1.0

# ✓ 用同一個差值的 Z-score,跨時期都有意義
diff = df['Close'] - df['SMA_50']
df['diff_z'] = (diff - diff.rolling(720).mean()) / diff.rolling(720).std()
signal[df['diff_z'] > 1.5] = 1.0

範例 2 — MACD 跨標的

MACD 的單位是價格,不同標的之間完全不可比較:

# ✗ MACD = 800 在 BTCUSDT 和台積電上代表完全不同的意義
signal[df['MACD'] > 800] = 1.0

# ✓ 對每個標的各自標準化,再用相同門檻
df['macd_z'] = (df['MACD'] - df['MACD'].rolling(720).mean()) / df['MACD'].rolling(720).std()
signal[df['macd_z'] > 1.0] = 1.0

範例 3 — 組合兩個指標

RSI(0–100)和原始 OI(數十億美元)不能直接相加,量級差太多:

# ✗ OI 的數值完全蓋掉 RSI 的訊號
combined = df['RSI'] + df['OI']

# ✓ 兩個都標準化後再合併
rsi_z = (df['RSI'] - df['RSI'].rolling(720).mean()) / df['RSI'].rolling(720).std()
oi_z  = (df['OI']  - df['OI'].rolling(720).mean())  / df['OI'].rolling(720).std()
combined = rsi_z + oi_z
signal[combined > 1.5] = 1.0

範例 4 — 股東人數(台股)

不同持股區間的股東人數(例如持有 1,000–5,000 股的人數)在大型股和小型股之間差距極大。台積電的散戶股東可能有數十萬人;小型股可能只有幾千人。原始人數無法作為跨股票的門檻。

真正有意義的是相對於該股自己近期歷史的變化——散戶參與度是否異常快速增加?把人數(或其變化率)相對於每檔股票自身的滾動窗口做標準化:

# 原始散戶股東人數無法跨股票比較
# ✗ 作為跨股票門檻沒有意義
signal[df['retail_holders'] > 50000] = 1.0

# ✓ 對每檔股票分別標準化:當前人數有多不尋常?
df['holders_z'] = (
    (df['retail_holders'] - df['retail_holders'].rolling(52).mean())
    / df['retail_holders'].rolling(52).std()   # 52 週滾動窗口
)
# Z-score > 2:散戶異常擁擠 → 可能的反向放空訊號
signal[df['holders_z'] > 2.0] = 0.0
signal[df['holders_z'] < -1.0] = 1.0

同樣的原則適用於融資餘額(margin_balance)、外資買賣超(foreign_net),或任何其他台股資料中絕對量級隨公司規模變化的欄位。

其他常用的標準化方法

方法公式適合
滾動 Z-score(x − 均值) / 標準差大多數指標;保留極端值資訊
百分位排名在滾動窗口內的 rank / count輸出有界 [0, 1];對極端值有抵抗力
Min-max(x − 最小值) / (最大值 − 最小值)簡單,但容易被窗口內的極端值扭曲

對大多數 Type A 策略來說,滾動 Z-score 是預設的最佳選擇。如果你想要有界的訊號(例如「歷史讀數的前 10%」),且不想被窗口中的極端值影響 Z-score,百分位排名是更好的替代。

← 回到目錄