Dark Energy Divergence Oscillator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © ka1n0s

// Dark Energy Divergence Oscillator
// DEDO, pronounced "deed-oh"

//@version=5
indicator("Dark Energy Divergence Oscillator", "DEDO")

//INPUTS ----------------------------------------------------------------------------

// Uncomment and use the input var for dedo_symbol if desired.
// Allows DEDO to chart a symbol different than the current chart symbol
//dedo_symbol = input.symbol("SPX", "DEDO Symbol", "The symbol to analyze with DEDO")
dedo_symbol = syminfo.tickerid

// helper function to calculate plot colors
oscillator_gradient_color(signal, high_color, low_color) =>
    signal_max = ta.max(signal)
    signal_min = ta.min(signal)
    bull_color = color.from_gradient(signal, 0, signal_max, color.new(high_color, 60), color.new(high_color, 0))
    bear_color = color.from_gradient(signal, signal_min, 0, color.new(low_color,   0), color.new(low_color, 60))
    osc_color  = signal < 0 ? bear_color : bull_color

use_pre_ponzi_offset = input.bool(false, "Use Pre-Ponzification Offset", "Uses the DEDO Symbol price at the pre-ponzi date (pre-QE 9/9/2008 is default) to factor into the calculation against current liquidity", group = "Ponzi Settings")
pre_ponzi_date = input.time(timestamp('2008-9-9 10:00 GMT-3'), 'Ponzi Start Date', "The date to sample price used in the ponzification offset calculation.  Subtracts this price first before normalization against liquidity factors", group = "Ponzi Settings")

// CB Assets
include_jpy = input.bool(false, "JPY Assets", group = "Non-US Central Bank Liquidity")
include_cny = input.bool(false, "CNY Assets", group = "Non-US Central Bank Liquidity")
include_uk  = input.bool(false, "UK Assets",  group = "Non-US Central Bank Liquidity")
include_snb = input.bool(false, "SNB Assets", group = "Non-US Central Bank Liquidity")
include_ecb = input.bool(false, "ECB Assets", group = "Non-US Central Bank Liquidity")
include_krc = input.bool(false, "KRC Assets", group = "Non-US Central Bank Liquidity")
include_cad = input.bool(false, "CAD Assets", group = "Non-US Central Bank Liquidity")

include_wshoicl = input.bool(true, "Inflation Compensation (WSHOICL)", "Include Fed 'Inflation Compensation' (WSHOICL) from assets portion of balance sheet", group = "Include Fed Balance Sheet Items")
include_wupsho  = input.bool(true, "Unamortized Premiums (WUPSHO)", "Include Fed 'Unamortized Premiums' (WUPSHO) from assets portion of balance sheet", group = "Include Fed Balance Sheet Items")
include_wlcfll  = input.bool(true, "Loans (WLCFLL)", "Include Fed 'Loans' (WLCFLL) from assets portion of balance sheet", group = "Include Fed Balance Sheet Items")

// Allocation table helper
show_allocation_table = input.bool(true, "Show Asset Allocation Table", "Show a table that provides liquidity allocation info, and suggests CB allocation settings are sufficient to support the market cap of the DEDO symbol being evaluated", group = "Table Settings")

// Multiplier to make the final values more readable. Different symbols will produced varied results.
dedo_multiplier = input.float(100.0, "Multiplier",1.0,1000, 1.0, group = "Chart Settings")
// END INPUTS ----------------------------------------------------------------------------

// HELPER METHODS ------------------------------------------------------------------------
billions_str(value) =>
    "$" + str.tostring(value/1000000000, format.mintick) + " B"
// END HELPER METHODS --------------------------------------------------------------------

// FED BS
line_wresbal     = request.security("FRED:WRESBAL",                   "D", close, currency = currency.USD)

// Optional factors on Fed balance sheet
line_fed_wshoicl   = request.security("WSHOICL",                        "D", close, currency = currency.USD)
line_fed_wupsho    = request.security("WUPSHO",                         "D", close, currency = currency.USD)
line_fed_wlcfll    = request.security("WLCFLL",                         "D", close, currency = currency.USD)

// Non US CENTRAL BANK ASSETS
line_japan       = request.security("FRED:JPNASSETS * FX_IDC:JPYUSD", "D", close, currency = currency.USD)
line_china       = request.security("CNCBBS         * FX_IDC:CNYUSD", "D", close, currency = currency.USD)
line_uk          = request.security("GBCBBS         * FX:GBPUSD",     "D", close, currency = currency.USD)
line_ecb         = request.security("ECBASSETSW     * FX:EURUSD",     "D", close, currency = currency.USD)
line_snb         = request.security("CHCBBS",                         "D", close, currency = currency.USD)
line_krc         = request.security("ECONOMICS:KRCBBS*FX_IDC:KRWUSD", "D", close, currency = currency.USD)
line_cad         = request.security("CACBBS         * CADUSD",        "D", close, currency = currency.USD)

// FED subtractions
wshoicl_final = (include_wshoicl ? 0 : line_fed_wshoicl)
wupsho_final  = (include_wupsho ? 0 : line_fed_wupsho)
wlcfll_final  = (include_wlcfll ? 0 : line_fed_wlcfll)
subtractions_total = wlcfll_final + wupsho_final + wshoicl_final

