Crude Oil: Backwardation Vs Contango
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//@version=5

//Crude Oil: CL
// Plots Futures contracts prices over the next 3.5 years; to easily visualize Backwardation Vs Contango (carrying charge) markets.
// Carrying charge (contract prices increasing into the future) = normal, representing the costs of carrying/storage of a commodity. When this is flipped to Backwardation (contract prices decreasing into the future): its a bullish sign: Buyers want this commodity, and they want it NOW.

// Note: indicator does not map to time axis in the same way as price; it simply plots the progression of contract months out into the future; left to right; so timeframe doesn't matter for this plot
// There's likely some more efficient way to write this; e.g. when plotting for Gold (GC); 21 of the security requests are redundant; but they are still made; and can make this slower to load
// TO UPDATE: in REQUEST CONTRACTS section, delete old contracts (top) and add new ones (bottom). Then in PLOTTING section, Delete old [expired] contract labels (bottom); add new [distant future] contract labels (top); adjust the X in 'bar_index-(X+_historical)' numbers accordingly

// This is one of several similar indicators: Meats | Metals | Grains | VIX | Crude Oil
// -If you want to build from this; to work on other commodities; be aware that Tradingview limits the number of contract calls to 40 (hence the multiple indicators)

// Tips:
// -Right click and reset chart if you can't see the plot; or if you have trouble with the scaling.
// -Right click and add to new scale if you prefer this not to overlay directly on price. Or move to new pane below.
// -If this takes too long to load; comment out the more distant future half of the contracts; and their respective labels. Or comment out every other contract and every other label.

// --Added historical input: input days back in time; to see the historical shape of the Futures curve via selecting 'days back' snapshot
//updated to work on WTI (MATBAROFEX): Plots CL (NYMEX) futures curve when selected asset is WTI (3rd July 2022)
// updated 1st Feb 2023
// © twingall


indicator("Crude Oil: Backwardation Vs Contango", overlay = true, scale = scale.right)
_historical = input(0, "time travel back; days")
_adr = ta.atr(5)
_root = syminfo.root== "WTI"? "CL": syminfo.root
colorNone= color.new(color.white, 100)

//Function to test if contract is expired
int oneWeek = 5*24*60*60*1000 // 5 or more days since last reported closing price => expired
isExp (int _timeClose)=>
    expired = _timeClose <= (last_bar_time-oneWeek) 

     
///REQUEST CONTRACTS---

