A variation using VXX.
Tested on the last two years, performs adequately. Prior to this, not so much.
Note that the original logic had apparent issues. This version attempts to rectify those.
'''
Contrarian style:
Long Entry: VXX close >= 5% above 10SMA
Long Exit: VXX <= 5% below 10SMA
Short Entry: VXX close <= 5% below 10SMA
Short Exit: VXX >= 5% above 10SMA
Exit: 5 days
Momentum style:
Long Entry: VXX close < 5% below 10SMA
Long Exit: VXX >= 5% above 10SMA
Short Entry: VXX close > 5% above 10SMA
Short Exit: VXX >= 5% above 10SMA
Exit: 5 days
Original:
When the VIX close is > or = to 5% above its 10SMA you buy the SPY
till the VIX is 5% below its 10SMA or 5days what ever comes first
When the VIX close is > or = to 5% below its 10SMA you sell the SPY
till the VIX is 5% above its 10SMA or 5days what ever comes first
'''
import numpy
import talib
periodsToConsider = 4
positionDuration = 4
minimumPercentDeltaThreshold = .04
def initialize(context):
context.target = symbol('SPY')
context.signal = symbol('VXX')
context.openPositionDuration = -1
set_benchmark(symbol('SPY'))
set_commission(commission.PerTrade(cost=2))
schedule_function(func=HandleDataScheduled,
date_rule=date_rules.every_day(),
time_rule=time_rules.market_open(hours=0, minutes=1))
def handle_data(context, data):
pass
def HandleDataScheduled(context, data):
prices = history(periodsToConsider, '1d', 'price')
targetPrice = prices[context.target][-1]
signalPrice = prices[context.signal][-1]
sma = prices.apply(talib.SMA, timeperiod=periodsToConsider).iloc[-1]
signalSMA = sma[context.signal]
pctDelta = (signalPrice - signalSMA) / signalSMA
isLong = context.portfolio.positions_value > 0.0
isShort = context.portfolio.positions_value < 0.0
isBuyLongCondition = False
isSellLongCondition = False
isSellShortCondition = False
isCoverShortCondition = False
### Contrarian style:
#if (pctDelta >= minimumPercentDeltaThreshold):
# isBuyLongCondition = True
#if (pctDelta <= -minimumPercentDeltaThreshold):
# isSellLongCondition = True
#if (pctDelta <= -minimumPercentDeltaThreshold):
# isSellShortCondition = True
#if (pctDelta >= minimumPercentDeltaThreshold):
# isCoverShortCondition = True
### Momentum style:
if (pctDelta <= -minimumPercentDeltaThreshold):
isBuyLongCondition = True
if (pctDelta >= minimumPercentDeltaThreshold):
isSellLongCondition = True
if (pctDelta >= minimumPercentDeltaThreshold):
isSellShortCondition = True
if (pctDelta <= -minimumPercentDeltaThreshold):
isCoverShortCondition = True
if (isLong or isShort):
### Period exit
context.openPositionDuration -= 1
if (context.openPositionDuration < 0):
order_target_percent(context.target, 0)
print("<<< Time exit: {0} @ {1:<7.2f}".format(context.target.symbol, targetPrice))
### Long exit
elif (isLong and isSellLongCondition):
order_target_percent(context.target, 0)
print("<<< Long exit: {0} @ {1:<7.2f}".format(context.target.symbol, targetPrice))
### Short exit
elif (isShort and isCoverShortCondition):
order_target_percent(context.target, 0)
print("<<< Short exit: {0} @ {1:<7.2f}".format(context.target.symbol, targetPrice))
### Long entry
if (not isLong and isBuyLongCondition):
order_target_percent(context.target, 1)
context.openPositionDuration = positionDuration
print(" Long entry: {0} @ {1:<7.2f} >>>".format(context.target.symbol, targetPrice))
### Short entry
elif (not isShort and isSellShortCondition):
order_target_percent(context.target, -1)
context.openPositionDuration = positionDuration
print(" Short entry: {0} @ {1:<7.2f} >>>".format(context.target.symbol, targetPrice))
record(Target=targetPrice, Signal=signalPrice, SignalSMA=signalSMA, PctDelta=pctDelta)