#分享 升息不是崩潰的原因,你被騙了二十年
每次股災之後,市場都會找到一個「兇手」——升息、戰爭、病毒、關稅。媒體需要一個故事,散戶需要一個解釋,於是那個事件就成了崩潰的原因
但這個邏輯是倒過來的
真實的順序是:經濟早就開始惡化,市場能量早就耗竭殆盡,只是還沒有一個事件把它引爆。當系統已經脆弱到臨界點,任何一根稻草都能壓垮它——所以那根稻草看起來像原因,其實只是時機
換句話說,如果不是升息,就是別的。如果不是戰爭,就是數據。如果不是關稅,就是某間銀行倒閉。一個已經耗竭的市場,不缺理由崩潰,它只是在等一個藉口
這也是為什麼每次崩潰事後看都「顯而易見」,但事前沒人相信。因為大家都在等那個藉口出現,而不是在觀察市場本身的狀態
外部事件從來不是崩潰的原因,它只是扣下板機。真正決定子彈會不會打出去的,是槍膛裡有沒有火藥
D-EE 指標試圖偵測的,正是那些火藥
🔬 核心假說
牛市頂部的形成,是一個可觀測的內生耗竭過程,而非隨機事件
這個假說有三層:
第一層 — 耗竭是內生的 🔩 頂部不需要外部觸發。資金在高位越堆越多,推進效率卻越來越低,這個過程是市場參與者集體行為自發演化的結果。火藥是市場自己裝進去的
第二層 — 耗竭是可觀測的 📡 它直接體現在量價結構上:花了多少力氣(成交量 × 波動幅度),換來多少結果(實際價格推進)。比值持續升高,代表買方正在被耗盡。與此同時,價格分布從集中走向均勻,方向性悄悄消散——這是趨勢能量瓦解的物理學語言
第三層 — 耗竭是有節奏的 🎯 它不是一次性事件,而是以週期性峰值重複出現。更關鍵的是:峰值之間的間距,會隨頂部臨近而系統性收斂。間距越來越短,代表市場越來越頻繁地觸及耗竭臨界,直到結構崩塌
這就是為什麼 D-EE指標 不看新聞、不預測事件,卻能在歷次崩潰前持續預警
它偵測的不是「發生了什麼」,而是「市場還剩下多少能量」
當能量耗盡,崩潰只是時間問題,不是運氣問題
⚙️ 從假說到代碼:我怎麼把想法變成可計算的東西
假說有了,接下來的問題是:怎麼讓電腦看懂「耗竭」這件事
每個維度都要從一個可以量化的問題出發
🔋 第一個問題:市場「用力」了多少,「推進」了多少?
用力 = 成交量 × 當根K線的高低價差(代表這根K線消耗的總能量) 推進 = 成交量 × 收盤與開盤的實際距離(代表這些能量真正移動了多遠)
兩者都用長週期 RMA 平滑,再取比值。比值越高,代表能量消耗越多、實際推進越少——這就是 EMR
但單純比值沒有意義,要知道「現在的 EMR 在歷史上算高還是低」,所以還要對歷史窗口做正規化,壓縮到 0-100 的尺度。另外,下跌趨勢中的 EMR 訊號意義不同,所以用長期 EMA 判斷趨勢方向,下跌時 EMR 直接歸零,只在上漲趨勢中計算
🌀 第二個問題:價格的「方向感」消失了多少?
我用 Shannon Entropy 來度量這件事。作法是把長週期內的價格範圍切成 N 個等寬區間,然後用指數加權的方式動態更新每個區間被落入的機率。每一根K線進來,就更新一次分布
熵值用這個分布計算出來之後,再除以理論最大熵(所有區間等機率時的熵值),正規化成 0-100。數字越高,代表價格分布越均勻、方向性越弱
⚡ 第三個問題:兩者「同時加速」怎麼定義?
光看兩個數字高不高還不夠,我需要的是它們同時往上衝的那個時間窗口
作法是分別對 EMR 和熵值算一階差分,再用短週期 EMA 平滑成速度項。兩個速度項同時為正,才算「共振」。共振時,把兩個速度項相乘當作 IBI 脈衝——相乘的好處是只要有一個方向反轉,IBI 就立刻歸零,不會累積假訊號
持續共振達到最低根數門檻才開始累積 IBI 值,中斷後用衰減係數慢慢消退而非硬歸零,模擬能量殘留的物理直覺
🧮 最後:三個維度怎麼合成一個分數?
用加權線性組合打底,再疊加一個三維乘積的非線性交互項
線性部分確保任何一個維度有訊號都能反映;非線性部分確保三者同時高才會讓分數大幅拉升——這對應的假說是「真實的耗竭需要三個維度共振,缺任何一個都只是局部現象」
兩者的比例由 λ 參數控制,可以調整系統對「三維共振」的敏感程度
這就是整個設計邏輯。每一行代碼背後都有一個對應的假說要回答,而不是憑感覺堆疊指標
📍 2007-2008 次貸危機 市場在崩潰前出現 1 個紅色耗竭峰,伴隨 1 個橙色警界峰。峰值出現後市場仍撐了相當長的時間才真正崩潰——我定義為「單峰緩頂」結構,火藥裝好了,但板機扣得很慢
📍 2011 信用評級調降 這次是特殊案例。D-EE 出現了第 4 個紅色耗竭峰,間距長達 299 天,間距極長代表市場能量耗竭的速度非常緩慢,對應的正是一個拖磨型的頂部結構——不是急崩,是慢慢被榨乾的
📍 2015 中國股災 耗竭峰在崩潰前多次出現,且峰值訊號在主跌段來臨前已經累積了足夠的警告次數。這次的特徵是峰值密集、反覆觸及閾值,市場在高位震盪耗竭的時間拉得很長,直到外部衝擊點火
📍 2018 貿易戰 D-EE 在年初急跌與年底系統性下跌之前,累積出現多個耗竭峰,且峰值間距呈現收斂趨勢。這次是「長期結構型頂部」的典型——不是一次爆發,而是能量一批一批地被耗掉,直到再也撐不住
📍 2020 新冠暴跌 這次是 D-EE 最重要的反例之一。暴跌前 D-EE 沒有出現耗竭峰,分數維持在低位。這驗證了核心假說的另一面:真正的外生衝擊,市場來不及耗竭就直接崩了。新冠是板機,但槍膛裡當時沒有足夠的火藥——所以跌得快,也彈得快
📍 2022 通膨升息 崩潰前出現 2-3 個紅色耗竭峰,且峰值間距急速收斂,壓縮在 50 天以內。間距越來越短,代表市場越來越頻繁地衝擊耗竭臨界,從最後一個峰到真正崩跌只剩不到 33 天
📍 2025 關稅衝擊 峰值出現後間距迅速收斂,節奏比 2022 更快。D-EE 在主跌前已累積多個耗竭峰,收斂速度之快是近年最極端的案例之一。市場的火藥早就裝好,關稅只是那根火柴
以下為開源代碼:
//@version=6
indicator("D-EE v2.2 [雙層峰值偵測]", "D-EE", overlay=false, max_bars_back=600, max_labels_count=500)
//─────────────────────────────────────────────────────────────────────────────
// SECTION 1:參數設定
//─────────────────────────────────────────────────────────────────────────────
grp1 = "核心參數"
grp2 = "熵值設定"
grp3 = "IBI 持續性設定"
grp4 = "警戒閾值"
grp5 = "顯示設定"
grp6 = "權重設定"
grp7 = "非線性交互設定"
grp8 = "峰值偵測設定"
lp = input.int(250, "長週期窗口", minval=50, maxval=500, group=grp1)
sp = input.int(14, "短週期窗口(IBI)", minval=3, maxval=30, group=grp1)
hist_len = input.int(500, "歷史上界估算窗口", minval=200, maxval=1000, group=grp1)
src = input.source(close, "來源", group=grp1)
n_bins = input.int(8, "價格區間數", minval=4, maxval=16, group=grp2)
ibi_min_bars = input.int(3, "IBI 最低持續根數", minval=1, maxval=10, group=grp3)
ibi_decay = input.float(0.85,"IBI 中斷衰減係數", minval=0.5, maxval=0.99, step=0.01, group=grp3)
lvl_y = input.float(35.0,"🟡 黃色警戒線", step=1.0, group=grp4)
lvl_o = input.float(40.0,"🟠 橙色警戒線(警界峰)", step=1.0, group=grp4)
lvl_r = input.float(50.0,"🔴 紅色警戒線(風險遞增峰)", step=1.0, group=grp4)
show_score = input.bool(true, "顯示 D-EE Score", group=grp5)
show_emr = input.bool(false,"顯示 EMR線", group=grp5)
show_ent = input.bool(false,"顯示 熵值線", group=grp5)
show_ibi = input.bool(false,"顯示 IBI線", group=grp5)
show_bg = input.bool(true, "顯示警戒背景", group=grp5)
show_lbl = input.bool(true, "顯示事件標籤", group=grp5)
show_type = input.bool(true, "顯示股災型態推斷", group=grp5)
w_emr = input.float(0.4, "EMR 權重", minval=0.0, maxval=1.0, step=0.05, group=grp6)
w_ent = input.float(0.35, "熵值 權重", minval=0.0, maxval=1.0, step=0.05, group=grp6)
w_ibi = input.float(0.25, "IBI 權重", minval=0.0, maxval=1.0, step=0.05, group=grp6)
lambda = input.float(0.5, "λ 非線性交互強度", minval=0.0, maxval=1.0, step=0.05, group=grp7)
interact_exp = input.float(0.7, "交互項冪次", minval=0.3, maxval=1.0, step=0.05, group=grp7)
peak_timeout = input.int(200, "峰值逾時重置(日曆天)", minval=50, maxval=500, group=grp8, tooltip="每次新峰值出現後重新計時,超過此天數無新峰值則重置")
red_merge_days = input.int(10, "紅色峰合併(日曆天)", minval=3, maxval=30, group=grp8)
orange_merge_days = input.int(20, "橙色峰合併(日曆天)", minval=5, maxval=60, group=grp8)
interval_fast = input.int(50, "快速收斂閾值(日曆天)", minval=20, maxval=100, group=grp8)
interval_mid = input.int(100, "中速收斂閾值(日曆天)", minval=50, maxval=200, group=grp8)
// 毫秒轉日曆天
ms_per_day = 86400000
//─────────────────────────────────────────────────────────────────────────────
// SECTION 2:工具函數
//─────────────────────────────────────────────────────────────────────────────
abs_norm100(x, lo_abs, hi_window) =>
hi = ta.highest(x, hi_window)
rng = hi - lo_abs
rng > 0.0 ? math.min((x - lo_abs) / rng * 100.0, 100.0) : 50.0
//─────────────────────────────────────────────────────────────────────────────
// SECTION 3:EMR 努力動量比
//─────────────────────────────────────────────────────────────────────────────
effort_raw = volume * (high - low)
momentum_raw = volume * math.abs(close - open)
effort_ma = ta.rma(effort_raw, lp)
momentum_ma = ta.rma(momentum_raw, lp)
emr_raw = momentum_ma > 0.0 ? effort_ma / momentum_ma : 1.0
emr_norm_abs = abs_norm100(emr_raw, 1.0, hist_len)
ema_lp = ta.ema(src, lp)
trend_up = ema_lp > ema_lp[10]
emr_norm = trend_up ? emr_norm_abs : 0.0
//─────────────────────────────────────────────────────────────────────────────
// SECTION 4:Shannon Entropy
//─────────────────────────────────────────────────────────────────────────────
p_hi = ta.highest(src, lp)
p_lo = ta.lowest(src, lp)
p_rng = p_hi - p_lo
p_rel = p_rng > 0.0 ? (src - p_lo) / p_rng : 0.5
var float[] bin_prob = array.new_float(16, 1.0 / 8)
bin_size = 1.0 / n_bins
cur_bin = math.min(int(p_rel / bin_size), n_bins - 1)
alpha_ent = 2.0 / (lp + 1.0)
for i = 0 to n_bins - 1
hit = cur_bin == i ? 1.0 : 0.0
prev_p = array.get(bin_prob, i)
array.set(bin_prob, i, prev_p + alpha_ent * (hit - prev_p))
entropy_raw = 0.0
for i = 0 to n_bins - 1
p_i = array.get(bin_prob, i)
if p_i > 0.001
entropy_raw -= p_i * math.log(p_i) / math.log(2.0)
max_entropy = math.log(float(n_bins)) / math.log(2.0)
entropy_norm = max_entropy > 0.0 ? (entropy_raw / max_entropy) * 100.0 : 0.0
//─────────────────────────────────────────────────────────────────────────────
// SECTION 5:IBI 慣性破壞係數
//─────────────────────────────────────────────────────────────────────────────
emr_vel = ta.ema(emr_norm_abs - emr_norm_abs[1], sp)
ent_vel = ta.ema(entropy_norm - entropy_norm[1], sp)
both_rising = emr_vel > 0.0 and ent_vel > 0.0
ibi_pulse = both_rising ? emr_vel * ent_vel : 0.0
var int ibi_count = 0
var float ibi_val = 0.0
ibi_count := both_rising ? ibi_count + 1 : 0
if ibi_count >= ibi_min_bars
ibi_val := ibi_pulse
else if not both_rising
ibi_val := ibi_val * ibi_decay
ibi_hi = ta.highest(ibi_val, hist_len)
ibi_norm = ibi_hi > 0.0 ? math.min(ibi_val / ibi_hi * 100.0, 100.0) : 0.0
//─────────────────────────────────────────────────────────────────────────────
// SECTION 6:D-EE Score 合成
//─────────────────────────────────────────────────────────────────────────────
w_sum = w_emr + w_ent + w_ibi
linear_score = (emr_norm * w_emr + entropy_norm * w_ent + ibi_norm * w_ibi) / w_sum
interaction = math.pow(emr_norm / 100.0, interact_exp) * math.pow(entropy_norm / 100.0, interact_exp) * math.pow(ibi_norm / 100.0, interact_exp) * 100.0
ee_score = (1.0 - lambda) * linear_score + lambda * interaction
//─────────────────────────────────────────────────────────────────────────────
// SECTION 7:警戒狀態
//─────────────────────────────────────────────────────────────────────────────
at_yellow = ee_score >= lvl_y
at_orange = ee_score >= lvl_o
at_red = ee_score >= lvl_r
bg_col = show_bg ? (at_red ? color.new(#ff1744, 70) : at_orange ? color.new(#ff6b00, 78) : at_yellow ? color.new(#f5c518, 88) : na) : na
bgcolor(bg_col)
//─────────────────────────────────────────────────────────────────────────────
// SECTION 8:雙層峰值偵測系統(日曆天版本)
//─────────────────────────────────────────────────────────────────────────────
var int r_peak_count = 0
var int r_peak_interval = 0 // 日曆天
var int r_peak_interval_prev = 0 // 日曆天
var float r_peak_score_max = 0.0
var bool r_in_peak = false
var int o_peak_count = 0
var float o_peak_score_max = 0.0
var bool o_in_peak = false
// 用 time(毫秒時間戳)記錄峰值發生時間,換算成日曆天
var int r_peak_time_last = 0 // 上一個紅色峰的 time(ms)
var int o_peak_time_last = 0 // 上一個橙色峰的 time(ms)
var int first_peak_time = 0 // 本週期第一個峰的 time(ms)
// 黑天鵝判斷旗標:只有從未有過任何峰值(全新週期)才可能是黑天鵝
// 重置後 is_fresh_cycle = true,出現第2個峰後永遠是 false
var bool is_fresh_cycle = true
entered_red = at_red and not at_red[1]
exited_red = not at_red and at_red[1]
entered_orange = at_orange and not at_orange[1] and not at_red
exited_orange = not at_orange and at_orange[1] and not at_red
// 當前 time 轉換為日曆天的輔助計算
cur_time = time
// 逾時計算(日曆天):從最後一個峰起算
last_any_peak_time = r_peak_time_last > o_peak_time_last ? r_peak_time_last : o_peak_time_last
any_peak_count = r_peak_count + o_peak_count
days_since_last_any = any_peak_count > 0 ? int((cur_time - last_any_peak_time) / ms_per_day) : 0
days_since_first = any_peak_count > 0 ? int((cur_time - first_peak_time) / ms_per_day) : 0
do_reset = any_peak_count > 0 and days_since_last_any >= peak_timeout and not at_orange
if do_reset
r_peak_count := 0
r_peak_interval := 0
r_peak_interval_prev := 0
r_peak_score_max := 0.0
r_in_peak := false
o_peak_count := 0
o_peak_score_max := 0.0
o_in_peak := false
r_peak_time_last := 0
o_peak_time_last := 0
first_peak_time := 0
// ── 紅色風險遞增峰 ──
days_since_last_red = r_peak_count > 0 ? int((cur_time - r_peak_time_last) / ms_per_day) : 999
is_new_red = entered_red and not do_reset and (r_peak_count == 0 or days_since_last_red > red_merge_days)
is_same_red = entered_red and not do_reset and r_peak_count > 0 and days_since_last_red <= red_merge_days
if is_new_red
r_peak_interval_prev := r_peak_count > 0 ? r_peak_interval : 0
r_peak_interval := r_peak_count > 0 ? int((cur_time - r_peak_time_last) / ms_per_day) : 0
r_peak_count := r_peak_count + 1
r_peak_time_last := cur_time
r_peak_score_max := ee_score
r_in_peak := true
if first_peak_time == 0
first_peak_time := cur_time
if is_same_red
r_peak_time_last := cur_time
r_peak_score_max := math.max(r_peak_score_max, ee_score)
r_in_peak := true
if r_in_peak and at_red and not entered_red
r_peak_score_max := math.max(r_peak_score_max, ee_score)
if exited_red
r_in_peak := false
// ── 橙色警界峰(未達紅色才計)──
days_since_last_orange = o_peak_count > 0 ? int((cur_time - o_peak_time_last) / ms_per_day) : 999
is_new_orange = entered_orange and not do_reset and (o_peak_count == 0 or days_since_last_orange > orange_merge_days)
is_same_orange = entered_orange and not do_reset and o_peak_count > 0 and days_since_last_orange <= orange_merge_days
if is_new_orange
o_peak_count := o_peak_count + 1
o_peak_time_last := cur_time
o_peak_score_max := ee_score
o_in_peak := true
if first_peak_time == 0
first_peak_time := cur_time
if is_same_orange
o_peak_time_last := cur_time
o_peak_score_max := math.max(o_peak_score_max, ee_score)
o_in_peak := true
if o_in_peak and at_orange and not at_red and not entered_orange
o_peak_score_max := math.max(o_peak_score_max, ee_score)
if exited_orange
o_in_peak := false
// 紅色峰收斂判斷
r_converging = r_peak_count >= 3 and r_peak_interval_prev > 0 and r_peak_interval < r_peak_interval_prev
// 減倉建議
reduce_pct = r_peak_count <= 1 ? 0 : r_peak_count == 2 and r_peak_interval > interval_mid ? 10 : r_peak_count == 2 and r_peak_interval > interval_fast ? 20 : r_peak_count == 2 ? 30 : r_peak_count == 3 and r_converging ? 40 : r_peak_count == 3 ? 30 : r_converging ? math.min(10 * r_peak_count, 70) : math.min(10 * (r_peak_count - 1), 60)
//─────────────────────────────────────────────────────────────────────────────
// SECTION 9:股災型態推斷
// 黑天鵝條件:必須是 is_fresh_cycle(全新週期,從未累積過多個峰值)
// 不再用 days_since_first,避免重置後誤判
//─────────────────────────────────────────────────────────────────────────────
// 重置後的當根 any_peak_count 已歸零,用實際歸零後的值來判斷型態
effective_peak_count = do_reset ? 0 : any_peak_count
effective_r_count = do_reset ? 0 : r_peak_count
effective_o_count = do_reset ? 0 : o_peak_count
// 型態比對邏輯(根據 SOXX 2004-2025 實測數據)
// 優先順序:峰值數 → 間距 → 收斂速度 → 警界峰數量
// 計算平均間距(只有2個以上紅色峰才有意義)
avg_interval = r_peak_count >= 2 ? (r_peak_interval + r_peak_interval_prev) / 2 : 0
crash_type =
effective_peak_count == 0 ? "✅ 等待訊號" :
// 單紅色峰 + 大量警界峰 → 2004政策驅動超早型
effective_r_count == 1 and effective_o_count >= 3 ? "🕐 類2004 政策驅動超早型 | 預警可能300+天 | 從容分批減倉" :
// 單紅色峰 + 少量警界峰 → 觀察中,可能是2011或2020
effective_r_count == 1 and effective_o_count <= 1 ? "🔍 類2011/2020 觀察中 | 單峰無法判斷 | 等第2峰確認" :
// 單紅色峰 + 中等警界峰
effective_r_count == 1 ? "🔍 觀察中(第1風險遞增峰) | 等第2峰判斷間距" :
// 雙紅色峰 + 間距收斂快(<50天)→ 類2022
effective_r_count == 2 and r_peak_interval < interval_fast ? "⚠ 類2022 中等累積加速型 | 間距急縮 | 最後峰後約33天 | 立即減倉30%" :
// 雙紅色峰 + 間距中等(50-100天)→ 類2008
effective_r_count == 2 and r_peak_interval >= interval_fast and r_peak_interval < interval_mid ? "📊 類2008 中等累積型 | 間距中等 | 最後峰後約144天 | 減倉20%" :
// 雙紅色峰 + 間距較長(>100天)→ 類2008緩慢版
effective_r_count == 2 ? "📊 類2008 中等累積型(緩) | 間距寬鬆 | 減倉10%" :
// 三紅色峰 + 收斂中 → 類2025
effective_r_count == 3 and r_converging ? "⚠ 類2025 中等累積加速型 | 間距收斂中 | 最後峰後約35天 | 減倉40%" :
// 三紅色峰 + 未收斂 → 類2022擴展版
effective_r_count == 3 and not r_converging ? "📊 類2022擴展 中等累積型 | 間距持平 | 減倉30%" :
// 四紅色峰 + 收斂 → 類2018
effective_r_count == 4 and r_converging ? "🏗 類2018 長期結構型(收斂) | 間距加速縮短 | 最後峰後約90天 | 減倉50%" :
// 四紅色峰 + 未收斂 → 類2018早期
effective_r_count == 4 ? "🏗 類2018 長期結構型 | 間距尚未收斂 | 減倉40%" :
// 五紅色峰以上 + 大量警界峰 → 類2015
effective_r_count >= 5 and effective_o_count >= 3 ? "🏗 類2015 長期結構型 | 出場機會最多 | 最後峰後約44天 | 減倉60%" :
// 五紅色峰以上
effective_r_count >= 5 ? "🏗 類2015/2018 長期結構型 | 多峰累積 | 減倉60%" :
// 只有橙色峰
effective_r_count == 0 and effective_o_count >= 2 ? "👁 早期預警累積中 | 等待紅色風險遞增峰" :
effective_r_count == 0 and effective_o_count == 1 ? "👁 早期預警初現 | 單一警界峰,持續觀察" :
"🔍 持續觀察中"
//─────────────────────────────────────────────────────────────────────────────
// SECTION 10:繪圖
//─────────────────────────────────────────────────────────────────────────────
plot(show_emr ? emr_norm : na, "EMR", color.new(#ff9800, 20), 1)
plot(show_ent ? entropy_norm : na, "熵值", color.new(#2196f3, 20), 1)
plot(show_ibi ? ibi_norm : na, "IBI", color.new(#e040fb, 30), 1)
ee_col = at_red ? #ff1744 : at_orange ? #ff6b00 : at_yellow ? #f5c518 : #089981
p_ee = plot(show_score ? ee_score : na, "D-EE Score", ee_col, 2)
p_mid = plot(50, color=na, editable=false)
fill(p_ee, p_mid, ee_score > 50.0 ? color.new(#ff5252, 92) : color.new(#089981, 92))
hline(lvl_r, "🔴 風險遞增峰線", color.new(#ff1744, 40), linestyle=hline.style_dashed)
hline(lvl_o, "🟠 警界峰線", color.new(#ff6b00, 40), linestyle=hline.style_dashed)
hline(lvl_y, "🟡 黃色警戒", color.new(#f5c518, 40), linestyle=hline.style_dashed)
hline(50, "中線", color.new(color.gray, 60), linestyle=hline.style_dotted)
//─────────────────────────────────────────────────────────────────────────────
// SECTION 11:事件標籤
//─────────────────────────────────────────────────────────────────────────────
if barstate.isconfirmed
if show_lbl and is_new_orange
label.new(bar_index, ee_score + 4, "🟠 警界峰#" + str.tostring(o_peak_count), style=label.style_label_down, color=#ff6b00, textcolor=color.white, size=size.tiny)
if show_lbl and is_new_red and r_peak_count == 1
label.new(bar_index, ee_score + 4, "⚠ 風險遞增峰#1 | 停止加倉 | 警界峰" + str.tostring(o_peak_count) + "個", style=label.style_label_down, color=#f5c518, textcolor=color.black, size=size.small)
if show_lbl and is_new_red and r_peak_count >= 2
lbl_col = r_peak_interval < interval_fast ? #ff1744 : r_peak_interval < interval_mid ? #ff6b00 : #f5c518
label.new(bar_index, ee_score + 4, "🔴 風險遞增峰#" + str.tostring(r_peak_count) + " | 間距:" + str.tostring(r_peak_interval) + "天 " + (r_converging ? "↓收斂" : "→持平") + " | 減倉" + str.tostring(reduce_pct) + "%", style=label.style_label_down, color=lbl_col, textcolor=color.white, size=size.small)
if show_lbl and do_reset
label.new(bar_index, lvl_y - 4, "🔄 週期重置 | 紅色峰" + str.tostring(r_peak_count) + "個 / 警界峰" + str.tostring(o_peak_count) + "個", style=label.style_label_up, color=#089981, textcolor=color.white, size=size.small)
if show_lbl and ta.crossunder(ee_score, lvl_y) and any_peak_count > 0 and not do_reset
label.new(bar_index, ee_score - 3, "✅ 風險緩解 | 逾時重置剩" + str.tostring(peak_timeout - days_since_last_any) + "天", style=label.style_label_up, color=#089981, textcolor=color.white, size=size.small)
//─────────────────────────────────────────────────────────────────────────────
// SECTION 12:資訊面板
//─────────────────────────────────────────────────────────────────────────────
var table info = table.new(position.top_right, 2, 10, border_width=1, bgcolor=color.new(color.black, 20))
if barstate.islast
int_col = r_peak_count < 2 ? color.gray : r_peak_interval < interval_fast ? color.red : r_peak_interval < interval_mid ? color.orange : color.yellow
conv_str = r_peak_count < 3 ? "─" : r_converging ? "↓ 收斂中" : "→ 持平"
conv_col = r_converging ? color.red : color.gray
red_col = reduce_pct >= 50 ? color.red : reduce_pct >= 30 ? color.orange : reduce_pct >= 10 ? color.yellow : color.green
days_left = peak_timeout - days_since_last_any
table.cell(info, 0, 0, "D-EE 雙層峰值系統", bgcolor=color.new(#ff1744,40), text_color=color.white, text_size=size.normal)
table.cell(info, 1, 0, "v2.2", bgcolor=color.new(#ff1744,40), text_color=color.white)
table.cell(info, 0, 1, "D-EE Score", text_color=color.gray)
table.cell(info, 1, 1, str.tostring(ee_score, "#.##"), text_color=ee_col)
table.cell(info, 0, 2, "🔴 風險遞增峰", text_color=color.gray)
table.cell(info, 1, 2, r_peak_count > 0 ? "第" + str.tostring(r_peak_count) + "峰" : "未出現", text_color=r_peak_count > 0 ? color.red : color.green)
table.cell(info, 0, 3, "🟠 警界峰", text_color=color.gray)
table.cell(info, 1, 3, o_peak_count > 0 ? "共" + str.tostring(o_peak_count) + "峰" : "未出現", text_color=o_peak_count > 0 ? color.orange : color.green)
table.cell(info, 0, 4, "風險遞增峰間距", text_color=color.gray)
table.cell(info, 1, 4, r_peak_count >= 2 ? str.tostring(r_peak_interval) + " 天" : "─", text_color=int_col)
table.cell(info, 0, 5, "收斂狀態", text_color=color.gray)
table.cell(info, 1, 5, conv_str, text_color=conv_col)
table.cell(info, 0, 6, "逾時倒數", text_color=color.gray)
table.cell(info, 1, 6, any_peak_count > 0 ? str.tostring(days_left) + " 天" : "─", text_color=days_left < peak_timeout * 0.3 ? color.orange : color.gray)
table.cell(info, 0, 7, "建議減倉", text_color=color.gray)
table.cell(info, 1, 7, any_peak_count > 0 ? str.tostring(reduce_pct) + "%" : "持倉", text_color=red_col)
table.cell(info, 0, 8, "━━━━━━━", text_color=color.new(color.gray,60), text_size=size.small)
table.merge_cells(info, 0, 8, 1, 8)
type_col = crash_type == "✅ 無風險信號" ? color.green : str.contains(crash_type, "黑天鵝") ? color.red : str.contains(crash_type, "加速") ? color.red : str.contains(crash_type, "長期") ? color.orange : color.yellow
table.cell(info, 0, 9, "推斷型態", text_color=color.gray)
table.cell(info, 1, 9, show_type ? crash_type : "已隱藏", text_color=type_col, text_size=size.small)
//─────────────────────────────────────────────────────────────────────────────
// SECTION 13:Alert 條件
//─────────────────────────────────────────────────────────────────────────────
alertcondition(is_new_orange, "[D-EE] 🟠 警界峰出現", "橙色警界峰觸發,開始監控風險遞增峰")
alertcondition(is_new_red and r_peak_count == 1, "[D-EE] ⚠ 風險遞增峰#1:停止加倉", "紅色風險遞增峰首次出現")
alertcondition(is_new_red and r_peak_count == 2, "[D-EE] 🔴 風險遞增峰#2:開始減倉", "第2風險遞增峰,建議減倉10-30%")
alertcondition(is_new_red and r_peak_count == 3, "[D-EE] 🔴 風險遞增峰#3:加速減倉", "第3風險遞增峰,間距收斂中")
alertcondition(is_new_red and r_peak_count >= 4, "[D-EE] 🚨 風險遞增峰#4+:防禦倉位","累積4個以上風險遞增峰")
alertcondition(do_reset, "[D-EE] 🔄 週期重置", "逾時無新峰值,計數器歸零")此指標已經整合進LEI指標裡,作為S6維度的判斷有興趣指標或交流的,歡迎嘉我的DC








