DCA Simulator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Julien-PH
//@version=5

indicator("DCA Simulator", shorttitle="DCA", overlay=true)

// Input
showMeanPrice   = input(true, "Show average price ?", tooltip = "Show the average price from this date to now")
sourceMeanPrice = input(close, "Source average price")
colorMeanPrice  = input(color.blue, "Color average price")

showDCA     = input(true, "Show average DCA price ?", tooltip = "Show the average DCA price from this date to now")
sourceDCA   = input(open, "DCA time")
colorDCA    = input(color.orange, "Color DCA")

maxNbBars   = input(4000, "Maximum number of bars for the duration of the DCA/average")
previousBar = math.min(bar_index,maxNbBars)

// PRICE AVERAGE
// List of mean price sort buy starting date
var ListMeanPrice = array.new<float>(0)
// Previous price
if bar_index > maxNbBars
    array.shift(ListMeanPrice)
if ListMeanPrice.size() > 0
    for i = 0 to (previousBar - 1)
        newValue = ((ListMeanPrice.get(i) * (previousBar + 1 - i)) + sourceMeanPrice) / (previousBar + 2 - i)
        array.set(ListMeanPrice, i, newValue)
// Current Price
array.push(ListMeanPrice, sourceMeanPrice)

// DCA
// List of DCA sort buy starting date
var ListBagDCA  = array.new<float>(0)
var ListMeanDCA = array.new<float>(0)
// Previous DCA
if bar_index > maxNbBars
    array.shift(ListBagDCA)
    array.shift(ListMeanDCA)
if ListBagDCA.size() > 0
    for i = 0 to (previousBar - 1)
        newBag = ListBagDCA.get(i) + (sourceDCA[previousBar-i] / sourceDCA)
        array.set(ListBagDCA, i, newBag)
        // Update average price per bag
        newMeanPrice = (sourceDCA[previousBar - i] * (previousBar - i + 1)) / ListBagDCA.get(i)
        array.set(ListMeanDCA, i, newMeanPrice)
// Current DCA
array.push(ListBagDCA , 1)
array.push(ListMeanDCA, sourceDCA)

// Plot
if barstate.islast
    var pMeanPrice = array.new<chart.point>()
    var pMeanDCA = array.new<chart.point>()
    for i = 0 to previousBar //No -1 becase of the push on series
        pMeanPrice.push(chart.point.from_index(bar_index-previousBar+i,ListMeanPrice.get(i)   ))
        pMeanDCA.push(  chart.point.from_index(bar_index-previousBar+i,ListMeanDCA.get(i)     ))

    polyline.new(showMeanPrice  ? pMeanPrice : na, curved = false, closed = false, line_color = colorMeanPrice   )
    polyline.new(showDCA        ? pMeanDCA   : na, curved = false, closed = false, line_color = colorDCA         )