// Apply offsets to Fed liquidity total
fed_final = line_wresbal - subtractions_total

// conditionally determine which CB assets are used in the total liquidity pool based on user settings
jpy_final = (include_jpy ? line_japan : 0)
cny_final = (include_cny ? line_china : 0)
gbp_final = (include_uk  ? line_uk : 0)
snb_final = (include_snb ? line_snb : 0)
ecb_final = (include_ecb ? line_ecb : 0)
krc_final = (include_krc ? line_krc : 0)
cad_final = (include_cad ? line_cad : 0)

// 
non_us_total = jpy_final + cny_final + gbp_final + snb_final + ecb_final + krc_final + cad_final
liquidity_total = fed_final + non_us_total
cb_assets_max_allocated = ta.max(liquidity_total)
norm_total_cb = liquidity_total / cb_assets_max_allocated
//plot(norm_total_cb, "norm-tot", color.red)

dedo_symbol_o   = request.security(dedo_symbol,timeframe.period, open, currency = currency.USD)
dedo_symbol_h   = request.security(dedo_symbol,timeframe.period, high, currency = currency.USD)
dedo_symbol_l   = request.security(dedo_symbol,timeframe.period, low, currency = currency.USD)
dedo_symbol_c   = request.security(dedo_symbol,timeframe.period, close, currency = currency.USD)

period = time >= pre_ponzi_date and time[1] < pre_ponzi_date
pre_ponzi = use_pre_ponzi_offset ? ta.valuewhen(period, dedo_symbol_c, 0) : 0
// Debug plot to see the value
//plot(pre_ponzi, "pre-ponz", color.white)

dedo_series_open =  (norm_total_cb - ((dedo_symbol_o - pre_ponzi)/(ta.max(dedo_symbol_o) - pre_ponzi))) * dedo_multiplier
dedo_series_high =  (norm_total_cb - ((dedo_symbol_h - pre_ponzi)/(ta.max(dedo_symbol_h) - pre_ponzi))) * dedo_multiplier
dedo_series_low =   (norm_total_cb - ((dedo_symbol_l - pre_ponzi)/(ta.max(dedo_symbol_l) - pre_ponzi))) * dedo_multiplier
dedo_series_close = (norm_total_cb - ((dedo_symbol_c - pre_ponzi)/(ta.max(dedo_symbol_c) - pre_ponzi))) * dedo_multiplier

dedo_zero_price = norm_total_cb * (ta.max(dedo_symbol_h) - pre_ponzi) + pre_ponzi

candle_color = dedo_series_close >= dedo_series_open ? color.lime : color.red
wick_color = dedo_series_close >= dedo_series_open ? color.new(color.lime, 25) : color.new(color.red, 25)

// Plot candles for dedo signal
plotcandle(dedo_series_open, dedo_series_high, dedo_series_low, dedo_series_close, title = "Candle Chart", color = color.new(candle_color, 60), wickcolor = wick_color, bordercolor = candle_color)
plot(dedo_series_close, title = "Line Chart", linewidth = 2, color = oscillator_gradient_color(dedo_series_close, color.green, color.red), trackprice = true, display = display.none)

// Zero Bound
hline(0)

// Get the shares outstanding to calculate the mkt cap of the dedo symbol
tso = nz(request.financial(str.tostring(dedo_symbol), "TOTAL_SHARES_OUTSTANDING", "FQ", ignore_invalid_symbol=true))
mkt_cap = (na(tso) ? 0 : tso * dedo_symbol_c)

if show_allocation_table
    var table mkt_cap_liquidity_tbl = table.new(position.bottom_right, 4, 2, frame_color = color.gray, bgcolor = color.gray, border_width = 1, frame_width = 1, border_color = color.white)
    // Header
    table.cell(mkt_cap_liquidity_tbl, 0, 0, "Total CB Liquidity",                     bgcolor = color.white)
    table.cell(mkt_cap_liquidity_tbl, 1, 0, "Mkt Cap " + str.tostring(dedo_symbol),   bgcolor = color.white)
    table.cell(mkt_cap_liquidity_tbl, 2, 0, "Mkt Cap % Total CB Assets",              bgcolor = color.white)
    table.cell(mkt_cap_liquidity_tbl, 3, 0, "DEDO 0 Price",                           bgcolor = color.white)

    // fill the table
    table.cell(mkt_cap_liquidity_tbl, 0, 1, billions_str(liquidity_total),            bgcolor = color.white)
    table.cell(mkt_cap_liquidity_tbl, 1, 1, mkt_cap == 0 ? "N/A" : billions_str(mkt_cap),                bgcolor = color.white)

    // create a string that indicates mkt cap % of total liquidity
    mkt_cap_pct_str = mkt_cap == 0 ? "N/A" : str.tostring(mkt_cap/nz(liquidity_total)*100, format.percent)
    table.cell(mkt_cap_liquidity_tbl, 2, 1, mkt_cap_pct_str,                          bgcolor = color.white)

    // DEDO zero price cell
    table.cell(mkt_cap_liquidity_tbl, 3, 1, "$" + str.tostring(dedo_zero_price,format.mintick), bgcolor = color.white)