Grains:Backwardation/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
// Wheat, Soybeans, Corn (ZW, ZS, ZC)
// Quickly visualize carrying charge market vs backwardized market by comparing the price of the next 2 years of futures contracts.
// 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): it's 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 ZW; 15 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 three similar indicators: Meats | Metals | Grains
// -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 3 seperate 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.

// --Added historical input: input days back in time; to see the historical shape of the Futures curve via selecting 'days back' snapshot
// updated 15th June 2022
// updated 29th Jan 2023
// © twingall


indicator("Grains:Backwardation/Contango", overlay = true) //, scale = scale.right)
_historical = input(0, "time travel back; days")
_adr = ta.atr(5)
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---

//shared contracts and/or All wheat contracts.
cash=request.security(syminfo.root + "1!", "D", [close[_historical],time_close], ignore_invalid_symbol=true)

[jul22,jul22t]= request.security(syminfo.root + "N2022", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[sept22,sept22t]= request.security(syminfo.root + "U2022", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[dec22,dec22t]= request.security(syminfo.root + "Z2022", "D", [close[_historical],time_close], ignore_invalid_symbol=true)

[mar23,mar23t]= request.security(syminfo.root + "H2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[may23,may23t]= request.security(syminfo.root + "K2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[jul23,jul23t]= request.security(syminfo.root + "N2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[sept23,sept23t]= request.security(syminfo.root + "U2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[dec23,dec23t]= request.security(syminfo.root + "Z2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[mar24,mar24t]=request.security(syminfo.root + "H2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[may24,may24t]=request.security(syminfo.root + "K2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[jul24,jul24t]=request.security(syminfo.root + "N2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[sept24,sept24t]=request.security(syminfo.root + "U2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[dec24,dec24t] =request.security(syminfo.root + "Z2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[mar25,mar25t]=request.security(syminfo.root + "H2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[may25,may25t]=request.security(syminfo.root + "K2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[jul25,jul25t]=request.security(syminfo.root + "N2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)

//additional contracts for soybeans

[aug22,aug22t]=request.security(syminfo.root + "Q2022", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[nov22,nov22t]=request.security(syminfo.root + "X2022", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[jan23,jan23t]=request.security(syminfo.root + "F2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)

[aug23,aug23t]=request.security(syminfo.root + "Q2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[nov23,nov23t]=request.security(syminfo.root + "X2023", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[jan24,jan24t]=request.security(syminfo.root + "F2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[aug24,aug24t]=request.security(syminfo.root + "Q2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[nov24,nov24t]=request.security(syminfo.root + "X2024", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[jan25,jan25t]=request.security(syminfo.root + "F2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[aug25,aug25t]=request.security(syminfo.root + "Q2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[sept25,sept25t]=request.security(syminfo.root + "U2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[nov25,nov25t]=request.security(syminfo.root + "X2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[jul26,jul26t]=request.security(syminfo.root + "N2026", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[nov26,nov26t]=request.security(syminfo.root + "X2026", "D", [close[_historical],time_close], ignore_invalid_symbol=true)

//additional contracts for Corn
[dec25,dec25t]=request.security(syminfo.root + "Z2025", "D", [close[_historical],time_close], ignore_invalid_symbol=true)
[dec26,dec26t]=request.security(syminfo.root + "Z2026", "D", [close[_historical],time_close], ignore_invalid_symbol=true)

//---PLOTTING----
//
//Wheat plotting
if barstate.islast and syminfo.root=='ZW'
    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(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-(4+_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-(6+_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-(8+_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-(10+_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)
    label.new(bar_index-(12+_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-(14+_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-(16+_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-(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(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-(22+_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-(24+_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-(26+_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)
//historical (3rd Feb 2023)
    label.new(bar_index-(28+_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-(30+_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-(32+_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)


//Soybeans plotting
if barstate.islast and  syminfo.root == 'ZS'
    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(nov26t)?0:nov26, text = 'Nov26', textcolor =isExp(nov26t)?colorNone: color.red, style=isExp(nov26t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(4+_historical), isExp(jul26t)?0:jul26, text = 'Jul26', textcolor =isExp(jul26t)?colorNone: color.red, style=isExp(jul26t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(6+_historical), isExp(nov25t)?0:nov25, text = 'Nov25', textcolor =isExp(nov25t)?colorNone: color.red, style=isExp(nov25t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(8+_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-(10+_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-(12+_historical), isExp(jul25t)?0:jul25, text = 'July25', textcolor =isExp(jul25t)?colorNone: color.red, style=isExp(jul25t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(14+_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-(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(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-(20+_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-(22+_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)
    label.new(bar_index-(24+_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-(26+_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-(28+_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-(30+_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-(32+_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-(34+_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-(36+_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-(38+_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-(40+_historical), isExp(jul23t)?0:jul23, text = 'July23', textcolor =isExp(jul23t)?colorNone: color.red, style=isExp(jul23t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(42+_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-(44+_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)
//historical
    label.new(bar_index-(46+_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-(48+_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-(50+_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-(52+_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)

    
//Corn plotting    
if barstate.islast and syminfo.root == 'ZC'
    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(dec26t)?0:dec26 , text = 'Dec26', textcolor =isExp(dec26t)?colorNone: color.red, style=isExp(dec26t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(4+_historical), isExp(jul26t)?0:jul26, text = 'Jul26', textcolor =isExp(jul26t)?colorNone: color.red, style=isExp(jul26t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(6+_historical), isExp(dec25t)?0:dec25 , text = 'Dec25', textcolor =isExp(dec25t)?colorNone: color.red, style=isExp(dec25t)?label.style_none:label.style_diamond, size = size.tiny)
    label.new(bar_index-(8+_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-(10+_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-(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(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-(16+_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-(18+_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)
    label.new(bar_index-(20+_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-(22+_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-(24+_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-(26+_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-(28+_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-(30+_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-(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(mar23t)?0:mar23, text = 'Mar23', textcolor =isExp(mar23t)?colorNone: color.red, style=isExp(mar23t)?label.style_none:label.style_diamond, size = size.tiny)
//historical
    label.new(bar_index-(36+_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-(38+_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-(40+_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)
