← К каталогу
Исходный код · ID 4178

SMC Confluence Suite

indicator smc confluence suite for tradingview.pine

Похожие материалы по тегам

#__slope direction line.mq5MQL5 / MetaTrader 5 · 1 общих теговrange breakout @meowforex1.pineTradingView · 1 общих тегов#1.mtf_collider_h4_close_13_v18bar.mq4MQL4 / MetaTrader 4 · 1 общих тегов!mth_fasttmaline_edit3.mq4MQL4 / MetaTrader 4 · 1 общих тегов!mth_fasttmaline_edit2.mq4MQL4 / MetaTrader 4 · 1 общих тегов!mth_fasttmaline_edit.mq4MQL4 / MetaTrader 4 · 1 общих тегов
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

SMC Confluence Suite — это индикатор для TradingView, который анализирует рыночную структуру на основе концепций SMC. Он отображает на графике прорывы структуры (BOS), смену характера (CHoCH), зоны справедливой стоимости (FVG), ордер-блоки и зоны оптимального входа (OTE). Индикатор работает поверх графика и поддерживает мультитаймфреймный анализ через получение данных с двух дополнительных таймфреймов.

Индикатор предоставляет визуальное отображение множества зон: премиум/дисконт, ликвидностные спреды, равные уровни (EQH/EQL), а также зоны с совпадением факторов (confluence). Все визуальные объекты ограничиваются настраиваемым максимальным количеством, чтобы избежать перегрузки графика. Доступны теги для максимумов и минимумов, цветовое кодирование бычьих и медвежьих зон.

Встроена система оценки совпадения факторов (Confluence Score) от 0 до 100 с буквенной оценкой и таблицей разбора каждого фактора. Индикатор рассчитывает параметры управления риском: размер позиции, стоп-лосс, тейк-профиты и соотношение риск/прибыль на основе заданного баланса аккаунта и процента риска.

Алертная система поддерживает множество настраиваемых событий — от структурных Break/Change до касаний зон и пересечения порога оценки. Действует охлаждение между оповещениями, фильтр по времени закрытия свечи и настраиваемые префиксы сообщений. На графике отображается панель с текущей информацией о настройке и статистикой оповещений.

Настройки программы

