Indicator · Pine Script v6 · Own pane

FVG Screener TW

by gplee789-afk

This indicator scans up to 40 symbols across a user-defined timeframe to identify Smart Money Concepts Fair Value Gaps, Inversion FVGs, displacement bars, and internal order blocks.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code510
Settings36inputs
LicenceMPL-2.0
Last update3 weeks ago2 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

510 lines of Pine Script v6 from fvg_screener.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

fvg_screener.pine
//@version=6
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// 邏輯源自 © GainzAlgo "FVG with Probabilities"(https://www.tradingview.com/script/sSsrTFwp-FVG-with-Probabilities-GainzAlgo/)
// FVG 掃描器(台股)— 單週期 × 40 檔,單一 alert
//
// 版面與用法照 SMC OB 掃描器(https://github.com/gplee789-afk/SMC-ob-scanner-for-tradingview-v2 的 pine/smc_ob_screener.pine);每檔的判斷用 fvg_prob_strategy.pine 的邏輯
// (GainzAlgo "FVG with Probabilities" 台股版:FVG、分數、IFVG、內部 OB、掃蕩、訊號引擎)。
// request.security 裡不能畫圖,所以這裡是不畫框的純計算版,判斷規則相同。
// 分數是寫死權重的評分,不是機率。
indicator("FVG Screener TW", overlay = false, max_bars_back = 500)

TZ = "Asia/Taipei"

G_SCAN = "① 掃描"
G_SYM  = "② 代號清單"
G_DISP = "③ 顯示"
G_ALRT = "④ 警報"
G_SIG  = "⑤ 訊號邏輯(同 fvg_prob_strategy)"

// ═══════════════ ① 掃描 ═══════════════
tf = input.timeframe("30", "掃描週期", group = G_SCAN,
     tooltip = "一份腳本只掃一個週期。圖表週期必須小於或等於掃描週期。")
nearPct = input.float(1.5, "「快碰到」門檻(%)", minval = 0.1, step = 0.5, group = G_SCAN,
     tooltip = "離最近的 FVG 在這個百分比以內會上色,但不發警報。")
i_calcBars = input.int(1500, "每檔計算幾根 K 棒", minval = 300, maxval = 5000, group = G_SCAN,
     tooltip = "越多越慢。EMA200 需要約 200 根暖機,1500 根通常就夠。跑不動時先降到 800。")

// ═══════════════ ② 代號清單 ═══════════════
symTxt = input.text_area(
     "TWSE:2330\nTWSE:2317\nTWSE:2454\nTWSE:2382\nTWSE:2308\nTWSE:3231\nTWSE:2303\nTWSE:3037\nTWSE:2368\nTPEX:6488",
     "代號(每行一檔,上限 40)", group = G_SYM,
     tooltip = "格式:交易所:代號,例如 TWSE:2330(上市)、TPEX:6488(上櫃)。\n一行一檔;逗號、空格分隔也可以。超過 40 檔的部分會被忽略。")

// ═══════════════ ③ 顯示 ═══════════════
showRows = input.int(20, "顯示前幾名", minval = 5, maxval = 40, group = G_DISP)
perCol   = input.int(5, "每欄幾檔", minval = 5, maxval = 40, group = G_DISP)
txtSize  = input.string("normal", "字級", options = ["small", "normal", "large", "huge"], group = G_DISP)
tblPos   = input.string("正中", "表格位置", options = ["正中", "中上", "中下", "右上", "右下", "左上", "左下"], group = G_DISP)

// ═══════════════ ④ 警報 ═══════════════
i_alSig      = input.bool(true, "訊號(TRND / REV)", group = G_ALRT)
i_alEnter    = input.bool(false, "進入 FVG", group = G_ALRT,
     tooltip = "價格從外面進入 FVG 的那一根發警報,只算分數不低於下面門檻的 FVG。")
i_alMinScore = input.float(0.65, "進入 FVG 的最低分數", minval = 0.0, maxval = 0.95, step = 0.05, group = G_ALRT)