//Crude Oil Contracts. Add the commented out ones if you prefer, but they may cause slower loading
[jul22,jul22t]= request.security("NYMEX:" + _root + "N2022", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[aug22,aug22t]= request.security("NYMEX:" + _root + "Q2022", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[sept22,sept22t]=request.security("NYMEX:" + _root + "U2022", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[oct22,oct22t]= request.security("NYMEX:" + _root + "V2022", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[nov22,nov22t]= request.security("NYMEX:" + _root + "X2022", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[dec22,dec22t]= request.security("NYMEX:" + _root + "Z2022", "D",[close[_historical], time_close], ignore_invalid_symbol=true)

[jan23,jan23t]= request.security("NYMEX:" + _root + "F2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[feb23,feb23t]= request.security("NYMEX:" + _root + "G2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[mar23,mar23t]= request.security("NYMEX:" + _root + "H2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[apr23,apr23t]= request.security("NYMEX:" + _root + "J2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[may23,may23t]= request.security("NYMEX:" + _root + "K2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[jun23,jun23t]= request.security("NYMEX:" + _root + "M2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[jul23,jul23t]= request.security("NYMEX:" + _root + "N2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[aug23,aug23t]= request.security("NYMEX:" + _root + "Q2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[sept23,sept23t]=request.security("NYMEX:" + _root + "U2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[oct23,oct23t]= request.security("NYMEX:" + _root + "V2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[nov23,nov23t]= request.security("NYMEX:" + _root + "X2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[dec23,dec23t]= request.security("NYMEX:" + _root + "Z2023", "D",[close[_historical], time_close], ignore_invalid_symbol=true)

[jan24,jan24t]= request.security("NYMEX:" + _root + "f2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[feb24,feb24t]= request.security("NYMEX:" + _root + "G2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[mar24,mar24t]= request.security("NYMEX:" + _root + "H2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[apr24,apr24t]= request.security("NYMEX:" + _root + "J2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[may24,may24t]= request.security("NYMEX:" + _root + "K2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[jun24,jun24t]= request.security("NYMEX:" + _root + "M2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[jul24,jul24t]= request.security("NYMEX:" + _root + "N2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[aug24,aug24t]= request.security("NYMEX:" + _root + "Q2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)

[sept24,sept24t]=request.security("NYMEX:" + _root + "U2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[oct24,oct24t]= request.security("NYMEX:" + _root + "V2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[nov24,nov24t]= request.security("NYMEX:" + _root + "X2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
[dec24,dec24t]= request.security("NYMEX:" + _root + "Z2024", "D",[close[_historical], time_close], ignore_invalid_symbol=true)

// [jan25,jan25t]= request.security("NYMEX:" + _root + "F2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [feb25,feb25t]= request.security("NYMEX:" + _root + "G2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [mar25,mar25t]= request.security("NYMEX:" + _root + "H2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [apr25,apr25t]= request.security("NYMEX:" + _root + "J2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [may25,may25t]= request.security("NYMEX:" + _root + "K2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [jun25,jun25t]= request.security("NYMEX:" + _root + "M2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [jul25,jul25t]= request.security("NYMEX:" + _root + "N2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [aug25,aug25t]= request.security("NYMEX:" + _root + "Q2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [sept25,sept25t]=request.security("NYMEX:" + _root + "U2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)
// [oct25,oct25t]= request.security("NYMEX:" + _root + "V2025", "D",[close[_historical], time_close], ignore_invalid_symbol=true)

//PLOTTING----
//if you've uncommented the contracts above; comment-out lines 80-97, then uncomment lines 99-138
if barstate.islastconfirmedhistory and _root=='CL'
    label.new(bar_index-(_historical), close[_historical]+ 2*_adr, text = 'S\nN\nA\nP\nS\nH\nO\nT', textcolor = color.red, style=label.style_arrowdown, color= color.red, size = size.tiny)
    
    label.new(bar_index-(2+_historical), isExp(aug24t)?0:aug24, text = 'Aug24', textcolor =isExp(aug24t)?colorNone: color.red, style=isExp(aug24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(4+_historical), isExp(jul24t)?0:jul24, text = 'Jul24', textcolor = isExp(jul24t)?colorNone:color.red, style=isExp(jul24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(6+_historical), isExp(jun24t)?0:jun24, text = 'Jun24', textcolor =isExp(jun24t)?colorNone: color.red, style=isExp(jun24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(8+_historical), isExp(may24t)?0:may24, text = 'May24', textcolor =isExp(may24t)?colorNone: color.red, style=isExp(may24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(10+_historical), isExp(apr24t)?0:apr24, text = 'Apr24', textcolor =isExp(apr24t)?colorNone: color.red, style=isExp(apr24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(12+_historical), isExp(mar24t)?0:mar24, text = 'Mar24', textcolor =isExp(mar24t)?colorNone: color.red, style=isExp(mar24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(14+_historical), isExp(feb24t)?0:feb24, text = 'Feb24', textcolor =isExp(feb24t)?colorNone: color.red, style=isExp(feb24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(16+_historical), isExp(jan24t)?0:jan24, text = 'Jan24', textcolor =isExp(jan24t)?colorNone: color.red, style=isExp(jan24t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(18+_historical), isExp(dec23t)?0:dec23, text = 'Dec23', textcolor =isExp(dec23t)?colorNone: color.red, style=isExp(dec23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(20+_historical), isExp(nov23t)?0:nov23, text = 'Nov23', textcolor =isExp(nov23t)?colorNone: color.red, style=isExp(nov23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(22+_historical), isExp(oct23t)?0:oct23, text = 'Oct23', textcolor =isExp(oct23t)?colorNone: color.red, style=isExp(oct23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(24+_historical), isExp(sept23t)?0:sept23, text = 'Sept23', textcolor =isExp(sept23t)?colorNone: color.red, style=isExp(sept23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(26+_historical), isExp(aug23t)?0:aug23, text = 'Aug23', textcolor = isExp(aug23t)?colorNone:color.red, style=isExp(aug23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(28+_historical), isExp(jul23t)?0:jul23, text = 'Jul23', textcolor = isExp(jul23t)?colorNone:color.red, style=isExp(jul23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(30+_historical), isExp(jun23t)?0:jun23, text = 'Jun23', textcolor = isExp(jun23t)?colorNone: color.red, style= isExp(jun23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(32+_historical), isExp(may23t)?0:may23, text = 'May23', textcolor =isExp(may23t)?colorNone: color.red, style=isExp(may23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(34+_historical), isExp(apr23t)?0:apr23, text = 'Apr23', textcolor =isExp(apr23t)?colorNone: color.red, style=isExp(apr23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(36+_historical), isExp(mar23t)?0:mar23, text = 'Mar23', textcolor =isExp(mar23t)?colorNone: color.red, style=isExp(mar23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(38+_historical), isExp(feb23t)?0:feb23, text = 'Feb23', textcolor =isExp(feb23t)?colorNone: color.red, style=isExp(feb23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(40+_historical), isExp(jan23t)?0:jan23, text = 'Jan23', textcolor =isExp(jan23t)?colorNone: color.red, style=isExp(jan23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(42+_historical), isExp(dec22t)?0:dec22, text = 'Dec22', textcolor =isExp(dec22t)?colorNone: color.red, style=isExp(dec22t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(44+_historical), isExp(nov22t)?0:nov22, text = 'Nov22', textcolor =isExp(nov22t)?colorNone: color.red, style=isExp(nov22t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(46+_historical), isExp(oct22t)?0:oct22, text = 'Oct22', textcolor =isExp(oct22t)?colorNone: color.red, style=isExp(oct22t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(48+_historical), isExp(sept22t)?0:sept22, text = 'Sept22', textcolor =isExp(sept22t)?colorNone: color.red, style=isExp(sept22t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(50+_historical), isExp(aug22t)?0:aug22, text = 'Aug22', textcolor =isExp(aug22t)?colorNone: color.red, style=isExp(aug22t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(52+_historical), isExp(jul22t)?0:jul22, text = 'Jul22', textcolor =isExp(jul22t)?colorNone: color.red, style=isExp(jul22t)?label.style_none:label.style_diamond, size = size.tiny)


    // label.new(bar_index-(2+_historical), isExp(oct25t)?0:oct25, text = 'Oct25', textcolor = isExp(oct25t)?colorNone: color.red, style= isExp(oct25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(4+_historical),  isExp(sept25t)?0:sept25, text = 'Sept25', textcolor =isExp(sept25t)?colorNone: color.red, style=isExp(sept25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(6+_historical),  isExp(aug25t)?0:aug25, text = 'Aug25', textcolor = isExp(aug25t)?colorNone:color.red, style=isExp(aug25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(8+_historical),  isExp(jul25t)?0:jul25, text = 'Jul25', textcolor =isExp(jul25t)?colorNone: color.red, style=isExp(jul25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(10+_historical),  isExp(jun25t)?0:jun25, text = 'Jun25', textcolor =isExp(jun25t)?colorNone: color.red, style=isExp(jun25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(12+_historical),  isExp(may25t)?0:may25, text = 'May25', textcolor =isExp(may25t)?colorNone: color.red, style=isExp(may25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(14+_historical),  isExp(apr25t)?0:apr25, text = 'Apr25', textcolor = isExp(apr25t)?colorNone: color.red, style= isExp(apr25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(16+_historical),  isExp(mar25t)?0:mar25, text = 'Mar25', textcolor = isExp(mar25t)?colorNone: color.red, style= isExp(mar25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(18+_historical),  isExp(feb25t)?0:feb25, text = 'Feb25', textcolor =isExp(feb25t)?colorNone: color.red, style=isExp(feb25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(20+_historical),  isExp(jan25t)?0:jan25, text = 'Jan25', textcolor = isExp(jan25t)?colorNone: color.red, style= isExp(jan25t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(22+_historical),  isExp(dec24t)?0:dec24, text = 'Dec24', textcolor =isExp(dec24t)?colorNone: color.red, style=isExp(dec24t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(24+_historical),  isExp(nov24t)?0:nov24, text = 'Nov24', textcolor =isExp(nov24t)?colorNone: color.red, style=isExp(nov24t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(26+_historical),  isExp(oct24t)?0:oct24, text = 'Oct24', textcolor =isExp(oct24t)?colorNone: color.red, style=isExp(oct24t)?label.style_none:label.style_diamond, size = size.tiny)
    // label.new(bar_index-(28+_historical),  isExp(sept24t)?0:sept24, text = 'Sept24', textcolor =isExp(sept24t)?colorNone: color.red, style=isExp(sept24t)?label.style_none:label.style_diamond, size = size.tiny)

