/// Concretum Intraday SPY strategy ///
/// Based on https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4824172 ///
var UpperBoundary;
var LowerBoundary;
function calculateNoiseArea() {
int Lookback = 14;
int i;
int BarsPerDay = 13;
var volatilityMultiplier = 1.;
var OpenPrice = priceOpen(0);
var SumMove = 0;
for(i = 1; i <= Lookback; i++) {
var PreviousOpen = priceOpen(i * BarsPerDay);
var PreviousClose = priceClose(i * BarsPerDay - (BarsPerDay - 1));
var Move = abs(PreviousClose / PreviousOpen - 1);
SumMove += Move;
}
var AvgMove = SumMove / Lookback;
UpperBoundary = OpenPrice * (1 + volatilityMultiplier * AvgMove);
LowerBoundary = OpenPrice * (1 - volatilityMultiplier * AvgMove);
var PreviousClose = priceClose(1);
if(OpenPrice > PreviousClose) {
UpperBoundary += (OpenPrice - PreviousClose);
} else {
LowerBoundary -= (PreviousClose - OpenPrice);
}
}
void run() {
Verbose = 3;
NumCores = -2;
set(PLOTNOW|LOGFILE|TESTNOW);
setf(PlotMode, PL_DIFF);
StartDate = 2011;
EndDate = 2023;
LookBack = 14 * 13 + 1;
BarPeriod = 1;
// BarZone = EST;
StartMarket = 0930; // Start of market hours
EndMarket = 1600; // End of market hours
Capital = Margin = 10000;
BarMode = BR_NOSHIFT+BR_SLEEP; // Only calculate and trade during market hours
asset("SPY");
MaxLong = MaxShort = -1;
vars Prices = series(priceClose());
vars Volumes = series(marketVol());
var VWAP = VWAV(Prices, Volumes, 14);
calculateNoiseArea();
if(crossOver(Prices, UpperBoundary))
enterLong();
if(crossUnder(Prices, LowerBoundary))
enterShort();
if(TradeIsLong && (Prices[0] < UpperBoundary || crossUnder(Prices, VWAP)))
exitLong();
if(TradeIsShort && (Prices[0] > LowerBoundary || crossOver(Prices, VWAP)))
exitShort();
if(tod() == 1530){
exitShort();
exitLong();
}
// Plot the indicators
plot("VWAP", VWAP, LINE, PURPLE);
plot("Upper Boundary", UpperBoundary, LINE, BLUE);
plot("Lower Boundary", LowerBoundary, LINE, YELLOW);
plot("MarketVol", marketVol(), BARS|NEW, BLUE);
}