// ═══════════════ ⑤ 訊號邏輯(主要參數;其餘固定用策略預設值)═══════════════
i_atrLen      = input.int(14, "ATR 長度", minval = 1, group = G_SIG)
i_minAtrMult  = input.float(0.3, "最小缺口 (ATR 倍)", minval = 0.05, step = 0.05, group = G_SIG)
i_useDisp     = input.bool(true, "FVG 中間那根需為位移 K 棒", group = G_SIG)
i_dispBodyAtr = input.float(0.6, "位移:最小實體 (ATR 倍)", minval = 0.1, step = 0.05, group = G_SIG)
i_dispBodyRat = input.float(0.6, "位移:最小實體 / 全長", minval = 0.3, maxval = 0.95, step = 0.05, group = G_SIG)
i_fvgMitig    = input.string("影線回補", "FVG 失效判定", options = ["影線回補", "收盤穿越"], group = G_SIG)
i_trackIFVG   = input.bool(true, "追蹤 IFVG", group = G_SIG)
i_highProb    = input.float(0.65, "高分門檻 (H)", minval = 0.5, maxval = 0.99, step = 0.01, group = G_SIG)
i_medProb     = input.float(0.45, "中分門檻 (M)", minval = 0.2, maxval = 0.64, step = 0.01, group = G_SIG)
i_maxScore    = input.float(0.85, "分數上限", minval = 0.70, maxval = 0.98, step = 0.01, group = G_SIG)
i_swingLen    = input.int(5, "Pivot 左右根數", minval = 2, maxval = 20, group = G_SIG)
i_sigMode     = input.string("兩者", "訊號種類", options = ["順勢", "反轉", "兩者"], group = G_SIG)
i_sigMinScore = input.float(0.60, "CE 觸發的最低 FVG 分數", minval = 0.40, maxval = 0.95, step = 0.01, group = G_SIG)
i_sigReqConf  = input.bool(true, "需確認 K(同向位移 K 棒)", group = G_SIG)
i_sigReqPD    = input.bool(true, "順勢需在折價 / 溢價區", group = G_SIG)
i_sigReqKZ    = input.bool(true, "需在啟用時段內", group = G_SIG)
i_sigCooldown = input.int(10, "同向訊號最少間隔 (根)", minval = 0, group = G_SIG)
i_rvolMin     = input.float(1.0, "訊號最低 RVOL", minval = 0.3, step = 0.1, group = G_SIG)
i_trigCE      = input.bool(true, "觸發:回測 FVG 的 CE", group = G_SIG)
i_trigOB      = input.bool(true, "觸發:回測 OB", group = G_SIG)
i_trigSweep   = input.bool(true, "觸發:流動性掃蕩", group = G_SIG)
i_useOpen     = input.bool(true, "早盤", inline = "kz", group = G_SIG)
i_useMid      = input.bool(true, "中盤", inline = "kz", group = G_SIG)
i_useClose    = input.bool(true, "尾盤", inline = "kz", group = G_SIG,
     tooltip = "勾選的時段算「啟用時段」(早 09:00–10:30、中 10:30–12:30、尾 12:30–13:30)。")
i_useTimeF    = input.bool(true, "開盤後 5 分、收盤前 15 分、11:30–12:30 不出訊號", group = G_SIG,
     tooltip = "只在日內週期生效。")

f_size() =>
    switch txtSize
        "small"  => size.small
        "normal" => size.normal
        "large"  => size.large
        => size.huge

f_pos() =>
    switch tblPos
        "中上" => position.top_center
        "中下" => position.bottom_center
        "右上" => position.top_right
        "右下" => position.bottom_right
        "左上" => position.top_left
        "左下" => position.bottom_left
        => position.middle_center

// 表頭的週期文字:分鐘週期加 m,日 / 週 / 月照原樣
f_tfLabel(string s) => str.contains(s, "D") or str.contains(s, "W") or str.contains(s, "M") ? s : s + "m"

// ── 配色(同 OB 掃描器,另加訊號色)──
C_HEAD     = #1f2933
C_HEADTXT  = #c9d3df
C_LINE     = #2c3846
C_ROW_A    = #161b22
C_ROW_B    = #1b2028
C_SYMTXT   = #7d8996
C_DIM      = #5a6572
C_BULL_SIG = #00a35a
C_BEAR_SIG = #c62a3d
C_BULL_HIT = #0f7a52
C_BEAR_HIT = #9e2b3a
C_BULL_NEAR= #12312a
C_BEAR_NEAR= #33181e
C_BULL_TXT = #4ad9a0
C_BEAR_TXT = #ff7b8a
C_ROW_HIT  = #2a3340