НастройкаОписание
leftLen Длина свинга слева — Количество баров слева для поиска свинг-хай/лоу.
rightLen Длина свинга справа — Количество баров справа для поиска свинг-хай/лоу.
bosUseWick Подтверждать BOS тенями — Подтверждение прорыва структуры по теням свечей вместо цен закрытия.
allowRetro Разрешить ретро BOS — Разрешает отложенные прорывы структуры с поздним подтверждением.
maxObjects Максимум линий/меток — Максимальное количество линий и меток, сохраняемых на графике.
tf1 Таймфрейм 1 — Первый дополнительный таймфрейм для анализа структуры.
col1 Цвет TF1 — Цвет отображения структуры на таймфрейме 1.
tf2 Таймфрейм 2 — Второй дополнительный таймфрейм для анализа структуры.
col2 Цвет TF2 — Цвет отображения структуры на таймфрейме 2.
show_tag Показать метки High/Low — Отображает метки High/Low для свинг-поинтов.
show_fvg Показать FVG — Отображает зоны справедливой стоимости (FVG).
fvgFilter Фильтр размера FVG — Фильтр размера зон FVG: выключен, по пунктам, по ATR или оба.
fvgMinPts Минимальный размер (пункты) — Минимальный размер зоны FVG в пунктах.
fvgMinAtr Минимальный размер (x ATR) — Минимальный размер зоны FVG в кратных значениях ATR.
fvgAtrLen Длина ATR — Период расчёта ATR для фильтра размера FVG.
maxFvgZones Максимум зон FVG — Максимальное количество хранимых зон FVG на графике.
fvg_col_bull Бычий цвет FVG — Цвет бычьих зон FVG.
fvg_col_bear Медвежий цвет FVG — Цвет медвежьих зон FVG.
show_ob Показать ордер-блоки — Отображает ордер-блоки.
obMode Режим обнаружения ордер-блоков — Режим обнаружения ордер-блоков: на основе BOS (SMC) или смещение (устаревший).
obSource Источник структуры — Источник структуры для обнаружения ордер-блоков: TF1, TF2 или оба.
obLookback Глубина поиска ордер-блока (бары) — Глубина поиска ордер-блока в количестве баров.
obFallback Использовать экстремальный бар как запас — При отсутствии противоположной свечи использовать экстремальный бар для поиска ордер-блока.
useExtFilter Включить фильтр экстремальных ордер-блоков — Включает фильтр экстремальных ордер-блоков, ограничивая количество отображаемых.
max_ob_show Максимум OB на свинг — Максимальное количество отображаемых ордер-блоков на один свинг.
maxObZones Максимум ордер-блоков (на сторону) — Максимальное количество хранимых ордер-блоков на каждую сторону.
ob_col_bull Бычий цвет ордер-блоков — Цвет бычьих ордер-блоков.
ob_col_bear Медвежий цвет ордер-блоков — Цвет медвежьих ордер-блоков.
mitigMode Режим митигации — Режим митигации зон: по касанию, заполнение на 50% или полное заполнение.
showZoneTxt Показать метку внутри зоны — Отображает текстовую метку внутри зоны (ордер-блок/FVG).
zoneTxtDir Добавить направление к метке — Добавляет направление (OB BUY / FVG SELL) к тексту метки внутри зоны.
zoneTxtCol Цвет текста в зоне — Цвет текста внутри зон.
zoneTxtSize Размер текста в зоне — Размер текста внутри зон: мелкий, малый, нормальный, большой.
show_ote Показать зону OTE — Отображает зоны оптимального входа (OTE).
oteShallow Неглубокий уровень OTE — Неглубинный уровень OTE как доля расстояния.
oteMid Средний уровень OTE (вход) — Средний уровень OTE, используемый как точка входа.
oteDeep Глубокий уровень OTE — Глубина зоны OTE (глубокий уровень) как доля расстояния.
snapEntry Привязка входа к зоне совпадения — Привязка точки входа к ближайшей зоне совпадения факторов.
tp2Ext Расширение Фибоначчи для TP2 — Расширение Фибоначчи для второго тейк-профита.
ote_col Цвет зоны OTE — Цвет зоны OTE.
oteConfCol Цвет границы при совпадении — Цвет границы зоны OTE при наличии совпадения факторов.
acc_size Баланс аккаунта ($) — Баланс аккаунта в долларах для расчёта размера позиции.
risk_pct Риск на сделку (%) — Процент риска на одну сделку от баланса аккаунта.
slBuffer Отступ стоп-лосса (пункты) — Отступ стоп-лосса в пунктах от уровня.
autoPV Автоматическая стоимость пункта — Автоматическое определение стоимости пункта на основе символа.
manualPV Стоимость пункта на лот ($) — Стоимость пункта на лот в долларах (используется при отключённом авто-определении).
show_pd Показать премиум/дисконт — Отображает зоны премиума и дисконта.
pdMode Фильтр премиум/дисконт — Фильтр премиум/дисконт для ордер-блоков и FVG: выключен, исключить, затемнить.
pdShowEq Показать линию равенства (50%) — Отображение линии равенства (50%) между последними свинг-хаем и лоу.
pdPremCol Цвет премиума — Цвет зоны премиума.
pdDiscCol Цвет дисконта — Цвет зоны дисконта.
pdEqCol Цвет линии равенства — Цвет линии равенства (50%).
show_sweep Показать ликвидностные спреды — Отображает ликвидностные спреды (прорисовку ликвидности).
swpLeft Пивот слева (бары) — Количество баров слева для определения пивота ликвидностного спреда.
swpRight Пивот справа (бары) — Количество баров справа для определения пивота ликвидностного спреда.
sweepMinPen Минимальное проникновение (x ATR) — Минимальное проникновение ликвидности в кратных значениях ATR.
sweepNeedBack Требовать возврат внутрь уровня — Требовать закрытие цены обратно внутри уровня после спреда.
sweepUpCol Цвет спреда на максимуме — Цвет спреда на максимуме (покупка).
sweepDnCol Цвет спреда на минимуме — Цвет спреда на минимуме (продажа).
show_eq Показать EQH/EQL — Отображает линии равных максимумов и минимумов (EQH/EQL).
eqTol Допуск равных уровней (x ATR) — Допуск равенства уровней в кратных значениях ATR.
eqCol Цвет линии EQ — Цвет линий равных уровней (EQH/EQL).
useScore Включить оценку совпадения — Включает систему оценки совпадения факторов (Confluence Score).
showScoreP Показать таблицу разбора оценки — Отображает таблицу разбора факторов оценки совпадения.
scDecay Срок жизни сигнала (бары) — Количество баров до обнуления свежести сигнала в оценке.
scRrTarget R:R для полной оценки — Соотношение риск/прибыль, за которое начисляется полная оценка.
scAlertLv Порог оценки для оповещения — Порог оценки совпадения факторов для срабатывания оповещения.
scBgTint Заливка фона выше порога — Заливка фона графика при превышении порога оценки.
w_struct Вес свежей структуры TF1 — Вес свежего прорыва/смены характера на таймфрейме 1 в формуле оценки.
w_htf Вес тренда TF2 — Вес совпадения тренда на таймфрейме 2 в формуле оценки.
w_ob Вес ордер-блока внутри OTE — Вес ордер-блока внутри OTE в формуле оценки.
w_fvg Вес FVG внутри OTE — Вес зоны FVG внутри OTE в формуле оценки.
w_pd Вес стороны равенства — Вес правильной стороны равенства в формуле оценки.
w_sweep Вес подтверждающего спреда — Вес подтверждающего спреда в формуле оценки.
w_ote Вес цены внутри OTE — Вес нахождения цены внутри зоны OTE в формуле оценки.
w_rr Вес качества R:R — Вес качества соотношения риск/прибыль в формуле оценки.
w_fresh Вес свежих зон — Вес свежих (нетронутых) зон в формуле оценки.
alertMasterStr Оповещения — Главный переключатель всех оповещений: включить или отключить.
alertOnClose Срабатывать при закрытии свечи — Оповещение срабатывает только при закрытии свечи (если отключено — внутри свечи, может перерисовываться).
alertCooldown Пауза между оповещениями (бары) — Количество баров между оповещениями одного типа (0 — без ограничений).
alertPrefix Префикс сообщения — Префикс в тексте оповещения.
a_bos1 BOS таймфрейм 1 — Включает оповещение при прорыве структуры (BOS) на таймфрейме 1.
a_choch1 CHoCH таймфрейм 1 — Включает оповещение при смене характера (CHoCH) на таймфрейме 1.
a_bos2 BOS таймфрейм 2 — Включает оповещение при прорыве структуры (BOS) на таймфрейме 2.
a_choch2 CHoCH таймфрейм 2 — Включает оповещение при смене характера (CHoCH) на таймфрейме 2.
a_retro Включить ретро BOS — Включает отслеживание отложенных (ретро) прорывов структуры в оповещениях.
a_newOb Новый ордер-блок — Включает оповещение при появлении нового ордер-блока.
a_newFvg Новый FVG — Включает оповещение при появлении новой зоны справедливой стоимости (FVG).
a_touchOb Цена касается ордер-блока — Включает оповещение при касании цены ордер-блока.
a_touchFvg Цена касается FVG — Включает оповещение при касании цены зоны FVG.
a_newOte Новая зона OTE — Включает оповещение при появлении новой зоны OTE.
a_enterOte Цена входит в OTE — Включает оповещение при входе цены в зону OTE.
a_sweep Ликвидностный спред — Включает оповещение при обнаружении ликвидностного спреда.
a_eq Формирование EQH/EQL — Включает оповещение при формировании равных максимумов/минимумов (EQH/EQL).
a_score Оценка пересекает порог — Включает оповещение при пересечении порога оценки совпадения факторов.
show_dash Показать панель сигналов — Отображает панель сигналов в правом верхнем углу графика.
showAlertRow Показать диагностику оповещений — Показывает строку диагностики оповещений на панели (количество отправленных оповещений).
dashSize Размер шрифта дашборда — Размер шрифта панели сигналов на графике.
Получить полный код

