Gap Reversion Strategy
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// @version=5
// Author = TradeAutomation


strategy(title="Gap Reversion Strategy", shorttitle="Gap Reversion Strategy", process_orders_on_close=false, overlay=true, pyramiding=0, commission_type=strategy.commission.cash_per_order, commission_value=1, slippage = 1, margin_long = 75, initial_capital = 1000000, default_qty_type=strategy.percent_of_equity, default_qty_value=100)


// Backtest Date Range Inputs // 
StartTime = input.time(defval=timestamp('01 Jan 2010 06:00 +0000'), group="Backtest Date Range", title='Start Time')
EndTime = input.time(defval=timestamp('01 Jan 2099 00:00 +0000'), group="Backtest Date Range", title='End Time')
InDateRange = time>=StartTime and time<=EndTime

// Wilder's RSI //
lenrsi=input.int(2, title="RSI-length", group="RSI Settings")
src = input.source(close, title="RSI Source", group="RSI Settings")
RSI = ta.rsi(src, lenrsi)

// VIX Volatility Warning Indicator & Filter //
vix = request.security("CBOE:VIX", "60", high)
mean = ta.sma(vix, 350)
SquaredDifference = math.pow(vix-mean, 2)
VolWarningLength = input.int(5, "Sustain Volatility Filter For X Bars", group="Volatility Filter Settings")
SquaredDifferenceThreshold = input.int(500, "Variance Threshold", group="Volatility Filter Settings")
VolatilityWarning = ta.highest(SquaredDifference, VolWarningLength)<SquaredDifferenceThreshold
EarlyWarningInput = input.bool(false, "Use VIX Variance Filter?", group="Volatility Filter Settings", tooltip="This will prevent new signals from entering trades when the VIX is unusually high")
ReversionFilter = EarlyWarningInput == true ? VolatilityWarning : close>0

// Long Entry Rules //
ReversionRule = RSI<input.float(20, "RSI Long Qualifier", tooltip="The selected RSI / reversion indicator value must be below this input after a gap down to place a trade", group="Trade Entry/Exit Settings", step=5)
GapPerc = (1-(input.float(.25, "Minimum Gap % of Price", step=.1, group="Limit Entry Price Settings", minval=0)*.01))
GapDown = open<close[1]*GapPerc
var float LongEntryLimit=na
PercLimit = (close*GapPerc)*(1-input.float(1, "Price % Entry Limit (close-gap-%)", tooltip="When the strategy issues a long buy signal, a limit order is generated at this % below the prior day's close price minus Gap % input", step=.1, minval=0, group="Limit Entry Price Settings")*.01)
ATRLimit = (close*GapPerc)-(ta.atr(input.int(5, "ATR Length"))*input.float(20, "ATR Long Entry Limit (close-gap-%ofATR)", tooltip="When the strategy issues a long buy signal, a limit order is generated at this % of ATR below the prior day's close price minus Gap % input",step=5, minval=0, group="Limit Entry Price Settings")*.01)
LimitInput = input.bool(false, "Use % of ATR entry limit instead of % of price entry limit?", group="Limit Entry Price Settings")
Limit = LimitInput == true ? ATRLimit : PercLimit
LongEntryLimit := ReversionRule==true ? Limit : na
LongExit = RSI>input.float(70, "RSI Indicator Exit Value", tooltip="The strategy will exit the long position when the Reversion Indicator crosses over this value", group="Trade Entry/Exit Settings", step=5)

// Stop //
StopPercInput = 1-(input.float(99, "Stop %", step=0.25, group="Trade Entry/Exit Settings")*.01)
PercStop = strategy.position_avg_price*StopPercInput

// Entry and Exit Functions //
if (InDateRange)
    strategy.entry("Long", strategy.long, limit=LongEntryLimit, when = ReversionRule==true and ReversionFilter, alert_message="Buy")
    strategy.exit("Exit", "Long", stop=PercStop, alert_message="Sell")
    strategy.cancel_all(when = GapDown==false) 
    strategy.close("Long", when = LongExit, alert_message="Sell")
if (not InDateRange)
    strategy.close_all()
    