// ═══════════════ 型別 ═══════════════
// FVG:state 0 新生、1 已碰 CE、3 IFVG
type FZ
    float top
    float btm
    bool  isBull
    bool  origBull
    float score
    int   state
    int   birth

type IOB
    float top
    float btm
    bool  isBull
    int   origin
    int   created

// ═══════════════ 全域函式(不能寫在 fvgScan 裡)═══════════════
f_isDisp(int ofs, bool wantBull, float atrS) =>
    body = math.abs(close[ofs] - open[ofs])
    rng  = math.max(high[ofs] - low[ofs], syminfo.mintick)
    dir  = wantBull ? close[ofs] > open[ofs] : close[ofs] < open[ofs]
    body / atrS >= i_dispBodyAtr and body / rng >= i_dispBodyRat and dir

f_clamp(float v, float lo, float hi) => math.max(lo, math.min(hi, v))
f_l(float p) =>
    q = f_clamp(p, 0.1, 0.9)
    math.log(q / (1.0 - q))

// 8 因子分數(同策略):f5、f7 由呼叫端算好傳進來
f_score(float gapRatio, bool fav2, bool fav3, float volRel, float f5, bool fav6, float f7, bool volN, bool volE) =>
    f1 = gapRatio > 1.5 ? 0.82 : gapRatio > 0.9 ? 0.65 : gapRatio > 0.4 ? 0.50 : 0.35
    f2 = fav2 ? 0.78 : 0.30
    f3 = fav3 ? 0.76 : 0.34
    f4 = volRel > 1.5 ? 0.72 : volRel > 0.8 ? 0.55 : 0.38
    f6 = fav6 ? 0.75 : 0.40
    f8 = volN ? 0.60 : volE ? 0.75 : 0.35
    ll = 1.2 * f_l(f1) + 1.0 * f_l(f2) + 1.0 * f_l(f3) + 0.8 * f_l(f4) + 1.5 * f_l(f5) + 1.3 * f_l(f6) + 0.7 * f_l(f7) + 0.9 * f_l(f8)
    f_clamp(1.0 / (1.0 + math.exp(-(ll - 0.60))), 0.04, i_maxScore)

f_tier(float p) => p >= i_highProb ? "H" : p >= i_medProb ? "M" : "L"
f_pct(float p)  => str.tostring(math.round(p * 100)) + "%"

f_overlaps(array<FZ> a, float t, float b) =>
    bool hit = false
    for f in a
        if t >= f.btm and b <= f.top
            hit := true
            break
    hit

// 出現位移 K 棒時,往前 10 根找最近一根反向 K 當作 OB
f_findOB(array<IOB> obs, bool trigger, bool isBull) =>
    bool found = false
    if trigger
        for k = 1 to 10
            if isBull ? close[k] < open[k] : close[k] > open[k]
                t = high[k]
                b = low[k]
                bool dup = false
                for o in obs
                    if math.abs(o.top - t) < syminfo.mintick and math.abs(o.btm - b) < syminfo.mintick
                        dup := true
                        break
                if not dup
                    array.push(obs, IOB.new(t, b, isBull, bar_index - k, bar_index))
                    found := true
                break
    found