Поиск по коду файла

indicator("SMC Confluence Suite", overlay = true, max_lines_count = 500, max_labels_count = 500, max_boxes_count = 500)

DSP_OFF = display.data_window
DSP_ON  = display.status_line + display.data_window

var string GRP_STRUCT = "1 · Market Structure"
var string GRP_MTF    = "2 · Multi-Timeframe Swings"
var string GRP_FVG    = "3 · Fair Value Gap"
var string GRP_OB     = "4 · Order Block"
var string GRP_ZONE   = "5 · Zone Display"
var string GRP_RISK   = "6 · OTE & Risk Management"
var string GRP_PD     = "7 · Premium / Discount"
var string GRP_LIQ    = "8 · Liquidity"
var string GRP_SCORE  = "9 · Confluence Score"
var string GRP_ALERT  = "10 · Alerts"
var string GRP_DASH   = "11 · Dashboard"

leftLen    = input.int(5, "Swing Left Length",  group = GRP_STRUCT, minval = 1, display = DSP_OFF)
rightLen   = input.int(5, "Swing Right Length", group = GRP_STRUCT, minval = 1, display = DSP_OFF)
bosUseWick = input.bool(false, "Confirm BOS with wicks", group = GRP_STRUCT, display = DSP_OFF)
allowRetro = input.bool(true, "Allow Retro BOS (late confirmation)", group = GRP_STRUCT, display = DSP_OFF)
maxObjects = input.int(300, "Max lines / labels kept", group = GRP_STRUCT, minval = 50, maxval = 480, display = DSP_OFF)

tf1      = input.timeframe("15", "Timeframe 1", group = GRP_MTF, display = DSP_OFF)
col1     = input.color(color.aqua, "TF1 colour", group = GRP_MTF, inline = "c1", display = DSP_OFF)
tf2      = input.timeframe("60", "Timeframe 2", group = GRP_MTF, display = DSP_OFF)
col2     = input.color(color.orange, "TF2 colour", group = GRP_MTF, inline = "c2", display = DSP_OFF)
show_tag = input.bool(true, "Show High / Low tags", group = GRP_MTF, display = DSP_OFF)

show_fvg     = input.bool(true, "Show FVG", group = GRP_FVG, display = DSP_OFF)
fvgFilter    = input.string("ATR", "Size filter", options = ["Off", "Points", "ATR", "Both"], group = GRP_FVG, display = DSP_OFF)
fvgMinPts    = input.float(50, "Min size (points)", group = GRP_FVG, minval = 0, step = 10, display = DSP_OFF)
fvgMinAtr    = input.float(0.25, "Min size (x ATR)", group = GRP_FVG, minval = 0, step = 0.05, display = DSP_OFF)
fvgAtrLen    = input.int(14, "ATR length", group = GRP_FVG, minval = 1, display = DSP_OFF)
maxFvgZones  = input.int(30, "Max FVG kept", group = GRP_FVG, minval = 1, maxval = 150, display = DSP_OFF)
fvg_col_bull = input.color(color.new(color.green, 80), "Bullish", group = GRP_FVG, inline = "f", display = DSP_OFF)
fvg_col_bear = input.color(color.new(color.red, 80),   "Bearish", group = GRP_FVG, inline = "f", display = DSP_OFF)

