// This source code is subject to the terms of the Mozilla Public License 2.0 // © Perkytradess / Peak Ventures // PERKY SMC ULTIMATE V5 — Obsidian Edition // Visual rebuild 2026-08 · palette, dashboard, labels and density. // Signal logic, entry prices and TP/SL math are byte-for-byte unchanged. //@version=6 indicator('Perky SMC Ultimate V5', 'PerkySMCV5', overlay=true, max_labels_count=500, max_lines_count=500, max_boxes_count=500) //---------------------------------------------------------------------------------------------------------------------} // CONSTANTS //---------------------------------------------------------------------------------------------------------------------{ BULLISH_LEG = 1 BEARISH_LEG = 0 BULLISH = +1 BEARISH = -1 // ── OBSIDIAN PALETTE ──────────────────────────────────────────────── GOLD = #D8B25F // champagne accent — brand GOLD_DIM = #7A6430 // hairline gold SILVER = #9AA3B2 // cool graphite TEAL = #2FC79A // bull — jade ROSE = #E4596E // bear — garnet NAVY = #080A10 // card ground DARK_GRAY = #10131B // surface GRAY = #2A3040 // hairline LIGHT_GRAY = #8B95A7 // secondary text TEXT_HI = #D7DDE8 // primary text MONO_BULLISH = #E6EAF2 // monochrome bull — bone MONO_BEARISH = #6B7280 // monochrome bear — graphite GREEN = #2FC79A RED = #E4596E BLUE = #4C7DF0 HAIR = '──────────────' HISTORICAL = 'Historical' PRESENT = 'Present' COLORED = 'Colored' MONOCHROME = 'Monochrome' ALL = 'All' BOS = 'BOS' CHOCH = 'CHoCH' TINY = size.tiny SMALL = size.small NORMAL = size.normal ATR = 'Atr' RANGE = 'Cumulative Mean Range' CLOSE = 'Close' HIGHLOW = 'High/Low' SOLID = '⎯⎯⎯' DASHED = '----' DOTTED = '····' UI_GROUP = '◆ Appearance' SCORE_GROUP = '◆ Signal Quality' SMART_GROUP = 'Smart Money Concepts' INTERNAL_GROUP = 'Real Time Internal Structure' SWING_GROUP = 'Real Time Swing Structure' BLOCKS_GROUP = 'Order Blocks' EQUAL_GROUP = 'EQH/EQL' GAPS_GROUP = 'Fair Value Gaps' LEVELS_GROUP = 'Highs & Lows MTF' ZONES_GROUP = 'Premium & Discount Zones' SWEEPS_GROUP = 'Liquidity Sweeps' ENTRY_GROUP = 'Entry & Exit Strategy' EMA_RSI_GROUP = '📈 EMA / RSI' DASH_GROUP = 'MTF Dashboard' //---------------------------------------------------------------------------------------------------------------------} // INPUTS — APPEARANCE //---------------------------------------------------------------------------------------------------------------------{ densityInput = input.string('Minimal', 'Chart Density', group=UI_GROUP, options=['Minimal','Balanced','Full'], tooltip='Minimal hides decorative text (FVG tags, sweep tags, swing-point labels) and forces compact label sizes. Signals are never hidden — only chrome.') entryCardInput = input.string('Micro', 'Signal Card', group=UI_GROUP, options=['Micro','Compact','Full']) watermarkInput = input.string('Modern', 'Watermark', group=UI_GROUP, options=['Modern','Serif','Off']) accentInput = input.color(GOLD, 'Accent', group=UI_GROUP, inline='surf') surfaceInput = input.color(NAVY, 'Surface', group=UI_GROUP, inline='surf') dnsMin = densityInput == 'Minimal' dnsFull = densityInput == 'Full' ACCENT = accentInput SURFACE = surfaceInput labelOffsetInput = input.float(1.0, 'Label Distance', group=UI_GROUP, minval=0.1, maxval=6.0, step=0.1, tooltip='Measured in units of 10% of the last 100 bars\' range, so cards clear the candles by the same visual amount on any symbol or timeframe. 1.0 ≈ one tenth of the visible range.') crossOffsetInput = input.float(1.5, 'Cross Label Distance', group=UI_GROUP, minval=0.1, maxval=8.0, step=0.1) crossMinBarsInput = input.int(20, 'Min Bars Between Cross Labels', group=UI_GROUP, minval=0, maxval=300, tooltip='EMA crosses cluster in chop and stack their labels on top of each other. This suppresses repeats inside the window — the alerts still fire.') edgeOffsetInput = input.int(5, 'Right-Edge Label Offset (bars)', group=UI_GROUP, minval=1, maxval=40, tooltip='Pushes Strong/Weak High-Low and MTF level tags closer to the last candle so they stop colliding with the dashboard.') uiSize(string s) => dnsMin ? size.tiny : s //---------------------------------------------------------------------------------------------------------------------} // INPUTS — SMC //---------------------------------------------------------------------------------------------------------------------{ modeInput = input.string(HISTORICAL, 'Mode', group=SMART_GROUP, options=[HISTORICAL,PRESENT]) styleInput = input.string(COLORED, 'Style', group=SMART_GROUP, options=[COLORED,MONOCHROME]) showTrendInput = input(false, 'Color Candles', group=SMART_GROUP) showInternalsInput = input(true, 'Show Internal Structure', group=INTERNAL_GROUP) showInternalBullInput = input.string(ALL, 'Bullish Structure', group=INTERNAL_GROUP, inline='ibull', options=[ALL,BOS,CHOCH]) internalBullColorInput = input(TEAL, '', group=INTERNAL_GROUP, inline='ibull') showInternalBearInput = input.string(ALL, 'Bearish Structure', group=INTERNAL_GROUP, inline='ibear', options=[ALL,BOS,CHOCH]) internalBearColorInput = input(ROSE, '', group=INTERNAL_GROUP, inline='ibear') internalFilterConfluenceInput = input(false, 'Confluence Filter', group=INTERNAL_GROUP) internalStructureSize = input.string(TINY, 'Internal Label Size', group=INTERNAL_GROUP, options=[TINY,SMALL,NORMAL]) showStructureInput = input(true, 'Show Swing Structure', group=SWING_GROUP) showSwingBullInput = input.string(ALL, 'Bullish Structure', group=SWING_GROUP, inline='bull', options=[ALL,BOS,CHOCH]) swingBullColorInput = input(TEAL, '', group=SWING_GROUP, inline='bull') showSwingBearInput = input.string(ALL, 'Bearish Structure', group=SWING_GROUP, inline='bear', options=[ALL,BOS,CHOCH]) swingBearColorInput = input(ROSE, '', group=SWING_GROUP, inline='bear') swingStructureSize = input.string(SMALL, 'Swing Label Size', group=SWING_GROUP, options=[TINY,SMALL,NORMAL]) showSwingsInput = input(false, 'Show Swings Points', group=SWING_GROUP, inline='swings') swingsLengthInput = input.int(50, '', group=SWING_GROUP, minval=10, inline='swings') showHighLowSwingsInput = input(true, 'Show Strong/Weak High/Low',group=SWING_GROUP) showInternalOrderBlocksInput = input(true, 'Internal Order Blocks', group=BLOCKS_GROUP, inline='iob') internalOrderBlocksSizeInput = input.int(5, '', group=BLOCKS_GROUP, minval=1, maxval=20, inline='iob') showSwingOrderBlocksInput = input(false, 'Swing Order Blocks', group=BLOCKS_GROUP, inline='ob') swingOrderBlocksSizeInput = input.int(5, '', group=BLOCKS_GROUP, minval=1, maxval=20, inline='ob') orderBlockFilterInput = input.string('Atr', 'Order Block Filter', group=BLOCKS_GROUP, options=[ATR,RANGE]) orderBlockMitigationInput = input.string(HIGHLOW, 'Order Block Mitigation', group=BLOCKS_GROUP, options=[CLOSE,HIGHLOW]) internalBullishOrderBlockColor = input.color(color.new(TEAL,88), 'Internal Bullish OB', group=BLOCKS_GROUP) internalBearishOrderBlockColor = input.color(color.new(ROSE,88), 'Internal Bearish OB', group=BLOCKS_GROUP) swingBullishOrderBlockColor = input.color(color.new(TEAL,80), 'Bullish OB', group=BLOCKS_GROUP) swingBearishOrderBlockColor = input.color(color.new(ROSE,80), 'Bearish OB', group=BLOCKS_GROUP) showEqualHighsLowsInput = input(true, 'Equal High/Low', group=EQUAL_GROUP) equalHighsLowsLengthInput = input.int(3, 'Bars Confirmation', group=EQUAL_GROUP, minval=1) equalHighsLowsThresholdInput = input.float(0.1, 'Threshold', group=EQUAL_GROUP, minval=0, maxval=0.5, step=0.1) equalHighsLowsSizeInput = input.string(TINY, 'Label Size', group=EQUAL_GROUP, options=[TINY,SMALL,NORMAL]) showFairValueGapsInput = input(true, 'Fair Value Gaps', group=GAPS_GROUP) fairValueGapsThresholdInput = input(true, 'Auto Threshold', group=GAPS_GROUP) fairValueGapsTimeframeInput = input.timeframe('', 'Timeframe', group=GAPS_GROUP) fairValueGapsBullColorInput = input.color(color.new(TEAL,91), 'Bullish FVG', group=GAPS_GROUP) fairValueGapsBearColorInput = input.color(color.new(ROSE,91), 'Bearish FVG', group=GAPS_GROUP) fairValueGapsExtendInput = input.int(1, 'Extend FVG', group=GAPS_GROUP, minval=0) showFVGLabelsInput = input(true, 'Show FVG Labels', group=GAPS_GROUP) showDailyLevelsInput = input(false, 'Daily', group=LEVELS_GROUP, inline='daily') dailyLevelsStyleInput = input.string(SOLID, '', group=LEVELS_GROUP, inline='daily', options=[SOLID,DASHED,DOTTED]) dailyLevelsColorInput = input(GOLD, '', group=LEVELS_GROUP, inline='daily') showWeeklyLevelsInput = input(false, 'Weekly', group=LEVELS_GROUP, inline='weekly') weeklyLevelsStyleInput = input.string(SOLID, '', group=LEVELS_GROUP, inline='weekly', options=[SOLID,DASHED,DOTTED]) weeklyLevelsColorInput = input(GOLD, '', group=LEVELS_GROUP, inline='weekly') showMonthlyLevelsInput = input(false, 'Monthly', group=LEVELS_GROUP, inline='monthly') monthlyLevelsStyleInput = input.string(SOLID, '', group=LEVELS_GROUP, inline='monthly', options=[SOLID,DASHED,DOTTED]) monthlyLevelsColorInput = input(GOLD, '', group=LEVELS_GROUP, inline='monthly') showPremiumDiscountZonesInput = input(false, 'Premium/Discount Zones', group=ZONES_GROUP) premiumZoneColorInput = input.color(ROSE, 'Premium Zone', group=ZONES_GROUP) equilibriumZoneColorInput = input.color(LIGHT_GRAY, 'Equilibrium Zone', group=ZONES_GROUP) discountZoneColorInput = input.color(TEAL, 'Discount Zone', group=ZONES_GROUP) //---------------------------------------------------------------------------------------------------------------------} // INPUTS — SWEEPS //---------------------------------------------------------------------------------------------------------------------{ sweepLen = input.int(5, 'Swings', minval=1, group=SWEEPS_GROUP) sweepOpt = input.string('Only Wicks', 'Mode', options=['Only Wicks','Only Outbreaks & Retest','Wicks + Outbreaks & Retest'], group=SWEEPS_GROUP) sweepBullColor = input.color(TEAL, 'Bull', group=SWEEPS_GROUP, inline='sc1') sweepBullColor2 = input.color(color.new(TEAL,68), '', group=SWEEPS_GROUP, inline='sc1') sweepBearColor = input.color(ROSE, 'Bear', group=SWEEPS_GROUP, inline='sc2') sweepBearColor2 = input.color(color.new(ROSE,68), '', group=SWEEPS_GROUP, inline='sc2') sweepExtend = input.bool(true, 'Extend Sweep Area', group=SWEEPS_GROUP) sweepMaxBars = input.int(300, 'Max Bars', minval=1, maxval=5000, group=SWEEPS_GROUP) sweepBullArea = input.color(color.new(TEAL,94), 'Bull Area', group=SWEEPS_GROUP, inline='sa1') sweepBearArea = input.color(color.new(ROSE,94), 'Bear Area', group=SWEEPS_GROUP, inline='sa2') showSweepLabel = input(true, 'Show Sweep Labels', group=SWEEPS_GROUP) //---------------------------------------------------------------------------------------------------------------------} // INPUTS — ENTRY //---------------------------------------------------------------------------------------------------------------------{ showEntryInput = input(true, 'Show Entry & Exit Signals', group=ENTRY_GROUP) showSweepEntriesInput = input(true, 'Sweep-Based Entries', group=ENTRY_GROUP) showStructEntries = input(true, 'CHoCH/BOS-Based Entries', group=ENTRY_GROUP) requireFVGInput = input(false, 'Filter: Require FVG Confluence', group=ENTRY_GROUP) requireOBInput = input(false, 'Filter: Require OB Confluence', group=ENTRY_GROUP) requireCHoCHInput = input(false, 'Filter: Require CHoCH Confirm', group=ENTRY_GROUP) requireSMCBiasInput = input(false, 'Filter: Require SMC Bias Align', group=ENTRY_GROUP) slMultInput = input.float(0.5, 'Stop Loss ATR Mult', group=ENTRY_GROUP, minval=0.1, step=0.05) fadeOldLabelsInput = input.bool(true, 'Fade Previous Day Labels', group=ENTRY_GROUP) fadeDaysInput = input.int(2, 'Days Before Fading', group=ENTRY_GROUP, minval=1, maxval=10) //---------------------------------------------------------------------------------------------------------------------} // INPUTS — SIGNAL QUALITY //---------------------------------------------------------------------------------------------------------------------{ qualityModeInput = input.string('Filtered', 'Signal Mode', group=SCORE_GROUP, options=['Legacy V5','Filtered','Strict'], tooltip='Legacy V5 reproduces the original build exactly — every signal, price and stop identical. Filtered applies the confluence score and the shared cooldown to CHoCH and momentum entries too. Strict additionally forces score ≥6, ≥3 of 4 HTF timeframes aligned, and kill-zone-only entries.') minScoreInput = input.int(4, 'Min Score (0-10)', group=SCORE_GROUP, minval=0, maxval=10) htfAlignInput = input.int(0, 'HTF Agreement Required (0-4)', group=SCORE_GROUP, minval=0, maxval=4, tooltip='How many of the four dashboard timeframes must agree with the entry direction. 0 disables the gate — recommended, because f_bias() is a slow EMA20/50 cross, so during a bullish HTF regime it blocks every short even while price is selling off. HTF alignment still contributes +1 to the score.') gateAllInput = input.bool(true, 'Cooldown + filters on CHoCH / momentum entries', group=SCORE_GROUP, tooltip='The original build applied the confluence filters and the 25-bar cooldown to sweep entries only — CHoCH and momentum entries fired unfiltered. This extends them to every entry engine.') kzGateInput = input.bool(false, 'Kill Zone entries only', group=SCORE_GROUP) sortTPInput = input.bool(true, 'Sort TP1/2/3 by distance', group=SCORE_GROUP, tooltip='The targets are drawn from three independent sources (FVG, order block, swing) and are not ordered — without this, TP1 can sit further away than TP3.') slModeInput = input.string('Structure', 'Stop Loss', group=SCORE_GROUP, options=['ATR','Structure']) slBufInput = input.float(0.25, 'Structure SL Buffer (ATR)', group=SCORE_GROUP, minval=0.0, maxval=2.0, step=0.05) kzLondonInput = input.session('0800-1000', 'London Kill Zone', group=SCORE_GROUP) kzNYInput = input.session('1330-1530', 'New York Kill Zone', group=SCORE_GROUP) scoreSwpInput = input.bool(true, '+2 Liquidity Sweep', group=SCORE_GROUP) scoreChochInput = input.bool(true, '+1 CHoCH Confirmed', group=SCORE_GROUP) scoreFvgInput = input.bool(true, '+1 FVG in Direction', group=SCORE_GROUP) scoreObInput = input.bool(true, '+1 OB in Direction', group=SCORE_GROUP) scoreKzInput = input.bool(true, '+1 Inside Kill Zone', group=SCORE_GROUP) scoreEmaInput = input.bool(true, '+1 EMA Trend Aligned', group=SCORE_GROUP) scoreRsiInput = input.bool(true, '+1 RSI Not Exhausted', group=SCORE_GROUP) scoreHtfInput = input.bool(true, '+1 HTF Bias Aligned', group=SCORE_GROUP) scoreVolInput = input.bool(true, '+1 Volume Above Average', group=SCORE_GROUP) showScoreInput = input.bool(true, 'Print score on card', group=SCORE_GROUP) qLegacy = qualityModeInput == 'Legacy V5' qStrict = qualityModeInput == 'Strict' effMinScore = qLegacy ? 0 : qStrict ? math.max(minScoreInput, 6) : minScoreInput effHtfMin = qLegacy ? 0 : qStrict ? math.max(htfAlignInput, 3) : htfAlignInput effGateAll = qLegacy ? false : gateAllInput effKZ = qLegacy ? false : qStrict ? true : kzGateInput effSortTP = qLegacy ? false : sortTPInput effSLmode = qLegacy ? 'ATR' : slModeInput //---------------------------------------------------------------------------------------------------------------------} // INPUTS — EMA / RSI //---------------------------------------------------------------------------------------------------------------------{ showEMAInput = input.bool(true, 'Show EMA 50 / 200', group=EMA_RSI_GROUP) emaFilterInput = input.bool(false, 'EMA Filter (CALL above EMA50 only)', group=EMA_RSI_GROUP) showRSIInput = input.bool(true, 'Show RSI Pane', group=EMA_RSI_GROUP) rsiLenInput = input.int(14, 'RSI Length', group=EMA_RSI_GROUP, minval=2, maxval=50) rsiOBInput = input.int(70, 'RSI Overbought', group=EMA_RSI_GROUP, minval=60, maxval=90) rsiOSInput = input.int(30, 'RSI Oversold', group=EMA_RSI_GROUP, minval=10, maxval=40) rsiFilterInput = input.bool(false, 'RSI Filter (block exhausted entries)',group=EMA_RSI_GROUP) ema50Color = input.color(GOLD, 'EMA 50 Color', group=EMA_RSI_GROUP) ema200Color = input.color(SILVER, 'EMA 200 Color', group=EMA_RSI_GROUP) //---------------------------------------------------------------------------------------------------------------------} // INPUTS — DASHBOARD //---------------------------------------------------------------------------------------------------------------------{ showDashInput = input.bool(true, '▣ Show MTF Dashboard', group=DASH_GROUP) showDashToggle = input.bool(false, '↺ Click to Flip Dashboard', group=DASH_GROUP) dashPosInput = input.string('Top Right', 'Position', group=DASH_GROUP, options=['Top Right','Top Left','Bottom Right','Bottom Left']) dashSizeInput = input.string('Small', 'Text Size', group=DASH_GROUP, options=['Tiny','Small','Normal','Large']) dashTF1 = input.timeframe('15', 'Timeframe 1', group=DASH_GROUP) dashTF2 = input.timeframe('60', 'Timeframe 2', group=DASH_GROUP) dashTF3 = input.timeframe('240', 'Timeframe 3', group=DASH_GROUP) dashTF4 = input.timeframe('D', 'Timeframe 4', group=DASH_GROUP) dashLangInput = input.string('English', '🌐 Language', group=DASH_GROUP, options=['English','Turkish','Spanish','French','Arabic','Chinese','Portuguese','Hindi','Russian','Japanese','German','Italian','Korean','Indonesian','Dutch']) //---------------------------------------------------------------------------------------------------------------------} // EMA / RSI CALCULATIONS //---------------------------------------------------------------------------------------------------------------------{ emaFastLen = timeframe.in_seconds() < 300 ? 9 : 50 emaSlowLen = timeframe.in_seconds() < 300 ? 21 : 200 ema50 = ta.ema(close, emaFastLen) ema200 = ta.ema(close, emaSlowLen) emaCrossBull = ta.crossover(ema50, ema200) emaCrossBear = ta.crossunder(ema50, ema200) priceAboveEMA50 = close > ema50 priceBelowEMA50 = close < ema50 emaBull = ema50 > ema200 emaBear = ema50 < ema200 rsiVal = ta.rsi(close, rsiLenInput) rsiOBNow = rsiVal >= rsiOBInput rsiOSNow = rsiVal <= rsiOSInput isBullBar = close > open isBearBar = close < open consecBears = isBearBar[1] and isBearBar[2] consecBulls = isBullBar[1] and isBullBar[2] momShiftBull = isBullBar and consecBears momShiftBear = isBearBar and consecBulls momCallSignal = momShiftBull and (not emaFilterInput or priceAboveEMA50) and (not rsiFilterInput or not rsiOBNow) momPutSignal = momShiftBear and (not emaFilterInput or priceBelowEMA50) and (not rsiFilterInput or not rsiOSNow) inLondonKZ = not na(time(timeframe.period, kzLondonInput, 'UTC')) inNYKZ = not na(time(timeframe.period, kzNYInput, 'UTC')) inKillZone = inLondonKZ or inNYKZ volAvg = ta.sma(volume, 20) volAboveAvg = not na(volume) and not na(volAvg) and volume > volAvg recentHigh = ta.highest(high, 10) recentLow = ta.lowest(low, 10) inExpansionUp = close > recentHigh[1] inExpansionDown = close < recentLow[1] var int lastEntryBar = -999 cooldownBars = 25 barsSinceEntry = bar_index - lastEntryBar cooldownExpired = barsSinceEntry >= cooldownBars expansionReentry = barsSinceEntry >= 5 and (inExpansionUp or inExpansionDown) entryAllowed = cooldownExpired or expansionReentry //---------------------------------------------------------------------------------------------------------------------} // REQUEST.SECURITY //---------------------------------------------------------------------------------------------------------------------{ [fvg_lc, fvg_lo, fvg_lt, fvg_ch, fvg_cl, fvg_ct, fvg_l2h, fvg_l2l] = request.security(syminfo.tickerid, fairValueGapsTimeframeInput, [close[1], open[1], time[1], high[0], low[0], time[0], high[2], low[2]], lookahead=barmerge.lookahead_on) [d_top, d_bot, d_lt, d_rt] = request.security(syminfo.tickerid, 'D', [high[1], low[1], time[1], time], lookahead=barmerge.lookahead_on) [w_top, w_bot, w_lt, w_rt] = request.security(syminfo.tickerid, 'W', [high[1], low[1], time[1], time], lookahead=barmerge.lookahead_on) [m_top, m_bot, m_lt, m_rt] = request.security(syminfo.tickerid, 'M', [high[1], low[1], time[1], time], lookahead=barmerge.lookahead_on) f_bias() => e1 = ta.ema(close, 20) e2 = ta.ema(close, 50) e1 > e2 ? 1 : e1 < e2 ? -1 : 0 f_struct() => var int state = 0 bullBOS = ta.crossover(close, ta.highest(high, 20)[1]) bearBOS = ta.crossunder(close, ta.lowest(low, 20)[1]) bullCH = ta.crossover(close, ta.highest(high, 10)[1]) bearCH = ta.crossunder(close, ta.lowest(low, 10)[1]) if bullCH state := 2 else if bearCH state := -2 else if bullBOS state := 1 else if bearBOS state := -1 state f_ob() => var int state = 0 h10 = ta.highest(high, 10)[1] l10 = ta.lowest(low, 10)[1] l5 = ta.lowest(low, 5) h5 = ta.highest(high, 5) bullOB = high > h10 and close < h10 bearOB = low < l10 and close > l10 if state == 1 and close < l5 state := 0 if state == -1 and close > h5 state := 0 if bullOB state := 1 if bearOB state := -1 state htf1_intBias = request.security(syminfo.tickerid, dashTF1, f_bias(), lookahead=barmerge.lookahead_off) htf2_intBias = request.security(syminfo.tickerid, dashTF2, f_bias(), lookahead=barmerge.lookahead_off) htf3_intBias = request.security(syminfo.tickerid, dashTF3, f_bias(), lookahead=barmerge.lookahead_off) htf4_intBias = request.security(syminfo.tickerid, dashTF4, f_bias(), lookahead=barmerge.lookahead_off) htf1_swgBias = htf1_intBias htf2_swgBias = htf2_intBias htf3_swgBias = htf3_intBias htf4_swgBias = htf4_intBias htf1_struct = request.security(syminfo.tickerid, dashTF1, f_struct(), lookahead=barmerge.lookahead_off) htf2_struct = request.security(syminfo.tickerid, dashTF2, f_struct(), lookahead=barmerge.lookahead_off) htf3_struct = request.security(syminfo.tickerid, dashTF3, f_struct(), lookahead=barmerge.lookahead_off) htf4_struct = request.security(syminfo.tickerid, dashTF4, f_struct(), lookahead=barmerge.lookahead_off) htf1_ob = request.security(syminfo.tickerid, dashTF1, f_ob(), lookahead=barmerge.lookahead_off) htf2_ob = request.security(syminfo.tickerid, dashTF2, f_ob(), lookahead=barmerge.lookahead_off) htf3_ob = request.security(syminfo.tickerid, dashTF3, f_ob(), lookahead=barmerge.lookahead_off) htf4_ob = request.security(syminfo.tickerid, dashTF4, f_ob(), lookahead=barmerge.lookahead_off) htf1_rsi = request.security(syminfo.tickerid, dashTF1, ta.rsi(close, rsiLenInput), lookahead=barmerge.lookahead_off) htf2_rsi = request.security(syminfo.tickerid, dashTF2, ta.rsi(close, rsiLenInput), lookahead=barmerge.lookahead_off) htf3_rsi = request.security(syminfo.tickerid, dashTF3, ta.rsi(close, rsiLenInput), lookahead=barmerge.lookahead_off) htf4_rsi = request.security(syminfo.tickerid, dashTF4, ta.rsi(close, rsiLenInput), lookahead=barmerge.lookahead_off) htf1_bullBOS = htf1_struct == 1 htf1_bearBOS = htf1_struct == -1 htf1_bullCH = htf1_struct == 2 htf1_bearCH = htf1_struct == -2 htf2_bullBOS = htf2_struct == 1 htf2_bearBOS = htf2_struct == -1 htf2_bullCH = htf2_struct == 2 htf2_bearCH = htf2_struct == -2 htf3_bullBOS = htf3_struct == 1 htf3_bearBOS = htf3_struct == -1 htf3_bullCH = htf3_struct == 2 htf3_bearCH = htf3_struct == -2 htf4_bullBOS = htf4_struct == 1 htf4_bearBOS = htf4_struct == -1 htf4_bullCH = htf4_struct == 2 htf4_bearCH = htf4_struct == -2 htf1_bullOB = htf1_ob == 1 htf1_bearOB = htf1_ob == -1 htf2_bullOB = htf2_ob == 1 htf2_bearOB = htf2_ob == -1 htf3_bullOB = htf3_ob == 1 htf3_bearOB = htf3_ob == -1 htf4_bullOB = htf4_ob == 1 htf4_bearOB = htf4_ob == -1 //---------------------------------------------------------------------------------------------------------------------} // CONFLUENCE SCORE ENGINE //---------------------------------------------------------------------------------------------------------------------{ htfBullCount = (htf1_intBias == BULLISH ? 1 : 0) + (htf2_intBias == BULLISH ? 1 : 0) + (htf3_intBias == BULLISH ? 1 : 0) + (htf4_intBias == BULLISH ? 1 : 0) htfBearCount = (htf1_intBias == BEARISH ? 1 : 0) + (htf2_intBias == BEARISH ? 1 : 0) + (htf3_intBias == BEARISH ? 1 : 0) + (htf4_intBias == BEARISH ? 1 : 0) htfBullBias = htfBullCount >= 2 htfBearBias = htfBearCount >= 2 calcScore(bool isBull, bool hasSweep, bool hasChoch, bool hasFVG, bool hasOB) => score = 0 if scoreSwpInput and hasSweep score += 2 if scoreChochInput and hasChoch score += 1 if scoreFvgInput and hasFVG score += 1 if scoreObInput and hasOB score += 1 if scoreKzInput and inKillZone score += 1 if scoreEmaInput and (isBull ? priceAboveEMA50 : priceBelowEMA50) score += 1 if scoreRsiInput and (isBull ? not rsiOBNow : not rsiOSNow) score += 1 if scoreHtfInput and (isBull ? htfBullBias : htfBearBias) score += 1 if scoreVolInput and volAboveAvg score += 1 score scoreTag(int score) => score >= 9 ? str.tostring(score) + '/10 ✦' : str.tostring(score) + '/10' //---------------------------------------------------------------------------------------------------------------------} // DATA STRUCTURES //---------------------------------------------------------------------------------------------------------------------{ type alerts bool internalBullishBOS = false bool internalBearishBOS = false bool internalBullishCHoCH = false bool internalBearishCHoCH = false bool swingBullishBOS = false bool swingBearishBOS = false bool swingBullishCHoCH = false bool swingBearishCHoCH = false bool internalBullishOrderBlock = false bool internalBearishOrderBlock = false bool swingBullishOrderBlock = false bool swingBearishOrderBlock = false bool equalHighs = false bool equalLows = false bool bullishFairValueGap = false bool bearishFairValueGap = false type trailingExtremes float top float bottom int barTime int barIndex int lastTopTime int lastBottomTime type fairValueGap float top float bottom int bias box topBox box bottomBox label fvgLabel type trend int bias type equalDisplay line l_ine = na label l_abel = na type pivot float currentLevel float lastLevel bool crossed int barTime = time int barIndex = bar_index type orderBlock float barHigh float barLow int barTime int bias type piv float prc int bix bool brk bool mit bool tak bool wic line lin type boxBr box bx line ln bool br int dr type entryLabel label lbl int barCreated //---------------------------------------------------------------------------------------------------------------------} // VARIABLES //---------------------------------------------------------------------------------------------------------------------{ var pivot swingHigh = pivot.new(na,na,false) var pivot swingLow = pivot.new(na,na,false) var pivot internalHigh = pivot.new(na,na,false) var pivot internalLow = pivot.new(na,na,false) var pivot equalHigh = pivot.new(na,na,false) var pivot equalLow = pivot.new(na,na,false) var trend swingTrend = trend.new(0) var trend internalTrend = trend.new(0) var equalDisplay equalHighDisplay = equalDisplay.new() var equalDisplay equalLowDisplay = equalDisplay.new() var array fairValueGaps = array.new() var array parsedHighs = array.new() var array parsedLows = array.new() var array highs = array.new() var array lows = array.new() var array times = array.new() var trailingExtremes trailing = trailingExtremes.new() var array swingOrderBlocks = array.new() var array internalOrderBlocks = array.new() var array swingOrderBlocksBoxes = array.new() var array internalOrderBlocksBoxes = array.new() var array aPivH = array.new(1, piv.new()) var array aPivL = array.new(1, piv.new()) var array aBoxBr = array.new(1, boxBr.new()) var bool lastBullCHoCH = false var bool lastBearCHoCH = false var bool inLong = false var bool inShort = false var swingBullishColor = styleInput == MONOCHROME ? MONO_BULLISH : swingBullColorInput var swingBearishColor = styleInput == MONOCHROME ? MONO_BEARISH : swingBearColorInput var fairValueGapBullishColor = styleInput == MONOCHROME ? color.new(MONO_BULLISH,70) : fairValueGapsBullColorInput var fairValueGapBearishColor = styleInput == MONOCHROME ? color.new(MONO_BEARISH,70) : fairValueGapsBearColorInput var premiumZoneColor = styleInput == MONOCHROME ? MONO_BEARISH : premiumZoneColorInput var discountZoneColor = styleInput == MONOCHROME ? MONO_BULLISH : discountZoneColorInput varip int currentBarIndex = bar_index varip int lastBarIndex = bar_index alerts currentAlerts = alerts.new() var initialTime = time // Entry label tracking — use bar_index instead of day counter to avoid same-day fade var array callEntries = array.new() var array putEntries = array.new() //---------------------------------------------------------------------------------------------------------------------} // STRUCTURE-BASED TP/SL //---------------------------------------------------------------------------------------------------------------------{ atr14 = ta.atr(14) // hoisted: ta.* must evaluate every bar, not only on entry bars getNearestBullFVG() => result = close + ta.atr(14) for fvg in fairValueGaps if fvg.bias == BULLISH and fvg.bottom > close if fvg.bottom < result result := fvg.bottom result getNearestBearFVG() => result = close - ta.atr(14) for fvg in fairValueGaps if fvg.bias == BEARISH and fvg.top < close if fvg.top > result result := fvg.top result getNearestBullOB() => result = close + ta.atr(14) * 1.5 for ob in internalOrderBlocks if ob.bias == BEARISH and ob.barLow > close if ob.barLow < result result := ob.barLow result getNearestBearOB() => result = close - ta.atr(14) * 1.5 for ob in internalOrderBlocks if ob.bias == BULLISH and ob.barHigh < close if ob.barHigh > result result := ob.barHigh result nearBullFVGVal = getNearestBullFVG() nearBearFVGVal = getNearestBearFVG() nearBullOBVal = getNearestBullOB() nearBearOBVal = getNearestBearOB() sortTP(bool isBull, float x, float y, float z) => lo = math.min(x, math.min(y, z)) hi = math.max(x, math.max(y, z)) mid = x + y + z - lo - hi [isBull ? lo : hi, mid, isBull ? hi : lo] getStructTP(bool isBull, float entryPrice) => atr = atr14 swingLevel = isBull ? swingHigh.currentLevel : swingLow.currentLevel t1 = isBull ? nearBullFVGVal : nearBearFVGVal t2 = isBull ? nearBullOBVal : nearBearOBVal t3 = isBull ? (na(swingLevel) ? close + atr * 2 : swingLevel) : (na(swingLevel) ? close - atr * 2 : swingLevel) [s1, s2, s3] = sortTP(isBull, t1, t2, t3) tp1 = effSortTP ? s1 : t1 tp2 = effSortTP ? s2 : t2 tp3 = effSortTP ? s3 : t3 slATR = isBull ? entryPrice - atr * slMultInput : entryPrice + atr * slMultInput anchor = isBull ? (na(swingLow.currentLevel) ? low : math.min(swingLow.currentLevel, low)) : (na(swingHigh.currentLevel) ? high : math.max(swingHigh.currentLevel, high)) slStruct = isBull ? math.min(math.max(anchor - atr * slBufInput, entryPrice - atr * 3), entryPrice - atr * 0.15) : math.max(math.min(anchor + atr * slBufInput, entryPrice + atr * 3), entryPrice + atr * 0.15) sl = effSLmode == 'Structure' ? slStruct : slATR [tp1, tp2, tp3, sl] //---------------------------------------------------------------------------------------------------------------------} // INITIALIZATION //---------------------------------------------------------------------------------------------------------------------{ if barstate.isfirst if showSwingOrderBlocksInput for index = 1 to swingOrderBlocksSizeInput swingOrderBlocksBoxes.push(box.new(na,na,na,na,xloc=xloc.bar_time,extend=extend.right)) if showInternalOrderBlocksInput for index = 1 to internalOrderBlocksSizeInput internalOrderBlocksBoxes.push(box.new(na,na,na,na,xloc=xloc.bar_time,extend=extend.right)) bearishOrderBlockMitigationSource = orderBlockMitigationInput == CLOSE ? close : high bullishOrderBlockMitigationSource = orderBlockMitigationInput == CLOSE ? close : low atrMeasure = ta.atr(200) visRange = ta.highest(high, 100) - ta.lowest(low, 100) visUnit = math.max(nz(visRange) * 0.10, nz(atrMeasure) * 1.5) volatilityMeasure = orderBlockFilterInput == ATR ? atrMeasure : ta.cum(ta.tr)/bar_index highVolatilityBar = (high - low) >= (2 * volatilityMeasure) parsedHigh = highVolatilityBar ? low : high parsedLow = highVolatilityBar ? high : low parsedHighs.push(parsedHigh) parsedLows.push(parsedLow) highs.push(high) lows.push(low) times.push(time) //---------------------------------------------------------------------------------------------------------------------} // FADE LOGIC — bar based not day based //---------------------------------------------------------------------------------------------------------------------{ barsPerDay = math.max(1, math.round(86400 / math.max(1, timeframe.in_seconds()))) fadeBarCount = fadeDaysInput * math.min(barsPerDay, 500) // true days on any timeframe if fadeOldLabelsInput and callEntries.size() > 0 for i = callEntries.size()-1 to 0 e = callEntries.get(i) if bar_index - e.barCreated >= fadeBarCount e.lbl.set_textcolor(color.new(TEAL,80)) e.lbl.set_color(color.new(TEAL,92)) callEntries.remove(i) if fadeOldLabelsInput and putEntries.size() > 0 for i = putEntries.size()-1 to 0 e = putEntries.get(i) if bar_index - e.barCreated >= fadeBarCount e.lbl.set_textcolor(color.new(ROSE,80)) e.lbl.set_color(color.new(ROSE,92)) putEntries.remove(i) //---------------------------------------------------------------------------------------------------------------------} // SMC FUNCTIONS //---------------------------------------------------------------------------------------------------------------------{ leg(int size) => var leg = 0 newLegHigh = high[size] > ta.highest(size) newLegLow = low[size] < ta.lowest(size) if newLegHigh leg := BEARISH_LEG else if newLegLow leg := BULLISH_LEG leg startOfNewLeg(int leg) => ta.change(leg) != 0 startOfBearishLeg(int leg) => ta.change(leg) == -1 startOfBullishLeg(int leg) => ta.change(leg) == +1 drawLabel(int labelTime, float labelPrice, string tag, color labelColor, string labelStyle) => var label l_abel = na if modeInput == PRESENT l_abel.delete() l_abel := label.new(labelTime, labelPrice, tag, xloc=xloc.bar_time, color=color.new(#000000,100), textcolor=labelColor, style=labelStyle, size=uiSize(SMALL)) drawEqualHighLow(pivot p_ivot, float level, int size, bool equalHigh) => equalDisplay e_qualDisplay = equalHigh ? equalHighDisplay : equalLowDisplay string tag = 'EQL' color equalColor = swingBullishColor string labelStyle = label.style_label_up if equalHigh tag := 'EQH' equalColor := swingBearishColor labelStyle := label.style_label_down if modeInput == PRESENT line.delete(e_qualDisplay.l_ine) label.delete(e_qualDisplay.l_abel) e_qualDisplay.l_ine := line.new(p_ivot.barTime, p_ivot.currentLevel, time[size], level, xloc=xloc.bar_time, color=equalColor, style=line.style_dotted) labelPosition = math.round(0.5*(p_ivot.barIndex + bar_index - size)) e_qualDisplay.l_abel := label.new(labelPosition, level, tag, xloc=xloc.bar_index, color=color.new(#000000,100), textcolor=equalColor, style=labelStyle, size=uiSize(equalHighsLowsSizeInput)) getCurrentStructure(int size, bool equalHighLow=false, bool internal=false) => currentLeg = leg(size) newPivot = startOfNewLeg(currentLeg) pivotLow = startOfBullishLeg(currentLeg) pivotHigh = startOfBearishLeg(currentLeg) if newPivot if pivotLow pivot p_ivot = equalHighLow ? equalLow : internal ? internalLow : swingLow if equalHighLow and math.abs(p_ivot.currentLevel - low[size]) < equalHighsLowsThresholdInput * atrMeasure drawEqualHighLow(p_ivot, low[size], size, false) currentAlerts.equalLows := true p_ivot.lastLevel := p_ivot.currentLevel p_ivot.currentLevel := low[size] p_ivot.crossed := false p_ivot.barTime := time[size] p_ivot.barIndex := bar_index[size] if not equalHighLow and not internal trailing.bottom := p_ivot.currentLevel trailing.barTime := p_ivot.barTime trailing.barIndex := p_ivot.barIndex trailing.lastBottomTime := p_ivot.barTime if showSwingsInput and not internal and not equalHighLow drawLabel(time[size], p_ivot.currentLevel, p_ivot.currentLevel < p_ivot.lastLevel ? 'LL' : 'HL', swingBullishColor, label.style_label_up) else pivot p_ivot = equalHighLow ? equalHigh : internal ? internalHigh : swingHigh if equalHighLow and math.abs(p_ivot.currentLevel - high[size]) < equalHighsLowsThresholdInput * atrMeasure drawEqualHighLow(p_ivot, high[size], size, true) currentAlerts.equalHighs := true p_ivot.lastLevel := p_ivot.currentLevel p_ivot.currentLevel := high[size] p_ivot.crossed := false p_ivot.barTime := time[size] p_ivot.barIndex := bar_index[size] if not equalHighLow and not internal trailing.top := p_ivot.currentLevel trailing.barTime := p_ivot.barTime trailing.barIndex := p_ivot.barIndex trailing.lastTopTime := p_ivot.barTime if showSwingsInput and not internal and not equalHighLow drawLabel(time[size], p_ivot.currentLevel, p_ivot.currentLevel > p_ivot.lastLevel ? 'HH' : 'LH', swingBearishColor, label.style_label_down) drawStructure(pivot p_ivot, string tag, color structureColor, string lineStyle, string labelSize) => var line l_ine = line.new(na,na,na,na,xloc=xloc.bar_time) if modeInput == PRESENT l_ine.delete() l_ine := line.new(p_ivot.barTime, p_ivot.currentLevel, time, p_ivot.currentLevel, xloc=xloc.bar_time, color=structureColor, style=lineStyle, width=lineStyle == line.style_dashed ? 1 : 2, extend=extend.none) midBar = math.round(0.5 * (p_ivot.barIndex + bar_index)) label.new(midBar, p_ivot.currentLevel, tag, xloc=xloc.bar_index, color=color.new(color.black,100), textcolor=structureColor, style=label.style_label_center, size=uiSize(labelSize)) deleteOrderBlocks(bool internal=false) => array orderBlocks = internal ? internalOrderBlocks : swingOrderBlocks for [index,eachOrderBlock] in orderBlocks bool crossedOderBlock = false if bearishOrderBlockMitigationSource > eachOrderBlock.barHigh and eachOrderBlock.bias == BEARISH crossedOderBlock := true if internal currentAlerts.internalBearishOrderBlock := true else currentAlerts.swingBearishOrderBlock := true else if bullishOrderBlockMitigationSource < eachOrderBlock.barLow and eachOrderBlock.bias == BULLISH crossedOderBlock := true if internal currentAlerts.internalBullishOrderBlock := true else currentAlerts.swingBullishOrderBlock := true if crossedOderBlock orderBlocks.remove(index) storeOrdeBlock(pivot p_ivot, bool internal=false, int bias) => if (not internal and showSwingOrderBlocksInput) or (internal and showInternalOrderBlocksInput) array a_rray = na int parsedIndex = na if bias == BEARISH a_rray := parsedHighs.slice(p_ivot.barIndex,bar_index) parsedIndex := p_ivot.barIndex + a_rray.indexof(a_rray.max()) else a_rray := parsedLows.slice(p_ivot.barIndex,bar_index) parsedIndex := p_ivot.barIndex + a_rray.indexof(a_rray.min()) orderBlock o_rderBlock = orderBlock.new(parsedHighs.get(parsedIndex), parsedLows.get(parsedIndex), times.get(parsedIndex), bias) array orderBlocks = internal ? internalOrderBlocks : swingOrderBlocks if orderBlocks.size() >= 100 orderBlocks.pop() orderBlocks.unshift(o_rderBlock) drawOrderBlocks(bool internal=false) => array orderBlocks = internal ? internalOrderBlocks : swingOrderBlocks orderBlocksSize = orderBlocks.size() if orderBlocksSize > 0 maxOrderBlocks = internal ? internalOrderBlocksSizeInput : swingOrderBlocksSizeInput array parsedOrdeBlocks = orderBlocks.slice(0, math.min(maxOrderBlocks,orderBlocksSize)) array b_oxes = internal ? internalOrderBlocksBoxes : swingOrderBlocksBoxes for [index,eachOrderBlock] in parsedOrdeBlocks orderBlockColor = styleInput == MONOCHROME ? (eachOrderBlock.bias == BEARISH ? color.new(MONO_BEARISH,80) : color.new(MONO_BULLISH,80)) : internal ? (eachOrderBlock.bias == BEARISH ? internalBearishOrderBlockColor : internalBullishOrderBlockColor) : (eachOrderBlock.bias == BEARISH ? swingBearishOrderBlockColor : swingBullishOrderBlockColor) box b_ox = b_oxes.get(index) b_ox.set_lefttop(eachOrderBlock.barTime, eachOrderBlock.barHigh) b_ox.set_rightbottom(last_bar_time, eachOrderBlock.barLow) b_ox.set_border_color(na) b_ox.set_bgcolor(orderBlockColor) displayStructure(bool internal=false) => var bullishBar = true var bearishBar = true if internalFilterConfluenceInput bullishBar := high - math.max(close, open) > math.min(close, open - low) bearishBar := high - math.max(close, open) < math.min(close, open - low) pivot p_ivot = internal ? internalHigh : swingHigh trend t_rend = internal ? internalTrend : swingTrend lineStyle = internal ? line.style_dashed : line.style_solid labelSize = internal ? internalStructureSize : swingStructureSize extraCondition = internal ? internalHigh.currentLevel != swingHigh.currentLevel and bullishBar : true bullishColor = styleInput == MONOCHROME ? MONO_BULLISH : internal ? internalBullColorInput : swingBullColorInput if ta.crossover(close,p_ivot.currentLevel) and not p_ivot.crossed and extraCondition string tag = t_rend.bias == BEARISH ? CHOCH : BOS if internal currentAlerts.internalBullishCHoCH := tag == CHOCH currentAlerts.internalBullishBOS := tag == BOS else currentAlerts.swingBullishCHoCH := tag == CHOCH currentAlerts.swingBullishBOS := tag == BOS p_ivot.crossed := true t_rend.bias := BULLISH displayCondition = internal ? showInternalsInput and (showInternalBullInput == ALL or (showInternalBullInput == BOS and tag != CHOCH) or (showInternalBullInput == CHOCH and tag == CHOCH)) : showStructureInput and (showSwingBullInput == ALL or (showSwingBullInput == BOS and tag != CHOCH) or (showSwingBullInput == CHOCH and tag == CHOCH)) if displayCondition drawStructure(p_ivot,tag,bullishColor,lineStyle,labelSize) if (internal and showInternalOrderBlocksInput) or (not internal and showSwingOrderBlocksInput) storeOrdeBlock(p_ivot,internal,BULLISH) p_ivot := internal ? internalLow : swingLow extraCondition := internal ? internalLow.currentLevel != swingLow.currentLevel and bearishBar : true bearishColor = styleInput == MONOCHROME ? MONO_BEARISH : internal ? internalBearColorInput : swingBearColorInput if ta.crossunder(close,p_ivot.currentLevel) and not p_ivot.crossed and extraCondition string tag = t_rend.bias == BULLISH ? CHOCH : BOS if internal currentAlerts.internalBearishCHoCH := tag == CHOCH currentAlerts.internalBearishBOS := tag == BOS else currentAlerts.swingBearishCHoCH := tag == CHOCH currentAlerts.swingBearishBOS := tag == BOS p_ivot.crossed := true t_rend.bias := BEARISH displayCondition = internal ? showInternalsInput and (showInternalBearInput == ALL or (showInternalBearInput == BOS and tag != CHOCH) or (showInternalBearInput == CHOCH and tag == CHOCH)) : showStructureInput and (showSwingBearInput == ALL or (showSwingBearInput == BOS and tag != CHOCH) or (showSwingBearInput == CHOCH and tag == CHOCH)) if displayCondition drawStructure(p_ivot,tag,bearishColor,lineStyle,labelSize) if (internal and showInternalOrderBlocksInput) or (not internal and showSwingOrderBlocksInput) storeOrdeBlock(p_ivot,internal,BEARISH) //---------------------------------------------------------------------------------------------------------------------} // FVG FUNCTIONS //---------------------------------------------------------------------------------------------------------------------{ fairValueGapBox(leftTime, rightTime, topPrice, bottomPrice, boxColor) => box.new(leftTime, topPrice, rightTime + fairValueGapsExtendInput * (time-time[1]), bottomPrice, xloc=xloc.bar_time, border_color=boxColor, bgcolor=boxColor) deleteFairValueGaps() => for [index,eachFairValueGap] in fairValueGaps if (low < eachFairValueGap.bottom and eachFairValueGap.bias == BULLISH) or (high > eachFairValueGap.top and eachFairValueGap.bias == BEARISH) eachFairValueGap.topBox.delete() eachFairValueGap.bottomBox.delete() eachFairValueGap.fvgLabel.delete() fairValueGaps.remove(index) drawFairValueGaps(float lastClose, float lastOpen, int lastTime, float currentHigh, float currentLow, int currentTime, float last2High, float last2Low) => barDeltaPercent = (lastClose - lastOpen) / (lastOpen * 100) newTimeframe = timeframe.change(fairValueGapsTimeframeInput) threshold = fairValueGapsThresholdInput ? ta.cum(math.abs(newTimeframe ? barDeltaPercent : 0)) / bar_index * 2 : 0 bullishFairValueGap = currentLow > last2High and lastClose > last2High and barDeltaPercent > threshold and newTimeframe bearishFairValueGap = currentHigh < last2Low and lastClose < last2Low and -barDeltaPercent > threshold and newTimeframe if bullishFairValueGap currentAlerts.bullishFairValueGap := true midPrice = math.avg(currentLow, last2High) midTime = lastTime + math.round((currentTime - lastTime) * 0.5) topBx = fairValueGapBox(lastTime, currentTime, currentLow, midPrice, fairValueGapBullishColor) botBx = fairValueGapBox(lastTime, currentTime, midPrice, last2High, fairValueGapBullishColor) fvgLbl = showFVGLabelsInput and not dnsMin ? label.new(midTime, midPrice, 'FVG', xloc=xloc.bar_time, color=color.new(color.black,100), textcolor=color.new(TEAL,38), style=label.style_label_center, size=size.tiny) : label.new(na,na) fairValueGaps.unshift(fairValueGap.new(currentLow, last2High, BULLISH, topBx, botBx, fvgLbl)) if bearishFairValueGap currentAlerts.bearishFairValueGap := true midPrice = math.avg(currentHigh, last2Low) midTime = lastTime + math.round((currentTime - lastTime) * 0.5) topBx = fairValueGapBox(lastTime, currentTime, currentHigh, midPrice, fairValueGapBearishColor) botBx = fairValueGapBox(lastTime, currentTime, midPrice, last2Low, fairValueGapBearishColor) fvgLbl = showFVGLabelsInput and not dnsMin ? label.new(midTime, midPrice, 'FVG', xloc=xloc.bar_time, color=color.new(color.black,100), textcolor=color.new(ROSE,38), style=label.style_label_center, size=size.tiny) : label.new(na,na) fairValueGaps.unshift(fairValueGap.new(currentHigh, last2Low, BEARISH, topBx, botBx, fvgLbl)) inBullFVG() => result = false for fvg in fairValueGaps if fvg.bias == BULLISH and close >= fvg.bottom and close <= fvg.top result := true result inBearFVG() => result = false for fvg in fairValueGaps if fvg.bias == BEARISH and close <= fvg.top and close >= fvg.bottom result := true result nearBullOB() => result = false for ob in internalOrderBlocks if ob.bias == BULLISH and close >= ob.barLow and close <= ob.barHigh + atrMeasure * 2 result := true result nearBearOB() => result = false for ob in internalOrderBlocks if ob.bias == BEARISH and close <= ob.barHigh and close >= ob.barLow - atrMeasure * 2 result := true result //---------------------------------------------------------------------------------------------------------------------} // LIQUIDITY SWEEPS //---------------------------------------------------------------------------------------------------------------------{ n_sweep = bar_index oW_s = sweepOpt == 'Only Wicks' oO_s = sweepOpt == 'Only Outbreaks & Retest' method n_piv(float piv_val) => bool out = not na(piv_val) method p_met(piv p_obj, float val) => float out = (100 / p_obj.prc * val) - 100 method l_met(piv get, color c, string s='sd') => style = switch s 'dt' => line.style_dotted 'ds' => line.style_dashed => line.style_solid line.new(get.bix, get.prc, n_sweep, get.prc, color=c, style=style) method br_met(piv get, color c3, color c, int d) => y1 = d == 1 ? high : get.prc y2 = d == 1 ? get.prc : low boxBr.new( box.new(n_sweep-1, y1, n_sweep+1, y2, border_color=color.new(na,na), bgcolor=c3), line.new(n_sweep, y1, n_sweep, y2, color=c, width=2), false, d) lnDot_sweep(y, c) => line.new(n_sweep, y, n_sweep+2, y, color=c, style=line.style_dotted) drawSweepLabel(float price, bool isBull, bool entryFired=false) => if showSweepLabel and not entryFired lc = isBull ? sweepBullColor : sweepBearColor ls = isBull ? label.style_label_up : label.style_label_down label.new(n_sweep, price, dnsMin ? '⌁' : '⌁ SWEEP', color=color.new(color.black,100), textcolor=color.new(lc,15), style=ls, size=size.tiny) ph_sweep = ta.pivothigh(sweepLen, sweepLen) pl_sweep = ta.pivotlow (sweepLen, sweepLen) if ph_sweep.n_piv() aPivH.unshift(piv.new(ph_sweep, n_sweep - sweepLen, false, false, false, false)) if pl_sweep.n_piv() aPivL.unshift(piv.new(pl_sweep, n_sweep - sweepLen, false, false, false, false)) var bool greenSweepFired = false var bool redSweepFired = false var float greenSweepPrice = na var float redSweepPrice = na greenSweepFired := false redSweepFired := false smcBullBiasPre = internalTrend.bias == BULLISH smcBearBiasPre = internalTrend.bias == BEARISH for i = aPivH.size()-1 to 0 get = aPivH.get(i) if not get.mit if not get.brk if close > get.prc if not oW_s get.brk := true else get.mit := true if not oO_s and not get.wic if high > get.prc and close < get.prc aBoxBr.unshift(get.br_met(sweepBearArea, sweepBearColor, 1)) get.l_met(sweepBearColor2, 'dt'), lnDot_sweep(low, sweepBearColor) get.wic := true redSweepFired := true redSweepPrice := high else if close < get.prc get.mit := true if not oW_s and low < get.prc and close > get.prc aBoxBr.unshift(get.br_met(sweepBullArea, sweepBullColor, -1)) get.l_met(sweepBullColor2, 'ds'), lnDot_sweep(high, sweepBullColor) get.tak := true greenSweepFired := true greenSweepPrice := low if n_sweep - get.bix > 2000 or get.mit or get.tak aPivH.remove(i).lin.delete() for i = aPivL.size()-1 to 0 get = aPivL.get(i) if not get.mit if not get.brk if close < get.prc if not oW_s get.brk := true else get.mit := true if not oO_s and not get.wic if low < get.prc and close > get.prc aBoxBr.unshift(get.br_met(sweepBullArea, sweepBullColor, -1)) get.l_met(sweepBullColor2, 'dt'), lnDot_sweep(high, sweepBullColor) get.wic := true greenSweepFired := true greenSweepPrice := low else if close > get.prc get.mit := true if not oW_s and high > get.prc and close < get.prc aBoxBr.unshift(get.br_met(sweepBearArea, sweepBearColor, 1)) get.l_met(sweepBearColor2, 'ds'), lnDot_sweep(low, sweepBearColor) get.tak := true redSweepFired := true redSweepPrice := high if n_sweep - get.bix > 2000 or get.mit or get.tak aPivL.remove(i).lin.delete() fvgBullConfPre = requireFVGInput ? inBullFVG() : true fvgBearConfPre = requireFVGInput ? inBearFVG() : true obBullConfPre = requireOBInput ? nearBullOB() : true obBearConfPre = requireOBInput ? nearBearOB() : true chochBullOkPre = requireCHoCHInput ? lastBullCHoCH : true chochBearOkPre = requireCHoCHInput ? lastBearCHoCH : true biasBullOkPre = requireSMCBiasInput ? smcBullBiasPre : true biasBearOkPre = requireSMCBiasInput ? smcBearBiasPre : true emaLongOk = not emaFilterInput or priceAboveEMA50 emaShortOk = not emaFilterInput or priceBelowEMA50 rsiLongOk = not rsiFilterInput or not rsiOBNow rsiShortOk = not rsiFilterInput or not rsiOSNow sweepLongEntryRaw = showSweepEntriesInput and greenSweepFired and biasBullOkPre and chochBullOkPre and fvgBullConfPre and obBullConfPre and emaLongOk and rsiLongOk and entryAllowed sweepShortEntryRaw = showSweepEntriesInput and redSweepFired and biasBearOkPre and chochBearOkPre and fvgBearConfPre and obBearConfPre and emaShortOk and rsiShortOk and entryAllowed sweepLongEntry = sweepLongEntryRaw and barstate.isconfirmed sweepShortEntry = sweepShortEntryRaw and barstate.isconfirmed if greenSweepFired drawSweepLabel(greenSweepPrice, true, sweepLongEntry) if redSweepFired drawSweepLabel(redSweepPrice, false, sweepShortEntry) if sweepExtend for bx in aBoxBr if not bx.br and n_sweep - bx.bx.get_left() -1 <= sweepMaxBars bx.bx.set_right(bar_index) if bx.dr == -1 and close < bx.bx.get_bottom() bx.br := true if bx.dr == 1 and close > bx.bx.get_top() bx.br := true //---------------------------------------------------------------------------------------------------------------------} // MTF LEVELS //---------------------------------------------------------------------------------------------------------------------{ getStyle(string style) => switch style SOLID => line.style_solid DASHED => line.style_dashed DOTTED => line.style_dotted higherTimeframe(string tf_str) => timeframe.in_seconds() > timeframe.in_seconds(tf_str) drawLevels(string tf_str, bool sameTimeframe, string style, color levelColor, float topLevel, float bottomLevel, int leftTime, int rightTime) => float parsedTop = sameTimeframe ? high : topLevel float parsedBottom = sameTimeframe ? low : bottomLevel int parsedLeftTime = sameTimeframe ? time : leftTime int parsedRightTime = sameTimeframe ? time : rightTime int parsedTopTime = time int parsedBottomTime = time if not sameTimeframe int leftIndex = times.binary_search_rightmost(parsedLeftTime) int rightIndex = times.binary_search_rightmost(parsedRightTime) array timeArray = times.slice(leftIndex, rightIndex) array topArray = highs.slice(leftIndex, rightIndex) array bottomArray = lows.slice(leftIndex, rightIndex) parsedTopTime := timeArray.size() > 0 ? timeArray.get(topArray.indexof(topArray.max())) : initialTime parsedBottomTime := timeArray.size() > 0 ? timeArray.get(bottomArray.indexof(bottomArray.min())) : initialTime int labelX = last_bar_time + edgeOffsetInput * (time - time[1]) var line topLine = line.new(na,na,na,na,xloc=xloc.bar_time,color=levelColor,style=getStyle(style)) var line bottomLine = line.new(na,na,na,na,xloc=xloc.bar_time,color=levelColor,style=getStyle(style)) var label topLabel = na var label bottomLabel = na label.delete(topLabel) label.delete(bottomLabel) topLine.set_x1(parsedTopTime) topLine.set_y1(parsedTop) topLine.set_x2(labelX) topLine.set_y2(parsedTop) topLabel := label.new(labelX, parsedTop, str.format('P{0}H', tf_str), xloc=xloc.bar_time, color=color.new(color.black,100), textcolor=levelColor, size=size.small, style=label.style_label_left) bottomLine.set_x1(parsedBottomTime) bottomLine.set_y1(parsedBottom) bottomLine.set_x2(labelX) bottomLine.set_y2(parsedBottom) bottomLabel := label.new(labelX, parsedBottom, str.format('P{0}L', tf_str), xloc=xloc.bar_time, color=color.new(color.black,100), textcolor=levelColor, size=size.small, style=label.style_label_left) //---------------------------------------------------------------------------------------------------------------------} // HIGH/LOW & ZONES //---------------------------------------------------------------------------------------------------------------------{ updateTrailingExtremes() => trailing.top := math.max(high, trailing.top) trailing.lastTopTime := trailing.top == high ? time : trailing.lastTopTime trailing.bottom := math.min(low, trailing.bottom) trailing.lastBottomTime := trailing.bottom == low ? time : trailing.lastBottomTime drawHighLowSwings() => rightTimeBar = last_bar_time + edgeOffsetInput * (time - time[1]) var line topLine = line.new(na,na,na,na,color=swingBearishColor,xloc=xloc.bar_time,style=line.style_dotted) var line bottomLine = line.new(na,na,na,na,color=swingBullishColor,xloc=xloc.bar_time,style=line.style_dotted) var label topLabel = na var label bottomLabel = na label.delete(topLabel) label.delete(bottomLabel) topLine.set_x1(trailing.lastTopTime) topLine.set_y1(trailing.top) topLine.set_x2(rightTimeBar) topLine.set_y2(trailing.top) topLabel := label.new(rightTimeBar, trailing.top, swingTrend.bias == BEARISH ? 'Strong High' : 'Weak High', xloc=xloc.bar_time, color=color.new(color.black,100), textcolor=swingBearishColor, style=label.style_label_down, size=size.tiny) bottomLine.set_x1(trailing.lastBottomTime) bottomLine.set_y1(trailing.bottom) bottomLine.set_x2(rightTimeBar) bottomLine.set_y2(trailing.bottom) bottomLabel := label.new(rightTimeBar, trailing.bottom, swingTrend.bias == BULLISH ? 'Strong Low' : 'Weak Low', xloc=xloc.bar_time, color=color.new(color.black,100), textcolor=swingBullishColor, style=label.style_label_up, size=size.tiny) drawZone(float labelLevel, int labelIndex, float top, float bottom, string tag, color zoneColor, string style) => var box b_ox = box.new(na,na,na,na,bgcolor=color.new(zoneColor,91),border_color=color.new(color.black,100),xloc=xloc.bar_time) var label l_abel = na label.delete(l_abel) b_ox.set_lefttop(trailing.barTime, top) b_ox.set_rightbottom(last_bar_time, bottom) l_abel := label.new(labelIndex, labelLevel, tag, xloc=xloc.bar_index, color=color.new(color.black,100), textcolor=color.new(zoneColor,20), style=style, size=size.tiny) drawPremiumDiscountZones() => drawZone(trailing.top, math.round(0.5*(trailing.barIndex+last_bar_index)), trailing.top, 0.95*trailing.top+0.05*trailing.bottom, 'Premium', premiumZoneColor, label.style_label_down) equilibriumLevel = math.avg(trailing.top, trailing.bottom) drawZone(equilibriumLevel, last_bar_index, 0.525*trailing.top+0.475*trailing.bottom, 0.525*trailing.bottom+0.475*trailing.top, 'Equilibrium', equilibriumZoneColorInput, label.style_label_left) drawZone(trailing.bottom, math.round(0.5*(trailing.barIndex+last_bar_index)), 0.95*trailing.bottom+0.05*trailing.top, trailing.bottom, 'Discount', discountZoneColor, label.style_label_up) //---------------------------------------------------------------------------------------------------------------------} // EXECUTION — SMC //---------------------------------------------------------------------------------------------------------------------{ parsedOpen = showTrendInput ? open : na candleColor = showTrendInput ? (isBullBar ? color.new(TEAL,0) : color.new(ROSE,0)) : na plotcandle(parsedOpen,high,low,close,color=candleColor,wickcolor=candleColor,bordercolor=candleColor) plot(showEMAInput ? ema50 : na, 'EMA 50', color=ema50Color, linewidth=1) plot(showEMAInput ? ema200 : na, 'EMA 200', color=ema200Color, linewidth=2) var int lastCrossBar = -9999 crossSpaced = bar_index - lastCrossBar >= crossMinBarsInput if showEMAInput and emaCrossBull and crossSpaced label.new(bar_index, low - visUnit * crossOffsetInput, '✦ GOLDEN CROSS', color=color.new(SURFACE,25), textcolor=color.new(ACCENT,10), style=label.style_label_up, size=size.tiny) lastCrossBar := bar_index if showEMAInput and emaCrossBear and crossSpaced label.new(bar_index, high + visUnit * crossOffsetInput, '✦ DEATH CROSS', color=color.new(SURFACE,25), textcolor=color.new(SILVER,10), style=label.style_label_down, size=size.tiny) lastCrossBar := bar_index if showHighLowSwingsInput or showPremiumDiscountZonesInput updateTrailingExtremes() if showHighLowSwingsInput drawHighLowSwings() if showPremiumDiscountZonesInput drawPremiumDiscountZones() if showFairValueGapsInput deleteFairValueGaps() getCurrentStructure(swingsLengthInput,false) getCurrentStructure(5,false,true) if showEqualHighsLowsInput getCurrentStructure(equalHighsLowsLengthInput,true) if showInternalsInput or showInternalOrderBlocksInput or showTrendInput displayStructure(true) if showStructureInput or showSwingOrderBlocksInput or showHighLowSwingsInput displayStructure() if showInternalOrderBlocksInput deleteOrderBlocks(true) if showSwingOrderBlocksInput deleteOrderBlocks() if showFairValueGapsInput drawFairValueGaps(fvg_lc,fvg_lo,fvg_lt,fvg_ch,fvg_cl,fvg_ct,fvg_l2h,fvg_l2l) if barstate.islastconfirmedhistory or barstate.islast if showInternalOrderBlocksInput drawOrderBlocks(true) if showSwingOrderBlocksInput drawOrderBlocks() lastBarIndex := currentBarIndex currentBarIndex := bar_index newBar = currentBarIndex != lastBarIndex if barstate.islastconfirmedhistory or (barstate.isrealtime and newBar) if showDailyLevelsInput and not higherTimeframe('D') drawLevels('D', timeframe.isdaily, dailyLevelsStyleInput, dailyLevelsColorInput, d_top, d_bot, d_lt, d_rt) if showWeeklyLevelsInput and not higherTimeframe('W') drawLevels('W', timeframe.isweekly, weeklyLevelsStyleInput, weeklyLevelsColorInput, w_top, w_bot, w_lt, w_rt) if showMonthlyLevelsInput and not higherTimeframe('M') drawLevels('M', timeframe.ismonthly, monthlyLevelsStyleInput, monthlyLevelsColorInput, m_top, m_bot, m_lt, m_rt) //---------------------------------------------------------------------------------------------------------------------} // ENTRY & EXIT //---------------------------------------------------------------------------------------------------------------------{ bullCHoCH = currentAlerts.internalBullishCHoCH bearCHoCH = currentAlerts.internalBearishCHoCH bullBOS = currentAlerts.internalBullishBOS or currentAlerts.swingBullishBOS bearBOS = currentAlerts.internalBearishBOS or currentAlerts.swingBearishBOS if bullCHoCH lastBullCHoCH := true lastBearCHoCH := false if bearCHoCH lastBearCHoCH := true lastBullCHoCH := false fvgBullConf = requireFVGInput ? inBullFVG() : true fvgBearConf = requireFVGInput ? inBearFVG() : true obBullConf = requireOBInput ? nearBullOB() : true obBearConf = requireOBInput ? nearBearOB() : true longConditionCHoCH = showEntryInput and lastBullCHoCH and not inLong and fvgBullConf and obBullConf shortConditionCHoCH = showEntryInput and lastBearCHoCH and not inShort and fvgBearConf and obBearConf exitLong = showEntryInput and inLong and (bearBOS or bearCHoCH) exitShort = showEntryInput and inShort and (bullBOS or bullCHoCH) if longConditionCHoCH inLong := true inShort := false if shortConditionCHoCH inShort := true inLong := false if exitLong inLong := false if exitShort inShort := false // HELPER — create entry label and track it makeCardText(bool isBull, float tp1, float tp2, float tp3, float sl, int score) => head = isBull ? '▲ CALL' : '▼ PUT' wide = isBull ? '▲ C A L L' : '▼ P U T' sfx = showScoreInput and not qLegacy ? ' ' + (entryCardInput == 'Micro' ? str.tostring(score) : scoreTag(score)) : '' a = str.tostring(tp1, format.mintick) b = str.tostring(tp2, format.mintick) c = str.tostring(tp3, format.mintick) s = str.tostring(sl, format.mintick) switch entryCardInput 'Full' => wide + sfx + '\n' + HAIR + '\n' + 'TP1 ' + a + '\n' + 'TP2 ' + b + '\n' + 'TP3 ' + c + '\n' + 'SL ' + s 'Compact' => wide + sfx + '\n' + HAIR + '\n' + 'TP ' + a + ' · ' + b + ' · ' + c + '\n' + 'SL ' + s => head + sfx + '\n' + a + ' · ' + b + ' · ' + c + '\n' + 'SL ' + s makeCallLabel(float entryPrice, int score, float off) => ok = score >= effMinScore if ok [tp1, tp2, tp3, sl] = getStructTP(true, entryPrice) lbl = label.new(bar_index, low - visUnit * off, makeCardText(true, tp1, tp2, tp3, sl, score), color=color.new(SURFACE,8), textcolor=TEAL, style=label.style_label_up, size=entryCardInput == 'Micro' ? size.tiny : uiSize(SMALL), textalign=text.align_left) callEntries.push(entryLabel.new(lbl, bar_index)) ok makePutLabel(float entryPrice, int score, float off) => ok = score >= effMinScore if ok [tp1, tp2, tp3, sl] = getStructTP(false, entryPrice) lbl = label.new(bar_index, high + visUnit * off, makeCardText(false, tp1, tp2, tp3, sl, score), color=color.new(SURFACE,8), textcolor=ROSE, style=label.style_label_down, size=entryCardInput == 'Micro' ? size.tiny : uiSize(SMALL), textalign=text.align_left) putEntries.push(entryLabel.new(lbl, bar_index)) ok // ── CONFLUENCE STATE ── hasFVGBull = inBullFVG() hasFVGBear = inBearFVG() hasOBBull = nearBullOB() hasOBBear = nearBearOB() scoreBull = calcScore(true, greenSweepFired, lastBullCHoCH, hasFVGBull, hasOBBull) scoreBear = calcScore(false, redSweepFired, lastBearCHoCH, hasFVGBear, hasOBBear) kzOk = not effKZ or inKillZone qualLongOk = qLegacy or (scoreBull >= effMinScore and kzOk and htfBullCount >= effHtfMin) qualShortOk = qLegacy or (scoreBear >= effMinScore and kzOk and htfBearCount >= effHtfMin) var int lastCallBar = -9999 var int lastPutBar = -9999 longCdOk = (bar_index - lastCallBar >= cooldownBars) or (bar_index - lastCallBar >= 5 and (inExpansionUp or inExpansionDown)) shortCdOk = (bar_index - lastPutBar >= cooldownBars) or (bar_index - lastPutBar >= 5 and (inExpansionUp or inExpansionDown)) extraLongOk = not effGateAll or (longCdOk and fvgBullConf and obBullConf and emaLongOk and rsiLongOk) extraShortOk = not effGateAll or (shortCdOk and fvgBearConf and obBearConf and emaShortOk and rsiShortOk) // ── WHAT ACTUALLY FIRES ── sweepLongFire = sweepLongEntry and qualLongOk sweepShortFire = sweepShortEntry and qualShortOk chochLongFire = showStructEntries and showEntryInput and bullCHoCH and barstate.isconfirmed and not sweepLongFire and qualLongOk and extraLongOk chochShortFire = showStructEntries and showEntryInput and bearCHoCH and barstate.isconfirmed and not sweepShortFire and qualShortOk and extraShortOk momCallFire = momCallSignal and not sweepLongFire and not bullCHoCH and barstate.isconfirmed and (not effGateAll or (longCdOk and qualLongOk)) momPutFire = momPutSignal and not sweepShortFire and not bearCHoCH and barstate.isconfirmed and (not effGateAll or (shortCdOk and qualShortOk)) // ── CARD PLACEMENT — step further out when cards crowd each other ── callOff = labelOffsetInput + (bar_index - lastCallBar < 20 ? 0.6 : 0.0) putOff = labelOffsetInput + (bar_index - lastPutBar < 20 ? 0.6 : 0.0) // SWEEP ENTRIES if sweepLongFire if makeCallLabel(greenSweepPrice, scoreBull, callOff) lastEntryBar := bar_index lastCallBar := bar_index if sweepShortFire if makePutLabel(redSweepPrice, scoreBear, putOff) lastEntryBar := bar_index lastPutBar := bar_index // CHOCH ENTRIES — fire on every bullish/bearish CHoCH confirmed bar if chochLongFire if makeCallLabel(low, scoreBull, callOff) lastEntryBar := bar_index lastCallBar := bar_index if chochShortFire if makePutLabel(high, scoreBear, putOff) lastEntryBar := bar_index lastPutBar := bar_index // MOMENTUM MARKS — only when no CHoCH or sweep fired if momCallFire lbl = label.new(bar_index, low - visUnit * 0.18, '▲', color=color.new(color.black,100), textcolor=color.new(TEAL,10), style=label.style_label_up, size=size.tiny) callEntries.push(entryLabel.new(lbl, bar_index)) if effGateAll lastEntryBar := bar_index if momPutFire lbl = label.new(bar_index, high + visUnit * 0.18, '▼', color=color.new(color.black,100), textcolor=color.new(ROSE,10), style=label.style_label_down, size=size.tiny) putEntries.push(entryLabel.new(lbl, bar_index)) if effGateAll lastEntryBar := bar_index //---------------------------------------------------------------------------------------------------------------------} // RSI PANE //---------------------------------------------------------------------------------------------------------------------{ rsiColor = rsiOBNow ? color.new(ROSE,0) : rsiOSNow ? color.new(TEAL,0) : color.new(SILVER,15) rsiOBPlot = hline(rsiOBInput, 'OB', color=color.new(ROSE,68), linestyle=hline.style_dotted, linewidth=1) rsiOSPlot = hline(rsiOSInput, 'OS', color=color.new(TEAL,68), linestyle=hline.style_dotted, linewidth=1) rsiMidPlt = hline(50, 'Mid', color=color.new(SILVER,80), linestyle=hline.style_dotted, linewidth=1) plot(showRSIInput ? rsiVal : na, 'RSI', color=rsiColor, linewidth=2, display=display.pane) fill(rsiOBPlot, rsiMidPlt, color=color.new(ROSE,95)) fill(rsiOSPlot, rsiMidPlt, color=color.new(TEAL,95)) //---------------------------------------------------------------------------------------------------------------------} // MTF DASHBOARD — LANGUAGE //---------------------------------------------------------------------------------------------------------------------{ tlang(en, tr_s, es, fr, ar, zh, pt, hi, ru, ja, de, it, ko, id, nl) => switch dashLangInput 'Turkish' => tr_s 'Spanish' => es 'French' => fr 'Arabic' => ar 'Chinese' => zh 'Portuguese' => pt 'Hindi' => hi 'Russian' => ru 'Japanese' => ja 'German' => de 'Italian' => it 'Korean' => ko 'Indonesian' => id 'Dutch' => nl => en t_title = tlang('P E R K Y · S M C','SMC ÇZD Paneli','Panel SMC MTF','Tableau SMC MTF','لوحة SMC','SMC多周期','Painel SMC MTF','SMC डैशबोर्ड','SMC МТФ Панель','SMCダッシュボード','SMC MTF Panel','Pannello SMC','SMC 대시보드','Panel SMC','SMC Dashboard') t_tf = tlang('TF','ZD','MT','UT','الإطار','周期','TF','TF','ТФ','TF','ZR','TF','TF','TF','TF') t_bias = tlang('Bias','Yön','Sesgo','Biais','الاتجاه','趋势','Viés','दिशा','Направл.','バイアス','Tendenz','Bias','방향','Arah','Richting') t_struct = tlang('Structure','Yapı','Estructura','Structure','الهيكل','结构','Estrutura','संरचना','Структура','構造','Struktur','Struttura','구조','Struktur','Structuur') t_ob = tlang('OB','OB','OB','OB','OB','OB','OB','OB','OB','OB','OB','OB','OB','OB','OB') t_session = tlang('Session','Seans','Sesión','Session','الجلسة','交易时段','Sessão','सत्र','Сессия','セッション','Sitzung','Sessione','세션','Sesi','Sessie') t_bull = tlang('Bullish','Yükselen','Alcista','Haussier','صاعد','看涨','Alta','तेजी','Бычий','強気','Bullish','Rialzista','강세','Bullish','Bullish') t_bear = tlang('Bearish','Düşen','Bajista','Baissier','هابط','看跌','Baixa','मंदी','Медвежий','弱気','Bearish','Ribassista','약세','Bearish','Bearish') t_neut = tlang('Neutral','Nötr','Neutral','Neutre','محايد','中性','Neutro','तटस्थ','Нейтрально','ニュートラル','Neutral','Neutro','중립','Netral','Neutraal') t_bos = tlang('BOS','YKK','BOS','BOS','كسر الهيكل','结构突破','BOS','BOS','БОС','BOS','BOS','BOS','BOS','BOS','BOS') t_choch = tlang('CHoCH','YD','CHoCH','CHoCH','تغيير الطابع','结构转换','CHoCH','CHoCH','ЧОХЧ','CHoCH','CHoCH','CHoCH','CHoCH','CHoCH','CHoCH') t_none = tlang('—','—','—','—','—','—','—','—','—','—','—','—','—','—','—') t_bullOB = tlang('▲ Bull','▲ Yük.','▲ Alcista','▲ Hauss.','▲ صاعد','▲ 多头','▲ Alta','▲ बुल','▲ Бык.','▲ 強気','▲ Bull','▲ Rialz.','▲ 상승','▲ Bull','▲ Bull') t_bearOB = tlang('▼ Bear','▼ Düş.','▼ Bajista','▼ Baiss.','▼ هابط','▼ 空头','▼ Baixa','▼ बेयर','▼ Медв.','▼ 弱気','▼ Bear','▼ Ribassi.','▼ 하락','▼ Bear','▼ Bear') t_alignB = tlang('✦ Full Bullish','✦ Tümü Yük.','✦ Todo Alcista','✦ Tout Hauss.','✦ كل صاعد','✦ 全多头','✦ Tudo Alta','✦ सब तेजी','✦ Всё Бычье','✦ 全強気','✦ Alles Bull','✦ Tutto Rialz.','✦ 모두 강세','✦ Semua Bull','✦ Alles Bull') t_alignBR = tlang('✦ Full Bearish','✦ Tümü Düş.','✦ Todo Bajista','✦ Tout Baiss.','✦ كل هابط','✦ 全空头','✦ Tudo Baixa','✦ सब मंदी','✦ Всё Медвежье','✦ 全弱気','✦ Alles Bear','✦ Tutto Ribassi.','✦ 모두 약세','✦ Semua Bear','✦ Alles Bear') //---------------------------------------------------------------------------------------------------------------------} // DASHBOARD HELPERS //---------------------------------------------------------------------------------------------------------------------{ dashBiasStr(intB, swgB) => b = intB != 0 ? intB : swgB b == BULLISH ? t_bull : b == BEARISH ? t_bear : t_neut dashBiasCol(intB, swgB) => b = intB != 0 ? intB : swgB b == BULLISH ? TEAL : b == BEARISH ? ROSE : color.new(LIGHT_GRAY,35) dashStructStr(bullBOS, bearBOS, bullCH, bearCH) => bullCH ? '↑ ' + t_choch : bearCH ? '↓ ' + t_choch : bullBOS ? '↑ ' + t_bos : bearBOS ? '↓ ' + t_bos : '—' dashStructCol(bullBOS, bearBOS, bullCH, bearCH) => bullCH or bullBOS ? TEAL : bearCH or bearBOS ? ROSE : color.new(LIGHT_GRAY,35) dashOBStr(bullOB, bearOB) => bullOB ? t_bullOB : bearOB ? t_bearOB : t_none dashOBCol(bullOB, bearOB) => bullOB ? TEAL : bearOB ? ROSE : color.new(LIGHT_GRAY,35) f_london() => not na(time(timeframe.period, '0800-1630:23456', 'UTC')) f_ny() => not na(time(timeframe.period, '1330-2100:23456', 'UTC')) f_asia() => not na(time(timeframe.period, '0000-0800:23456', 'UTC')) dashSessionStr() => ny = f_ny() london = f_london() and not ny asia = f_asia() ny ? 'NEW YORK' : london ? 'LONDON' : asia ? 'ASIA' : 'CLOSED' dashSessionCol() => ny = f_ny() london = f_london() and not ny asia = f_asia() ny ? color.new(#57C7D4,0) : london ? color.new(#7B93E8,0) : asia ? color.new(#D9A45B,0) : color.new(LIGHT_GRAY,45) dashTxtSize() => switch dashSizeInput 'Tiny' => size.tiny 'Normal' => size.normal 'Large' => size.large => size.small dashPosition() => switch dashPosInput 'Top Left' => position.top_left 'Bottom Right' => position.bottom_right 'Bottom Left' => position.bottom_left => position.top_right allBullish = htf1_intBias == BULLISH and htf2_intBias == BULLISH and htf3_intBias == BULLISH and htf4_intBias == BULLISH allBearish = htf1_intBias == BEARISH and htf2_intBias == BEARISH and htf3_intBias == BEARISH and htf4_intBias == BEARISH //---------------------------------------------------------------------------------------------------------------------} // DASHBOARD TOGGLE //---------------------------------------------------------------------------------------------------------------------{ varip bool _dashVisible = true varip bool _lastToggleState = false if barstate.isfirst _dashVisible := showDashInput _lastToggleState := showDashToggle if showDashToggle != _lastToggleState _dashVisible := not _dashVisible _lastToggleState := showDashToggle dashOn = showDashInput ? _dashVisible : false togglePos = dashPosInput == 'Top Right' ? position.top_left : dashPosInput == 'Top Left' ? position.top_right : dashPosInput == 'Bottom Right' ? position.bottom_left : position.bottom_right var table toggleBtn = table.new(togglePos, 1, 1, frame_width=0) if barstate.islast or barstate.isrealtime table.cell(toggleBtn, 0, 0, dashOn ? '◆' : '◇', text_color=dashOn ? color.new(ACCENT,20) : color.new(LIGHT_GRAY,50), text_size=size.tiny, bgcolor=color.new(SURFACE,82), text_halign=text.align_center) //---------------------------------------------------------------------------------------------------------------------} // DASHBOARD TABLE //---------------------------------------------------------------------------------------------------------------------{ var table mtfDash = table.new(dashPosition(), 5, 7, border_width=0, frame_width=1, frame_color=color.new(GRAY,40)) if (barstate.islast or barstate.isrealtime) and dashOn ts = dashTxtSize() sesStr = dashSessionStr() sesCol = dashSessionCol() capBG = color.new(SURFACE,6) hdrBG = color.new(SURFACE,34) rowBG1 = color.new(SURFACE,58) rowBG2 = color.new(DARK_GRAY,58) dimTxt = color.new(LIGHT_GRAY,28) // ── caption row: brand left · live session right ── table.cell(mtfDash, 0, 0, t_title, text_color=color.new(ACCENT,5), text_size=ts, bgcolor=capBG, text_halign=text.align_left) table.cell(mtfDash, 1, 0, '', bgcolor=capBG) table.cell(mtfDash, 2, 0, '', bgcolor=capBG) table.cell(mtfDash, 3, 0, '● ' + sesStr, text_color=sesCol, text_size=size.tiny, bgcolor=capBG, text_halign=text.align_right) table.cell(mtfDash, 4, 0, '', bgcolor=capBG) table.merge_cells(mtfDash, 0, 0, 2, 0) table.merge_cells(mtfDash, 3, 0, 4, 0) // ── column heads ── headers = array.from(t_tf, t_bias, t_struct, t_ob, 'RSI') for col = 0 to 4 table.cell(mtfDash, col, 1, array.get(headers,col), text_color=color.new(LIGHT_GRAY,32), text_size=size.tiny, bgcolor=hdrBG, text_halign=text.align_center) tfs = array.from(dashTF1, dashTF2, dashTF3, dashTF4) intBiases = array.from(htf1_intBias, htf2_intBias, htf3_intBias, htf4_intBias) swgBiases = array.from(htf1_swgBias, htf2_swgBias, htf3_swgBias, htf4_swgBias) bBOS = array.from(htf1_bullBOS, htf2_bullBOS, htf3_bullBOS, htf4_bullBOS) brBOS = array.from(htf1_bearBOS, htf2_bearBOS, htf3_bearBOS, htf4_bearBOS) bCH = array.from(htf1_bullCH, htf2_bullCH, htf3_bullCH, htf4_bullCH) brCH = array.from(htf1_bearCH, htf2_bearCH, htf3_bearCH, htf4_bearCH) bOB = array.from(htf1_bullOB, htf2_bullOB, htf3_bullOB, htf4_bullOB) brOB = array.from(htf1_bearOB, htf2_bearOB, htf3_bearOB, htf4_bearOB) rsiArr = array.from(htf1_rsi, htf2_rsi, htf3_rsi, htf4_rsi) for i = 0 to 3 row = i + 2 rowBG = i % 2 == 0 ? rowBG1 : rowBG2 ib = array.get(intBiases, i) sb = array.get(swgBiases, i) bb = array.get(bBOS, i) brb = array.get(brBOS, i) bc = array.get(bCH, i) brc = array.get(brCH, i) bo = array.get(bOB, i) bro = array.get(brOB, i) rsiV = array.get(rsiArr, i) rsiC = nz(rsiV) >= rsiOBInput ? ROSE : nz(rsiV) <= rsiOSInput ? TEAL : dimTxt table.cell(mtfDash, 0, row, array.get(tfs,i), text_color=color.new(TEXT_HI,22), text_size=ts, bgcolor=rowBG, text_halign=text.align_center) table.cell(mtfDash, 1, row, dashBiasStr(ib,sb), text_color=dashBiasCol(ib,sb), text_size=ts, bgcolor=rowBG, text_halign=text.align_center) table.cell(mtfDash, 2, row, dashStructStr(bb,brb,bc,brc), text_color=dashStructCol(bb,brb,bc,brc), text_size=ts, bgcolor=rowBG, text_halign=text.align_center) table.cell(mtfDash, 3, row, dashOBStr(bo,bro), text_color=dashOBCol(bo,bro), text_size=ts, bgcolor=rowBG, text_halign=text.align_center) table.cell(mtfDash, 4, row, str.tostring(math.round(nz(rsiV),1)), text_color=rsiC, text_size=ts, bgcolor=rowBG, text_halign=text.align_center) // ── alignment strip ── alignStr = allBullish ? t_alignB : allBearish ? t_alignBR : HAIR alignCol = allBullish ? TEAL : allBearish ? ROSE : color.new(LIGHT_GRAY,55) table.cell(mtfDash, 0, 6, alignStr, text_color=alignCol, text_size=ts, bgcolor=capBG, text_halign=text.align_center) for col = 1 to 4 table.cell(mtfDash, col, 6, '', bgcolor=capBG) table.merge_cells(mtfDash, 0, 6, 4, 6) //---------------------------------------------------------------------------------------------------------------------} // WATERMARK //---------------------------------------------------------------------------------------------------------------------{ var table brandingTable = table.new(position.bottom_center, 1, 1) if (barstate.islast or barstate.isrealtime) and watermarkInput != 'Off' wmTxt = watermarkInput == 'Serif' ? '𝔓𝔢𝔞𝔨 𝔙𝔢𝔫𝔱𝔲𝔯𝔢𝔰 · 𝔭𝔢𝔯𝔨𝔶𝔱𝔯𝔞𝔡𝔢𝔰𝔰' : 'P E A K V E N T U R E S · P E R K Y T R A D E S S' table.cell(brandingTable, 0, 0, wmTxt, text_color=color.new(ACCENT,62), text_size=watermarkInput == 'Serif' ? size.normal : size.small, bgcolor=color.new(color.black,100)) //---------------------------------------------------------------------------------------------------------------------} // ALERTS //---------------------------------------------------------------------------------------------------------------------{ alertcondition(currentAlerts.internalBullishBOS, 'Internal Bullish BOS', 'Internal Bullish BOS formed') alertcondition(currentAlerts.internalBullishCHoCH, 'Internal Bullish CHoCH', 'Internal Bullish CHoCH formed') alertcondition(currentAlerts.internalBearishBOS, 'Internal Bearish BOS', 'Internal Bearish BOS formed') alertcondition(currentAlerts.internalBearishCHoCH, 'Internal Bearish CHoCH', 'Internal Bearish CHoCH formed') alertcondition(currentAlerts.swingBullishBOS, 'Bullish BOS', 'Bullish BOS formed') alertcondition(currentAlerts.swingBullishCHoCH, 'Bullish CHoCH', 'Bullish CHoCH formed') alertcondition(currentAlerts.swingBearishBOS, 'Bearish BOS', 'Bearish BOS formed') alertcondition(currentAlerts.swingBearishCHoCH, 'Bearish CHoCH', 'Bearish CHoCH formed') alertcondition(currentAlerts.internalBullishOrderBlock, 'Bullish Internal OB Breakout', 'Price broke bullish internal OB') alertcondition(currentAlerts.internalBearishOrderBlock, 'Bearish Internal OB Breakout', 'Price broke bearish internal OB') alertcondition(currentAlerts.swingBullishOrderBlock, 'Bullish Swing OB Breakout', 'Price broke bullish swing OB') alertcondition(currentAlerts.swingBearishOrderBlock, 'Bearish Swing OB Breakout', 'Price broke bearish swing OB') alertcondition(currentAlerts.equalHighs, 'Equal Highs', 'Equal highs detected') alertcondition(currentAlerts.equalLows, 'Equal Lows', 'Equal lows detected') alertcondition(currentAlerts.bullishFairValueGap, 'Bullish FVG', 'Bullish FVG formed') alertcondition(currentAlerts.bearishFairValueGap, 'Bearish FVG', 'Bearish FVG formed') alertcondition(sweepLongFire, '▲ CALL Entry — Sweep', 'Bull sweep CALL entry triggered') alertcondition(sweepShortFire, '▼ PUT Entry — Sweep', 'Bear sweep PUT entry triggered') alertcondition(chochLongFire, '▲ CALL Entry — CHoCH', 'Bullish CHoCH CALL entry triggered') alertcondition(chochShortFire, '▼ PUT Entry — CHoCH', 'Bearish CHoCH PUT entry triggered') alertcondition(exitLong, 'Exit Long', 'Exit long signal triggered') alertcondition(exitShort, 'Exit Short', 'Exit short signal triggered') alertcondition(allBullish, '✦ Full Bullish Alignment', 'All 4 timeframes Bullish') alertcondition(allBearish, '✦ Full Bearish Alignment', 'All 4 timeframes Bearish') alertcondition(emaCrossBull, '✦ Golden Cross', 'EMA Golden Cross') alertcondition(emaCrossBear, '✦ Death Cross', 'EMA Death Cross') alertcondition(rsiOBNow and not rsiOBNow[1], 'RSI Overbought', 'RSI entered overbought') alertcondition(rsiOSNow and not rsiOSNow[1], 'RSI Oversold', 'RSI entered oversold') alertcondition(momCallFire, '▲ Momentum CALL', 'Momentum shift bullish') alertcondition(momPutFire, '▼ Momentum PUT', 'Momentum shift bearish')