// ═══════════════ 掃描主函式(每檔在 request.security 裡跑一次)═══════════════
fvgScan() =>
    // ── 基礎數值(EMA 20 / 50 / 200、RVOL 20、波動 ATR 50 等同策略預設)──
    atr      = ta.atr(i_atrLen)
    atrS     = math.max(nz(atr), syminfo.mintick)
    atrLong  = ta.atr(50)
    emaF     = ta.ema(close, 20)
    emaS     = ta.ema(close, 50)
    emaH     = ta.ema(close, 200)
    volMA    = ta.sma(volume, 20)
    rvol     = volume / math.max(nz(volMA), 1)
    bullTrend = emaF > emaS
    bearTrend = emaF < emaS
    aboveHTF  = close > emaH + 0.3 * atr
    belowHTF  = close < emaH - 0.3 * atr
    volRatio  = atr / math.max(nz(atrLong), syminfo.mintick)
    volComp   = volRatio < 0.7
    volExp    = volRatio > 1.3
    volNorm   = not volComp and not volExp

    // ── 台股時段 ──
    intraday = timeframe.isintraday
    inOpen   = intraday and not na(time(timeframe.period, "0900-1030", TZ))
    inMid    = intraday and not na(time(timeframe.period, "1030-1230", TZ))
    inClose  = intraday and not na(time(timeframe.period, "1230-1330", TZ))
    inKZ     = (i_useOpen and inOpen) or (i_useMid and inMid) or (i_useClose and inClose)
    kzPass   = not intraday or inKZ
    barMin   = hour(time, TZ) * 60 + minute(time, TZ)
    blk      = i_useTimeF and intraday and ((barMin >= 540 and barMin < 545) or (barMin >= 795 and barMin < 810) or (barMin >= 690 and barMin < 750))
    f7       = not intraday ? 0.50 : inKZ ? 0.68 : 0.45

    // ── 位移 K 棒 ──
    bDispC = f_isDisp(0, true,  atrS)
    sDispC = f_isDisp(0, false, atrS)
    bDispM = f_isDisp(1, true,  atrS)
    sDispM = f_isDisp(1, false, atrS)
    bVel   = (bDispC ? 1 : 0) + (bDispM ? 1 : 0) + (f_isDisp(2, true,  atrS) ? 1 : 0)
    sVel   = (sDispC ? 1 : 0) + (sDispM ? 1 : 0) + (f_isDisp(2, false, atrS) ? 1 : 0)
    volRelDisp = volume[1] / math.max(nz(volMA[1]), 1)

    // ── 結構:pivot 與 HH / LL、溢價 / 折價、掃蕩 ──
    ph = ta.pivothigh(high, i_swingLen, i_swingLen)
    pl = ta.pivotlow(low,   i_swingLen, i_swingLen)
    var float lastSH = na
    var float prevSH = na
    var float lastSL = na
    var float prevSL = na
    if not na(ph)
        prevSH := lastSH
        lastSH := ph
    if not na(pl)
        prevSL := lastSL
        lastSL := pl
    isHH      = not na(lastSH) and not na(prevSH) and lastSH > prevSH
    isLL      = not na(lastSL) and not na(prevSL) and lastSL < prevSL
    haveRange = not na(lastSH) and not na(lastSL)
    rangeMid  = haveRange ? (lastSH + lastSL) / 2 : na
    inDisc    = haveRange and close < rangeMid
    inPrem    = haveRange and close > rangeMid
    sweepBull = haveRange and low < lastSL and lastSL - low >= 0.3 * atr and close > lastSL
    sweepBear = haveRange and high > lastSH and high - lastSH >= 0.3 * atr and close < lastSH

    // ── FVG 產生 ──
    var array<FZ> fz = array.new<FZ>()
    bullGap = low - high[2]
    bearGap = low[2] - high
    if bullGap > 0 and bullGap >= i_minAtrMult * atr and (not i_useDisp or bDispM) and not f_overlaps(fz, low, high[2])
        mid = (low + high[2]) / 2
        f5  = not haveRange ? 0.50 : mid < rangeMid ? 0.80 : 0.30
        array.push(fz, FZ.new(low, high[2], true, true, f_score(bullGap / atrS, bullTrend, aboveHTF, volRelDisp, f5, isHH, f7, volNorm, volExp), 0, bar_index))
    if bearGap > 0 and bearGap >= i_minAtrMult * atr and (not i_useDisp or sDispM) and not f_overlaps(fz, low[2], high)
        mid = (low[2] + high) / 2
        f5  = not haveRange ? 0.50 : mid > rangeMid ? 0.80 : 0.30
        array.push(fz, FZ.new(low[2], high, false, false, f_score(bearGap / atrS, bearTrend, belowHTF, volRelDisp, f5, isLL, f7, volNorm, volExp), 0, bar_index))

    // ── FVG 生命週期:碰 CE、轉 IFVG、失效 ──
    bool  tapBull   = false
    bool  tapBear   = false
    float tapBullSc = 0.0
    float tapBearSc = 0.0
    if array.size(fz) > 0
        for i = array.size(fz) - 1 to 0
            f   = array.get(fz, i)
            mid = (f.top + f.btm) / 2
            bool kill = bar_index - f.birth > 300
            if not kill and f.state < 3
                if f.state == 0 and (f.isBull ? low <= mid : high >= mid)
                    f.state := 1
                    if f.isBull and f.score > tapBullSc
                        tapBull   := true
                        tapBullSc := f.score
                    if not f.isBull and f.score > tapBearSc
                        tapBear   := true
                        tapBearSc := f.score
                if f.isBull ? low <= f.btm : high >= f.top
                    closeBeyond = f.isBull ? close < f.btm : close > f.top
                    distOk = f.isBull ? f.btm - close >= 0.3 * atr : close - f.top >= 0.3 * atr
                    dispOk = f.isBull ? sDispC : bDispC
                    strOk  = f.isBull ? isLL : isHH
                    if i_trackIFVG and closeBeyond and distOk and dispOk and strOk
                        f.top    := math.max(open, close)
                        f.btm    := math.min(open, close)
                        f.isBull := not f.isBull
                        f.state  := 3
                    else
                        kill := i_fvgMitig == "影線回補" or closeBeyond
            else if not kill and f.state == 3
                kill := f.isBull ? close < f.btm : close > f.top
            if kill
                array.remove(fz, i)
    while array.size(fz) > 30
        array.shift(fz)

    // ── 內部 OB(只當觸發)──
    var array<IOB> obs = array.new<IOB>()
    f_findOB(obs, bDispC, true)
    f_findOB(obs, sDispC, false)
    bool obBull = false
    bool obBear = false
    if array.size(obs) > 0
        for i = array.size(obs) - 1 to 0
            o = array.get(obs, i)
            bool kill = bar_index - o.origin > 100
            if not kill and bar_index > o.created
                if o.isBull
                    obBull := obBull or (low <= o.top and low >= o.btm and close > o.btm)
                    kill   := close < o.btm
                else
                    obBear := obBear or (high >= o.btm and high <= o.top and close < o.top)
                    kill   := close > o.top
            if kill
                array.remove(obs, i)
    while array.size(obs) > 10
        array.shift(obs)

    // ── 訊號引擎(觸發看前一根,當根確認)──
    tLCE = i_trigCE    and tapBull[1]
    tSCE = i_trigCE    and tapBear[1]
    tLOB = i_trigOB    and obBull[1]
    tSOB = i_trigOB    and obBear[1]
    tLSw = i_trigSweep and sweepBull[1]
    tSSw = i_trigSweep and sweepBear[1]
    scL  = tapBullSc[1]
    scS  = tapBearSc[1]

    var int lastL = -100000
    var int lastS = -100000
    base   = rvol >= i_rvolMin and (not i_sigReqKZ or kzPass) and not blk and not volComp
    modeT  = i_sigMode != "反轉"
    modeR  = i_sigMode != "順勢"
    trendL = modeT and base and (tLCE or tLOB or tLSw) and (not i_sigReqConf or bDispC) and (not tLCE or scL >= i_sigMinScore) and
         bullTrend and isHH and aboveHTF and (not i_sigReqPD or inDisc) and bar_index - lastL >= i_sigCooldown
    trendS = modeT and base and (tSCE or tSOB or tSSw) and (not i_sigReqConf or sDispC) and (not tSCE or scS >= i_sigMinScore) and
         bearTrend and isLL and belowHTF and (not i_sigReqPD or inPrem) and bar_index - lastS >= i_sigCooldown
    revL   = modeR and base and tLSw and (not i_sigReqConf or bDispC) and bearTrend and bar_index - lastL >= i_sigCooldown
    revS   = modeR and base and tSSw and (not i_sigReqConf or sDispC) and bullTrend and bar_index - lastS >= i_sigCooldown

    nL = (tLCE ? 1 : 0) + (tLOB ? 1 : 0) + (tLSw ? 1 : 0)
    nS = (tSCE ? 1 : 0) + (tSOB ? 1 : 0) + (tSSw ? 1 : 0)
    // 分級:3 = A+、2 = A、1 = B
    gL = trendL ? (nL >= 2 and volExp and bVel >= 2 ? 3 : nL >= 2 or (scL >= i_highProb and bVel >= 2) ? 2 : 1) : 1
    gS = trendS ? (nS >= 2 and volExp and sVel >= 2 ? 3 : nS >= 2 or (scS >= i_highProb and sVel >= 2) ? 2 : 1) : 1

    sigDir = trendL or revL ? 1 : trendS or revS ? -1 : 0
    sigRev = sigDir == 1 ? not trendL : sigDir == -1 ? not trendS : false
    grade  = sigDir == 1 ? gL : sigDir == -1 ? gS : 0
    if sigDir == 1
        lastL := bar_index
    if sigDir == -1
        lastS := bar_index

    // ── 最近的多方 / 空方 FVG(含 IFVG)、是否在裡面 ──
    float bTop = na
    float bBtm = na
    float bSc  = na
    bool  bIF  = false
    float sTop = na
    float sBtm = na
    float sSc  = na
    bool  sIF  = false
    bool  inB  = false
    bool  inS  = false
    for f in fz
        isIn = low <= f.top and high >= f.btm
        if f.isBull
            inB := inB or isIn
            if na(bTop) or math.abs(close - f.top) < math.abs(close - bTop)
                bTop := f.top
                bBtm := f.btm
                bSc  := f.score
                bIF  := f.state == 3
        else
            inS := inS or isIn
            if na(sBtm) or math.abs(close - f.btm) < math.abs(close - sBtm)
                sTop := f.top
                sBtm := f.btm
                sSc  := f.score
                sIF  := f.state == 3
    newInB = inB and not inB[1]
    newInS = inS and not inS[1]
    // 距離要在這裡用該檔自己的收盤價算(外層的 close 是圖表上那檔)。正值 = 還差幾 % 才碰到
    bDist = na(bTop) ? na : (close - bTop) / close * 100
    sDist = na(sBtm) ? na : (sBtm - close) / close * 100

    [sigDir, sigRev, grade, bTop, bBtm, bSc, bIF, bDist, sTop, sBtm, sSc, sIF, sDist, inB, inS, newInB, newInS]