show_ob      = input.bool(true, "Show Order Blocks", group = GRP_OB, display = DSP_OFF)
obMode       = input.string("BOS-based (SMC)", "Detection mode", options = ["BOS-based (SMC)", "Displacement (Legacy)"], group = GRP_OB, display = DSP_OFF)
obSource     = input.string("Both", "Structure source", options = ["TF1", "TF2", "Both"], group = GRP_OB, display = DSP_OFF)
obLookback   = input.int(15, "Displacement lookback (bars)", group = GRP_OB, minval = 2, maxval = 50, display = DSP_OFF)
obFallback   = input.bool(true, "Fall back to extreme bar if no opposite candle", group = GRP_OB, display = DSP_OFF)
useExtFilter = input.bool(false, "Enable extreme-OB filter", group = GRP_OB, display = DSP_OFF)
max_ob_show  = input.int(2, "Max OB per swing", group = GRP_OB, minval = 1, display = DSP_OFF)
maxObZones   = input.int(20, "Max OB kept (per side)", group = GRP_OB, minval = 1, maxval = 100, display = DSP_OFF)
ob_col_bull  = input.color(color.new(color.blue, 70),   "Bullish", group = GRP_OB, inline = "o", display = DSP_OFF)
ob_col_bear  = input.color(color.new(color.orange, 70), "Bearish", group = GRP_OB, inline = "o", display = DSP_OFF)

mitigMode   = input.string("50% Fill", "Mitigation mode", options = ["Touch", "50% Fill", "Full Fill"], group = GRP_ZONE, display = DSP_OFF)
showZoneTxt = input.bool(true, "Show label inside zone", group = GRP_ZONE, display = DSP_OFF)
zoneTxtDir  = input.bool(false, "Append direction (OB BUY / FVG SELL)", group = GRP_ZONE, display = DSP_OFF)
zoneTxtCol  = input.color(color.white, "Text colour", group = GRP_ZONE, inline = "zt", display = DSP_OFF)
zoneTxtSize = input.string("Small", "Size", options = ["Tiny", "Small", "Normal", "Large"], group = GRP_ZONE, inline = "zt", display = DSP_OFF)

show_ote   = input.bool(true, "Show OTE zone", group = GRP_RISK, display = DSP_OFF)
oteShallow = input.float(0.62,  "OTE shallow", group = GRP_RISK, minval = 0.1, maxval = 1.0, step = 0.005, display = DSP_OFF)
oteMid     = input.float(0.705, "OTE mid (entry)", group = GRP_RISK, minval = 0.1, maxval = 1.0, step = 0.005, display = DSP_OFF)
oteDeep    = input.float(0.79,  "OTE deep", group = GRP_RISK, minval = 0.1, maxval = 1.0, step = 0.005, display = DSP_OFF)
snapEntry  = input.bool(true, "Snap entry to confluence zone", group = GRP_RISK, display = DSP_OFF)
tp2Ext     = input.float(0.5, "TP2 fib extension", group = GRP_RISK, minval = 0.1, step = 0.1, display = DSP_OFF)
ote_col    = input.color(color.new(color.purple, 70), "OTE zone colour", group = GRP_RISK, display = DSP_OFF)
oteConfCol = input.color(color.lime, "Border colour when confluent", group = GRP_RISK, display = DSP_OFF)
acc_size   = input.float(1000.0, "Account balance ($)", group = GRP_RISK, minval = 1, display = DSP_OFF)
risk_pct   = input.float(1.0, "Risk per trade (%)", group = GRP_RISK, step = 0.1, minval = 0.1, display = DSP_OFF)
slBuffer   = input.float(100, "SL buffer (points)", group = GRP_RISK, step = 1, minval = 0, display = DSP_OFF) / 100
autoPV     = input.bool(false, "Auto point value", group = GRP_RISK, display = DSP_OFF)
manualPV   = input.float(100, "Point value per lot ($)", group = GRP_RISK, minval = 0.0001, display = DSP_OFF)

show_pd   = input.bool(true, "Show Premium / Discount zones", group = GRP_PD, display = DSP_OFF)
pdMode    = input.string("Dim Only", "P/D filter for OB & FVG", options = ["Off", "Filter Out", "Dim Only"], group = GRP_PD, display = DSP_OFF)
pdShowEq  = input.bool(true, "Show equilibrium line (50%)", group = GRP_PD, display = DSP_OFF)
pdPremCol = input.color(color.new(color.red, 92),   "Premium", group = GRP_PD, inline = "pd", display = DSP_OFF)
pdDiscCol = input.color(color.new(color.green, 92), "Discount", group = GRP_PD, inline = "pd", display = DSP_OFF)
pdEqCol   = input.color(color.new(color.gray, 40),  "EQ line", group = GRP_PD, display = DSP_OFF)

show_sweep    = input.bool(true, "Show liquidity sweeps", group = GRP_LIQ, display = DSP_OFF)
swpLeft       = input.int(5, "Sweep pivot left",  group = GRP_LIQ, minval = 1, inline = "sp", display = DSP_OFF)
swpRight      = input.int(2, "Right", group = GRP_LIQ, minval = 1, inline = "sp", display = DSP_OFF)
sweepMinPen   = input.float(0.05, "Min penetration (x ATR)", group = GRP_LIQ, minval = 0, step = 0.05, display = DSP_OFF)
sweepNeedBack = input.bool(true, "Require close back inside level", group = GRP_LIQ, display = DSP_OFF)
sweepUpCol    = input.color(color.red,  "Sweep high", group = GRP_LIQ, inline = "sc", display = DSP_OFF)
sweepDnCol    = input.color(color.lime, "Sweep low",  group = GRP_LIQ, inline = "sc", display = DSP_OFF)
show_eq       = input.bool(true, "Show EQH / EQL", group = GRP_LIQ, display = DSP_OFF)
eqTol         = input.float(0.10, "Equal-level tolerance (x ATR)", group = GRP_LIQ, minval = 0.01, step = 0.05, display = DSP_OFF)
eqCol         = input.color(color.new(color.yellow, 20), "EQ line colour", group = GRP_LIQ, display = DSP_OFF)

