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

AI ALGO [SANDIP]

indicatorgoldy.pine

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

blessing_3_v3_9_6.mq4MQL4 / MetaTrader 4 · 3 общих теговblessing_3_v3.9.6.15.mq4MQL4 / MetaTrader 4 · 3 общих теговblessing_3_v3.9.6.23.mq4MQL4 / MetaTrader 4 · 3 общих теговblessing 3 v4.mq4MQL4 / MetaTrader 4 · 3 общих теговblessing_3_v3.9.6.21.mq4MQL4 / MetaTrader 4 · 3 общих теговblessing_3_v3.9.6.18.mq4MQL4 / MetaTrader 4 · 3 общих тегов
Вы автор или правообладатель?

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

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

О программе

Это стратегия для TradingView на Pine Script v5, предназначенная для моделирования сделок и проверки результатов в тестере. Скрипт объединяет несколько блоков: построение уровней поддержки и сопротивления с возможностью работы на нескольких таймфреймах, отображение зигзагообразных меток и линий, поиск ордерных блоков, а также торговую логику с несколькими вариантами сопровождения позиции. В основе лежит расчет волатильности и скользящих средних, что позволяет формировать сигналы на вход и выход.

Пользователь может настраивать параметры отображения уровней, зон, меток и линий, выбирать тип трейлинга и способ управления тейк-профитами. Стратегия поддерживает фильтрацию сделок по датам и рыночным условиям, а также выводит панели с результатами тестирования, включая недельную и месячную статистику. Все расчеты выполняются на стороне TradingView, а торговые операции симулируются в тестере.

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

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

НастройкаОписание
ShowSmartTrail Включает отображение умного трейлинга на графике.
enableSR Включает отображение уровней поддержки и сопротивления.
colorSup Цвет линий поддержки.
colorRes Цвет линий сопротивления.
strengthSR Сила уровней поддержки и сопротивления.
lineStyle Стиль линий поддержки и сопротивления: сплошной, пунктирный или штриховой.
lineWidth Толщина линий поддержки и сопротивления.
useZones Включает использование зон поддержки и сопротивления.
useHLZones Включает зоны на основе максимумов и минимумов.
zoneWidth Ширина зоны в процентах от диапазона за последние 300 баров.
expandSR Расширяет линии поддержки и сопротивления.
trailType Тип трейлинга: модифицированный или немодифицированный.
ATRPeriod Период для расчета среднего истинного диапазона (ATR).
ATRFactor Множитель для расчета волатильности, влияет на чувствительность сигналов.
Smoothing Период сглаживания для линий трейлинга.
length1 Период для расчета уровней зигзага.
colorUp Цвет для восходящего тренда.
colorDn Цвет для нисходящего тренда.
showLabel Включает отображение меток на графике.
showLine Включает отображение линий на графике.
disKlayLabel Текст меток: HHLL или HL.
nameHL Выбор отображения меток: короткие (H/L) или длинные (HIGH/LOW).
colorLabel Цвет меток: контрастный, пользовательский или по тренду.
customLabel Пользовательский цвет для меток.
sizeLabel Размер шрифта меток.
lineType Тип отображения линий зигзага: штрих, точка, сплошная, стрелки.
width Толщина линий зигзага.
colorLine Цвет линий: контрастный, пользовательский или по тренду.
customLine Пользовательский цвет для линий.
resistanceSupportCount Количество отображаемых уровней поддержки и сопротивления.
pivotRange Диапазон для поиска пивотов: больше значение — более общие пивоты.
strength Количество касаний ценой уровня для подтверждения зоны.
expandLines Расширяет линии и зоны поддержки/сопротивления.
enableZones Включает отображение зон поддержки и сопротивления.
zoneWidth1 Ширина зоны поддержки и сопротивления.
timeframe1Enabled Включает использование первого дополнительного таймфрейма.
timeframe1 Первый дополнительный таймфрейм для анализа.
timeframe2Enabled Включает использование второго дополнительного таймфрейма.
timeframe2 Второй дополнительный таймфрейм для анализа.
timeframe3Enabled Включает использование третьего дополнительного таймфрейма.
timeframe3 Третий дополнительный таймфрейм для анализа.
showBreaks Показывает пробои уровней на графике.
showRetests Показывает ретесты уровней на графике.
avoidFalseBreaks Фильтр для избежания ложных пробоев с использованием объема.
falseBreakoutVolumeThreshold Порог объема в процентах для фильтрации ложных пробоев.
inverseBrokenLineColor Инвертирует цвет линии после пробоя.
lineStyle1 Стиль линий для зон: сплошной, штриховой или пунктирный.
lineWidth1 Толщина линий для зон.
supportColor Цвет линий поддержки.
resistanceColor Цвет линий сопротивления.
textColor Цвет текста на графике.
enableRetestAlerts Включает оповещения о ретестах уровней.
enableBreakAlerts Включает оповещения о пробоях уровней.
memoryOptimizatonEnabled Включает оптимизацию памяти для снижения нагрузки.
colors Цветовая схема для ордерных блоков: темная или яркая.
periods Количество последующих свечей для идентификации ордерного блока.
threshold Минимальное процентное движение для идентификации ордерного блока.
usewicks Использовать весь диапазон High/Low для разметки ордерного блока.
showbull Показывает последний бычий канал ордерного блока.
showbear Показывает последний медвежий канал ордерного блока.
showdocu Показывает метку с документацией в виде всплывающей подсказки.
info_pan Показывает панель с последней статистикой ордерных блоков.
TPSType Выбор метода управления тейк-профитами: ATR, трейлинг или опционы.
setupType Выбор торговой установки: Open/Close или Renko.
scolor Включает окрашивание баров для индикации тренда.
almaRibbon Включает отображение ленты на основе данных Renko или Heikin Ashi.
enableFilter Включает фильтрацию сделок по датам.
fromDate Начальная дата для фильтрации сделок.
toDate Конечная дата для фильтрации сделок.
typefilter Выбор фильтра для бокового движения: ATR, RSI, комбинации или без фильтра.
toplimitrsi Верхний порог RSI для фильтрации бокового движения.
botlimitrsi Нижний порог RSI для фильтрации бокового движения.
EMA1_length Длина первой экспоненциальной скользящей средней для сигналов Renko.
EMA2_length Длина второй экспоненциальной скользящей средней для сигналов Renko.
i_lxQtyTP1 Процент объема для первого тейк-профита.
i_lxQtyTP2 Процент объема для второго тейк-профита.
i_lxQtyTP3 Процент объема для третьего тейк-профита.
drawTester Включает отображение панели с результатами тестирования стратегии.
i_showweeklyPerformance Включает отображение недельной производительности.
i_showMonthlyPerformance Включает отображение месячной производительности.
showcloud Включает отображение облака EMA.
useHTF Использовать данные старшего таймфрейма для расчета EMA.
Получить полный код

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

VERSION                   = 'v1'// 2025.04.17
strategy(
  'AI ALGO [SANDIP]',
  shorttitle              = 'AI ALGO [SANDIP] ' + VERSION,
  overlay                 = true,
  explicit_plot_zorder    = true,
  pyramiding              = 0,
  default_qty_type        = strategy.percent_of_equity,
  default_qty_value       = 50,
  calc_on_every_tick      = false,
  process_orders_on_close = true,
  max_bars_back           = 500,
  initial_capital         = 5000,
  commission_type         = strategy.commission.percent,
  commission_value        = 0.02
  )

