HARMONIC Lab
Похожие материалы по тегам
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «indicator harmonic lab for tradingview.pine» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
HARMONIC Lab — индикатор TradingView для обнаружения гармонических и классических ценовых паттернов на графике. Он выявляет структуры XABCD (Gartley, Butterfly, Bat, Crab и другие), классические формации (голова и плечи, двойная вершина/дно, треугольники, 3-Drive) и зоны Supply | Demand. Для каждого обнаруженного паттерна рассчитываются уровни входа, цели и стоп-лосс, отображаются линии, заливки, метки и зоны подтверждения. Индикатор работает на основе свинг-пивотов и не использует внешние библиотеки или данные будущих баров.
Настройки программы
| Настройка | Описание |
|---|---|
| depth | Минимальная длина ZigZag — Минимальное количество баров между пивотами для построения волн ZigZag. |
| dMode | Режим обнаружения D — Способ подтверждения точки D: по закрытию бара (развивающаяся) или по подтверждённому пивоту. |
| confirmBars | Бары подтверждения пивота — Количество баров после пивота, необходимых для его подтверждения. |
| multiscale | Поиск по нескольким масштабам — Искать паттерны на глубинах 1x, 2x и 3x от базовой длины ZigZag. |
| searchNested | Поиск вложенных комбинаций — Разрешить вложенные XABCD-структуры внутри одной волны. |
| candidateLimit | Максимум кандидатов — Максимальное количество кандидатов на паттерн на каждую глубину. |
| errorPct | Допуск ошибки — Процентная допустимая погрешность соотношений паттерна. |
| minSize | Минимум баров паттерна — Минимальное количество баров от X до D в паттерне. |
| maxSize | Максимум баров паттерна — Максимальное количество баров от X до D в паттерне. |
| minHeight | Минимальная высота паттерна — Минимальная высота паттерна в процентах от диапазона. |
| minCD | Минимум баров C–D — Минимальное количество баров между точками C и D. |
| direction | Направление — Направление поиска паттернов: оба, только длинные или только короткие. |
| sessionHours | Сессия обнаружения — Временной интервал, в течение которого разрешено обнаружение паттернов. |
| utcOffset | Смещение сессии UTC — Часовое смещение сессии обнаружения от UTC. |
| maxPerBar | Максимум новых паттернов за бар — Максимальное количество новых паттернов, добавляемых за один бар. |
| maxActive | Максимум активных паттернов — Максимальное количество одновременно активных паттернов на графике. |
| noSame | Блокировка дублей — Запрещать одновременно активные паттерны одного семейства и направления. |
| maxAge | Срок жизни паттерна — Количество баров после обнаружения, через которое паттерн считается истёкшим. |
| useGartley | Gartley — Включить обнаружение паттерна Gartley. |
| useButterfly | Butterfly — Включить обнаружение паттерна Butterfly. |
| useBat | Bat — Включить обнаружение паттерна Bat. |
| useCrab | Crab — Включить обнаружение паттерна Crab. |
| useAltBat | Alternate Bat — Включить обнаружение альтернативного Bat. |
| useDeepCrab | Deep Crab — Включить обнаружение Deep Crab. |
| useCypher | Cypher — Включить обнаружение паттерна Cypher. |
| cypherMin | Минимум XC/XA для Cypher — Минимальное соотношение XC к XA для паттерна Cypher. |
| useABCD | AB=CD — Включить обнаружение паттерна AB=CD. |
| useWhiteSwan | White Swan — Включить обнаружение White Swan. |
| useBlackSwan | Black Swan — Включить обнаружение Black Swan. |
| levelBasis | Основа расчёта уровней — База для расчёта уровней входа и целей: по семейству, по AD или по CD. |
| entryPct | Процент входа — Процент от выбранного отрезка для уровня входа. |
| t1Pct | Процент цели 1 — Процент от выбранного отрезка для первой цели. |
| t2Pct | Процент цели 2 — Процент от выбранного отрезка для второй цели. |
| keepUntil | Завершение паттерна при — Условие завершения паттерна: достижение Target 1 или Target 2. |
| useRR | Цели по отношению риск/доход — Рассчитывать цели по соотношению reward/risk вместо процентного отрезка. |
| rr1 | Отношение риск/доход цели 1 — Соотношение reward/risk для первой цели. |
| rr2 | Отношение риск/доход цели 2 — Соотношение reward/risk для второй цели. |
| entryMode | Триггер входа — Условие подтверждения входа: по закрытию, по касанию или по свечному паттерну. |
| stopMode | Режим стопа — Способ расчёта стоп-лосса: по зоне, вручную, по точке безубыточности или трейлинг. |
| manualPct | Ручной стоп % — Процент от цены входа для ручного стоп-лосса. |
| zonePadPct | Отступ зоны проверки — Процентное расширение зоны проверки от отрезка CD. |
| bePct | Безубыточность % — Процент смещения стопа в точку безубыточности от входа к T1. |
| trailAfter | Начало трейлинга — После какого события начинается трейлинг-стоп: после входа или после T1. |
| trailMult | Множитель трейлинга — Множитель расстояния от входа до T1 для расчёта трейлинга. |
| invalidSource | Источник инвалидации — Источник цены для проверки инвалидации до входа: закрытие или высокий/низкий. |
| requireEntrySide | Требование стороны цены — Требовать, чтобы цена была ниже/выше уровня входа при подтверждении. |
| entryOvershootPct | Допуск отклонения входа — Допустимое отклонение цены от уровня входа в процентах. |
| zoneStyle | Стиль линии зоны — Стиль линии зоны подтверждения: сплошной, пунктирный или точечный. |
| requireZone | Требовать зону подтверждения — Требовать, чтобы закрытие оставалось внутри зоны подтверждения. |
| showPatterns | Рисовать паттерны — Отображать линии и фигуры паттернов на графике. |
| hideLetters | Скрыть подписи XABCD — Не отображать буквенные метки точек XABCD. |
| showOnlyLevels | Только уровни — Показывать только уровни входа, целей и стопа без линий паттерна. |
| showRatios | Показывать соотношения — Отображать числовые значения соотношений на графике. |
| showLevels | Рисовать уровни — Отображать уровни входа, целей и стопа на графике. |
| showZones | Показать зоны подтверждения — Отображать зоны валидации паттернов на графике. |
| showFill | Заливка паттернов — Заливать треугольники паттернов цветом. |
| fillAlpha | Прозрачность заливки — Уровень прозрачности заливки паттернов. |
| colorMode | Цвета паттернов — Режим окраски паттернов: классическая палитра или по направлению. |
| labelSize | Размер подписей — Размер текста подписей на графике. |
| showGuides | Внутренние диагонали — Показывать вспомогательные измерительные линии внутри паттернов. |
| levelLength | Длина сегмента уровня — Длина горизонтального сегмента уровня на графике. |
| palette1 | Цвет паттерна 1 — Первый цвет палитры для паттернов. |
| palette2 | Цвет паттерна 2 — Второй цвет палитры для паттернов. |
| palette3 | Цвет паттерна 3 — Третий цвет палитры для паттернов. |
| palette4 | Цвет паттерна 4 — Четвёртый цвет палитры для паттернов. |
| palette5 | Цвет паттерна 5 — Пятый цвет палитры для паттернов. |
| palette6 | Цвет паттерна 6 — Шестой цвет палитры для паттернов. |
| palette7 | Цвет паттерна 7 — Седьмой цвет палитры для паттернов. |
| palette8 | Цвет паттерна 8 — Восьмой цвет палитры для паттернов. |
| palette9 | Цвет паттерна 9 — Девятый цвет палитры для паттернов. |
| palette10 | Цвет паттерна 10 — Десятый цвет палитры для паттернов. |
| longColor | Цвет длинной позиции — Цвет для обозначения бычьих (длинных) паттернов. |
| shortColor | Цвет короткой позиции — Цвет для обозначения медвежьих (коротких) паттернов. |
| textColor | Цвет текста — Цвет текста на графике. |
| lineWidth | Толщина линий — Толщина линий паттернов на графике. |
| patternStyle | Стиль линий паттерна — Стиль линий паттернов: сплошной, пунктирный или точечный. |
| levelStyle | Стиль линий уровней — Стиль линий уровней: сплошной, пунктирный или точечный. |
| projection | Проекция уровней — Количество баров вправо для проекции горизонтальных уровней. |
| showOnlyActive | Только активные паттерны — Показывать на графике только активные (незавершённые) паттерны. |
| keepLast | Сохранять последний паттерн — Оставлять последний завершённый паттерн на графике. |
| maxShown | Максимум отображаемых — Максимальное количество паттернов, отображаемых на графике. |
| historyCount | Минимум сохранённых — Минимальное количество завершённых паттернов, оставляемых на графике. |
| predict | Показать прогноз зоны D — Отображать возможную зону D на основе текущей структуры свинг-пивотов. |
| predDisplay | Отображение прогноза — Что показывать для прогноза: паттерн с меткой, только паттерн или только метку. |
| predMaxFamilies | Максимум семейств в прогнозе — Максимальное количество семейств паттернов в метке прогноза (0 — все). |
| predDirection | Направление прогноза — Направление для прогноза: оба, только длинные или только короткие. |
| predColor | Цвет линии прогноза — Цвет линий прогнозной зоны D. |
| predZoneColor | Цвет зоны прогноза — Цвет заливки прогнозной зоны. |
| predLabelColor | Цвет фона метки прогноза — Фон метки прогнозной зоны. |
| predTextColor | Цвет текста прогноза — Цвет текста в метке прогноза. |
| predWidth | Толщина линии прогноза — Толщина линий прогноза. |
| predStyle | Стиль линии прогноза — Стиль линий прогноза: сплошной, пунктирный, точечный или отсутствует. |
| showPanel | Панель активных паттернов — Показывать таблицу активных паттернов на графике. |
| showStats | Счётчики жизненного цикла — Показывать счётчики найденных, вошедших, достигших целей и стопов. |
| panelSize | Размер панели — Размер панели активных паттернов. |
| panelPos | Позиция панели — Вертикальное расположение панели на графике. |
| panelAlign | Выравнивание панели — Горизонтальное выравнивание панели. |
| panelLongColor | Цвет покупки в панели — Фон ячейки направления Long в панели. |
| panelShortColor | Цвет продажи в панели — Фон ячейки направления Short в панели. |
| panelDoneColor | Цвет достигнутого — Фон ячейки для достигнутого уровня в панели. |
Поиск по коду файла
indicator("HARMONIC Lab", "Harmonic Lab", overlay = true, max_lines_count = 500, max_labels_count = 500, max_boxes_count = 200, max_polylines_count = 100, max_bars_back = 5000)
gSetup = "01 · Detection | Detection"
depth = input.int(8, "Minimum ZigZag Period | Minimum ZigZag Period", minval = 4, maxval = 50, group = gSetup)
dMode = input.string("Developing D (bar close)", "D detection mode | D detection mode", options = ["Developing D (bar close)", "Confirmed pivot"], group = gSetup, tooltip = "Developing D is tested at candle close before right-side pivot confirmation. It can be superseded by a later extreme; detected patterns remain frozen.")
confirmBars = input.int(2, "Pivot confirmation bars | Pivot confirmation bars", minval = 1, maxval = 20, group = gSetup, tooltip = "A pivot is known this many bars after its location. Signals are emitted only when known.")
multiscale = input.bool(false, "Search 1x / 2x / 3x depth | Search 1x / 2x / 3x depth", group = gSetup)
searchNested = input.bool(true, "Search nested XABCD combinations | Search nested XABCD combinations", group = gSetup)
candidateLimit = input.int(40, "Maximum candidate geometries per depth | Maximum candidate geometries per depth", minval = 1, maxval = 81, group = gSetup)
errorPct = input.float(8, "Error Rate % | Error Rate %", minval = 1, maxval = 20, step = 0.5, group = gSetup)
minSize = input.int(20, "Minimum pattern bars | Minimum pattern bars", minval = 10, maxval = 160, group = gSetup)
maxSize = input.int(150, "Maximum pattern bars | Maximum pattern bars", minval = 50, maxval = 200, group = gSetup)
windowLow = ta.lowest(low, maxSize)
windowHigh = ta.highest(high, maxSize)
minHeight = input.float(0, "Minimum pattern height % | Minimum pattern height %", minval = 0, step = 0.1, group = gSetup)
minCD = input.int(1, "Minimum C–D bars | Minimum C–D bars", minval = 1, maxval = 100, group = gSetup)
direction = input.string("Both", "Direction | Direction", options = ["Both", "Long", "Short"], group = gSetup)
sessionHours = input.session("0000-0000", "Detection session | Detection session", group = gSetup)
utcOffset = input.int(0, "Session UTC offset | Session UTC offset", minval = -12, maxval = 14, group = gSetup)
maxPerBar = input.int(2, "Maximum new patterns per bar | Maximum new patterns per bar", minval = 1, maxval = 3, group = gSetup)
maxActive = input.int(8, "Maximum active patterns | Maximum active patterns", minval = 1, maxval = 20, group = gSetup)
noSame = input.bool(true, "Block same active pattern / direction | Block same active pattern / direction", group = gSetup)
maxAge = input.int(160, "Expire after bars from detection | Expire after bars from detection", minval = 1, maxval = 2000, group = gSetup)
gPatterns = "02 · Pattern families | Pattern families"
useGartley = input.bool(true, "Gartley | Gartley", group = gPatterns)
useButterfly = input.bool(true, "Butterfly | Butterfly", group = gPatterns)
useBat = input.bool(true, "Bat | Bat", group = gPatterns)
useCrab = input.bool(true, "Crab | Crab", group = gPatterns)
useAltBat = input.bool(true, "Alternate Bat | Alternate Bat", group = gPatterns)
useDeepCrab = input.bool(true, "Deep Crab | Deep Crab", group = gPatterns)
useCypher = input.bool(true, "Cypher | Cypher", group = gPatterns)
cypherMin = input.float(1.13, "Cypher minimum XC / XA | Cypher minimum XC / XA", options = [1.13, 1.272], group = gPatterns)
useABCD = input.bool(true, "AB=CD", group = gPatterns)
useWhiteSwan = input.bool(true, "White Swan | White Swan", group = gPatterns)
useBlackSwan = input.bool(true, "Black Swan | Black Swan", group = gPatterns)
gLevels = "03 · Entry and targets | Entry and targets"
levelBasis = input.string("Standard (by family)", "Level calculation basis | Level calculation basis", options = ["Standard (by family)", "Standard (legacy)", "CD for all", "AD for XABCD"], group = gLevels, tooltip = "Calibrated modes use AD for Black Swan, Bat and Anti-Cypher, CD for White Swan and uncalibrated harmonic families. The older Swan option is retained as an alias for saved settings.")
entryPct = input.float(10, "Entry % of selected leg | Entry % of selected leg", minval = 0, maxval = 99, group = gLevels)
t1Pct = input.float(40, "Target 1 % of selected leg | Target 1 % of selected leg", minval = 1, maxval = 300, group = gLevels)
t2Pct = input.float(94, "Target 2 % of selected leg | Target 2 % of selected leg", minval = 2, maxval = 500, group = gLevels)
keepUntil = input.string("Target 2", "Finish pattern at | Finish pattern at", options = ["Target 1", "Target 2"], group = gLevels)
useRR = input.bool(false, "Set targets by reward / risk | Set targets by reward / risk", group = gLevels)
rr1 = input.float(1, "Target 1 reward / risk | Target 1 reward / risk", minval = 0.1, step = 0.1, group = gLevels)
rr2 = input.float(2, "Target 2 reward / risk | Target 2 reward / risk", minval = 0.2, step = 0.1, group = gLevels)
entryMode = input.string("High / low touch", "Entry trigger | Entry trigger", options = ["Close confirmation", "High / low touch", "Candle confirmation"], group = gLevels, tooltip = "All modes evaluate at bar close. Close confirmation needs a close beyond the entry level; High / low touch needs a wick touch; Candle confirmation needs a bullish/bearish engulfing or pin bar that touches the validation zone, and enters at that close.")
gRisk = "04 · Stop and validation | Stop and validation"
stopMode = input.string("Zone", "Stop mode | Stop mode", options = ["Zone", "Manual %", "Break even", "Trailing"], group = gRisk)
manualPct = input.float(1, "Manual stop % of entry | Manual stop % of entry", minval = 0.01, maxval = 50, step = 0.1, group = gRisk)
zonePadPct = input.float(0, "Validation band padding % of CD | Validation band padding % of CD", minval = 0, maxval = 25, step = 0.5, group = gRisk)
bePct = input.float(0, "Break-even % from entry toward T1 | Break-even % from entry toward T1", minval = 0, maxval = 100, group = gRisk)
trailAfter = input.string("Target 1", "Trail after | Trail after", options = ["Entry", "Target 1"], group = gRisk)
trailMult = input.float(1, "Trail distance / entry-to-T1 | Trail distance / entry-to-T1", minval = 0.1, step = 0.1, group = gRisk)
invalidSource = input.string("Close", "Pending invalidation source | Pending invalidation source", options = ["Close", "High / low"], group = gRisk)
requireEntrySide = input.bool(false, "Price must be lower/higher than Entry | Price must be lower/higher than Entry", group = gRisk)
entryOvershootPct = input.float(0, "Can be lower/higher % | Can be lower/higher %", minval = 0, maxval = 5, step = 0.1, group = gRisk)
zoneStyle = input.string("Dotted", "Validation line style | Validation line style", options = ["Solid", "Dashed", "Dotted"], group = gRisk)
requireZone = input.bool(false, "Confirmation close must remain in validation band | Confirmation close must remain in validation band", group = gRisk)
gView = "05 · Appearance | Appearance"
showPatterns = input.bool(true, "Draw patterns | Draw patterns", group = gView)
hideLetters = input.bool(false, "Dont show XABCD labels | Dont show XABCD labels", group = gView)
showOnlyLevels = input.bool(false, "Show Only Levels | Show Only Levels", group = gView)
showRatios = input.bool(true, "Show ratio measurements | Show ratio measurements", group = gView)
showLevels = input.bool(true, "Draw entry / targets / stop | Draw entry / targets / stop", group = gView)
showZones = input.bool(true, "Show Pattern Validation Zones | Show Pattern Validation Zones", group = gView, tooltip = "This is not the displayed prediction PRZ. Visibility never changes detection, stops or targets.")
showFill = input.bool(true, "Shade patterns | Shade patterns", group = gView)
fillAlpha = input.int(70, "Shading transparency | Shading transparency", minval = 0, maxval = 100, group = gView)
colorMode = input.string("Classic palette", "Pattern colors | Pattern colors", options = ["Classic palette", "Direction"], group = gView)
labelSize = input.string("normal", "Pattern text size | Pattern text size", options = ["tiny", "small", "normal", "large"], group = gView)
showGuides = input.bool(true, "Internal measurement diagonals | Internal measurement diagonals", group = gView)
levelLength = input.int(6, "Level segment length | Level segment length", minval = 2, maxval = 40, group = gView)
palette1 = input.color(#2962ff, "Pattern color 1 | Pattern color 1", group = gView)
palette2 = input.color(#F23645, "Pattern color 2 | Pattern color 2", group = gView)
palette3 = input.color(#00E676, "Pattern color 3 | Pattern color 3", group = gView)
palette4 = input.color(#787B86, "Pattern color 4 | Pattern color 4", group = gView)
palette5 = input.color(#FF9800, "Pattern color 5 | Pattern color 5", group = gView)
palette6 = input.color(#B2B5BE, "Pattern color 6 | Pattern color 6", group = gView)
palette7 = input.color(#FDD835, "Pattern color 7 | Pattern color 7", group = gView)
palette8 = input.color(#808000, "Pattern color 8 | Pattern color 8", group = gView)
palette9 = input.color(#512da8, "Pattern color 9 | Pattern color 9", group = gView)
palette10 = input.color(#4dd0e1, "Pattern color 10 | Pattern color 10", group = gView)
longColor = input.color(#22ab94, "Bullish color | Bullish color", group = gView)
shortColor = input.color(#f7525f, "Bearish color | Bearish color", group = gView)
textColor = input.color(color.white, "Text color | Text color", group = gView)
lineWidth = input.int(2, "Pattern width | Pattern width", minval = 1, maxval = 4, group = gView)
patternStyle = input.string("Solid", "Pattern line style | Pattern line style", options = ["Solid", "Dashed", "Dotted"], group = gView)
levelStyle = input.string("Solid", "Level line style | Level line style", options = ["Solid", "Dashed", "Dotted"], group = gView)
projection = input.int(12, "Level projection bars | Level projection bars", minval = 1, maxval = 100, group = gView)
showOnlyActive = input.bool(false, "Show Only Active Patterns | Show Only Active Patterns", group = gView)
keepLast = input.bool(true, "Keep Last Pattern on the Chart | Keep Last Pattern on the Chart", group = gView)
maxShown = input.int(6, "Maximum patterns drawn | Maximum patterns drawn", minval = 1, maxval = 12, group = gView, tooltip = "Only the newest patterns keep their drawings; older ones are removed from the chart but keep running their lifecycle, counters and alerts. The prediction is not counted.")
historyCount = input.int(0, "Completed patterns retained (minimum) | Completed patterns retained (minimum)", minval = 0, maxval = 12, group = gView, tooltip = "Completed patterns stay on the chart until they are older than the expiry age, up to 12. This sets a minimum kept beyond that age.")
gPrediction = "06 · Projection | Projection"
predict = input.bool(true, "Show nearest possible D zone | Show nearest possible D zone", group = gPrediction, tooltip = "Unconfirmed illustration only. Can move or disappear.")
predDisplay = input.string("Pattern&Label", "Show Prediction => | Show Prediction =>", options = ["Pattern&Label", "Only Pattern", "Only Label"], group = gPrediction)
predMaxFamilies = input.int(4, "Families listed in the label (0 = all) | Families listed in the label (0 = all)", minval = 0, maxval = 30, group = gPrediction, tooltip = "Nearest zones first. its cap is unknown.")
predDirection = input.string("Both", "Prediction for | Prediction for", options = ["Both", "Long", "Short"], group = gPrediction)
predColor = input.color(#2962ff, "Predicted Line Color | Predicted Line Color", group = gPrediction)
predZoneColor = input.color(color.new(#2962ff, 75), "Prediction Zone Color | Prediction Zone Color", group = gPrediction)
predLabelColor = input.color(#2962ff, "Prediction Label Color | Prediction Label Color", group = gPrediction)
predTextColor = input.color(color.white, "Prediction Text Color | Prediction Text Color", group = gPrediction)
predWidth = input.int(3, "Prediction line width | Prediction line width", minval = 1, maxval = 4, group = gPrediction)
predStyle = input.string("Dotted", "Prediction line style | Prediction line style", options = ["Solid", "Dashed", "Dotted", "None"], group = gPrediction)
gPanel = "07 · Panels | Panels"
showPanel = input.bool(true, "Show Active Patterns in the Panel | Show Active Patterns in the Panel", group = gPanel)
showStats = input.bool(false, "Lifecycle counters (below the panel) | Lifecycle counters (below the panel)", group = gPanel)
panelSize = input.string("small", "Panel Size | Panel Size", options = ["tiny", "small", "normal", "large"], group = gPanel)
panelPos = input.string("top", "Panel Position | Panel Position", options = ["bottom", "middle", "top"], group = gPanel)
panelAlign = input.string("center", "Panel Align | Panel Align", options = ["left", "center", "right"], group = gPanel)
panelLongColor = input.color(#4caf50, "Panel Long | Panel Long", group = gPanel, inline = "pc")
panelShortColor = input.color(#f23645, "Short | Short", group = gPanel, inline = "pc")
panelDoneColor = input.color(#787b86, "Reached | Reached", group = gPanel, inline = "pc")
panelHeadBg = input.color(#2962ff, "Header | Header", group = gPanel, inline = "ph")
panelHeadText = input.color(color.white, "Header text | Header text", group = gPanel, inline = "ph")
panelBorder = input.color(color.white, "Border | Border", group = gPanel, inline = "ph")
startDate = input.time(timestamp("01 Jan 2021 00:00 +0000"), "Detect from | Detect from", group = gPanel)
gAlert = "08 · Alerts | Alerts"
aNew = input.bool(true, "New pattern | New pattern", group = gAlert)
aEntry = input.bool(true, "Entry | Entry", group = gAlert)
aT1 = input.bool(true, "Target 1 | Target 1", group = gAlert)
aT2 = input.bool(true, "Target 2 | Target 2", group = gAlert)
aStop = input.bool(true, "Stop | Stop", group = gAlert)
aInvalid = input.bool(true, "Invalidation | Invalidation", group = gAlert)
aExpired = input.bool(false, "Expiry | Expiry", group = gAlert)
alertTemplate = input.string("{ticker} | {tf} | {pattern} | {side} | {event} | Entry={entry} T1={t1} T2={t2} SL={sl}", "Dynamic alert template | Dynamic alert template", group = gAlert)
outsideBarMode = input.string("Both (continue, then reverse)", "Two-sided extreme bar | Two-sided extreme bar", options = ["Both (continue, then reverse)", "Continue current leg", "Opposite leg (legacy)"], group = gSetup, tooltip = "A bar that is both the highest high and the lowest low of the window. Continue current leg keeps one endpoint per bar;")
swingMethod = input.string("Rolling extrema", "Swing construction | Swing construction", options = ["Rolling extrema", "Confirmed pivots"], group = gSetup, tooltip = "Rolling extrema updates pivots at bar close without waiting for right-side bars. Confirmed pivots preserves the previous construction and uses D detection mode.")
stopSource = input.string("Close", "Stop trigger source | Stop trigger source", options = ["Close", "High / low"], group = gRisk, tooltip = "Close requires a confirmed candle close at or beyond the stop. High / low counts a wick touch. this indicator does not place broker stop orders.")
useShark = input.bool(true, "Shark | Shark", group = gPatterns)
useNenStar = input.bool(true, "Nen Star | Nen Star", group = gPatterns)
useLeonardo = input.bool(true, "Leonardo | Leonardo", group = gPatterns)
usePartizan = input.bool(true, "Partizan | Partizan", group = gPatterns)
useFiveZero = input.bool(true, "5-0", group = gPatterns)
useAntiGartley = input.bool(true, "Anti-Gartley | Anti-Gartley", group = gPatterns)
useAntiButterfly = input.bool(true, "Anti-Butterfly | Anti-Butterfly", group = gPatterns)
useAntiBat = input.bool(true, "Anti-Bat | Anti-Bat", group = gPatterns)
useAntiCrab = input.bool(true, "Anti-Crab | Anti-Crab", group = gPatterns)
useAntiShark = input.bool(true, "Anti-Shark | Anti-Shark", group = gPatterns)
useAntiCypher = input.bool(true, "Anti-Cypher | Anti-Cypher", group = gPatterns)
useAntiNenStar = input.bool(true, "Anti-Nen Star | Anti-Nen Star", group = gPatterns)
useThreeDrive = input.bool(true, "3-Drive | Three Drives", group = gPatterns)
useDoubleTop = input.bool(true, "Double Top | Double Top", group = gPatterns)
useDoubleBottom = input.bool(true, "Double Bottom | Double Bottom", group = gPatterns)
useHS = input.bool(true, "Head and Shoulders | Head and Shoulders", group = gPatterns)
useIHS = input.bool(true, "Inverse Head and Shoulders | Inverse Head and Shoulders", group = gPatterns)
useAscending = input.bool(true, "Ascending Triangle | Ascending Triangle", group = gPatterns)
useDescending = input.bool(true, "Descending Triangle | Descending Triangle", group = gPatterns)
useSymmetrical = input.bool(true, "Symmetrical Triangle | Symmetrical Triangle", group = gPatterns)
classicTolerance = input.float(8, "Classical symmetry tolerance % of height | Classical symmetry tolerance % of height", minval = 1, maxval = 30, group = gPatterns)
hsSkip = input.int(1, "H&S contained waves skipped per leg | H&S contained waves skipped per leg", minval = 0, maxval = 3, group = gPatterns)
hsTail = input.int(1, "H&S pivots allowed after the right shoulder | H&S pivots allowed after the right shoulder", minval = 0, maxval = 3, group = gPatterns, tooltip = "The break bar usually adds one pivot after the right shoulder.")
hsShoulderTolerance = input.float(50, "H&S shoulder difference % of head depth | H&S shoulder difference % of head depth", minval = 1, maxval = 100, group = gPatterns, tooltip = "Head and shoulders only. Provisional bound;")
triangleNested = input.bool(false, "Triangles from nested legs | Triangles from nested legs", group = gPatterns, tooltip = "Off: X, A, B, C must be consecutive zigzag pivots.")
triangleMinRetrace = input.float(0.618, "Triangle minimum leg retracement | Triangle minimum leg retracement", minval = 0, maxval = 0.95, step = 0.001, group = gPatterns, tooltip = "Provisional hard minimum for AB/XA and BC/AB, without an additional Error Rate allowance. Set 0 to disable this minimum.")
useABCDTime = input.bool(true, "AB=CD time symmetry filter | AB=CD time symmetry filter", group = gPatterns, tooltip = "The original author documents comparing AB/CD durations. The current hidden tolerance is unknown; this independent filter is configurable.")
abcdTimeShort = input.float(20, "AB=CD: CD may be shorter than AB by % | AB=CD: CD may be shorter than AB by %", minval = 0, maxval = 100, step = 1, group = gPatterns)
abcdTimeError = input.float(50, "AB=CD: CD may be longer than AB by % | AB=CD: CD may be longer than AB by %", minval = 0, maxval = 200, step = 1, group = gPatterns, tooltip = "Provisional;")
showPRZ = input.bool(true, "Draw prediction PRZ | Draw prediction PRZ", group = gPrediction, tooltip = "Display only. Uses the family completion range independently of diagnostic acceptance bands. Does not change signals or risk levels.")
cypherOldest = input.bool(true, "Cypher forecast: prefer oldest valid X | Cypher forecast: prefer oldest valid X", group = gPrediction, tooltip = "Keeps all ratio rules unchanged. Disable to restore nearest-price selection; not proven for every market.")
if barstate.isfirst
if minSize > maxSize
runtime.error("Minimum pattern bars must not exceed maximum.")
if not useRR and (entryPct >= t1Pct or t1Pct >= t2Pct)
runtime.error("Require Entry % < Target 1 % < Target 2 %.")
if useRR and rr1 >= rr2
runtime.error("Target 2 reward/risk must exceed Target 1.")
type Rule
string name
bool enabled
float b0
float b1
float c0
float c1
float e0
float e1
float d0
float d1
int mode
type Pivot
float price
int idx
int sign
type Swing
array<Pivot> points
type Candidate
Pivot x
Pivot a
Pivot b
Pivot c
Pivot d
type Pattern
string name
string key
int side
int born
int state
int entryBar
int doneBar
float entry
float t1
float t2
float stop
float zlo
float zhi
float best
array<line> legs
array<label> tags
array<polyline> fills
array<line> levels
array<label> levelTags
box zone
color ink
bool reachedT1
bool hidden = false
int dBar = na
bool inZone = false
label nameTag = na
float quality = na
bool diverge = false
float risk0 = na
float worst = na
bool volSpike = false
var array<Rule> rules = array.new<Rule>()
if barstate.isfirst
array.push(rules, Rule.new("Gartley", useGartley, .618, .618, .382, .886, 1.13, 1.618, .786, .786, 0))
array.push(rules, Rule.new("Butterfly", useButterfly, .786, .786, .382, .886, 1.618, 2.618, 1.27, 1.618, 0))
array.push(rules, Rule.new("Bat", useBat, .382, .50, .382, .886, 1.618, 2.618, .886, .886, 0))
array.push(rules, Rule.new("Crab", useCrab, .382, .618, .382, .886, 2.24, 3.618, 1.618, 1.618, 0))
array.push(rules, Rule.new("Alternate Bat", useAltBat, .236, .382, .382, .886, 2.0, 3.618, 1.13, 1.13, 0))
array.push(rules, Rule.new("Deep Crab", useDeepCrab, .886, .886, .382, .886, 2.0, 3.618, 1.618, 1.618, 0))
array.push(rules, Rule.new("Cypher", useCypher, .382, .618, cypherMin, 1.414, 0, 0, .786, .786, 1))
array.push(rules, Rule.new("AB=CD", useABCD, 0, 0, .618, .886, 1.13, 1.618, 1, 1, 2))
array.push(rules, Rule.new("White Swan", useWhiteSwan, .382, .786, 2.0, 4.237, .5, .886, .236, .886, 0))
array.push(rules, Rule.new("Black Swan", useBlackSwan, 1.382, 2.618, .236, .5, 1.128, 2.0, 1.128, 2.618, 0))
array.push(rules, Rule.new("Shark", useShark, 0.382, 0.618, 1.128, 1.618, 1.618, 2.236, 0.886, 1.13, 0))
array.push(rules, Rule.new("Nen Star", useNenStar, 0.382, 0.618, 1.414, 2.14, 1.128, 2, 1.272, 1.272, 0))
array.push(rules, Rule.new("Leonardo", useLeonardo, 0.5, 0.5, 0.382, 0.886, 1.128, 2.618, 0.786, 0.786, 0))
array.push(rules, Rule.new("Partizan", usePartizan, 0.128, 3.618, 0.382, 0.382, 1.618, 1.618, 0.618, 3.618, 0))
array.push(rules, Rule.new("5-0", useFiveZero, 1.13, 1.618, 1.618, 2.24, 0.5, 0.5, 0.5, 0.5, 3))
array.push(rules, Rule.new("Anti-Gartley", useAntiGartley, 0.618, 0.786, 1.128, 2.618, 1.618, 1.618, 1.272, 1.272, 0))
array.push(rules, Rule.new("Anti-Butterfly", useAntiButterfly, 0.382, 0.618, 1.128, 2.618, 1.272, 1.272, 0.618, 0.786, 0))
array.push(rules, Rule.new("Anti-Bat", useAntiBat, 0.382, 0.618, 1.128, 2.618, 2, 2.618, 1.128, 1.128, 0))
array.push(rules, Rule.new("Anti-Crab", useAntiCrab, 0.276, 0.446, 1.128, 2.618, 1.618, 2.618, 0.618, 0.618, 0))
array.push(rules, Rule.new("Anti-Shark", useAntiShark, 0.446, 0.618, 0.618, 0.886, 1.618, 2.618, 1.128, 1.128, 0))
array.push(rules, Rule.new("Anti-Cypher", useAntiCypher, 0.5, 0.786, 0.476, 0.707, 1.618, 2.618, 1.272, 1.272, 0))
array.push(rules, Rule.new("Anti-Nen Star", useAntiNenStar, 0.5, 0.886, 0.467, 0.707, 1.618, 2.618, 0.786, 0.786, 0))
var array<Swing> swings = array.new<Swing>()
if barstate.isfirst
for scale = 0 to 2
array.push(swings, Swing.new(array.new<Pivot>()))
var array<Pattern> patterns = array.new<Pattern>()
var array<string> seen = array.new<string>()
var array<string> seenGeom = array.new<string>()
var int foundCount = 0
var int enteredCount = 0
var int target1Count = 0
var int target2Count = 0
var int stopCount = 0
var int invalidCount = 0
var int expiredCount = 0
var array<string> perfNames = array.new<string>()
var array<int> perfEntered = array.new<int>()
var array<int> perfT1 = array.new<int>()
var array<int> perfT2 = array.new<int>()
var array<int> perfLoss = array.new<int>()
var array<int> perfBars = array.new<int>()
var array<float> perfR = array.new<float>()
var array<float> perfMAE = array.new<float>()
var array<int> perfClosed = array.new<int>()
var float perfAutoMin = 0
var bool perfDeep = true
f_perfIndex(string name) =>
int i = array.indexof(perfNames, name)
if i < 0
array.push(perfNames, name)
array.push(perfEntered, 0)
array.push(perfT1, 0)
array.push(perfT2, 0)
array.push(perfLoss, 0)
array.push(perfBars, 0)
array.push(perfR, 0.0)
array.push(perfMAE, 0.0)
array.push(perfClosed, 0)
i := array.size(perfNames) - 1
i
f_perfResult(Pattern p, float exitPrice, bool win) =>
int i = f_perfIndex(p.name)
float risk = math.max(p.risk0, syminfo.mintick)
array.set(perfR, i, array.get(perfR, i) + (exitPrice - p.entry) * p.side / risk)
array.set(perfMAE, i, array.get(perfMAE, i) + math.max(0, (p.entry - p.worst) * p.side) / risk)
array.set(perfClosed, i, array.get(perfClosed, i) + 1)
if win
array.set(perfBars, i, array.get(perfBars, i) + (bar_index - p.entryBar))
f_autoBlocked(string name) =>
bool blocked = false
if perfAutoMin > 0
int i = array.indexof(perfNames, name)
if i >= 0
int w = array.get(perfT1, i)
int l = array.get(perfLoss, i)
if w + l >= 5 and 100.0 * w / (w + l) < perfAutoMin
blocked := true
blocked
f_perf(string name, int kind) =>
int i = f_perfIndex(name)
array<int> target = kind == 0 ? perfEntered : kind == 1 ? perfT1 : kind == 2 ? perfT2 : perfLoss
array.set(target, i, array.get(target, i) + 1)
var array<line> predLines = array.new<line>()
var array<polyline> predFills = array.new<polyline>()
var array<label> predTags = array.new<label>()
var box predBox = na
var label predLabel = na
f_style(string s) =>
s == "Solid" ? line.style_solid : s == "Dashed" ? line.style_dashed : line.style_dotted
f_band(float value, float lo, float hi) =>
value >= lo * (1 - errorPct / 100) and value <= hi * (1 + errorPct / 100)
f_num(float n) =>
str.tostring(n, format.mintick)
f_state(int n) =>
switch n
0 => "PENDING"
1 => "ENTERED"
2 => "T1"
3 => "DONE"
4 => "STOP"
5 => "INVALID"
=> "EXPIRED"
f_timeOK(int mode, int aIdx, int bIdx, int cIdx, int dIdx) =>
int abBars = bIdx - aIdx
int cdBars = dIdx - cIdx
mode != 2 or not useABCDTime or (abBars > 0 and cdBars > 0 and cdBars / float(abBars) >= 1 - abcdTimeShort / 100 - 1e-9 and cdBars / float(abBars) <= 1 + abcdTimeError / 100 + 1e-9)
f_timeOpen(int mode, int aIdx, int bIdx, int cIdx) =>
mode != 2 or not useABCDTime or (bIdx > aIdx and bar_index - cIdx <= (bIdx - aIdx) * (1 + abcdTimeError / 100))
var float trendMa = na
var bool trendOn = false
float rsi14 = ta.rsi(close, 14)
var bool divOn = true
var string divMark = "↯"
var bool aDiv = true
float volAvg20 = ta.sma(volume, 20)
var bool volOn = true
var float volMult = 1.5
var string volMark = "⚡"
var bool volRequire = false
var bool aVol = true
f_volSpike(Pivot d) =>
int n = bar_index - d.idx
bool spike = false
if n >= 0 and not na(volume[n]) and not na(volAvg20[n]) and volAvg20[n] > 0
spike := volume[n] >= volMult * volAvg20[n]
spike
f_div(int side, Pivot ref, Pivot d) =>
int nd = bar_index - d.idx
int nr = bar_index - ref.idx
bool beyond = side == 1 ? d.price < ref.price : d.price > ref.price
beyond and nd >= 0 and nr >= 0 and (side == 1 ? rsi14[nd] > rsi14[nr] : rsi14[nd] < rsi14[nr])
f_allowed(int side) =>
bool dirOK = direction == "Both" or (direction == "Long" and side == 1) or (direction == "Short" and side == -1)
bool trendOK = not trendOn or na(trendMa) or (side == 1 ? close > trendMa : close < trendMa)
dirOK and trendOK
f_active() =>
int n = 0
for p in patterns
if p.state < 3
n += 1
n
f_blocked(string name, int side) =>
bool result = false
if noSame
for p in patterns
if p.name == name and p.side == side and p.state < 3
result := true
result
f_update(Swing sw, float ph, float pl) =>
bool changed = false
if (not na(ph)) != (not na(pl))
int sg = not na(ph) ? 1 : -1
float price = sg == 1 ? ph : pl
Pivot pt = Pivot.new(price, bar_index - confirmBars, sg)
int n = array.size(sw.points)
if n == 0
array.push(sw.points, pt)
changed := true
else
Pivot prev = array.get(sw.points, n - 1)
if pt.idx > prev.idx
if sg == prev.sign
if (price - prev.price) * sg > 0
array.set(sw.points, n - 1, pt)
changed := true
else if (price - prev.price) * sg > syminfo.mintick
array.push(sw.points, pt)
changed := true
if array.size(sw.points) > 20
array.shift(sw.points)
changed
f_updateRolling(Swing sw, bool newHigh, bool newLow) =>
bool changed = false
if newHigh or newLow
int previousSign = array.size(sw.points) > 0 ? array.get(sw.points, array.size(sw.points) - 1).sign : 0
int sg = newHigh and newLow ? (outsideBarMode == "Opposite leg (legacy)" ? -previousSign : previousSign) : newHigh ? 1 : -1
float value = sg == 1 ? high : low
Pivot pt = Pivot.new(value, bar_index, sg)
int n = array.size(sw.points)
if n == 0 and sg != 0
array.push(sw.points, pt)
changed := true
else if n > 0
Pivot prev = array.get(sw.points, n - 1)
if bar_index > prev.idx and (value - prev.price) * sg > syminfo.mintick
if sg == prev.sign
array.set(sw.points, n - 1, pt)
else
array.push(sw.points, pt)
changed := true
if newHigh and newLow and outsideBarMode == "Both (continue, then reverse)" and previousSign != 0
int n2 = array.size(sw.points)
Pivot last = array.get(sw.points, n2 - 1)
int sg2 = -last.sign
float value2 = sg2 == 1 ? high : low
if (value2 - last.price) * sg2 > syminfo.mintick
array.push(sw.points, Pivot.new(value2, bar_index, sg2))
changed := true
if array.size(sw.points) > 20
array.shift(sw.points)
changed
f_legContained(Swing sw, int fromIndex, int toIndex) =>
Pivot left = array.get(sw.points, fromIndex)
Pivot right = array.get(sw.points, toIndex)
float lo = math.min(left.price, right.price) - syminfo.mintick * 0.1
float hi = math.max(left.price, right.price) + syminfo.mintick * 0.1
bool ok = true
if toIndex - fromIndex > 1
for k = fromIndex + 1 to toIndex - 1
float v = array.get(sw.points, k).price
if v < lo or v > hi
ok := false
break
ok
f_xabcdCandidates(Swing sw, int limit) =>
array<Candidate> result = array.new<Candidate>()
int di = array.size(sw.points) - 1
int maxCG = searchNested ? int(math.floor((di - 4) / 2)) : 0
for cg = 0 to maxCG
if array.size(result) >= limit
break
int ci = di - 1 - 2 * cg
if not f_legContained(sw, ci, di)
continue
int maxBG = searchNested ? int(math.floor((ci - 3) / 2)) : 0
for bg = 0 to maxBG
if array.size(result) >= limit
break
int bi = ci - 1 - 2 * bg
if not f_legContained(sw, bi, ci)
continue
int maxAG = searchNested ? int(math.floor((bi - 2) / 2)) : 0
for ag = 0 to maxAG
if array.size(result) >= limit
break
int ai = bi - 1 - 2 * ag
if not f_legContained(sw, ai, bi)
continue
int maxXG = searchNested ? int(math.floor((ai - 1) / 2)) : 0
for xg = 0 to maxXG
if array.size(result) >= limit
break
int xi = ai - 1 - 2 * xg
if xi >= 0 and f_legContained(sw, xi, ai)
array.push(result, Candidate.new(array.get(sw.points, xi), array.get(sw.points, ai), array.get(sw.points, bi), array.get(sw.points, ci), array.get(sw.points, di)))
result
f_abcdCandidates(Swing sw, int limit) =>
array<Candidate> result = array.new<Candidate>()
int di = array.size(sw.points) - 1
if di >= 3
int maxCG = searchNested ? int(math.floor((di - 3) / 2)) : 0
for cg = 0 to maxCG
if array.size(result) >= limit
break
int ci = di - 1 - 2 * cg
if not f_legContained(sw, ci, di)
continue
int maxBG = searchNested ? int(math.floor((ci - 2) / 2)) : 0
for bg = 0 to maxBG
if array.size(result) >= limit
break
int bi = ci - 1 - 2 * bg
if not f_legContained(sw, bi, ci)
continue
int maxAG = searchNested ? int(math.floor((bi - 1) / 2)) : 0
for ag = 0 to maxAG
if array.size(result) >= limit
break
int ai = bi - 1 - 2 * ag
if ai >= 0 and f_legContained(sw, ai, bi)
Pivot a = array.get(sw.points, ai)
array.push(result, Candidate.new(a, a, array.get(sw.points, bi), array.get(sw.points, ci), array.get(sw.points, di)))
result
f_candidates(Swing sw, int limit = 0) =>
int cap = limit > 0 ? limit : candidateLimit
array<Candidate> result = array.size(sw.points) >= 5 ? f_xabcdCandidates(sw, cap) : array.new<Candidate>()
if useABCD
array.concat(result, f_abcdCandidates(sw, cap))
result
f_predictionCandidates(Swing sw) =>
array<Candidate> result = array.new<Candidate>()
Swing temp = Swing.new(array.copy(sw.points))
if array.size(temp.points) > 0
array.pop(temp.points)
int n = array.size(temp.points)
if n >= 3
Pivot c = array.get(temp.points, n - 1)
array.push(temp.points, Pivot.new(c.price, bar_index + projection, -c.sign))
array<Candidate> candidates = f_candidates(temp, 81)
for candidate in candidates
if candidate.c.idx == c.idx
array.push(result, candidate)
result
f_liveCandidates(Swing sw, bool newHigh, bool newLow) =>
Swing temp = Swing.new(array.copy(sw.points))
bool ready = false
if newHigh != newLow and array.size(temp.points) > 0
int sg = newHigh ? 1 : -1
float value = newHigh ? high : low
int lastIndex = array.size(temp.points) - 1
Pivot prev = array.get(temp.points, lastIndex)
Pivot live = Pivot.new(value, bar_index, sg)
if (value - prev.price) * sg > syminfo.mintick and bar_index > prev.idx
if sg == prev.sign
array.set(temp.points, lastIndex, live)
else
array.push(temp.points, live)
ready := true
ready and array.size(temp.points) >= 4 ? f_candidates(temp) : array.new<Candidate>()
f_zone(Rule r, float x, float a, float b, float c, int side) =>
float xa = math.abs(a - x)
float ab = math.abs(b - a)
float bc = math.abs(c - b)
float xc = math.abs(c - x)
bool geom = (a - b) * side > 0 and (c - b) * side > 0
bool valid = ab > syminfo.mintick and bc > syminfo.mintick and geom
if r.mode != 2
valid := valid and xa > syminfo.mintick
if r.mode != 2
valid := valid and (a - x) * side > 0 and (r.b1 > 1 or (b - x) * side > 0) and f_band(ab / xa, r.b0, r.b1)
valid := valid and (r.mode == 1 ? (c - a) * side > 0 and f_band(xc / xa, r.c0, r.c1) : (r.c1 > 1 or (a - c) * side > 0) and f_band(bc / ab, r.c0, r.c1))
float unit = r.mode == 0 ? xa : r.mode == 1 ? xc : r.mode == 3 ? bc : ab
float anchor = r.mode == 0 ? a : c
float q0 = anchor - side * unit * r.d0 * (1 - errorPct / 100)
float q1 = anchor - side * unit * r.d1 * (1 + errorPct / 100)
float lo = math.min(q0, q1)
float hi = math.max(q0, q1)
if r.mode != 1
float e0 = c - side * bc * r.e0 * (1 - errorPct / 100)
float e1 = c - side * bc * r.e1 * (1 + errorPct / 100)
lo := math.max(lo, math.min(e0, e1))
hi := math.min(hi, math.max(e0, e1))
bool pastB = r.mode != 1 and r.e0 >= 1
float boundary = pastB ? (side == 1 ? math.min(b, c) : math.max(b, c)) : c
if side == 1
hi := math.min(hi, boundary - syminfo.mintick)
else
lo := math.max(lo, boundary + syminfo.mintick)
if r.mode == 0
if r.d1 < 1
if side == 1
lo := math.max(lo, x + syminfo.mintick)
else
hi := math.min(hi, x - syminfo.mintick)
if r.d0 > 1
if side == 1
hi := math.min(hi, x - syminfo.mintick)
else
lo := math.max(lo, x + syminfo.mintick)
[valid and lo <= hi, lo, hi]
f_prz(Rule r, float x, float a, float b, float c, int side) =>
float displayE1 = r.name == "Shark" ? 2.24 : r.e1
Rule displayRule = Rule.new(r.name, r.enabled, r.b0, r.b1, r.c0, r.c1, r.e0, displayE1, r.d0, r.mode == 0 and r.d0 >= 1 ? r.d0 : r.d1, r.mode)
[valid, lo, hi] = f_zone(displayRule, x, a, b, c, side)
[valid, lo, hi]
f_candleOK(int side) =>
float body = math.abs(close - open)
bool bodyOK = (close - open) * side > 0
bool engulf = bodyOK and (side == 1 ? close > high[1] and open <= close[1] : close < low[1] and open >= close[1])
float wick = side == 1 ? math.min(open, close) - low : high - math.max(open, close)
bool pin = wick >= 2 * body and wick > 0 and (side == 1 ? close > (high + low) / 2 : close < (high + low) / 2)
engulf or pin
var bool alertJson = false
var string alertBotId = ""
f_jsonStr(string v) =>
"\"" + str.replace_all(str.replace_all(v, "\\", "\\\\"), "\"", "\\\"") + "\""
f_json(Pattern p, string eventName) =>
string ev = str.lower(str.replace_all(str.replace_all(eventName, " ", "_"), "(", ""))
ev := str.replace_all(ev, ")", "")
string j = "{"
j += "\"event\":" + f_jsonStr(ev)
j += ",\"symbol\":" + f_jsonStr(syminfo.tickerid)
j += ",\"ticker\":" + f_jsonStr(syminfo.ticker)
j += ",\"exchange\":" + f_jsonStr(syminfo.prefix)
j += ",\"tf\":" + f_jsonStr(timeframe.period)
j += ",\"pattern\":" + f_jsonStr(p.name)
j += ",\"side\":" + f_jsonStr(p.side == 1 ? "long" : "short")
j += ",\"action\":" + f_jsonStr(eventName == "Entry" ? (p.side == 1 ? "buy" : "sell") : eventName == "New pattern" ? "watch" : "close")
j += ",\"price\":" + f_num(close)
j += ",\"entry\":" + f_num(p.entry)
j += ",\"sl\":" + f_num(p.stop)
j += ",\"tp1\":" + f_num(p.t1)
j += ",\"tp2\":" + f_num(p.t2)
j += ",\"quality\":" + (na(p.quality) ? "null" : str.tostring(p.quality, "0"))
j += ",\"zone\":" + (p.inZone ? "true" : "false")
j += ",\"divergence\":" + (p.diverge ? "true" : "false")
j += ",\"volume\":" + (p.volSpike ? "true" : "false")
j += ",\"time\":" + f_jsonStr(str.format_time(time, "yyyy-MM-dd'T'HH:mm:ss'Z'", "UTC"))
if alertBotId != ""
j += ",\"bot_id\":" + f_jsonStr(alertBotId)
j + "}"
f_emit(Pattern p, string eventName, bool enabled) =>
if enabled and barstate.isrealtime and barstate.isconfirmed and alertJson
alert(f_json(p, eventName), alert.freq_all)
else if enabled and barstate.isrealtime and barstate.isconfirmed
string msg = alertTemplate
msg := str.replace_all(msg, "{ticker}", syminfo.tickerid)
msg := str.replace_all(msg, "{tf}", timeframe.period)
msg := str.replace_all(msg, "{pattern}", p.name)
msg := str.replace_all(msg, "{side}", p.side == 1 ? "Long" : "Short")
msg := str.replace_all(msg, "{event}", eventName)
msg := str.replace_all(msg, "{entry}", f_num(p.entry))
msg := str.replace_all(msg, "{t1}", f_num(p.t1))
msg := str.replace_all(msg, "{t2}", f_num(p.t2))
msg := str.replace_all(msg, "{sl}", f_num(p.stop))
msg := str.replace_all(msg, "{price}", f_num(close))
msg := str.replace_all(msg, "{quality}", na(p.quality) ? "-" : str.tostring(p.quality, "0"))
alert(msg, alert.freq_all)
f_color(int side) =>
array<color> palette = array.from(palette1, palette2, palette3, palette4, palette5, palette6, palette7, palette8, palette9, palette10)
color chosen = side == 1 ? longColor : shortColor
if colorMode == "Classic palette"
chosen := palette1
bool picked = false
for col in palette
bool occupied = false
for old in patterns
if old.state < 3 and old.ink == col
occupied := true
if not occupied and not picked
chosen := col
picked := true
chosen
f_leg(Pattern p, Pivot u, Pivot v, color col) =>
line ln = line.new(u.idx, u.price, v.idx, v.price, color = col, width = lineWidth, style = f_style(patternStyle))
array.push(p.legs, ln)
ln
f_triangle(Pattern p, Pivot u, Pivot v, Pivot w, color col) =>
array<chart.point> vertices = array.from(chart.point.from_index(u.idx, u.price), chart.point.from_index(v.idx, v.price), chart.point.from_index(w.idx, w.price))
array.push(p.fills, polyline.new(vertices, curved = false, closed = true, xloc = xloc.bar_index, line_color = color.new(col, 100), fill_color = color.new(col, fillAlpha)))
f_tag(Pattern p, Pivot pt, string txt, color col) =>
array.push(p.tags, label.new(pt.idx, pt.price, txt, style = pt.sign == 1 ? label.style_label_down : label.style_label_up, color = color.new(col, 100), textcolor = col, size = labelSize))
f_ratio(Pattern p, Pivot u, Pivot v, float ratio, color col) =>
int center = int(math.round((u.idx + v.idx) / 2.0))
float y = (u.price + v.price) / 2
array.push(p.tags, label.new(center, y, str.tostring(ratio, "0.###"), style = label.style_none, textcolor = col, size = labelSize))
f_guide(Pattern p, Pivot u, Pivot v, color col) =>
array.push(p.legs, line.new(u.idx, u.price, v.idx, v.price, color = col, width = 1, style = line.style_dotted))
f_level(Pattern p, float price, string title, color col) =>
int right = bar_index + projection
array.push(p.levels, line.new(right - levelLength, price, right, price, color = col, style = f_style(levelStyle)))
array.push(p.levelTags, label.new(right + 1, price, title + ": " + f_num(price), style = label.style_label_left, color = color.new(col, 100), textcolor = col, size = labelSize))
f_stopHit(int side, float stopPrice, float barClose, float barHigh, float barLow) =>
float price = stopSource == "Close" ? barClose : side == 1 ? barLow : barHigh
side == 1 ? price <= stopPrice : price >= stopPrice
f_unit(Rule r, float a, float c, float d) =>
bool calibrated = levelBasis == "Standard (by family)" or levelBasis == "Standard (legacy)"
bool useAD = (r.mode != 2 and levelBasis == "AD for XABCD") or (calibrated and (r.mode == 2 or r.name == "Black Swan" or r.name == "Bat" or r.name == "Anti-Cypher" or r.name == "Anti-Bat" or r.name == "Anti-Nen Star"))
useAD ? math.abs(a - d) : math.abs(c - d)
f_ratioScore(float value, float lo, float hi) =>
float tol = errorPct / 100
float score = 1.0
if value < lo
score := 1 - (lo - value) / math.max(lo * tol, syminfo.mintick)
else if value > hi
score := 1 - (value - hi) / math.max(hi * tol, syminfo.mintick)
math.max(0, math.min(1, score))
f_quality(Rule r, float x, float a, float b, float c, float d) =>
float result = na
if r.mode < 10
float xa = math.abs(a - x)
float ab = math.abs(b - a)
float bc = math.abs(c - b)
float cd = math.abs(d - c)
float xc = math.abs(c - x)
float sum = 0.0
int n = 0
if r.mode != 2 and xa > 0
sum += f_ratioScore(ab / xa, r.b0, r.b1)
n += 1
if r.mode == 1
if xa > 0
sum += f_ratioScore(xc / xa, r.c0, r.c1)
n += 1
else if ab > 0
sum += f_ratioScore(bc / ab, r.c0, r.c1)
n += 1
if r.mode != 1 and r.e0 > 0 and bc > 0
sum += f_ratioScore(cd / bc, r.e0, r.e1)
n += 1
float unit = r.mode == 0 ? xa : r.mode == 1 ? xc : r.mode == 3 ? bc : ab
float anchor = r.mode == 0 ? a : c
if unit > 0
sum += f_ratioScore(math.abs(anchor - d) / unit, math.min(r.d0, r.d1), math.max(r.d0, r.d1))
n += 1
result := n > 0 ? 100 * sum / n : na
result
var float qualityMin = 0
var bool qualityInName = true
f_create(Rule r, Pivot x, Pivot a, Pivot b, Pivot c, Pivot d, float lo, float hi, string key) =>
int side = -d.sign
float span = r.mode >= 10 ? r.d0 : f_unit(r, a.price, c.price, d.price)
float en = math.round_to_mintick(d.price + side * span * entryPct / 100)
float stopLo = lo
float stopHi = hi
if r.name == "Anti-Bat"
Rule stopRule = Rule.new(r.name, r.enabled, r.b0, r.b1, r.c0, r.c1, r.e0, r.e1, r.d0, 1.13, r.mode)
[stopValid, slLo, slHi] = f_zone(stopRule, x.price, a.price, b.price, c.price, side)
if stopValid
stopLo := slLo
stopHi := slHi
float zl = stopLo - math.abs(c.price - d.price) * zonePadPct / 100
float zh = stopHi + math.abs(c.price - d.price) * zonePadPct / 100
float sl = stopMode == "Manual %" ? en - side * math.abs(en) * manualPct / 100 : side == 1 ? zl : zh
sl := side == 1 ? math.min(sl, en - syminfo.mintick) : math.max(sl, en + syminfo.mintick)
float risk = math.abs(en - sl)
float t1 = useRR ? en + side * risk * rr1 : d.price + side * span * t1Pct / 100
float t2 = useRR ? en + side * risk * rr2 : d.price + side * span * t2Pct / 100
t1 := math.round_to_mintick(t1)
t2 := math.round_to_mintick(t2)
t1 := side == 1 ? math.max(t1, en + syminfo.mintick) : math.min(t1, en - syminfo.mintick)
t2 := side == 1 ? math.max(t2, t1 + syminfo.mintick) : math.min(t2, t1 - syminfo.mintick)
color col = f_color(side)
Pattern p = Pattern.new(r.name, key, side, bar_index, 0, na, na, en, t1, t2, sl, zl, zh, en, array.new<line>(), array.new<label>(), array.new<polyline>(), array.new<line>(), array.new<label>(), na, col, false)
p.dBar := d.idx
p.risk0 := math.abs(en - sl)
p.worst := en
p.quality := f_quality(r, x.price, a.price, b.price, c.price, d.price)
p.diverge := divOn and r.mode < 10 and (f_div(side, b, d) or (r.mode != 2 and x.sign == d.sign and f_div(side, x, d)))
p.volSpike := volOn and r.mode < 10 and f_volSpike(d)
if showPatterns and not showOnlyLevels and r.mode < 10
if r.mode != 2
f_leg(p, x, a, col)
if r.mode == 3
if showGuides
f_guide(p, x, b, col)
f_guide(p, x, d, col)
else
f_leg(p, x, b, col)
if showFill
f_triangle(p, x, a, b, col)
if showGuides and r.mode != 3
f_guide(p, x, d, col)
f_leg(p, a, b, col)
f_leg(p, b, c, col)
f_leg(p, c, d, col)
if r.mode != 2
if r.mode != 3
f_leg(p, b, d, col)
if showFill
f_triangle(p, b, c, d, col)
if showGuides
f_guide(p, a, c, col)
if r.mode == 2
f_guide(p, b, d, col)
if not hideLetters
if r.mode != 2
f_tag(p, x, "X", col)
f_tag(p, a, "A", col)
f_tag(p, b, "B", col)
f_tag(p, c, "C", col)
f_tag(p, d, "D", col)
if showRatios
float ab = math.abs(a.price - b.price)
float bc = math.abs(b.price - c.price)
float cd = math.abs(c.price - d.price)
f_ratio(p, a, c, r.mode == 1 ? math.abs(c.price - x.price) / math.abs(a.price - x.price) : bc / ab, col)
if r.mode == 3
f_ratio(p, c, d, cd / bc, col)
else
f_ratio(p, b, d, cd / bc, col)
if r.mode != 2
f_ratio(p, x, b, ab / math.abs(x.price - a.price), col)
if r.mode != 3
float endRatio = r.mode == 1 ? cd / math.abs(c.price - x.price) : math.abs(a.price - d.price) / math.abs(x.price - a.price)
f_ratio(p, x, d, endRatio, col)
string nameText = r.name + (side == 1 ? " ▲" : " ▼") + (qualityInName and not na(p.quality) ? " " + str.tostring(p.quality, "0") : "") + (p.diverge ? " " + divMark : "") + (p.volSpike ? " " + volMark : "")
p.nameTag := label.new(d.idx, d.price, nameText, style = side == 1 ? label.style_label_upper_right : label.style_label_lower_right, color = color.new(col, 100), textcolor = col, size = labelSize)
array.push(p.tags, p.nameTag)
if showLevels
f_level(p, en, "En", col)
f_level(p, t1, "T1", col)
f_level(p, t2, "T2", col)
f_level(p, sl, "SL", col)
if showZones and not showOnlyLevels
int zoneLeft = d.idx - 11
array.push(p.legs, line.new(zoneLeft, zl, d.idx, zl, color = col, width = 1, style = f_style(zoneStyle)))
array.push(p.legs, line.new(zoneLeft, zh, d.idx, zh, color = col, width = 1, style = f_style(zoneStyle)))
array.push(p.legs, line.new(zoneLeft, zl, zoneLeft, zh, color = col, width = 1, style = f_style(zoneStyle)))
p
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)
type ExtraFormation
string name
array<Pivot> points
int side
float trigger
float invalidation
float unit
string key
int kind
int dBar = 0
float dPrice = na
f_segmentPrice(Pivot p, Pivot q, int idx) =>
p.price + (q.price - p.price) * (idx - p.idx) / math.max(q.idx - p.idx, 1)
f_extremeBetween(Swing sw, int fromIndex, int toIndex, int sign) =>
int best = fromIndex + 1
if toIndex - fromIndex > 2
for k = fromIndex + 2 to toIndex - 1
Pivot q = array.get(sw.points, k)
if q.sign == sign and (q.price - array.get(sw.points, best).price) * sign > 0
best := k
best
f_extraCandidates(Swing sw) =>
array<ExtraFormation> result = array.new<ExtraFormation>()
int n = array.size(sw.points)
if n >= 4 and (useDoubleTop or useDoubleBottom)
for offset = 0 to math.min(3, n - 3)
int ci = n - 1 - offset
Pivot c = array.get(sw.points, ci)
int side = -c.sign
if (side == 1 and useDoubleBottom) or (side == -1 and useDoubleTop)
for bi = ci - 1 to 1
Pivot b = array.get(sw.points, bi)
if b.sign == side and bi >= 2
for ai = bi - 1 to 1
Pivot a = array.get(sw.points, ai)
Pivot lead = array.get(sw.points, ai - 1)
float height = (b.price - c.price) * side
float tolerance = height * classicTolerance / 100
bool symmetric = a.sign == c.sign and height > syminfo.mintick and math.abs(a.price - c.price) <= tolerance
bool approach = (lead.price - b.price) * side > 0
bool contained = symmetric and f_legContained(sw, ai, bi) and f_legContained(sw, bi, ci)
bool breakout = (side == 1 ? high >= b.price : low <= b.price) and bar_index > c.idx
if symmetric and approach and contained and breakout and bar_index - a.idx >= minSize and bar_index - a.idx <= maxSize and array.size(result) < candidateLimit
string name = side == 1 ? "Double Bottom" : "Double Top"
string key = name + "*" + str.tostring(a.idx) + "*" + str.tostring(b.idx) + "*" + str.tostring(c.idx)
array.push(result, ExtraFormation.new(name, array.from(lead, a, b, c), side, b.price, c.price, height * 1.5, key, 10))
if n >= 4 and (useAscending or useDescending or useSymmetrical)
for offset = 0 to math.min(1, n - 4)
Swing boundary = Swing.new(array.copy(sw.points))
if offset == 1
array.pop(boundary.points)
for triCandidate in f_abcdCandidates(boundary, triangleNested ? candidateLimit : 1)
Pivot x = triCandidate.a
Pivot a = triCandidate.b
Pivot b = triCandidate.c
Pivot c = triCandidate.d
float width = math.abs(x.price - a.price)
float eps = width * classicTolerance / 100
Pivot h0 = x.sign == 1 ? x : a
Pivot h1 = x.sign == 1 ? b : c
Pivot l0 = x.sign == -1 ? x : a
Pivot l1 = x.sign == -1 ? b : c
bool flatHigh = math.abs(h1.price - h0.price) <= eps
bool flatLow = math.abs(l1.price - l0.price) <= eps
bool lowerHigh = h1.price < h0.price - eps
bool higherLow = l1.price > l0.price + eps
string name = flatHigh and higherLow and useAscending ? "Ascending Triangle" : flatLow and lowerHigh and useDescending ? "Descending Triangle" : lowerHigh and higherLow and useSymmetrical ? "Symmetrical Triangle" : ""
float upper = f_segmentPrice(h0, h1, bar_index)
float lower = f_segmentPrice(l0, l1, bar_index)
int side = -c.sign
float trigger = side == 1 ? upper : lower
bool sized = bar_index - x.idx >= minSize and bar_index - x.idx <= maxSize and bar_index - c.idx >= minCD
bool crossed = (close - trigger) * side > 0
float ab = math.abs(b.price - a.price)
float bc = math.abs(c.price - b.price)
bool retracements = width > syminfo.mintick and ab > syminfo.mintick and ab / width >= triangleMinRetrace and bc / ab >= triangleMinRetrace
bool contracting = h1.price <= h0.price and l1.price >= l0.price
if contracting and retracements and sized and width > syminfo.mintick and upper > lower and name != "" and crossed and array.size(result) < candidateLimit
string key = name + "*" + str.tostring(x.idx) + "*" + str.tostring(a.idx) + "*" + str.tostring(b.idx) + "*" + str.tostring(c.idx) + "*" + str.tostring(side)
int dBar = bar_index
float dPrice = side == 1 ? high : low
for k = c.idx + 1 to bar_index
int back = bar_index - k
float v = side == 1 ? high[back] : low[back]
if (v - dPrice) * side > 0
dPrice := v
dBar := k
array.push(result, ExtraFormation.new(name, array.from(x, a, b, c), side, trigger, c.price, width, key, 12, dBar, dPrice))
if n >= 6
int lastIdx = n - 1
for tail = 0 to hsTail
int rIdx = lastIdx - tail
if rIdx < 5
break
Pivot p4 = array.get(sw.points, rIdx)
int side = -p4.sign
bool tailOK = bar_index > p4.idx
if tail > 0
for k = rIdx + 1 to lastIdx
if (array.get(sw.points, k).price - p4.price) * -side > 0
tailOK := false
if tailOK and ((side == 1 and useIHS) or (side == -1 and useHS))
bool taken = false
for skipH = 0 to hsSkip
int hIdx = rIdx - 2 - 2 * skipH
if hIdx < 3 or taken
break
Pivot p2 = array.get(sw.points, hIdx)
int m2 = f_extremeBetween(sw, hIdx, rIdx, side)
Pivot p3 = array.get(sw.points, m2)
if (p2.price - p4.price) * -side > 0 and f_legContained(sw, hIdx, m2) and f_legContained(sw, m2, rIdx)
for skipL = 0 to hsSkip
int lIdx = hIdx - 2 - 2 * skipL
if lIdx < 1 or taken
break
Pivot p0 = array.get(sw.points, lIdx)
int m1 = f_extremeBetween(sw, lIdx, hIdx, side)
Pivot p1 = array.get(sw.points, m1)
Pivot lead = array.get(sw.points, lIdx - 1)
if (p2.price - p0.price) * -side > 0 and f_legContained(sw, lIdx, m1) and f_legContained(sw, m1, hIdx)
bool sized = bar_index - lead.idx >= minSize and bar_index - lead.idx <= maxSize
float neck = p1.price
float height = (neck - p2.price) * side
bool shoulders = height > syminfo.mintick and (p0.price - p2.price) * side > 0 and (p4.price - p2.price) * side > 0 and (neck - p4.price) * side > 0 and math.abs(p0.price - p4.price) <= height * hsShoulderTolerance / 100
bool approach = (lead.price - neck) * side > 0
bool flatNeck = math.abs(p3.price - neck) <= height * errorPct / 100
float rightDepth = (p2.price - p3.price) * -side
float lsRatio = (p0.price - neck) * -side / height
float rsRatio = rightDepth > syminfo.mintick ? (p4.price - p3.price) * -side / rightDepth : 0
bool shoulderRatios = f_band(lsRatio, .382, .786) and f_band(rsRatio, .382, .786)
float outerNeck = side == 1 ? math.max(neck, p3.price) : math.min(neck, p3.price)
bool broken = side == 1 ? high > outerNeck : low < outerNeck
bool dominant = side == 1 ? p2.price <= windowLow + syminfo.mintick * 0.1 : p2.price >= windowHigh - syminfo.mintick * 0.1
if sized and shoulders and approach and flatNeck and shoulderRatios and dominant and broken and array.size(result) < candidateLimit
string name = side == 1 ? "Inverse Head and Shoulders" : "Head and Shoulders"
string key = name + "*" + str.tostring(p0.idx) + "*" + str.tostring(p2.idx) + "*" + str.tostring(p4.idx)
float outer = side == 1 ? math.max(neck, p3.price) : math.min(neck, p3.price)
array.push(result, ExtraFormation.new(name, array.from(lead, p0, p1, p2, p3, p4), side, outer, p2.price, height, key, 11))
taken := true
if useThreeDrive and n >= 5
array<Pivot> pts = array.new<Pivot>()
for k = n - 5 to n - 1
array.push(pts, array.get(sw.points, k))
Pivot p1 = array.get(pts, 0)
Pivot p2 = array.get(pts, 1)
Pivot p3 = array.get(pts, 2)
Pivot p4 = array.get(pts, 3)
Pivot p5 = array.get(pts, 4)
int side = -p5.sign
float retrace1 = math.abs(p2.price - p1.price)
float drive2 = math.abs(p3.price - p2.price)
float retrace2 = math.abs(p4.price - p3.price)
float drive3 = math.abs(p5.price - p4.price)
bool positive = math.min(math.min(retrace1, drive2), retrace2) > syminfo.mintick
bool geometry = (p1.price - p3.price) * side > 0 and (p3.price - p5.price) * side > 0 and (p2.price - p4.price) * side > 0
bool ratios = positive and f_band(drive2 / retrace1, 1.272, 1.618) and f_band(retrace2 / drive2, .618, .786) and f_band(drive3 / retrace2, 1.272, 1.618)
bool firstOK = true
if n >= 6
Pivot p0 = array.get(sw.points, n - 6)
float first = math.abs(p1.price - p0.price)
firstOK := first > syminfo.mintick and (p0.price - p2.price) * side > 0 and f_band(retrace1 / first, .618, .786)
if geometry and ratios and firstOK and bar_index - p1.idx >= minSize and bar_index - p1.idx <= maxSize and bar_index - p5.idx <= confirmBars
string key = "********" + str.tostring(p1.idx) + "*" + str.tostring(p5.idx)
array.push(result, ExtraFormation.new("3-Drive", pts, side, p5.price, p5.price - side * drive3 * errorPct / 100, math.abs(p2.price - p5.price), key, 13))
result
f_createExtra(ExtraFormation e) =>
Pivot first = array.get(e.points, 0)
Pivot last = array.get(e.points, array.size(e.points) - 1)
Pivot anchor = Pivot.new(e.trigger, bar_index, -e.side)
Rule r = Rule.new(e.name, true, 0, 0, 0, 0, 0, 0, e.unit, 0, e.kind)
float lo = e.side == 1 ? e.invalidation : e.trigger
float hi = e.side == 1 ? e.trigger : e.invalidation
if e.kind == 10
float ext = (hi - lo) * (1 + errorPct / 100)
if e.side == 1
hi := lo + ext
else
lo := hi - ext
if e.kind == 11
float n1 = array.get(e.points, 2).price
float n2 = array.get(e.points, 4).price
float innerNeck = e.side == 1 ? math.min(n1, n2) : math.max(n1, n2)
if e.side == 1
hi := innerNeck
else
lo := innerNeck
if e.kind == 13
Pivot bPt = array.get(e.points, 2)
Pivot cPt = array.get(e.points, 3)
float bc = math.abs(cPt.price - bPt.price)
float near = cPt.price - e.side * bc * 1.272 * (1 - errorPct / 100)
float far = cPt.price - e.side * bc * 1.618 * (1 + errorPct / 100)
lo := math.min(near, far)
hi := math.max(near, far)
Pattern p = f_create(r, first, first, last, last, anchor, lo, hi, e.key)
color col = p.ink
if showPatterns and not showOnlyLevels
if e.kind == 12
Pivot x = first
Pivot a = array.get(e.points, 1)
Pivot b = array.get(e.points, 2)
Pivot c = last
f_leg(p, x, Pivot.new(f_segmentPrice(x, b, bar_index), bar_index, x.sign), col)
f_leg(p, a, Pivot.new(f_segmentPrice(a, c, bar_index), bar_index, a.sign), col)
if showGuides
f_guide(p, x, a, col)
f_guide(p, a, b, col)
f_guide(p, b, c, col)
f_guide(p, c, anchor, col)
if showRatios
f_ratio(p, x, b, math.abs(b.price - a.price) / e.unit, col)
f_ratio(p, a, c, math.abs(c.price - b.price) / math.abs(b.price - a.price), col)
if not hideLetters
f_tag(p, Pivot.new(e.dPrice, e.dBar, e.side), "D", col)
else
for k = 0 to array.size(e.points) - 2
f_leg(p, array.get(e.points, k), array.get(e.points, k + 1), col)
if e.kind == 10
Pivot neck = array.get(e.points, 2)
f_leg(p, last, anchor, col)
int neckStart = first.idx + 1
for k = first.idx + 1 to array.get(e.points, 1).idx
int back = bar_index - k
if back >= 0 and (e.side == 1 ? low[back] <= neck.price : high[back] >= neck.price)
neckStart := k
break
f_leg(p, Pivot.new(neck.price, neckStart, neck.sign), neck, col)
f_leg(p, neck, Pivot.new(neck.price, bar_index, neck.sign), col)
if e.kind == 11
Pivot lead = first
Pivot n1 = array.get(e.points, 2)
Pivot n2 = array.get(e.points, 4)
float inner = e.side == 1 ? math.min(n1.price, n2.price) : math.max(n1.price, n2.price)
Pivot neckEnd = Pivot.new(inner, bar_index, n1.sign)
f_leg(p, last, neckEnd, col)
int neckStart = lead.idx + 1
for k = lead.idx + 1 to array.get(e.points, 1).idx
int back = bar_index - k
if back >= 0 and (e.side == 1 ? low[back] <= inner : high[back] >= inner)
neckStart :=Показано первые 50% кода (символов: 91640)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.