// ═══════════════ 呈現層 ═══════════════
f_zoneTxt(string side, float bt, float tp, float sc, bool isIF) =>
    side + (isIF ? " IFVG " : " ") + f_tier(sc) + f_pct(sc) + " " + str.tostring(bt, format.mintick) + "–" + str.tostring(tp, format.mintick)

// 每格回傳:文字、底色、文字色、排序鍵(訊號 < 在 FVG 裡 < 距離)、是否醒目
f_cell(int sigDir, bool sigRev, int grade, bool inB, bool inS, float bTop, float bBtm, float bSc, bool bIF, float bDist, float sTop, float sBtm, float sSc, bool sIF, float sDist) =>
    string txt = "–"
    color  bg  = na
    color  fg  = C_DIM
    float  key = 1e9
    bool   hot = false
    gTxt = grade == 3 ? "A+" : grade == 2 ? "A" : "B"
    if sigDir != 0
        txt := (sigDir == 1 ? "多 " : "空 ") + (sigRev ? "REV " : "TRND ") + gTxt
        bg  := sigDir == 1 ? C_BULL_SIG : C_BEAR_SIG
        fg  := color.white
        key := -2000. - grade
        hot := true
    else if inB
        txt := f_zoneTxt("多", bBtm, bTop, bSc, bIF)
        bg  := C_BULL_HIT
        fg  := color.white
        key := -1000. - bSc
        hot := true
    else if inS
        txt := f_zoneTxt("空", sBtm, sTop, sSc, sIF)
        bg  := C_BEAR_HIT
        fg  := color.white
        key := -1000. - sSc
        hot := true
    else
        bullNear = not na(bDist) and bDist >= 0
        bearNear = not na(sDist) and sDist >= 0
        if bullNear and (not bearNear or bDist <= sDist)
            key := bDist
            txt := "多 ▼" + str.tostring(bDist, "#.0") + "% " + f_tier(bSc) + f_pct(bSc) + " " + str.tostring(bTop, format.mintick)
            bg  := bDist <= nearPct ? C_BULL_NEAR : na
            fg  := bDist <= nearPct ? C_BULL_TXT : C_DIM
        else if bearNear
            key := sDist
            txt := "空 ▲" + str.tostring(sDist, "#.0") + "% " + f_tier(sSc) + f_pct(sSc) + " " + str.tostring(sBtm, format.mintick)
            bg  := sDist <= nearPct ? C_BEAR_NEAR : na
            fg  := sDist <= nearPct ? C_BEAR_TXT : C_DIM
    [txt, bg, fg, key, hot]