ShowSmartTrail = input.bool(true, 'Smart Trail      ', inline = 'overlayLine1', group = 'Smart Trail')

enableSR   = input(false, "SR On/Off", group="🧊 Support and Resistances")
colorSup   = input(color.new(#00DBFF,20), "Support Color", group="Support and Resistances")
colorRes   = input(color.new(#9598a1,50), "Resistance Color", group="Support and Resistances")
strengthSR = input.int(2, "S/R Strength", 1, group="Support and Resistances")
lineStyle  = input.string("Dotted", "Line Style", ["Solid", "Dotted", "Dashed"], group="Support and Resistances")
lineWidth  = input.int(1, "S/R Line Width", 1, group="Support and Resistances")
useZones   = input(true, "Zones On/Off", group="Support and Resistances")
useHLZones = input(true, "High Low Zones On/Off", group="Support and ResistancesSR")
zoneWidth  = input.int(2, "Zone Width %", 0, tooltip="it's calculated using % of the distance between highest/lowest in last 300 bars", group="Support and Resistances")
expandSR   = input(true, "Expand Support and Resistances")

trailType = input.string('modified', 'Trailtype', options=['modified', 'unmodified'], group = "S/R")
ATRPeriod = input(200, 'ATR Period')
ATRFactor = input.float(4.2, 'ATR Factor', minval = 2, maxval = 26,step=0.1,tooltip = "Changes the sensetivity of the signals.")
Smoothing = input(4, 'Smoothing')

norm_o = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, open)
norm_h = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, high)
norm_l = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, low)
norm_c = request.security(ticker.new(syminfo.prefix, syminfo.ticker), timeframe.period, close)

Wild_ma(_src, _malength) =>
    _wild = 0.0
    _wild := nz(_wild[1]) + (_src - nz(_wild[1])) / _malength
    _wild

HiLo = math.min(norm_h - norm_l, 1.5 * nz(ta.sma(norm_h - norm_l, ATRPeriod)))

HRef = norm_l <= norm_h[1] ? norm_h - norm_c[1] : norm_h - norm_c[1] - 0.5 * (norm_l - norm_h[1])

LRef = norm_h >= norm_l[1] ? norm_c[1] - norm_l : norm_c[1] - norm_l - 0.5 * (norm_l[1] - norm_h)

trueRange = trailType == 'modified' ? math.max(HiLo, HRef, LRef) : math.max(norm_h - norm_l, math.abs(norm_h - norm_c[1]), math.abs(norm_l - norm_c[1]))

loss = ATRFactor * Wild_ma(trueRange, ATRPeriod)

Up68 = norm_c - loss
Dn68 = norm_c + loss

TrendUp = Up68
TrendDown = Dn68
Trend = 1

TrendUp := norm_c[1] > TrendUp[1] ? math.max(Up68, TrendUp[1]) : Up68
TrendDown := norm_c[1] < TrendDown[1] ? math.min(Dn68, TrendDown[1]) : Dn68

Trend := norm_c > TrendDown[1] ? 1 : norm_c < TrendUp[1] ? -1 : nz(Trend[1], 1)
trail = Trend == 1 ? TrendUp : TrendDown

ex = 0.0
ex := ta.crossover(Trend, 0) ? norm_h : ta.crossunder(Trend, 0) ? norm_l : Trend == 1 ? math.max(ex[1], norm_h) : Trend == -1 ? math.min(ex[1], norm_l) : ex[1]

plot(trail, 'S/R - SIGNAL', style=plot.style_line, color=Trend == 1 ? color.rgb(0, 242, 255) : Trend == -1 ? color.rgb(255, 0, 200) : na,linewidth = 1, editable = false,display = display.none)

state = Trend == 1 ? 'long' : 'short'

fib1Level = 61.8
fib2Level = 78.6
fib3Level = 88.6

f1 = ex + (trail - ex) * fib1Level / 100
f2 = ex + (trail - ex) * fib2Level / 100
f3 = ex + (trail - ex) * fib3Level / 100
l100 = trail + 0

Fib1 = plot(f1, 'Ranger A', display = display.none, color=color.new(#f3ee00, 0), editable = false,display = display.none)
Fib2 = plot(f2, 'Ranger B', color=color.new(#f6ff00, 0),display = display.none, editable = false)
Fib3 = plot(f3, 'Ranger C',color=color.new(#f6ff00, 0), editable = false,display = display.none)
L100 = plot(l100, display = display.none, color=color.new(#f408a2, 0), editable = false,display = display.none)

fill(plot(ShowSmartTrail ? (ta.sma(trail, Smoothing)) : na, style=plot.style_line,display = display.none, editable = false, color=Trend == 1 ? color.new(#2157f9, 0) : Trend == -1 ? color.new(#ff1100, 0) : na),
 plot( ShowSmartTrail ? (ta.sma(f1, Smoothing)) : na, 'Fib 2', style=plot.style_line, editable = false,display = display.none),
 color=state == 'long' ? color.new(#2157f9, 70) : state == 'short' ? color.new(#ff1100, 70) : na,display = display.none)

fill(plot(ShowSmartTrail ? (ta.sma(trail, Smoothing)) : na, style=plot.style_line,display = display.none, editable = false, color=Trend == 1 ? color.new(#2157f9, 0) : Trend == -1 ? color.new(#ff1100, 0) : na),
 plot( ShowSmartTrail ? (ta.sma(f2, Smoothing)) : na, 'Fib 2', style=plot.style_line,editable = false,display = display.none),
 color=state == 'long' ? color.new(#2157f9, 71) : state == 'short' ? color.new(#ff1100, 72) : na,display = display.none)

fill(plot(ShowSmartTrail ? (ta.sma(trail, Smoothing)) : na, style=plot.style_line, editable = false, color=Trend == 1 ? color.new(#2157f9, 0) : Trend == -1 ? color.new(#ff1100, 0) : na),
 plot( ShowSmartTrail ? (ta.sma(f3, Smoothing)) : na, 'Fib 2', style=plot.style_line,  editable = false,display = display.none),
 color=state == 'long' ? color.new(#2157f9, 72) : state == 'short' ? color.new(#ff1100, 71) : na)

K0 = 'Zigzag values\nDefault : 14\nMin : 2\nMax : 50'
K1 = 'Short\nExamKle : L or LL\nLong\nExamKle : Low or Lower Low'
K2 = 'Constrast : Constrast color of chart background\nCustom : Input color\nNone : Color follow Trend Color'
K3 = 'Small font size recommended for mobile app or multiKle layout'
K4 = 'Default\nStyle : Solid\nWidth : 4'
length1     = input.int(            13,     ' Level ZigZag ', minval = 2, maxval = 50, tooltip = K0,group = " ZIGZAG HIGH - LOW")
colorUp      = input.color(color.rgb(0, 250, 75),'Trend Color', inline = '0')
colorDn      = input.color( color.rgb(202, 70, 70),           '', inline = '0')
showLabel    = input.bool(         true,      'Label', group = 'Show / hide', inline = '1')
showLine     = input.bool(         true,       'Line', group = 'Show / hide', inline = '1')
disKlayLabel = input.string(     'HHLL',       'Text', group = 'Label', inline = '2', options = ['HHLL', 'HL'])
nameHL       = input.string(    'Short',           '', group = 'Label', inline = '2', options = ['Short', 'Long'], tooltip = K1)
colorLabel   = input.string(    'Trend',      'Color', group = 'Label', inline = '3', options = ['Contrast', 'Custom', 'Trend'])
customLabel  = input.color(color.blue,           '', group = 'Label', inline = '3', tooltip = K2)
sizeLabel    = input.string(   'normal',       'Size', group = 'Label', inline = '4', options = ['tiny',  'small', 'normal', 'large', 'huge'], tooltip = K3)
lineType     = input.string(    'dash',    'DisKlay', group =  'Line', inline = '5', options = ['dash', 'dot', 'solid', 'arrow right', 'arrow left'])
width        = input.int(             1,           '', group =  'Line', inline = '5', minval = 1, maxval = 4, tooltip = K4)
colorLine    = input.string(    'Trend',      'Color', group =  'Line', inline = '6', options = ['Contrast', 'Custom', 'Trend'])
customLine   = input.color(color.blue,           '', group =  'Line', inline = '6', tooltip = K2)

type HL
    string      Hi = na
    string      Lo = na

type point
    int          x = na
    float        y = na
    string     sty = na
    color      col = na
    string     str = na

type startUp
    float       hi = na
    float       lo = na
    color  colorHi = na
    color  colorLo = na
    string   strHi = na
    string   strLo = na

[H, L]            = switch nameHL
    'Short'       => [   'H',   'L']
    'Long'        => ['HIGH', 'LOW']
[Hi, Lo]          = switch nameHL
    'Short'       => [       'H',       'L']
    'Long'        => ['HIGHER\n', 'LOWER\n']
switchLine        = switch lineType
    'dash'        => line.style_dashed
    'dot'         => line.style_dotted
    'solid'       => line.style_solid
    'arrow right' => line.style_arrow_right
    'arrow left'  => line.style_arrow_left
switchLabelColor  = switch colorLabel
    'Contrast'    => chart.fg_color
    'Custom'      => customLabel
switchLineColor   = switch colorLine
    'Contrast'    => chart.fg_color
    'Custom'      => customLine

float Kh   = na,  Kh := ta.highestbars(high, length1 ) == 0 ? high : na
float Kl   = na,  Kl := ta.lowestbars(  low, length1 ) == 0 ?  low : na  
var  dir   =  0, dir := Kh and na(Kl) ? 1 : Kl and na(Kh) ? -1 : dir
var zigzag = array.new<point>(0)
oldzigzag  = zigzag.copy()
dirchanged = ta.change(dir)
hiLo       = HL.new(Hi, Lo)
varSetup   = startUp.new(Kh, Kl, colorUp, colorDn, H, L)

method dirVariables(startUp setup = na) =>
    var point newPoint = na 
    x   = bar_index
    y   = dir == 1 ?               setup.hi : setup.lo
    sty = dir == 1 ? label.style_label_down : label.style_label_up
    col = dir == 1 ?          setup.colorHi : setup.colorLo
    str = dir == 1 ?            setup.strHi : setup.strLo  
    newPoint  := point.new(x, y, sty, col, str)
    newPoint

method initialize(point[] zigzag = na, startUp setup = na, int maxSize = 10)=>
    newPoint = setup.dirVariables()
    zigzag.unshift(newPoint)
    if zigzag.size() > maxSize
        zigzag.pop()

method update(point[] zigzag = na, startUp setup = na, maxSize = 10, int dir = na)=>
    if array.size(zigzag) == 0
        zigzag.initialize(setup, maxSize)
    else
        newPoint = setup.dirVariables()
        dirOver = dir ==  1 and newPoint.y > zigzag.get(0).y
        dirLess = dir == -1 and newPoint.y < zigzag.get(0).y
        if dirOver or dirLess
            zigzag.set(0, newPoint)
        point.new(na, na, na, na, na)

method boolPoint(point[] zigzag = na, point[] oldzigzag = na, int offset = 0) =>
    boolOr = zigzag.get(offset + 0).x != oldzigzag.get(offset + 0).x  or zigzag.get(offset + 0).y != oldzigzag.get(offset + 0).y
    boolAnd = zigzag.get(offset + 1).x == oldzigzag.get(offset + 1).x and zigzag.get(offset + 1).y == oldzigzag.get(offset + 1).y
    [boolOr, boolAnd]

method createLabel(point[] zigzag = na, string size = na, int offset = 0) =>
    label.new(   x         = int(zigzag.get(offset + 0).x),
                 y         =     zigzag.get(offset + 0).y,
                 text      =     zigzag.get(offset + 0).str,
                 xloc      =               xloc.bar_index,
                 color     = color.new(color.blue, 100),
                 style     =     zigzag.get(offset + 0).sty,
                 textcolor =     zigzag.get(offset + 0).col,
                 size      =                         size,
                 tooltip   =     zigzag.get(offset + 0).str + '\n' + str.tostring(zigzag.get(offset + 0).y)) 

method createLine(point[] zigzag = na, int width = na, string style = na, int offset = 0) =>
    line.new(x1    = int(zigzag.get(offset + 1).x),
             y1    =     zigzag.get(offset + 1).y,
             x2    = int(zigzag.get(offset + 0).x),
             y2    =     zigzag.get(offset + 0).y,
             xloc  =        xloc.bar_index,
             color =     zigzag.get(offset + 0).col,
             style = style,
             width = width)

method compareHL(point[] zigzag = na, HL hiLo = na, int offset = 0) =>
    dir ==   1 ? zigzag.get(offset + 0).y > zigzag.get(offset + 2).y ? hiLo.Hi : hiLo.Lo :
                 zigzag.get(offset + 0).y < zigzag.get(offset + 2).y ? hiLo.Lo : hiLo.Hi

method textTip(label this = na, string str = na, string tip = na) =>
    this.set_text(   str)
    this.set_tooltip(tip)

if Kh or Kl
    if dirchanged
        zigzag.initialize( varSetup, 4)
    else
        zigzag.update(varSetup, 4, dir)

if zigzag.size() >= 3
    var line   dirLine   = na
    var label  dirLabel  = na
    var string dirString = na
    [boolOr, boolAnd]    = zigzag.boolPoint(oldzigzag)
    if boolOr
        if boolAnd
            dirLine.delete()
            dirLabel.delete()
        if showLabel
            if disKlayLabel == 'HL' or disKlayLabel == 'HHLL'
                dirLabel := zigzag.createLabel(sizeLabel)
            if disKlayLabel == 'HHLL' and zigzag.size() >= 4                             
                dirString  := zigzag.compareHL(hiLo)
                dirLabel.textTip(dirString + zigzag.get(0).str, dirString + zigzag.get(0).str + '\n' + str.tostring(zigzag.get(0).y))
            if colorLabel != 'Trend'
                dirLabel.set_textcolor(switchLabelColor)
        if showLine
            dirLine := zigzag.createLine(width, switchLine)
            if colorLine  != 'Trend'
                dirLine.set_color(switchLineColor)

const bool DEBUG = false

const int timeframeCount = 3
const float labelOffsetsY = 1.001
const int labelOffsetsXIndex = 30
const float epsilon = 0.15 / 100.0
const float retestEpsilon = 0.015 / 100.0
const int maxPivotsBackSR = 15
const int retestLabelEveryXBars = 4
const int maxTraverse = 250  // Affects bar history limit. Default value 250.
const int maxRetestLabels = 4
const int maxSupports = 3
const int maxResistances = 3
const float retestPriceDifferencePercentMax = 0.40
const bool calculateTimeSkipMS = false
const int debug_maxPivotLabels = 25

resistanceSupportCount = input.int(3, "Support & Resistance Count", options = [1, 2, 3], group = "General Configuration")
pivotRange = input.int(15, "Pivot Range", options = [5, 15, 30], tooltip = "Increase for more general pivots, decrease for more private pivots.", group = "General Configuration")
strength = input.int(1, "Strength", options = [1, 2, 3, 4], tooltip = "X many times price touched relative price area in order to be considered a support/resistance zone.", group = "General Configuration")
expandLines = input.bool(false,"Expand Lines & Zones", group = "General Configuration")

enableZones = input.bool(false, "Enable Zones", group = "Support & Resistance Zones")
zoneWidth1 = input.int(2, "Zone Width", options = [1,2,3], group = "Support & Resistance Zones")

timeframe1Enabled = input.bool(false, title = "", group = "Timeframes", inline = "timeframe1")
timeframe1 = input.timeframe("", title = "", group = "Timeframes", inline = "timeframe1")
timeframe2Enabled = input.bool(false, title = "", group = "Timeframes", inline = "timeframe2")
timeframe2 = input.timeframe("60", title = "", group = "Timeframes", inline = "timeframe2")
timeframe3Enabled = input.bool(false, title = "", group = "Timeframes", inline = "timeframe3")
timeframe3 = input.timeframe("240", title = "", group = "Timeframes", inline = "timeframe3")

showBreaks = input.bool(false,"Show Breaks", group = "Breaks & Retests", inline = "ShowBR")
showRetests = input.bool(false,"Show Retests", group = "Breaks & Retests", inline = "ShowBR")
avoidFalseBreaks = input.bool(false,"Avoid False Breaks", group = "Breaks & Retests")
falseBreakoutVolumeThreshold = input.int(30, "Break Volume Threshold %", minval = 0, maxval = 100, group = "Breaks & Retests", tooltip = "Only taken into account if Avoid False Breakouts is enabled.\nHigher values mean it's less likely to be a break.")
inverseBrokenLineColor = input.bool(false,"Inverse Color After Broken", tooltip = "Needs Show Breaks & Expand Lines option enabled.", group = "Breaks & Retests")

lineStyle1 = input.string("____", "Line Style", ["____", "----", "...."], group = "Style")
lineWidth1 = input.int(2, "Line Width", minval = 1, group = "Style")
supportColor = input.color(#08d0af14, "Support Color", group = "Style", inline = "RScolors")
resistanceColor = input.color(#f4ba0b14, "Resistance Color", group = "Style", inline = "RScolors")
textColor = input.color(#ffffff80, "Text Color", group = "Style", inline = "RScolors")

enableRetestAlerts = input.bool(false, "Enable Retest Alerts", tooltip = "Needs Show Retests option enabled.", group = "Alerts")
enableBreakAlerts = input.bool(false, "Enable Break Alerts", group = "Alerts")

memoryOptimizatonEnabled = input.bool(false, "Enable Memory Optimization", tooltip = "Enable this option if you encounter memory errors.", group = "Advanced")

debug_labelPivots = not DEBUG ? "None" : input.string("None", title = "[DBG] Label Pivots", group = "DEBUG", options = ["All", "RS", "None"], tooltip = "All -> Debugs all pivot labels.\nRS -> Debugs RS pivot labels.\nNone -> Debugs none of the last R&S pivots.")
debug_pivotLabelText = not DEBUG ? false : input.bool(false, title = "[DBG] Pivot Label Text", group = "DEBUG")
debug_showBrokenOnLabel = not DEBUG ? false : input.bool(false, "[DBG] Show Broken Text On Label", group = "DEBUG")
debug_removeDuplicateRS = not DEBUG ? true : input.bool(true, "[DBG] Remove Duplicate RS", group = "DEBUG")
debug_lastXResistances = not DEBUG ? 3 : input.int(3, "[DBG] Show Last X Resistances", minval = 0, maxval = maxResistances, group = "DEBUG")
debug_lastXSupports = not DEBUG ? 3 : input.int(3, "[DBG] Show Last X Supports", minval = 0, maxval = maxSupports, group = "DEBUG")
debug_enabledHistory = not DEBUG ? true : input.bool(true, "[DBG] Enable History", group = "DEBUG")
debug_maxHistoryRecords = not DEBUG ? 10 : input.int(10, "[DBG] Max History Records", options =  [1, 2, 5, 10, 25], group = "DEBUG")

createRSLine (color) =>
    line.new(na, na, na, na, extend = expandLines ? extend.both : extend.none, xloc=xloc.bar_time, color = color, width = lineWidth, style = lineStyle == "----" ? line.style_dashed : lineStyle == "...." ? line.style_dotted : line.style_solid)

createRSBox (color, xlocType) =>
    box.new(na, na, na, na, text_size = size.normal, xloc = xlocType, extend = extend.both, bgcolor = color, text_color = textColor, text_halign = expandLines ? text.align_right : text.align_center, border_color = #00000000)

createRSLabel () =>
    label.new(na, na, "", style = label.style_none, textcolor = textColor)

createBreakLabel (RSType) =>
    label.new(na,na,style = RSType == "Resistance" ? label.style_label_up : label.style_label_down, color=color.rgb(33, 149, 243, 100), textcolor = color.rgb(255, 255, 255, 100), xloc = xloc.bar_time, size = size.tiny)

createRetestLabel (RSType) =>
    label.new(na,na,style = RSType == "Resistance" ? label.style_label_down : label.style_label_up, color = RSType == "Resistance" ? resistanceColor : supportColor, textcolor = color.rgb(255, 255, 255, 100), xloc = xloc.bar_time, size = size.tiny)

moveLine(_line, _x, _y, _x2) =>
    line.set_xy1(_line, _x,  _y)
    line.set_xy2(_line, _x2, _y)

moveBox (_box, _topLeftX, _topLeftY, _bottomRightX, _bottomRightY) =>
    box.set_lefttop(_box, _topLeftX, _topLeftY)
    box.set_rightbottom(_box, _bottomRightX, _bottomRightY)

moveRSInfoBox (_box, _startPointX, _price, _endPointX) =>
    zoneWidthPercent = zoneWidth == 1 ? 0.05 : zoneWidth == 2 ? 0.06 : 0.075
    topY = _price * (1.0 + (zoneWidthPercent / 2.0 / 100.0))
    bottomY = _price * (1.0 - (zoneWidthPercent / 2.0 / 100.0))
    moveBox(_box, _startPointX, topY, _endPointX, bottomY)

type RSInfo
    bool isBroken = na
    int brokenTime = na
    string RSType = na
    float price = na
    line line = na
    box box = na
    label priceLabel = na
    chart.point[] points = na
    label[] debugPoints = na
    label breakLabel = na
    label[] retestLabels = na
    line breakLine = na
    box breakBox = na

newRSInfo (RSType) =>
    newRSInfo = RSInfo.new()
    newRSInfo.RSType := RSType
    newRSInfo.price := na
    newRSInfo.isBroken := false
    newRSInfo.brokenTime := na

    newRSInfo.line := enableZones ? na : createRSLine(RSType == "Resistance" ? resistanceColor : supportColor)
    newRSInfo.box := enableZones ? createRSBox(RSType == "Resistance" ? resistanceColor : supportColor, xloc.bar_time) : na
    newRSInfo.priceLabel := enableZones ? na : createRSLabel()
    newRSInfo.points := array.new<chart.point>(0)
    newRSInfo.debugPoints := array.new<label>(0)
    newRSInfo.retestLabels := array.new<label>(0)
    newRSInfo.breakLabel := na
    newRSInfo.breakLine := na
    newRSInfo.breakBox := na

    newRSInfo

histRSInfo (RSInfo RSInfoF) =>
    RSType = RSInfoF.RSType
    newRS = RSInfo.new()
    newRS.RSType := RSType
    newRS.price := RSInfoF.price

    newRS.debugPoints := array.new<label>(0)
    newRS.retestLabels := array.new<label>(0)
    newRS.points := array.new<chart.point>(0)

    histText = "History | " + str.tostring(newRS.price, format.mintick)

    startTime = math.min(time, RSInfoF.points.get(strength - 1).time)
    endTime = RSInfoF.isBroken ? RSInfoF.brokenTime : time

    if enableZones
        newRS.box := createRSBox(RSType == "Resistance" ? resistanceColor : supportColor, xloc.bar_time)
        moveRSInfoBox(newRS.box, startTime, newRS.price, endTime)
        box.set_extend(newRS.box, expandLines ? extend.both : extend.none)
        box.set_text(newRS.box, histText)
    else
        newRS.line := line.copy(RSInfoF.line)
        moveLine(newRS.line, startTime, newRS.price, endTime)
        line.set_extend(newRS.line, expandLines ? extend.both : extend.none)

        newRS.priceLabel := label.copy(RSInfoF.priceLabel)
        label.set_text(newRS.priceLabel, histText)
        label.set_xloc(newRS.priceLabel, (startTime + endTime) / 2, xloc.bar_time)

    if not na(newRS.breakLabel)
        newRS.breakLabel := label.copy(RSInfoF.breakLabel)

    newRS

safeDeleteRSInfo (RSInfo RSInfoF) =>
    if not na(RSInfoF)
        line.delete(RSInfoF.line)
        box.delete(RSInfoF.box)
        label.delete(RSInfoF.priceLabel)

        RSInfoF.points.clear()

        if RSInfoF.debugPoints.size() > 0
            for i = 0 to RSInfoF.debugPoints.size() - 1
                label.delete(RSInfoF.debugPoints.get(i))
            RSInfoF.debugPoints.clear()

        if RSInfoF.retestLabels.size() > 0
            for i = 0 to RSInfoF.retestLabels.size() - 1
                label.delete(RSInfoF.retestLabels.get(i))
            RSInfoF.retestLabels.clear()

        label.delete(RSInfoF.breakLabel)
        line.delete(RSInfoF.breakLine)
        box.delete(RSInfoF.breakBox)

type timeframeInfo
    int index = na
    string timeframeStr = na
    bool isEnabled = false

    RSInfo[] resistances = na
    RSInfo[] supports = na

    float[] highPivots = na
    int[] highTimes = na

    float[] lowPivots = na
    int[] lowTimes = na

newTimeframeInfo (index, timeframeStr, isEnabled) =>
    newTFInfo = timeframeInfo.new()
    newTFInfo.index := index
    newTFInfo.isEnabled := isEnabled
    newTFInfo.timeframeStr := timeframeStr

    newTFInfo.resistances := array.new<RSInfo>(debug_lastXResistances)
    newTFInfo.supports := array.new<RSInfo>(debug_lastXSupports)

    newTFInfo.highPivots := array.new<float>()
    newTFInfo.highTimes := array.new<int>()

    newTFInfo.lowPivots := array.new<float>()
    newTFInfo.lowTimes := array.new<int>()
    newTFInfo

var timeframeInfo[] timeframeInfos = array.from(newTimeframeInfo(1, timeframe1, timeframe1Enabled), newTimeframeInfo(2, timeframe2, timeframe2Enabled), newTimeframeInfo(3, timeframe3, timeframe3Enabled))
var bool initRun = true
var int maxTimeskipMS = 0

var float[] allLowPivots = array.new<float>(0)
var float[] allHighPivots = array.new<float>(0)
var int[] allLowTimes = array.new<int>(0)
var int[] allHighTimes = array.new<int>(0)

var RSInfo[] history = array.new<RSInfo>(0)

RSInfo[] curRSList = array.new<RSInfo>(0)
RSInfo[] oldRSList = array.new<RSInfo>(0)

int maxPivotsAllowed = memoryOptimizatonEnabled ? 10 : 15 // Affects memory limit. Default value 30.

doValuesTouch (float value1, float value2) =>
    if math.abs(value1 - value2) / ((value1 + value2) / 2.0) <= epsilon
        true
    else
        false

doValuesTouch (float value1, float value2, float customEpsilon) =>
    if math.abs(value1 - value2) / ((value1 + value2) / 2.0) <= customEpsilon
        true
    else
        false

findLatestRS (timeframeInfo timeframeInfoF, string RSType, pivots, times, bannedValues) =>
    RSInfo latestRSF = na
    pivotsCount = pivots.size()
    if pivotsCount > 0
        for i = 0 to pivotsCount - 1
            if i >= maxTraverse
                break

            index = pivotsCount - i - 1
            occurances = 0
            invalidValue = false
            pivotValue1 = pivots.get(index)
            if bannedValues.size() > 0
                for a = 0 to bannedValues.size() - 1
                    if doValuesTouch(pivotValue1, bannedValues.get(a))
                        invalidValue := true
                        break

            if invalidValue
                continue

            for j = 0 to pivotsCount - 1
                if j >= maxTraverse
                    break

                index2 = pivotsCount - j - 1
                pivotValue2 = pivots.get(index2)
                if doValuesTouch(pivotValue1, pivotValue2)
                    occurances += 1

                if occurances >= strength
                    latestRSF := newRSInfo(RSType)
                    latestRSF.price := pivotValue1
                    break

                if math.abs(index - index2) > maxPivotsBackSR * strength
                    break

            if not na(latestRSF)
                break

    if not na(latestRSF)
        cnt = 0
        if pivotsCount > 0
            for i = 0 to pivotsCount - 1
                if i >= maxTraverse
                    break

                index = pivotsCount - i - 1
                pivotValue = pivots.get(index)
                if doValuesTouch(pivotValue, latestRSF.price)
                    labelTime = times.get(index)
                    latestRSF.points.push(chart.point.from_time(labelTime, pivotValue))
                    cnt += 1
                if cnt == strength
                    break

    if not (debug_labelPivots == "None")
        if not (debug_labelPivots == "All")
            if not na(latestRSF)
                cnt = 0
                if pivotsCount > 0
                    for i = 0 to pivotsCount - 1
                        index = pivotsCount - i - 1
                        pivotValue = pivots.get(index)
                        if doValuesTouch(pivotValue, latestRSF.price)
                            labelTime = times.get(index)
                            latestRSF.debugPoints.push(RSType == "Resistance" ? label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue) : "",xloc=xloc.bar_time, color=resistanceColor, textcolor=color.white) : label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue) : "",xloc=xloc.bar_time, color=supportColor,style = label.style_label_up, textcolor=color.white))
                            cnt += 1
                        if cnt == strength
                            break
        else
            if not na(latestRSF)
                if pivotsCount > 0
                    for i = 0 to pivotsCount - 1
                        index = pivotsCount - i - 1
                        pivotValue = pivots.get(index)
                        labelTime = times.get(index)
                        latestRSF.debugPoints.push(RSType == "Resistance" ? label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue) : "",xloc=xloc.bar_time, color=resistanceColor, textcolor=color.white) : label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue) : "",xloc=xloc.bar_time, color=supportColor,style = label.style_label_up, textcolor=color.white))
                        if latestRSF.debugPoints.size() > debug_maxPivotLabels
                            break
    latestRSF

findLatestNthRS (timeframeInfo timeframeInfoF, string RSType, pivots, times, n) =>
    float[] bannedValues = array.new<float>()
    foundRS = 0
    RSInfo foundLatestRS = na
    while foundRS < n
        foundLatestRS := findLatestRS(timeframeInfoF, RSType, pivots, times, bannedValues)
        if not na(foundLatestRS)
            foundRS += 1
            bannedValues.push(foundLatestRS.price)
        else
            break
    foundLatestRS

isTimeframeLower (timeframe1F, timeframe2F) =>
    timeframe.in_seconds(timeframe1F) < timeframe.in_seconds(timeframe2F)

getMinTimeframe (timeframe1F, timeframe2F) =>
    if isTimeframeLower(timeframe1F, timeframe2F)
        timeframe1F
    else
        timeframe2F

getMaxTimeframe (timeframe1F, timeframe2F) =>
    if isTimeframeLower(timeframe1F, timeframe2F)
        timeframe2F
    else
        timeframe1F

getFirstBreak (RSInfo rsInfo) =>
    if na(rsInfo)
        [na, na]

    curIndex = 0
    float foundBreakLevel = na
    int foundBreakTime = na
    while true
        if curIndex >= maxTraverse
            break
        isBarBreak = rsInfo.RSType == "Resistance" ? (close[curIndex + 1] <= rsInfo.price and close[curIndex] > rsInfo.price) : (close[curIndex + 1] >= rsInfo.price and close[curIndex] < rsInfo.price)
        if isBarBreak
            isTrueBreakout = true
            if avoidFalseBreaks
                shortTerm = 5
                longTerm = 15

                shortSum = 0.0
                longSum = 0.0

                for i = 0 to shortTerm
                    shortSum += volume[curIndex + i]

                for i = 0 to longTerm
                    longSum += volume[curIndex + i]

                shortVolumeAvg = shortSum / shortTerm
                longVolumeAvg = longSum / longTerm

                volumeRatio = ((shortVolumeAvg - longVolumeAvg) / longVolumeAvg) * 100.0
                isTrueBreakout := (volumeRatio >= falseBreakoutVolumeThreshold)

            if isTrueBreakout
                foundBreakLevel := rsInfo.RSType == "Resistance" ? low[curIndex] : high[curIndex]
                foundBreakTime := time[curIndex]

        curIndex += 1
        if time[curIndex] <= rsInfo.points.get(strength - 1).time
            break
    [foundBreakLevel, foundBreakTime]

getRetests (RSInfo rsInfo) =>
    if na(rsInfo)
        [na,na]

    curIndex = 0
    lastRetestIndex = -999
    int[] retestTimes = array.new<int>()
    float[] retestLevels = array.new<float>()

    while true
        if curIndex >= maxTraverse
            break
        if retestLevels.size() == maxRetestLabels
            break
        if rsInfo.isBroken and time[curIndex] >= rsInfo.brokenTime
            curIndex += 1
            continue

        differencePercent = 100.0 * math.min(math.abs(rsInfo.price - close[curIndex]) / ((rsInfo.price + close[curIndex]) / 2), rsInfo.RSType == "Resistance" ? math.abs(rsInfo.price - high[curIndex]) / ((rsInfo.price + high[curIndex]) / 2) : math.abs(rsInfo.price - low[curIndex]) / ((rsInfo.price + low[curIndex]) / 2))
        isRetest = (rsInfo.RSType == "Resistance" ? (doValuesTouch(rsInfo.price, close[curIndex], retestEpsilon) or doValuesTouch(rsInfo.price, high[curIndex], retestEpsilon) or high[curIndex] > rsInfo.price) : (doValuesTouch(rsInfo.price, close[curIndex], retestEpsilon) or doValuesTouch(rsInfo.price, low[curIndex], retestEpsilon) or low[curIndex] < rsInfo.price)) and differencePercent < retestPriceDifferencePercentMax
        if isRetest and curIndex - lastRetestIndex >= retestLabelEveryXBars
            retestLevels.push(rsInfo.RSType == "Resistance" ? high[curIndex] : low[curIndex])
            retestTimes.push(time[curIndex])
            lastRetestIndex := curIndex
        curIndex += 1
        if time[curIndex] <= rsInfo.points.get(strength - 1).time
            break
    [retestLevels, retestTimes]

formatTimeframeString (formatTimeframe) =>
    timeframeF = formatTimeframe == "" ? timeframe.period : formatTimeframe

    if str.contains(timeframeF, "D") or str.contains(timeframeF, "W") or str.contains(timeframeF, "S") or str.contains(timeframeF, "M")
        timeframeF
    else
        seconds = timeframe.in_seconds(timeframeF)
        if seconds >= 3600
            hourCount = int(seconds / 3600)
            str.tostring(hourCount) + " Hour" + (hourCount > 1 ? "s" : "")
        else
            timeframeF + " Min"

getPivot (pivotType) =>
    pivot = (pivotType == "high" ? ta.pivothigh(high, pivotRange, pivotRange) : ta.pivotlow(low, pivotRange, pivotRange))
    pivot

handleRSInfo (timeframeInfo timeframeInfoF, RSInfo RSInfoF, int index, string RSType) =>
    if not na(RSInfoF)
        if not na(timeframeInfoF)
            curRSList.push(RSInfoF)

        [foundBreakLevel, foundBreakTime] = getFirstBreak(RSInfoF)

        RSInfoF.isBroken := na(foundBreakLevel) ? false : true
        RSInfoF.brokenTime := na(foundBreakLevel) ? na : foundBreakTime

        if not na(foundBreakLevel)
            if showBreaks
                if na(RSInfoF.breakLabel)
                    RSInfoF.breakLabel := createBreakLabel(RSInfoF.RSType)
                label.set_xy(RSInfoF.breakLabel, foundBreakTime, foundBreakLevel * (RSInfoF.RSType == "Resistance" ? (1.0 / labelOffsetsY) : labelOffsetsY))

            if expandLines
                if na(RSInfoF.breakLine) and enableZones == false
                    RSInfoF.breakLine := createRSLine(color.black)

                if na(RSInfoF.breakBox) and enableZones == true
                    RSInfoF.breakBox := createRSBox(color.black, xloc.bar_time)

                if not enableZones
                    line.set_extend(RSInfoF.breakLine, extend.right)
                else
                    box.set_extend(RSInfoF.breakBox, extend.right)

                if inverseBrokenLineColor and showBreaks
                    if not enableZones
                        line.set_color(RSInfoF.breakLine, RSInfoF.RSType == "Resistance" ? supportColor : resistanceColor)
                    else    
                        box.set_bgcolor(RSInfoF.breakBox, RSInfoF.RSType == "Resistance" ? supportColor : resistanceColor)
                else
                    if not enableZones
                        line.set_color(RSInfoF.breakLine, RSInfoF.RSType == "Resistance" ? resistanceColor : supportColor)
                    else
                        box.set_bgcolor(RSInfoF.breakBox, RSInfoF.RSType == "Resistance" ? resistanceColor : supportColor)

        if showRetests
            [retestLevels, retestTimes] = getRetests(RSInfoF)

            if not na(retestLevels) and retestLevels.size() > 0
                for i = 0 to retestLevels.size() - 1
                    newRetestLabel = createRetestLabel(RSInfoF.RSType)
                    label.set_xy(newRetestLabel, retestTimes.get(i), retestLevels.get(i) * (RSInfoF.RSType == "Support" ? (1.0 / labelOffsetsY) : labelOffsetsY))
                    RSInfoF.retestLabels.push(newRetestLabel)

        timeSkipOffset = 0
        if enableZones
            zoneEndX = time + timeSkipOffset + timeframe.in_seconds(timeframe.period) * 1000 * labelOffsetsXIndex 
            startTime = math.min(time, RSInfoF.points.get(strength - 1).time)
            moveRSInfoBox(RSInfoF.box, startTime, RSInfoF.price, na(foundBreakTime) ? zoneEndX : foundBreakTime)
            moveRSInfoBox(RSInfoF.breakBox, foundBreakTime, RSInfoF.price, zoneEndX)
        else
            endTime = time + timeSkipOffset + timeframe.in_seconds(timeframe.period) * 1000
            startTime = math.min(time, RSInfoF.points.get(strength - 1).time)
            moveLine(RSInfoF.line, startTime, RSInfoF.price, na(foundBreakTime) ? endTime : foundBreakTime)
            moveLine(RSInfoF.breakLine, foundBreakTime, RSInfoF.price, endTime)

        if expandLines
            if not enableZones
                line.set_extend(RSInfoF.line, (na(foundBreakTime)) ? extend.both : extend.left)
            else    
                box.set_extend(RSInfoF.box, (na(foundBreakTime)) ? extend.both : extend.left)
        else
            if not enableZones
                line.set_extend(RSInfoF.line, na(foundBreakTime) ? extend.right : extend.none)
            else
                box.set_extend(RSInfoF.box, na(foundBreakTime) ? extend.right : extend.none)

        labelTitle = formatTimeframeString(timeframeInfoF.timeframeStr) + " | " + str.tostring(RSInfoF.price,format.mintick) + ((debug_showBrokenOnLabel and RSInfoF.isBroken)  ? " [B]" : "")

        if not enableZones
            label.set_text(RSInfoF.priceLabel, enableZones ? "" : labelTitle)
            label.set_y(RSInfoF.priceLabel, RSInfoF.price)
        else
            box.set_text(RSInfoF.box, (RSInfoF.isBroken and expandLines) ? "" : labelTitle)
            box.set_text(RSInfoF.breakBox, labelTitle)

        if expandLines or not RSInfoF.isBroken
            if not enableZones
                label.set_xloc(RSInfoF.priceLabel, bar_index + labelOffsetsXIndex, xloc.bar_index)
            else
                box.set_text_halign(RSInfoF.breakBox, text.align_right)
                box.set_text_halign(RSInfoF.box, text.align_right)
        else
            if not enableZones
                label.set_xloc(RSInfoF.priceLabel, (RSInfoF.points.get(strength - 1).time + RSInfoF.brokenTime) / 2, xloc.bar_time)
            else
                box.set_text_halign(RSInfoF.box, text.align_center)
                box.set_text_halign(RSInfoF.breakBox, text.align_center)
    else
        log.error("Couldn't find timeframe " + str.tostring(timeframeInfoF.index) + " " + str.tostring(index + 1) + "th " + RSType + " . Try decreasing pivot range in the settings.")

handleTimeframe (timeframeIndex, lowPivots, highPivots, lowTimes, highTimes) =>
    timeframeInfoF = timeframeInfos.get(timeframeIndex - 1)

    timeframeInfoF.lowPivots.clear()
    timeframeInfoF.highPivots.clear()
    timeframeInfoF.lowTimes.clear()
    timeframeInfoF.highTimes.clear()

    timeframeInfoF.lowPivots := lowPivots
    timeframeInfoF.highPivots := highPivots
    timeframeInfoF.lowTimes := lowTimes
    timeframeInfoF.highTimes := highTimes

getHigherTFData (timeframeStr) =>
    request.security(syminfo.tickerid, getMaxTimeframe(timeframe.period, timeframeStr), [allLowPivots, allHighPivots, allLowTimes, allHighTimes])

pushHighPivots (timeframeInfoF, highPivotF, timeF) =>
    if not na(highPivotF)
        timeframeInfoF.highPivots.push(highPivotF)
        timeframeInfoF.highTimes.push(timeF)

pushLowPivots (timeframeInfoF, lowPivotF, timeF) =>
    if not na(lowPivotF)
        timeframeInfoF.lowPivots.push(lowPivotF)
        timeframeInfoF.lowTimes.push(timeF)

handleTimeframeIfLower (timeframeInfo timeframeInfoF, highs, lows, int[] timesF) =>
    if timeframeInfoF.isEnabled and isTimeframeLower(timeframeInfoF.timeframeStr, timeframe.period)
        if highs.size() > 0
            for i = 0 to highs.size() - 1
                timeF = timesF.get(i)
                pushHighPivots(timeframeInfoF, highs.get(i), timeF)
        if lows.size() > 0
            for i = 0 to lows.size() - 1
                timeF = timesF.get(i)
                pushLowPivots(timeframeInfoF, lows.get(i), timeF)

getLowerTFData (timeframeStr) =>
    lowPivots = isTimeframeLower(timeframeStr, timeframe.period) ? request.security_lower_tf(syminfo.tickerid, getMinTimeframe(timeframeStr, timeframe.period), ta.pivotlow(low, pivotRange, pivotRange)) : na
    highPivots = isTimeframeLower(timeframeStr, timeframe.period) ? request.security_lower_tf(syminfo.tickerid, getMinTimeframe(timeframeStr, timeframe.period), ta.pivothigh(high, pivotRange, pivotRange)) : na
    times = isTimeframeLower(timeframeStr, timeframe.period) ? request.security_lower_tf(syminfo.tickerid, getMinTimeframe(timeframeStr, timeframe.period), time[pivotRange]) : na
    [lowPivots,highPivots,times,times]

getTFData (timeframeStr) =>
    if isTimeframeLower(timeframeStr, timeframe.period)
        getLowerTFData(timeframeStr)
    else
        getHigherTFData(timeframeStr)

checkIfRSAreSame (RSInfo rsInfo1, RSInfo rsInfo2) =>
    if na(rsInfo1) or na(rsInfo2)
        false
    else if rsInfo1.RSType != rsInfo2.RSType
        false
    else if rsInfo1.price != rsInfo2.price
        false
    else
        true

checkIfArrHasRS (RSInfo[] arr, RSInfo rsInfoF) =>
    if na(arr) or na(rsInfoF)
        true
    else if arr.size() == 0
        false
    else
        foundRS = false
        for i = 0 to arr.size() - 1
            arrRS = arr.get(i)
            if checkIfRSAreSame(arrRS, rsInfoF)
                foundRS := true
                break
        if foundRS
            true
        else
            false

clearTimeframeRS (timeframeInfoF) =>
    oldRetestsCount = 0
    oldBreaksCount = 0

    if timeframeInfoF.resistances.size() > 0
        for j = 0 to timeframeInfoF.resistances.size() - 1
            RSInfo RSInfoF = timeframeInfoF.resistances.get(j)
            if not na(RSInfoF)
                if debug_enabledHistory
                    if checkIfArrHasRS(oldRSList, RSInfoF) == false
                        oldRSList.push(RSInfoF)

                oldRetestsCount += RSInfoF.retestLabels.size()
                oldBreaksCount += RSInfoF.isBroken ? 1 : 0

    if timeframeInfoF.supports.size() > 0
        for j = 0 to timeframeInfoF.supports.size() - 1
            RSInfo RSInfoF = timeframeInfoF.supports.get(j)
            if not na(RSInfoF)
                if debug_enabledHistory
                    if checkIfArrHasRS(history, RSInfoF) == false
                        oldRSList.push(RSInfoF)

                oldRetestsCount += RSInfoF.retestLabels.size()
                oldBreaksCount += RSInfoF.isBroken ? 1 : 0

    timeframeInfoF.resistances.clear()
    timeframeInfoF.supports.clear()
    [oldRetestsCount, oldBreaksCount]

findTimeframeRS (timeframeInfoF, RSType, arr, count, pivots, times) =>
    curRetestsCount = 0
    curBreaksCount = 0

    if count > 0
        for j = 0 to count - 1
            foundRS = findLatestNthRS(timeframeInfoF, RSType, pivots, times, j + 1)
            if not na(foundRS)
                notDuplicate = true
                for a = 0 to timeframeInfos.size() - 1
                    aInfo = timeframeInfos.get(a)
                    if na(aInfo) or aInfo.isEnabled == false
                        continue
                    otherTimeframeArray = (RSType == "Resistance" ? aInfo.resistances : aInfo.supports)
                    if otherTimeframeArray.size() > 0
                        for b = 0 to otherTimeframeArray.size() - 1
                            if checkIfRSAreSame(foundRS, otherTimeframeArray.get(b))
                                notDuplicate := false
                                break
                    if notDuplicate == false
                        break

                if notDuplicate or not debug_removeDuplicateRS
                    arr.push(foundRS)

        if arr.size() > 0
            for j = 0 to arr.size() - 1
                curRS = arr.get(j)
                if not na(curRS)
                    handleRSInfo(timeframeInfoF, curRS, j, RSType)
                    curRetestsCount += curRS.retestLabels.size()
                    curBreaksCount += curRS.isBroken ? 1 : 0
    [curRetestsCount, curBreaksCount]

lowPivot = getPivot("low")
highPivot = getPivot("high")

if not na(lowPivot)
    allLowPivots.push(lowPivot)
    allLowTimes.push(time[pivotRange])
    if allLowPivots.size() > maxPivotsAllowed
        allLowPivots.remove(0)
        allLowTimes.remove(0)

if not na(highPivot)
    allHighPivots.push(highPivot)
    allHighTimes.push(time[pivotRange])
    if allHighPivots.size() > maxPivotsAllowed
        allHighPivots.remove(0)
        allHighTimes.remove(0)

if calculateTimeSkipMS
    if last_bar_index - bar_index < 350 and time - time[1] > timeframe.in_seconds(timeframe.period) * 1000
        maxTimeskipMS := math.max(maxTimeskipMS, time - time[1])

[lowPivotsTF1, highPivotsTF1, lowTimesTF1, highTimesTF1] = getTFData(timeframe1)
handleTimeframeIfLower(timeframeInfos.get(0), highPivotsTF1, lowPivotsTF1, highTimesTF1)

[lowPivotsTF2, highPivotsTF2, lowTimesTF2, highTimesTF2] = getTFData(timeframe2)
handleTimeframeIfLower(timeframeInfos.get(1), highPivotsTF2, lowPivotsTF2, highTimesTF2)

[lowPivotsTF3, highPivotsTF3, lowTimesTF3, highTimesTF3] = getTFData(timeframe3)
handleTimeframeIfLower(timeframeInfos.get(2), highPivotsTF3, lowPivotsTF3, highTimesTF3)

if barstate.islast

    if timeframe1Enabled and not isTimeframeLower(timeframe1, timeframe.period)
        handleTimeframe(1, lowPivotsTF1, highPivotsTF1, lowTimesTF1, highTimesTF1)

    if timeframe2Enabled and not isTimeframeLower(timeframe2, timeframe.period)
        handleTimeframe(2, lowPivotsTF2, highPivotsTF2, lowTimesTF2, highTimesTF2)

    if timeframe3Enabled and not isTimeframeLower(timeframe3, timeframe.period)
        handleTimeframe(3, lowPivotsTF3, highPivotsTF3, lowTimesTF3, highTimesTF3)

    int enabledTimeframeCount = 0
    for i = 0 to timeframeCount - 1
        timeframeInfo curInfo = timeframeInfos.get(i)
        if curInfo.isEnabled
            enabledTimeframeCount += 1

    int oldRetestsCount = 0
    int curRetestsCount = 0

    int oldBreaksCount = 0
    int curBreaksCount = 0

    for i = 0 to timeframeCount - 1
        timeframeInfo curInfo = timeframeInfos.get(i)
        if not curInfo.isEnabled
            continue

        [oldRetests, oldBreaks] = clearTimeframeRS(curInfo)
        oldRetestsCount += oldRetests
        oldBreaksCount += oldBreaks

        resistanceCount = math.min(DEBUG ? debug_lastXResistances : resistanceSupportCount, maxResistances - (enabledTimeframeCount > 1 ? 1 : 0))
        resistanceCount := math.max(resistanceCount, 0)

        supportCount = math.min(DEBUG ? debug_lastXSupports : resistanceSupportCount, maxSupports - (enabledTimeframeCount > 1 ? 1 : 0))
        supportCount := math.max(supportCount, 0)

        [curRetests1, curBreaks1] = findTimeframeRS(curInfo, "Resistance", curInfo.resistances, resistanceCount, curInfo.highPivots, curInfo.highTimes)
        [curRetests2, curBreaks2] = findTimeframeRS(curInfo, "Support", curInfo.supports, supportCount, curInfo.lowPivots, curInfo.lowTimes)
        curRetestsCount += curRetests1 + curRetests2
        curBreaksCount += curBreaks1 + curBreaks2

    if debug_enabledHistory
        historyIndexesToDelete = array.new<int>(0)
        if history.size() > 0
            for i = 0 to history.size() - 1
                if checkIfArrHasRS(curRSList, history.get(i))
                    historyIndexesToDelete.push(i)

            if historyIndexesToDelete.size() > 0
                for i = 0 to historyIndexesToDelete.size() - 1
                    deleteIndex = historyIndexesToDelete.get(historyIndexesToDelete.size() - i - 1)
                    safeDeleteRSInfo

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

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

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

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

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

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

Стоимость полного кода
7 079,90₽ ≈ $86.54