[VIP] Composite BTC Funding Rate APR
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © authorofthesurf & jacuotta
// Adopted from "Funding Rate FTX-Binance" by @CarlosGV
// https://www.tradingview.com/script/3XLrvgck/

// References used:
//  https://help.ftx.com/hc/en-us/articles/360027946571-Funding
//  Summary: The funding rate is the interest charged / credited to a 
//           perpetual futures trader for taking a long or short position. The 
//           direction of the funding rate is used as an indicator of trader sentiment 
//           (+ve = bullish; -ve = bearish), and therefore useful to plot in real time.
//
//           The FTX exchange has published the calculation of their funding rate as 
//           follows: TWAP((future - index) / index) / 24
//
//           The formula here is the same, but expresses it in the more common % per 8hr duration:
//           funding = TWAP((future / index) - 1) * (8 / 24) * 100 
//
//			For reference: future refers to the FTX bitcoin futures contract price (FTX:BTCPERP) and index
//          is the spot price of bitcoin on the exchange (FTX:BTCUSD)

//@version=5
indicator("[VIP] Composite BTC Funding Rate APR v3.2.2", format=format.percent)

//// BTC Funding Module {

// Match current chart
funding_interval = ''
twap_interval    = ''

PERP_BITMEX       = 'BITMEX:XBTUSD.P'
PERP_BINANCE_USDT = 'BINANCE:BTCUSDTPERP'
PERP_BINANCE_USD  = 'BINANCE:BTCPERP'
PERP_BYBIT_USDT   = 'BYBIT:BTCUSDT.P'
PERP_BYBIT_USD    = 'BYBIT:BTCUSD.P'
PERP_BINANCE_BUSD = 'BINANCE:BTCBUSDPERP'

SPOT_BITSTAMP     = 'BITSTAMP:BTCUSD'
SPOT_BINANCE      = 'BINANCE:BTCUSDT'
SPOT_COINBASE     = 'COINBASE:BTCUSD'
SPOT_KRAKEN       = 'KRAKEN:BTCUSD'

// Prevent repainting with security function
f_secureSecurity(_symbol, _res, _src) =>
    request.security(_symbol, _res, _src[1], lookahead=barmerge.lookahead_on)

// Get pricing data across exchanges
p1 = f_secureSecurity(PERP_BITMEX, funding_interval, ohlc4)
p2 = f_secureSecurity(PERP_BINANCE_USDT, funding_interval, ohlc4)
p3 = f_secureSecurity(PERP_BINANCE_USD, funding_interval, ohlc4)
p4 = f_secureSecurity(PERP_BYBIT_USDT, funding_interval, ohlc4)
p5 = f_secureSecurity(PERP_BYBIT_USD, funding_interval, ohlc4)
p6 = f_secureSecurity(PERP_BINANCE_BUSD, funding_interval, ohlc4)

[s1, h1, l1, c1] = request.security(SPOT_BITSTAMP, funding_interval, [ohlc4[1], high[1], low[1], close[1]], lookahead=barmerge.lookahead_on)
[s2, h2, l2, c2] = request.security(SPOT_BINANCE, funding_interval, [ohlc4[1], high[1], low[1], close[1]], lookahead=barmerge.lookahead_on)
[s3, h3, l3, c3] = request.security(SPOT_COINBASE, funding_interval, [ohlc4[1], high[1], low[1], close[1]], lookahead=barmerge.lookahead_on)
[s4, h4, l4, c4] = request.security(SPOT_KRAKEN, funding_interval, [ohlc4[1], high[1], low[1], close[1]], lookahead=barmerge.lookahead_on)

perp_twap_price = 0.0
spot_twap_price = 0.0
spot_twap_high  = 0.0
spot_twap_low   = 0.0
spot_twap_close = 0.0

i = 0
j = 0

if not na(p1)
    perp_twap_price += p1
    i += 1
if not na(p2)
    perp_twap_price += p2
    i += 1
if not na(p3)
    perp_twap_price += p3
    i += 1
if not na(p4)
    perp_twap_price += p4
    i += 1
if not na(p5)
    perp_twap_price += p5
    i += 1
if not na(p6)
    perp_twap_price += p6
    i += 1

if not na(s1)
    spot_twap_price += s1
    spot_twap_high  += h1
    spot_twap_low   += l1
    spot_twap_close += c1
    j += 1
if not na(s2)
    spot_twap_price += s2
    spot_twap_high  += h2
    spot_twap_low   += l2
    spot_twap_close += c2
    j += 1
if not na(s3)
    spot_twap_price += s3
    spot_twap_high  += h3
    spot_twap_low   += l3
    spot_twap_close += c3
    j += 1
if not na(s4)
    spot_twap_price += s4
    spot_twap_high  += h4
    spot_twap_low   += l4
    spot_twap_close += c4
    j += 1

// Calculate internal prices and make available for other parts of the script
perp_twap_price /= i
spot_twap_price /= j
spot_twap_high  /= j
spot_twap_low   /= j
spot_twap_close /= j

// Calculates number of bars, e.g. 24 hourly bars in the past 1 day
bars_elapsed = ta.barssince(ta.change(f_secureSecurity(syminfo.tickerid, twap_interval, time)))
// >0 = Perp is higher price = positive funding
// <0 = Perp is lower price = negative funding
ratio = perp_twap_price / spot_twap_price - 1
smoothed_average_price = 0.0
smoothed_average_price := bars_elapsed > 0 ? ratio + nz(smoothed_average_price[1]) : ratio
// Raw funding value
twap_ratio = smoothed_average_price / (bars_elapsed + 1)

AS_PERCENTAGE = 100
AS_APY        = 365
funding       = twap_ratio * AS_PERCENTAGE * AS_APY

//} END BTC Funding Module

//// Display
limit_values = input.bool(true,
     title="Limit Extreme Values",
     group="Bars",
     tooltip="Limits funding values between -100% and 100%")

if funding > 100 and limit_values
    funding := 100
if funding < -100 and limit_values
    funding := -100

funding_color = funding > 0 ? color.green : color.red
if funding == 0.0
    funding_color := color.rgb(0, 0, 0, 100)

plot(funding,
     title="funding",
     color=funding_color,
     linewidth=2,
     style=plot.style_histogram)
