Pivot Points
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// @agentsmith1337
//@version=5
indicator('Pivot Points', 'pivot-points', overlay = true)

///////////////////////////////////////////////////////////////////////////////
// inputs
i_leverage          = input.int(1,      "Leverage")
i_takeProfit        = input.float(1.0,  "Take Profit %") / i_leverage
i_dca               = input.float(-1.0, "DCA when < %") / i_leverage *-1
i_pivotFactor       = input.float(-1,   "Pivot Factor")
i_pivotLength       = input.int(60,     "Pivot Length", minval = 0)
i_lookbackFactor    = input.float(-1,   "Lookback Factor")

///////////////////////////////////////////////////////////////////////////////
// variables
// Manually track the average entry price and position size
var float avg_entry_price   = na
var int position_size       = 0

int pause   = 0
pause       := nz(pause[1])
bool paused = time < pause
float fill  = 0.0
fill        := nz(fill[1])
float count = 0.0
count       := nz(fill[1])

///////////////////////////////////////////////////////////////////////////////
// functions
update_position(avg_price, size, entry_price) =>
    new_avg_price = size > 0 ? (avg_price * size + entry_price) / (size + 1) : entry_price
    new_size = size + 1
    [new_avg_price, new_size]

///////////////////////////////////////////////////////////////////////////////
// calculations
pivotHigh           = ta.highest(i_pivotLength)
pivotHighAboveSMA   = ta.dev(pivotHigh, i_pivotLength) > 0
hi                  = pivotHighAboveSMA ? na : pivotHigh
hPivot              = ta.valuewhen(not na(hi), hi, 0)
pivotLow            = ta.lowest(i_pivotLength)
pivotLowAboveSMA    = ta.dev(pivotLow, i_pivotLength) > 0
lo                  = pivotLowAboveSMA ? na : pivotLow
lPivot              = ta.valuewhen(not na(lo), lo, 0)

entry           = ((((hPivot - lPivot)) * i_pivotFactor) + lPivot)
lookbackFactor  = (((hPivot - lPivot) * i_lookbackFactor) + lPivot)
profit          = avg_entry_price + avg_entry_price * (i_takeProfit / 100)

filled      = count > 0 ? entry > fill - fill / 100 * i_dca : false
signal      = nz(lookbackFactor[i_pivotLength]) > 0 and not paused and not filled ? 1 : 0
filledOrder = ta.crossunder(low[1], entry[1]) and signal[1] > 0

///////////////////////////////////////////////////////////////////////////////
// strategy
if filledOrder
    fill    := entry
    count   := count + 1
    pause   := time + 60000
    [temp_avg_entry_price, temp_position_size] = update_position(avg_entry_price, position_size, close)
    avg_entry_price := temp_avg_entry_price
    position_size   := temp_position_size

closeit = ta.crossover(high, profit) and position_size >= 1
if closeit
    // reset position
    avg_entry_price := na
    position_size   := 0
    count           := 0
    fill            := 0

///////////////////////////////////////////////////////////////////////////////
// plots
plotshape(filledOrder, 'Entry Signal', color = color.green, textcolor = color.white, location = location.belowbar, style = shape.labelup, text = 'ENTRY')
plotshape(closeit, 'Exit Signal', color = color.red, textcolor = color.white, location = location.abovebar, style = shape.labeldown, text = 'EXIT')
plot(filledOrder ? 1 : 0, 'Enter', color = color.green, editable = false)
plot(closeit ? 1 : 0, 'Exit', color = color.red, editable = false)