// ═══════════════ 主體 ═══════════════
rawSym  = str.replace_all(str.replace_all(str.replace_all(symTxt, "\r", ","), "\n", ","), " ", ",")
allSyms = str.split(rawSym, ",")
syms    = array.new<string>()
if array.size(allSyms) > 0
    for k = 0 to array.size(allSyms) - 1
        v = array.get(allSyms, k)
        if str.length(v) > 0 and array.size(syms) < 40
            array.push(syms, v)
n = array.size(syms)

colSym = array.new<string>()
colTxt = array.new<string>()
colBg  = array.new<color>()
colFg  = array.new<color>()
colHot = array.new<bool>()
colKey = array.new<float>()
msg    = ""

for i = 0 to n - 1
    sym = array.get(syms, i)
    [sd, sr, gr, bTop, bBtm, bSc, bIF, bDist, sTop, sBtm, sSc, sIF, sDist, iB, iS, nB, nS] = request.security(sym, tf, fvgScan(),
         ignore_invalid_symbol = true, calc_bars_count = i_calcBars)
    [txt, bg, fg, key, hot] = f_cell(sd, sr, gr, iB, iS, bTop, bBtm, bSc, bIF, bDist, sTop, sBtm, sSc, sIF, sDist)

    array.push(colSym, sym)
    array.push(colTxt, txt)
    array.push(colBg,  bg)
    array.push(colFg,  fg)
    array.push(colHot, hot)
    array.push(colKey, key)

    if i_alSig and sd != 0
        msg := msg + sym + " [" + tf + "] " + (sd == 1 ? "多方 " : "空方 ") + (sr ? "REV " : "TRND ") +
             (gr == 3 ? "A+" : gr == 2 ? "A" : "B") + "\n"
    if i_alEnter and nB and bSc >= i_alMinScore
        msg := msg + sym + " [" + tf + "] 進入多方 FVG " + f_tier(bSc) + f_pct(bSc) + " " +
             str.tostring(bBtm, format.mintick) + "~" + str.tostring(bTop, format.mintick) + "\n"
    if i_alEnter and nS and sSc >= i_alMinScore
        msg := msg + sym + " [" + tf + "] 進入空方 FVG " + f_tier(sSc) + f_pct(sSc) + " " +
             str.tostring(sBtm, format.mintick) + "~" + str.tostring(sTop, format.mintick) + "\n"