useScore   = input.bool(true, "Enable Confluence Score", group = GRP_SCORE, display = DSP_OFF)
showScoreP = input.bool(true, "Show score breakdown table", group = GRP_SCORE, display = DSP_OFF)
scDecay    = input.int(20, "Signal lifespan before score decays to 0 (bars)", group = GRP_SCORE, minval = 1, maxval = 500, display = DSP_OFF)
scRrTarget = input.float(2.0, "R:R that earns full credit", group = GRP_SCORE, minval = 0.5, step = 0.5, display = DSP_OFF)
scAlertLv  = input.int(70, "Alert threshold", group = GRP_SCORE, minval = 0, maxval = 100, display = DSP_OFF)
scBgTint   = input.bool(false, "Tint background above threshold", group = GRP_SCORE, display = DSP_OFF)

w_struct = input.float(20, "1 · Fresh BOS/CHoCH (TF1)", group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_htf    = input.float(15, "2 · TF2 trend aligned",     group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_ob     = input.float(15, "3 · OB inside OTE",         group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_fvg    = input.float(10, "4 · FVG inside OTE",        group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_pd     = input.float(15, "5 · Correct side of EQ",    group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_sweep  = input.float(10, "6 · Supporting sweep",      group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_ote    = input.float(10, "7 · Price inside OTE",      group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_rr     = input.float(10, "8 · R:R quality",           group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)
w_fresh  = input.float(5,  "9 · Untouched zones left",  group = GRP_SCORE, minval = 0, maxval = 50, step = 5, display = DSP_OFF)

alertMasterStr = input.string("ON", "Alerts", options = ["ON", "OFF"], group = GRP_ALERT, display = DSP_ON)
bool alertMaster = alertMasterStr == "ON"

alertOnClose  = input.bool(true, "Fire on bar close only", group = GRP_ALERT, tooltip = "OFF = intrabar (may repaint within the bar)", display = DSP_OFF)
alertCooldown = input.int(0, "Cooldown per event type (bars)", group = GRP_ALERT, minval = 0, maxval = 200, tooltip = "0 = no throttling. Raise only if you get spammed.", display = DSP_OFF)
alertPrefix   = input.string("SMC", "Message prefix", group = GRP_ALERT, display = DSP_OFF)

a_bos1     = input.bool(true,  "BOS TF1",        group = GRP_ALERT, inline = "a1", display = DSP_OFF)
a_choch1   = input.bool(true,  "CHoCH TF1",      group = GRP_ALERT, inline = "a1", display = DSP_OFF)
a_bos2     = input.bool(true,  "BOS TF2",        group = GRP_ALERT, inline = "a2", display = DSP_OFF)
a_choch2   = input.bool(true,  "CHoCH TF2",      group = GRP_ALERT, inline = "a2", display = DSP_OFF)
a_retro    = input.bool(false, "Include Retro BOS*", group = GRP_ALERT, display = DSP_OFF)
a_newOb    = input.bool(true,  "New OB",         group = GRP_ALERT, inline = "a3", display = DSP_OFF)
a_newFvg   = input.bool(false, "New FVG",        group = GRP_ALERT, inline = "a3", display = DSP_OFF)
a_touchOb  = input.bool(true,  "Price taps OB",  group = GRP_ALERT, inline = "a4", display = DSP_OFF)
a_touchFvg = input.bool(false, "Price taps FVG", group = GRP_ALERT, inline = "a4", display = DSP_OFF)
a_newOte   = input.bool(true,  "New OTE zone",   group = GRP_ALERT, inline = "a5", display = DSP_OFF)
a_enterOte = input.bool(true,  "Price enters OTE", group = GRP_ALERT, inline = "a5", display = DSP_OFF)
a_sweep    = input.bool(true,  "Liquidity sweep", group = GRP_ALERT, inline = "a6", display = DSP_OFF)
a_eq       = input.bool(false, "EQH / EQL formed", group = GRP_ALERT, inline = "a6", display = DSP_OFF)
a_score    = input.bool(true,  "Score crosses threshold", group = GRP_ALERT, display = DSP_OFF)

show_dash    = input.bool(true, "Show signal dashboard", group = GRP_DASH, display = DSP_OFF)
showAlertRow = input.bool(false, "Show alert diagnostics row", group = GRP_DASH, tooltip = "Confirms the alert engine is actually firing", display = DSP_OFF)
dashSize     = input.string("Small", "Dashboard font size", options = ["Tiny", "Small", "Normal"], group = GRP_DASH, display = DSP_OFF)

int  chartSec = timeframe.in_seconds(timeframe.period)
bool tf1Valid = timeframe.in_seconds(tf1) >= chartSec
bool tf2Valid = timeframe.in_seconds(tf2) >= chartSec
bool tfWarn   = not tf1Valid or not tf2Valid

string warnTxt = "Chart TF is higher than " + (not tf1Valid ? "TF1" : "") + (not tf1Valid and not tf2Valid ? " / " : "") + (not tf2Valid ? "TF2" : "") + " - that structure and its alerts are disabled"

string zTxtSize = zoneTxtSize == "Tiny" ? size.tiny : zoneTxtSize == "Small" ? size.small : zoneTxtSize == "Normal" ? size.normal : size.large
string dTxt     = dashSize == "Tiny" ? size.tiny : dashSize == "Small" ? size.small : size.normal

float atrVal   = ta.atr(fvgAtrLen)
float pointVal = autoPV ? (na(syminfo.pointvalue) or syminfo.pointvalue <= 0 ? manualPV : syminfo.pointvalue) : manualPV

type SwingPoint
    int   timeLoc
    float price
    int   ptype
    bool  isBroken
    int   confirmTime
    line  ln
    label lb

type StructState
    SwingPoint lastSwing
    SwingPoint lastHigh
    SwingPoint lastLow
    int    trend
    int    seenH
    int    seenL
    color  col
    bool   enabled
    int    retroSig
    int    evt
    bool   evtChoch
    bool   evtRetro
    float  evtPrice

type Zone
    box    bx
    float  top
    float  bottom
    int    dir
    int    originTime
    int    birthTime
    bool   mitigated
    string kind
    bool   touched      // [K3] real state - drives freshness score
    bool   notified     // [K3] alert de-duplication only
    bool   pdOk

var StructState st1 = StructState.new(na, na, na, 1, 0, 0, col1, false, 0, 0, false, false, na)
var StructState st2 = StructState.new(na, na, na, 1, 0, 0, col2, false, 0, 0, false, false, na)

var array<line>  structLines  = array.new<line>()
var array<label> structLabels = array.new<label>()

var array<Zone> fvgZones  = array.new<Zone>()
var array<Zone> obBull    = array.new<Zone>()
var array<Zone> obBear    = array.new<Zone>()
var array<Zone> interBull = array.new<Zone>()
var array<Zone> interBear = array.new<Zone>()

int ID_BOS1     = 0
int ID_CHOCH1   = 1
int ID_BOS2     = 2
int ID_CHOCH2   = 3
int ID_NEWOB    = 4
int ID_NEWFVG   = 5
int ID_TOUCHOB  = 6
int ID_TOUCHFVG = 7
int ID_NEWOTE   = 8
int ID_ENTEROTE = 9
int ID_SWEEP    = 10
int ID_EQ       = 11
int ID_SCORE    = 12

var array<int> alertClock = array.new<int>(13, -1000000)

var array<int> alertStat  = array.new<int>(2, 0)

fire(int id, bool enabled, string msg) =>
    bool sent = false
    if alertMaster and enabled
        int last = array.get(alertClock, id)
        if bar_index - last >= alertCooldown
            array.set(alertClock, id, bar_index)
            array.set(alertStat, 0, array.get(alertStat, 0) + 1)
            array.set(alertStat, 1, bar_index)
            if alertOnClose
                alert(msg, alert.freq_once_per_bar_close)
            else
                alert(msg, alert.freq_once_per_bar)
            sent := true
    sent

amsg(string body) =>
    alertPrefix + " | " + syminfo.ticker + " " + timeframe.period + " | " + body + " @ " + str.tostring(close, format.mintick)

method destroy(Zone z) =>
    box.delete(z.bx)
    true

method isMitigated(Zone z) =>
    float h = z.top - z.bottom
    bool res = false
    if h > 0
        float pen   = z.dir == 1 ? z.top - low : high - z.bottom
        float ratio = pen / h
        res := mitigMode == "Touch" ? ratio > 0 : mitigMode == "50% Fill" ? ratio >= 0.5 : ratio >= 1.0
    res

new_zone(int t, float top, float bottom, int dir, color bg, color border, string kind, bool pdOk) =>
    color  useBg = pdOk ? bg : color.new(bg, 94)
    color  useBd = na(border) ? border : (pdOk ? border : color.new(border, 90))
    string txt   = (not showZoneTxt or not pdOk) ? "" : zoneTxtDir ? kind + (dir == 1 ? " BUY" : " SELL") : kind
    box bx = box.new(left = t, top = top, right = t, bottom = bottom, border_color = useBd, border_style = line.style_solid, bgcolor = useBg, xloc = xloc.bar_time, extend = extend.right, text = txt, text_color = zoneTxtCol, text_halign = text.align_right, text_valign = text.align_center, text_size = zTxtSize)
    Zone.new(bx, top, bottom, dir, t, time, false, kind, false, false, pdOk)

detach(array<Zone> arr, Zone z) =>
    int i = array.indexof(arr, z)
    if i >= 0
        array.remove(arr, i)
    true

has_zone_at(array<Zone> zones, int t) =>
    bool found = false
    int sz = array.size(zones)
    if sz > 0
        for i = 0 to sz - 1
            if array.get(zones, i).originTime == t
                found := true
                break
    found

scan_touch(array<Zone> zones, bool enabled, int id) =>
    bool anyTouch = false
    int sz = array.size(zones)
    if sz > 0
        for i = 0 to sz - 1
            Zone z = array.get(zones, i)
            if not z.touched and z.pdOk and time > z.birthTime and low <= z.top and high >= z.bottom
                z.touched := true
                anyTouch  := true
                if not z.notified
                    z.notified := true
                    string side = z.dir == 1 ? "Bullish" : "Bearish"
                    fire(id, enabled, amsg("Price tapped " + side + " " + z.kind + " [" + str.tostring(z.bottom, format.mintick) + " - " + str.tostring(z.top, format.mintick) + "]"))
    anyTouch

count_fresh(array<Zone> zones) =>
    int c = 0
    int sz = array.size(zones)
    if sz > 0
        for i = 0 to sz - 1
            Zone z = array.get(zones, i)
            if z.pdOk and not z.touched
                c += 1
    c

manage_zones(array<Zone> zones, array<Zone> mirror, bool useMirror) =>
    int sz = array.size(zones)
    if sz > 0
        for i = sz - 1 to 0
            Zone z = array.get(zones, i)
            if time > z.birthTime and z.isMitigated()
                if useMirror
                    detach(mirror, z)
                z.destroy()
                array.remove(zones, i)
    true

prune_zones(array<Zone> zones, array<Zone> mirror, bool useMirror, int maxN) =>
    while array.size(zones) > maxN
        Zone z = array.shift(zones)
        if useMirror
            detach(mirror, z)
        z.destroy()
    true

get_mtf_pivots(int left, int right) =>
    float ph = ta.pivothigh(high, left, right)
    float pl = ta.pivotlow(low, left, right)

    float last_ph     = ta.valuewhen(not na(ph), ph, 0)
    int   last_time_h = int(ta.valuewhen(not na(ph), time[right], 0))
    float last_pl     = ta.valuewhen(not na(pl), pl, 0)
    int   last_time_l = int(ta.valuewhen(not na(pl), time[right], 0))

    [last_ph[1], last_pl[1], last_time_h[1], last_time_l[1]]

[ph1, pl1, pTimeH1, pTimeL1] = request.security(syminfo.tickerid, tf1, get_mtf_pivots(leftLen, rightLen), lookahead = barmerge.lookahead_on)
[ph2, pl2, pTimeH2, pTimeL2] = request.security(syminfo.tickerid, tf2, get_mtf_pivots(leftLen, rightLen), lookahead = barmerge.lookahead_on)

method push_swing(StructState st, int t, float p, int typ) =>
    bool changed = false
    bool sameRun = not na(st.lastSwing) and st.lastSwing.ptype == typ

    if sameRun
        SwingPoint cur = st.lastSwing
        bool moreExtreme = typ == 1 ? p > cur.price : p < cur.price

        if moreExtreme
            cur.timeLoc     := t
            cur.price       := p
            cur.confirmTime := time
            cur.isBroken    := false

            if not na(cur.lb)
                label.set_xy(cur.lb, t, p)
            if not na(cur.ln)
                line.set_x2(cur.ln, t)
                line.set_y2(cur.ln, p)

            if (typ == 1 and close > p) or (typ == -1 and close < p)
                cur.isBroken := true
                st.retroSig  := typ

            changed := true
    else
        label lb = na
        if show_tag
            lb := label.new(x = t, y = p, text = typ == 1 ? "H" : "L", style = typ == 1 ? label.style_label_down : label.style_label_up, color = color.new(st.col, 50), textcolor = color.white, xloc = xloc.bar_time)
            array.push(structLabels, lb)

        line ln = na
        if not na(st.lastSwing)
            ln := line.new(x1 = st.lastSwing.timeLoc, y1 = st.lastSwing.price, x2 = t, y2 = p, color = st.col, style = line.style_dashed, xloc = xloc.bar_time)
            array.push(structLines, ln)

        SwingPoint sp = SwingPoint.new(t, p, typ, false, time, ln, lb)

        if (typ == 1 and close > p) or (typ == -1 and close < p)
            sp.isBroken := true
            st.retroSig := typ

        st.lastSwing := sp
        if typ == 1
            st.lastHigh := sp
        else
            st.lastLow := sp

        changed := true

    changed

method update_swings(StructState st, float ph, float pl, int pTimeH, int pTimeL) =>
    bool touched = false
    int tH = int(nz(pTimeH))
    int tL = int(nz(pTimeL))

    bool gotH = st.enabled and not na(ph) and tH > 0 and tH != st.seenH
    bool gotL = st.enabled and not na(pl) and tL > 0 and tL != st.seenL

    if gotH and gotL

        if tH <= tL
            touched := st.push_swing(tH, ph, 1)
            touched := st.push_swing(tL, pl, -1) or touched
        else
            touched := st.push_swing(tL, pl, -1)
            touched := st.push_swing(tH, ph, 1) or touched
        st.seenH := tH
        st.seenL := tL
    else if gotH
        touched  := st.push_swing(tH, ph, 1)
        st.seenH := tH
    else if gotL
        touched  := st.push_swing(tL, pl, -1)
        st.seenL := tL

    touched

st1.enabled := tf1Valid
st2.enabled := tf2Valid

bool newSwing1 = st1.update_swings(ph1, pl1, pTimeH1, pTimeL1)
bool newSwing2 = st2.update_swings(ph2, pl2, pTimeH2, pTimeL2)

draw_break(StructState st, SwingPoint sp, bool isBull, bool retro) =>
    sp.isBroken := true
    string base = isBull ? (st.trend == -1 ? "CHoCH" : "BOS") : (st.trend == 1 ? "CHoCH" : "BOS")
    string txt  = retro ? base + "*" : base

    ln = line.new(x1 = sp.timeLoc, y1 = sp.price, x2 = time, y2 = sp.price, color = st.col, style = retro ? line.style_dotted : line.style_solid, width = 2, xloc = xloc.bar_time)
    array.push(structLines, ln)

    lbl = label.new(x = int(math.avg(sp.timeLoc, time)), y = sp.price, text = txt, color = color.new(color.white, 100), textcolor = st.col, style = isBull ? label.style_label_down : label.style_label_up, size = size.small, xloc = xloc.bar_time)
    array.push(structLabels, lbl)

    st.evt      := isBull ? 1 : -1
    st.evtChoch := base == "CHoCH"
    st.evtRetro := retro
    st.evtPrice := sp.price
    st.trend    := isBull ? 1 : -1
    true

check_structure(StructState st) =>
    st.evt := 0
    float upRef = bosUseWick ? high : close
    float dnRef = bosUseWick ? low  : close

    bool bullBreak = st.enabled and not na(st.lastHigh) and not st.lastHigh.isBroken and time > st.lastHigh.confirmTime and upRef > st.lastHigh.price
    bool bearBreak = st.enabled and not na(st.lastLow)  and not st.lastLow.isBroken  and time > st.lastLow.confirmTime  and dnRef < st.lastLow.price

    bool retroBull = allowRetro and st.enabled and st.retroSig == 1  and not na(st.lastHigh)
    bool retroBear = allowRetro and st.enabled and st.retroSig == -1 and not na(st.lastLow)
    st.retroSig := 0

    bool bearFirst = close >= open

    if bullBreak and bearBreak
        if bearFirst
            draw_break(st, st.lastLow, false, false)
            draw_break(st, st.lastHigh, true, false)
        else
            draw_break(st, st.lastHigh, true, false)
            draw_break(st, st.lastLow, false, false)
    else if bullBreak
        draw_break(st, st.lastHigh, true, false)
    else if bearBreak
        draw_break(st, st.lastLow, false, false)
    else if retroBull
        draw_break(st, st.lastHigh, true, true)
    else if retroBear
        draw_break(st, st.lastLow, false, true)

    [bullBreak or retroBull, bearBreak or retroBear]

[bull1, bear1] = check_structure(st1)
[bull2, bear2] = check_structure(st2)

bool retroPass1 = a_retro or not st1.evtRetro
bool retroPass2 = a_retro or not st2.evtRetro
bool evBos1     = st1.evt != 0 and not st1.evtChoch and retroPass1
bool evChoch1   = st1.evt != 0 and st1.evtChoch     and retroPass1
bool evBos2     = st2.evt != 0 and not st2.evtChoch and retroPass2
bool evChoch2   = st2.evt != 0 and st2.evtChoch     and retroPass2

struct_alert(StructState st, string tfName, bool okBos, bool okChoch, int idBos, int idChoch) =>
    bool sent = false
    if st.evt != 0 and (a_retro or not st.evtRetro)
        string dir  = st.evt == 1 ? "Bullish" : "Bearish"
        string kind = (st.evtChoch ? "CHoCH" : "BOS") + (st.evtRetro ? "*" : "")
        string body = kind + " " + dir + " [" + tfName + "] broke " + str.tostring(st.evtPrice, format.mintick)
        sent := fire(st.evtChoch ? idChoch : idBos, st.evtChoch ? okChoch : okBos, amsg(body))
    sent

bool sA1 = struct_alert(st1, tf1, a_bos1, a_choch1, ID_BOS1, ID_CHOCH1)
bool sA2 = struct_alert(st2, tf2, a_bos2, a_choch2, ID_BOS2, ID_CHOCH2)

while array.size(structLines) > maxObjects
    line.delete(array.shift(structLines))
while array.size(structLabels) > maxObjects
    label.delete(array.shift(structLabels))
var table wm = table.new(position.bottom_right, 1, 1)
if barstate.isfirst
    table.cell(wm, 0, 0, "Telegram @SimpleForexTools", text_color = color.new(color.gray, 70), text_size = size.large)

float rngHigh = na
float rngLow  = na
float rngEq   = na
int   rngLeft = 0

if not na(st1.lastHigh) and not na(st1.lastLow)
    rngHigh := st1.lastHigh.price
    rngLow  := st1.lastLow.price
    rngEq   := math.avg(rngHigh, rngLow)
    rngLeft := math.min(st1.lastHigh.timeLoc, st1.lastLow.timeLoc)

pd_ok(int dir, float top, float bottom) =>
    bool ok = true
    if pdMode != "Off" and not na(rngEq)
        float mid = math.avg(top, bottom)
        ok := dir == 1 ? mid <= rngEq : mid >= rngEq
    ok

pd_allow_create(bool ok) =>
    pdMode == "Filter Out" ? ok : true

var box   pdPremBx = na
var box   pdDiscBx = na
var line  pdEqLn   = na
var float lastRngH = na
var float lastRngL = na

if show_pd and not na(rngEq)
    if rngHigh != lastRngH or rngLow != lastRngL
        box.delete(pdPremBx)
        box.delete(pdDiscBx)
        line.delete(pdEqLn)
        pdPremBx := box.new(left = rngLeft, top = rngHigh, right = time, bottom = rngEq, border_color = color.new(pdPremCol, 60), bgcolor = pdPremCol, xloc = xloc.bar_time, extend = extend.

Показано первые 50% кода (символов: 39504)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
3 950,40₽ ≈ $48.28