OHLC
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © cryptolinx - jango_blockchained - open 💙 source

//@version=5

//  ▪ ──── LIBRARY
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

// @description
// This library provides a simple way to calculate OHLC values for any source.
library('OHLC', overlay = false)
// >>


//  ▪ ──── TYPES
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

// -- OHLC Source {
//
// @type    A source that can be used to calculate OHLC values.
// @field   close       The last close value.
// @field   open        The last open value.
// @field   high        The last high value.
// @field   low         The last low value.
// @field   update_no   The number of bars since the last open.
export type src
    // --
    float   close
    float   open 
    float   high
    float   low
    int     update_no
// }


//  ▪ ──── INTERNAL
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

// -- Build-In Overloaded/Expanded Functions {
//
method nz(series float _src, series float _target) => na(_src) ? _target : _src
method nz(series src _src, series src _target)     => na(_src) ? _target : _src
// }


//  ▪ ──── EXPORT
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

// -- OHLC Source Methods {
//
// @function    Hydrates the OHLC source with a new value.
// ___
// **Example**
// ```
// // basic
// mySrc.hydrateOHLC(rsi)
// ```
// or
// ```
// // inline
// rsi = ta.rsi(close, 14).hydrateOHLC(mySrc) 
// ```
// @param       this        The source to hydrate.
// @param       _src        The new value.
// @returns     src
export method hydrateOHLC(src this, float _src) =>
    if not na(_src)
        this.close := _src
        if barstate.isnew
            this.open       := this.close
            this.low        := this.close
            this.high       := this.close
            this.update_no  := 0
        this.low        := math.min(this.low.nz(this.close),  this.close)
        this.high       := math.max(this.high.nz(this.close), this.close)
        this.update_no  += 1
    // >>
    this
// --
// @note The "method overloading" and "argument flipping" pattern used in this code can also be manually applied to any
// custom function inside your script. This can be useful for creating more flexible and versatile functions that can be
// used in different contexts and with different argument orders.
export method hydrateOHLC(float _src, src this) => this.hydrateOHLC(_src), _src
// }

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// -- New OHLC Source {
//
// @function    Creates a new OHLC source.
// ___
// [![required varip](https://img.shields.io/badge/required-varip-blue?logo=tradingview&style=flat-square)](https://www.tradingview.com/pine-script-docs/en/v5/language/Variable_declarations.html?highlight=varip#varip)
// [![issue repainting](https://img.shields.io/badge/issue-repainting-red?logo=tradingview&style=flat-square)](https://www.tradingview.com/pine-script-docs/en/v5/concepts/Repainting.html?highlight=repainting)
// ___
// **Example**
// ```
// varip mySrc = src.new()
// ```
// **Notes** \
// Needs to be initialized by using the `varip` keyword.
// @returns     **src** A new blank OHLC source object.
export new() => src.new()
// }


//  ▪ ──── EXAMPLES
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

// -- Inputs {
//
// @variable    __PLOT_CANDLE   Holds the user inputs option.
// @variable    __PLOT_CANDLE   Holds the user inputs option.
var __PLOT_CANDLE   = input.bool(true, title='Plot Candle')
var __RSI_LENGTH    = input.int(14, title='RSI Length')
// }

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// -- Example #1 {
//
// @variable rsi    Example RSI calculation
// @variable mySrc  Example `<OHLC.src>` object.
rsi             = ta.rsi(close, __RSI_LENGTH)
varip mySrc     = src.new()
mySrc.hydrateOHLC(rsi)     // equals to rsi.hydrateOHLC(mySrc)
// }

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// -- Example #2 {
// @variable    mySrc2  Example `<OHLC.src>` object.
// @variable    rsi2    Example RSI calculation.
varip mySrc2   = src.new()
rsi2           = ta.rsi(close, __RSI_LENGTH).hydrateOHLC(mySrc2)    // equals to mySrc2.hydrateOHLC(rsi)
// }

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

// -- Plotting {
//
// @variable    confirmationPlot    Holds the RSI plot `id` for `mySrc2`.
confirmationPlot = plot(
 series         = not barstate.islast ? mySrc2.close : na, 
 color          = color.silver,
 style          = plot.style_circles,
 linewidth      = 1)
// --
// @variable    rsiPlot     Holds the RSI plot `id` for `mySrc`.
rsiPlot = plot(
 series         = not __PLOT_CANDLE or  not barstate.islast ? mySrc.close : na, 
 color          = mySrc.close > mySrc.open ? color.green
 :                mySrc.close < mySrc.open ? color.red
 :                                           color.blue,
 linewidth      = 1)
// --
fill(
 plot1          = plot(not __PLOT_CANDLE and barstate.islast ? mySrc.high : na, color = color.new(color.white, 80)),
 plot2          = rsiPlot,
 bottom_value   = 0, 
 top_value      = 100,
 bottom_color   = #00000000,
 top_color      = color.new(color.red, 90))
// --
fill(
 plot1          = rsiPlot,
 plot2          = plot(not __PLOT_CANDLE and barstate.islast ? mySrc.low : na, color = color.new(color.white, 80)),
 bottom_value   = 0, 
 top_value      = 100,
 bottom_color   = color.new(color.green, 90),
 top_color      = #00000000) 
// --
plotcandle(
 open           = __PLOT_CANDLE and barstate.islast ? mySrc.open  : na,
 high           = __PLOT_CANDLE and barstate.islast ? mySrc.high  : na,
 low            = __PLOT_CANDLE and barstate.islast ? mySrc.low   : na, 
 close          = __PLOT_CANDLE and barstate.islast ? mySrc.close : na,
 title          = 'RSI Candle', 
 color          = mySrc.open > mySrc.close ? color.red : color.green,
 wickcolor      = mySrc.open > mySrc.close ? color.red : color.green,
 bordercolor    = mySrc.open > mySrc.close ? color.red : color.green)
// }

// #EOF