// ═══════════════ 表格 ═══════════════
// 每欄 perCol 檔,排滿換到右邊。每欄佔 3 個表格欄:代號、結果、與下一欄之間的間隔
var table t = table.new(f_pos(), 24, 41, border_width = 0, frame_width = 1,
     frame_color = C_LINE, border_color = C_LINE)

if barstate.islast and n > 0
    table.clear(t, 0, 0, 23, 40)
    order  = array.sort_indices(colKey, order.ascending)
    rows   = math.min(n, showRows)
    groups = math.ceil(rows / perCol)

    for g = 0 to groups - 1
        c = g * 3
        table.cell(t, c,     0, "代號", bgcolor = C_HEAD, text_color = C_HEADTXT, text_size = f_size(), text_halign = text.align_left)
        table.cell(t, c + 1, 0, "FVG " + f_tfLabel(tf), bgcolor = C_HEAD, text_color = C_HEADTXT, text_size = f_size())
        if g < groups - 1
            table.cell(t, c + 2, 0, "", width = 0.5)

    for r = 0 to rows - 1
        i     = array.get(order, r)
        hot   = array.get(colHot, i)
        c     = math.floor(r / perCol) * 3
        row   = r % perCol + 1
        rowBg = hot ? C_ROW_HIT : (row % 2 == 1 ? C_ROW_A : C_ROW_B)

        table.cell(t, c, row, array.get(colSym, i), bgcolor = rowBg,
             text_color = hot ? color.white : C_SYMTXT, text_size = f_size(), text_halign = text.align_left)
        table.cell(t, c + 1, row, array.get(colTxt, i),
             bgcolor = na(array.get(colBg, i)) ? rowBg : array.get(colBg, i),
             text_color = array.get(colFg, i), text_size = f_size())

// ═══════════════ 單一 alert ═══════════════
if barstate.isconfirmed and str.length(msg) > 0
    alert(msg, alert.freq_once_per_bar_close)

Overview

FVG Screener TW calculates a weighted quality score for each gap, monitors price proximity, and evaluates trend or reversal setup triggers. The results are displayed in a separate pane dashboard table, ranking symbols and highlighting actionable setups. Configurable settings control the scanned symbol list, gap size ATR multipliers, score thresholds, table layout, and alert conditions.

Details

Published by

gplee789-afk on GitHub

Type

Indicator, Pine Script v6

Draws

Separate pane below the chart

Category

SMC / ICT / price action, Screeners & dashboards, Support & resistance

Markets

Stocks

Timeframes

M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
掃描週期timeframe30tf
「快碰到」門檻(%)float1.5nearPct
每檔計算幾根 K 棒int1500i_calcBars
代號(每行一檔,上限 40)textTWSE:2330 TWSE:2317 TWSE:2454 TWSE:2382 TWSE:2308 TWSE:3231 symTxt
顯示前幾名int20showRows
每欄幾檔int5perCol
字級stringnormaltxtSize
表格位置string正中tblPos
訊號(TRND / REV)booltruei_alSig
進入 FVGboolfalsei_alEnter
進入 FVG 的最低分數float0.65i_alMinScore
ATR 長度int14i_atrLen
Show all 36 settings
SettingTypeDefaultVariable
最小缺口 (ATR 倍)float0.3i_minAtrMult
FVG 中間那根需為位移 K 棒booltruei_useDisp
位移:最小實體 (ATR 倍)float0.6i_dispBodyAtr
位移:最小實體 / 全長float0.6i_dispBodyRat
FVG 失效判定string影線回補i_fvgMitig
追蹤 IFVGbooltruei_trackIFVG
高分門檻 (H)float0.65i_highProb
中分門檻 (M)float0.45i_medProb
分數上限float0.85i_maxScore
Pivot 左右根數int5i_swingLen
訊號種類string兩者i_sigMode
CE 觸發的最低 FVG 分數float0.60i_sigMinScore
需確認 K(同向位移 K 棒)booltruei_sigReqConf
順勢需在折價 / 溢價區booltruei_sigReqPD
需在啟用時段內booltruei_sigReqKZ
同向訊號最少間隔 (根)int10i_sigCooldown
訊號最低 RVOLfloat1.0i_rvolMin
觸發:回測 FVG 的 CEbooltruei_trigCE
觸發:回測 OBbooltruei_trigOB
觸發:流動性掃蕩booltruei_trigSweep
早盤booltruei_useOpen
中盤booltruei_useMid
尾盤booltruei_useClose
開盤後 5 分、收盤前 15 分、11:30–12:30 不出訊號booltruei_useTimeF
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

MTF Structure Bias classifies market structure across four timeframes by comparing rolling highest highs and lowest lows N bars ago. Each timeframe receives a bullish (+1), bearish (-1), or mixed (0) state based on whether highs and lows are rising or falling.

Indicator v6 SMC / ICT / price actionScreeners & dashboards
Updated yesterday · MIT GitHub repository of MTF Structure Bias [WavesUnchained]
575 stars

This overlay indicator scans a pasted list of symbols for ICT liquidity sweep patterns using prior swing sweeps. The screening method looks back one, two, or three swings and can list long and short signals in a results table with adjustable rows, position, an

Indicator v5 SMC / ICT / price actionScreeners & dashboards
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Liquidity Sweep Pattern Scanner

Golden Bullet Strategy

by TradersPost
218 stars

The Golden Bullet Strategy is an overlay signal indicator based on Smart Money Concepts and time-based liquidity models. It identifies liquidity sweeps of a designated reference session range during a specified hunt window. It then confirms Market Structure Sh

Indicator v6 SMC / ICT / price actionSessions & time
Updated 3 months ago · None stated GitHub repository of Golden Bullet Strategy
56 stars

This indicator identifies fractal-based pivot highs and lows to map out market structure directly on the price chart. It detects bullish and bearish structure breaks, automatically labeling Break of Structure (BOS) and Change of Character (ChoCH) events when p

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · None stated GitHub repository of Market Structure (Fractal)
53 stars

Apex Trend & Liquidity Master calculates a trend cloud using customizable moving averages expanded by a volatility multiplier directly on the main price chart. It identifies dynamic support and resistance liquidity zones from swing high and low pivots, extendi

Indicator v6 TrendSupport & resistance
Updated 2 months ago · MPL-2.0 GitHub repository of Apex Trend & Liquidity Master

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers