Back to Community
Robin Hood VIX Mix Extreme Vetting

This is the latest version of Robin Hood VIX Mix Rogue Trader. I am live trading this.

It is a work in progress. It includes an integration of Robin Hood Extreme Vetting.
If you search through the forums, you will eventually find a consensus that low volume stocks are difficult to accurately backtest. For that reason, the only real test of low volume stocks is live trading. So the high returns that are due to the low volume stocks are much less reliable than returns from higher volume stocks.

Clone Algorithm
380
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
from datetime import datetime  
import functools
import itertools
from itertools import cycle
import math
import numpy as np
import pandas as pd
from pytz import timezone      
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.factors import SimpleMovingAverage, AverageDollarVolume
from quantopian.pipeline.filters.morningstar import IsPrimaryShare
import re
from scipy import stats
import talib
import time
from zipline.utils import tradingcalendar

DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT = 0.20
History = 128

def initialize(context):

    ##
    # ExtremeVetting
    ##

    context.MaxCandidates=390 #6.5*60
    context.EveryThisManyMinutes=15
    context.MaxBuyOrdersAtOnce=context.EveryThisManyMinutes
    context.MyLeastPrice=2.00
    context.MyMostPrice=5.00
    context.MyRetreatPrice=context.MyLeastPrice
    context.MyRetreatAge=3
    context.MyDaysPerPennyReduction=0.33
    context.MyMinPurchase=1000
    context.MyMaxPurchase=25000
    context.EV_BuyFactor=.90
    context.SellFactor=1.08

    # over simplistic tracking of position age
    context.age={}
    print len(context.portfolio.positions)

    # ExtremeVetting
    EveryThisManyMinutes=context.EveryThisManyMinutes
    TradingDayHours=6.5
    TradingDayMinutes=int(TradingDayHours*60)
    for minutez in xrange(
        0, 
        TradingDayMinutes, 
        EveryThisManyMinutes
    ):
        if minutez >= 1:
            schedule_function(ExtremeVetting, date_rules.every_day(), time_rules.market_open(minutes=minutez))
        else:
            schedule_function(ExtremeVetting, date_rules.every_day(), time_rules.market_open())

    # Create our pipeline and attach it to our algorithm.
    my_pipe = make_pipeline(context)
    attach_pipeline(my_pipe, 'my_pipeline')

    ##
    # CherryPicker
    ##

    context.rsi_length = 3
    context.rsi_trigger = 50
    context.wvf_length = 100
    context.ema1 = 10
    context.ema2 = 30
    context.sell = False

    ##
    # Not CherryPicker Not ExtremeVetting
    ##
    
    vixUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv'
    vxvUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vxvdailyprices.csv'
    nokoUrl = 'http://52.15.233.150/noko.csv'  
    
    fetch_csv(nokoUrl, 
              symbol='v1', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX1, 
              post_func=shift_data)
    
    fetch_csv(nokoUrl, 
              symbol='v2', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX2, 
              post_func=shift_data)

    fetch_csv(vixUrl, 
              symbol='v', 
              skiprows=1,
              date_column='Date', 
              pre_func=addFieldsVIX,
              post_func=shift_data)

    fetch_csv(vxvUrl, 
              symbol='vxv', 
              skiprows=2,
              date_column='Date', 
              pre_func=addFieldsVXV,
              post_func=shift_data)

    context.xiv = sid(40516)
    context.tqqq = sid(39214)
    context.uvxy = sid(41969)
    context.spyg = sid(22009)
    
    context.vix = -1
    context.xiv_day = 0
    set_benchmark(context.xiv) # ALPHA and BETA will be different
    set_slippage(myVolumeShareSlippage(volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT, price_impact=0.0))
    set_commission(commission.PerTrade(cost=0.00))
    
    context.SetAsideLeverageTotal = 0.20 # 100% allocate when BigSignalTQQQ
    context.VIX_GrowthLeverage    = 1 - context.SetAsideLeverageTotal
    context.VIX_MinHedgeLeverage  = context.VIX_HedgeLeverage  = 0.666
    context.VIX_MaxHedgeLeverage  = 1.00 # if certain conditions are met
    context.ShowMaxLev            = True

    # 3x NASDAQ nonfinancial, generally profitable
    context.SetAsideStocks = symbols('TQQQ')

    context.PriceXIV = context.PriceUVXY = 0.00
    context.BoughtShortVIX = context.BoughtLongVIX = False
    context.XIV       = symbol('XIV')
    context.UVXY      = symbol('UVXY') # approx 8% weekly erosion, bigger spikes
    context.VIXstocks = (context.XIV, context.UVXY)
    context.LongVIX  = False  # no decisions until one of three conditions exists
    context.ShortVIX = False  # no decisions until one of three conditions exists
    # not necessary to set BigSignal variables because they get set by MoreSignals function early every day
    
    # apparently highly successful VIX signals
    schedule_function(CherryPickerOpen, date_rules.every_day(), time_rules.market_open(), False)
    schedule_function(MoreSignals, date_rules.every_day(), time_rules.market_open(minutes = 2))
    schedule_function(VIX_Mix, date_rules.every_day(), time_rules.market_open(minutes = 4))
    schedule_function(RogueTrader, date_rules.every_day(),time_rules.market_open(minutes = 60))
    schedule_function(cancel_open_orders, date_rules.every_day(), time_rules.market_close())    
    schedule_function(RecordVars, date_rules.every_day(), time_rules.market_close())    
    schedule_function(CherryPickerClose, date_rules.every_day(), time_rules.market_close(), False)

    #VXX used for strategy to buy XIV
    context.VXX = context.vxx = sid(38054) # VXX

    #Editable values to tweak backtest
    context.AvgLength = 20
    context.LengthWVF = 100
    context.LengthEMA1 = 10
    context.LengthEMA2 = 30
    
    #internal variables to store data
    context.vxxAvg = 0 
    context.SmoothedWVF1 = 0
    context.SmoothedWVF2 = 0
    context.vxxLow = 0
    context.vxxHigh = 0
    
    #Internal stop variables
    # context.stoploss is set in RogueTrader
    context.stoploss = 0.50
    context.stops         = {}
    context.stoppedout    = []
    context.SellAndWait   = 0

class myVolumeShareSlippage(slippage.SlippageModel):
    """Model slippage as a function of the volume of shares traded.
    """

    def __init__(self, volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT,
                 price_impact=0.1):

        self.volume_limit = volume_limit
        self.price_impact = price_impact

        slippage.SlippageModel.__init__(self)

    def process_order(self, data, order):
        volume = data.current(order.asset, "volume")

        max_volume = self.volume_limit * volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return None, None

        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return None, None

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / volume,
                           self.volume_limit)

        price = data.current(order.asset, "close")

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * price
        impacted_price = price + simulated_impact

        if order.limit:
            # this is tricky! if an order with a limit price has reached
            # the limit price, we will try to fill the order. do not fill
            # these shares if the impacted price is worse than the limit
            # price. return early to avoid creating the transaction.

            # buy order is worse if the impacted price is greater than
            # the limit price. sell order is worse if the impacted price
            # is less than the limit price
            if (order.direction > 0 and impacted_price > order.limit) or \
                    (order.direction < 0 and impacted_price < order.limit):
                return None, None
            
            # For marketable limit orders the price is 'impacted_price'
            # (that is current price + slippage) but for non-marketable
            # limit order the price must be the limit price.
            # To put it simple, if the market "goes through" the level
            # of a limit order (non-marketable) we have to use the limit
            # price, otherwise the 'impacted_price'
            # To disinguish between marketable and non-marketable limit
            # order we can use the following good approximation:
            # if both open and close price are below/above (buy/sell)
            # the limit price the order is markettable
            # if open price is above (or below for sell) limit price
            # and close price is below (or above for sell) limit pirce,
            # then the order is non-marketable
            
            open_price = data.current(order.asset, "open")
            # Note: no need to check for close price if we are here
            non_marketable = (order.direction > 0 and open_price > order.limit) or \
                             (order.direction < 0 and open_price < order.limit)
                
            if non_marketable:
                impacted_price = order.limit
                
            #print '%d limit %f open %f close %f marketable %s final price %f' % (order.direction, order.limit, open_price, price, not non_marketable, impacted_price)

        return (
            impacted_price,
            math.copysign(cur_volume, order.direction)
        )

def make_pipeline(context):
    """
    Create our pipeline.
    """

    # Filter for primary share equities. IsPrimaryShare is a built-in filter.
    primary_share = IsPrimaryShare()

    # Equities listed as common stock (as opposed to, say, preferred stock).
    # 'ST00000001' indicates common stock.
    common_stock = morningstar.share_class_reference.security_type.latest.eq('ST00000001')

    # Non-depositary receipts. Recall that the ~ operator inverts filters,
    # turning Trues into Falses and vice versa
    not_depositary = ~morningstar.share_class_reference.is_depositary_receipt.latest

    # Equities not trading over-the-counter.
    not_otc = ~morningstar.share_class_reference.exchange_id.latest.startswith('OTC')

    # Not when-issued equities.
    not_wi = ~morningstar.share_class_reference.symbol.latest.endswith('.WI')

    # Equities without LP in their name, .matches does a match using a regular
    # expression
    not_lp_name = ~morningstar.company_reference.standard_name.latest.matches('.* L[. ]?P.?$')

    # Equities with a null value in the limited_partnership Morningstar
    # fundamental field.
    not_lp_balance_sheet = morningstar.balance_sheet.limited_partnership.latest.isnull()

    # Equities whose most recent Morningstar market cap is not null have
    # fundamental data and therefore are not ETFs.
    have_market_cap = morningstar.valuation.market_cap.latest.notnull()

    # At least a certain price
    price = USEquityPricing.close.latest
    AtLeastPrice   = (price >= context.MyLeastPrice)
    AtMostPrice    = (price <= context.MyMostPrice)

    # Filter for stocks that pass all of our previous filters.
    tradeable_stocks = (
        primary_share
        & common_stock
        & not_depositary
        & not_otc
        & not_wi
        & not_lp_name
        & not_lp_balance_sheet
        & have_market_cap
        & AtLeastPrice
        & AtMostPrice
    )

    LowVar=6
    HighVar=40

    log.info('\nAlgorithm initialized variables:\n context.MaxCandidates %s \n LowVar %s \n HighVar %s'
        % (context.MaxCandidates, LowVar, HighVar)
    )

    # High dollar volume filter.
    base_universe = AverageDollarVolume(
        window_length=20,
        mask=tradeable_stocks
    ).percentile_between(LowVar, HighVar)

    # Short close price average.
    ShortAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=3,
        mask=base_universe
    )

    # Long close price average.
    LongAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=45,
        mask=base_universe
    )

    percent_difference = (ShortAvg - LongAvg) / LongAvg

    # Filter to select securities to long.
    stocks_worst = percent_difference.bottom(context.MaxCandidates)
    securities_to_trade = (stocks_worst)

    return Pipeline(
        columns={
            'stocks_worst': stocks_worst
        },
        screen=(securities_to_trade),
    )

def my_compute_weights(context):
    """
    Compute ordering weights.
    """
    # Compute even target weights for our long positions and short positions.
    stocks_worst_weight = 1.00/len(context.stocks_worst)

    return stocks_worst_weight

def before_trading_start(context, data):
    # Gets our pipeline output every day.
    context.output = pipeline_output('my_pipeline')
    context.stocks_worst = context.output[context.output['stocks_worst']].index.tolist()
    context.stocks_worst_weight = my_compute_weights(context)
    context.MyCandidate = cycle(context.stocks_worst)

    for stock in context.portfolio.positions:
        if stock in context.age:
            context.age[stock] += 1
        else:
            context.age[stock] = 1
    for stock in context.age:
        if stock not in context.portfolio.positions:
            context.age[stock] = 0

    context.RogueTrader = False # Not True until RogueTrader scheduled function runs

    context.mx_lvrg  = 0 # reset for recording daily max leverage

    # To help determine previous signal when start algo in live trade Robinhood
    if not context.ShortVIX and not context.LongVIX: # Maybe we can figure it out
        context.ShortVIX = True if 0 < context.portfolio.positions[context.XIV].amount  else False
        context.LongVIX  = True if 0 < context.portfolio.positions[context.UVXY].amount else False
        if context.ShortVIX and context.LongVIX: # Do no harm
            context.ShortVIX = context.LongVIX = False

def RecordVars(context, data):
    
    # handling this in handle_data now to show mx_lvrg
    if not context.ShowMaxLev:
        record(Leverage=context.account.leverage)
        pass

def CherryPickerOpen(context,data):
    c = context
    if c.sell:
        c.sell = False
        if c.portfolio.positions[c.XIV].amount > 0: 
            cancel_open_orders_for(context, data, c.XIV)
            TarPer(context, data, c.XIV, 0.00)
            
def RogueTrader(context, data):

    c = context
    c.RogueTrader = True # Not True until RogueTrader scheduled function runs

    cancel_open_orders(context, data)

    ##
    # Limit sell and Stop loss orders
    ##
    for stock in c.portfolio.positions:

        # Set stoploss
        c.stoploss = 0.21 if stock is c.UVXY else 0.035

        # Set LimitPrice for first order
        RemainingFactor  = 0.50 if stock is c.UVXY else 0.22
        MaxOrders        = 20   if stock is c.UVXY else 3
        if stock is c.UVXY:
            LimitPriceFactor = 1.06 if c.Agree else 1.05
        else:
            LimitPriceFactor = 1.04
        LimitPrice       = LimitPriceFactor * c.portfolio.positions[stock].cost_basis

        SharesRemaining = int(RemainingFactor * c.portfolio.positions[stock].amount)
        SharesPerOrder  = min(SharesRemaining, max(100, int(SharesRemaining / MaxOrders)))
        
        while 0 < SharesRemaining:

            order(stock, -SharesPerOrder, style=LimitOrder(LimitPrice))
            
            SharesRemaining -= SharesPerOrder
            SharesPerOrder = min(SharesRemaining, SharesPerOrder)
            LimitPrice *= LimitPriceFactor 
        if stock.symbol in c.stops: del c.stops[stock.symbol]
        
def TarPer(context, data, stock, TargetPercent):

    if DataCanTrade(context, data, stock):

        if 0 == TargetPercent:
            order_target_percent(stock, 0.00)
        else:
            # Always want money available to withdraw 
            # and also try to prevent margin related order rejections
            PV = context.portfolio.portfolio_value
            DoNotSpend = 2000 # 200 Cushion plus cash for withdrawals
            RhMargin = 24000.00 # Set to 0 if you do not have Robinhood Gold
            MaxLeverage = 1.33 - .12 # Hard Limit for leverage minus seemingly necessary cushion
            MaxLeverage = min(MaxLeverage, max(MaxLeverage, context.account.leverage))
            RhMargin = min(RhMargin, PV * (MaxLeverage - 1))
            RhPV = PV + RhMargin - DoNotSpend  
            amount = context.portfolio.positions[stock].amount
            price = data.current(stock, 'price')
            PosValue   = float(amount * price)
            TarValue   = float(RhPV * TargetPercent)
            DiffValue  = float(TarValue - PosValue)
            DiffAmount = int(DiffValue / price)
            DiffAmount = 0 if 0 > DiffAmount and 0 == amount else DiffAmount
            order(stock, DiffAmount)

        if stock.symbol in context.stops: del context.stops[stock.symbol]

def DataCanTrade(context, data, stock):

    try:
        if data.can_trade(stock):
            return True
        else:
            return False
    except:
        return False

def ExtremeVetting(context, data):
    c = context
    cash = c.portfolio.cash
    PValue = c.portfolio.portfolio_value

    cancel_open_buy_orders(context, data)

    # Order sell at profit target in hope that somebody actually buys it
    for stock in c.portfolio.positions:
        if not get_open_orders(stock):
            StockShares = c.portfolio.positions[stock].amount
            CurrPrice = float(data.current([stock], 'price'))
            CostBasis = float(c.portfolio.positions[stock].cost_basis)
            SellPrice = float(make_div_by_05(CostBasis*c.SellFactor, buy=False))
            if np.isnan(SellPrice):
                pass # probably best to wait until nan goes away
            elif (
                stock in c.age 
                and c.MyRetreatAge<=c.age[stock] 
                and (
                    c.MyRetreatPrice>CurrPrice
                    or CostBasis>CurrPrice
                )
            ):
                SellPrice = float(
                    CostBasis-(
                        c.age[stock]/(100.00*c.MyDaysPerPennyReduction)
                    )
                )
                SellPrice = .50 if .50 > SellPrice else SellPrice
                SellPrice = float(make_div_by_05(SellPrice, buy=False))
                order(stock, -StockShares,
                    style=LimitOrder(SellPrice)
                )
            else:
                order(stock, -StockShares,
                    style=LimitOrder(SellPrice)
                )

    WeightFactor = .33 if cash > .33 * PValue else 1
    WeightThisBuyOrder=float(WeightFactor * 1.00 / c.MaxBuyOrdersAtOnce)
    MaxBuyOrdersAtOnce = 1 if cash < c.MyMinPurchase * c.MaxBuyOrdersAtOnce else c.MaxBuyOrdersAtOnce        
    for ThisBuyOrder in range(MaxBuyOrdersAtOnce):
        stock = c.MyCandidate.next()
        PHshort = data.history([stock], 'price', 5, '1d')
        PHshortAvg = float(PHshort.mean())
        PHlong = data.history([stock], 'price', 40, '1d')
        PHlongAvg = float(PHlong.mean())
        CurrPrice = float(data.current([stock], 'price'))
        if PHshortAvg < PHlongAvg * c.EV_BuyFactor:
            if cash >= c.MyMinPurchase * MaxBuyOrdersAtOnce:
                if c.MyMinPurchase > WeightThisBuyOrder*cash:
                    Purchase=c.MyMinPurchase
                elif c.MyMaxPurchase < WeightThisBuyOrder*cash:
                    Purchase=c.MyMaxPurchase
                else:
                    Purchase=WeightThisBuyOrder*cash
                StockSharesToOwn = int(Purchase/CurrPrice)
                StockValueTarget = StockSharesToOwn * CurrPrice
                StockTarPer = StockValueTarget / PValue
                TarPer(context, data, stock, StockTarPer)

#if cents not divisible by .05, round down if buy, round up if sell
def make_div_by_05(s, buy=False):
    s *= 20.00
    s =  math.floor(s) if buy else math.ceil(s)
    s /= 20.00
    return s

def cancel_open_buy_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
            if 0<order.amount: #it is a buy order
                cancel_order(order)

def cancel_open_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            cancel_order(order)
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
    
def cancel_open_orders_for(context, data, security):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            if stock is security:
                if order.amount < context.portfolio.positions[stock].amount:
                    cancel_order(order)
                    #message = 'Canceling order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                else: # Do NOT want to cancel stop loss order
                    #message = 'NOT Canceling stop loss order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                    pass

def MoreSignals(context, data):  

    update_indices(context, data)     
    last_vix = context.VIXprice = data.current('v', 'Close')
    last_vx1 = data.current('v1','Close')  
    last_vx2 = data.current('v2','Close')      
    last_vxv = data.current('vxv', 'Close')
    last_vix_200ma_ratio = data.current('v', '200ma Ratio')
           
    # Calculating the gap between spot vix and the first month vix future
    last_ratio_v_v1 = last_vix/last_vx1

    # Calculating the contango ratio of the front and second month VIX Futures 
    last_ratio_v1_v2 = last_vx1/last_vx2

    # Blending the previous two ratios together using a weighted average
    ratio_weight = 0.7
    last_ratio = (ratio_weight*last_ratio_v_v1) + ((1-ratio_weight)*last_ratio_v1_v2) - 1
    
    vix_vxv_ratio = last_vix/last_vxv
    
    # Retrieve SPY prices for technical indicators
    prices = data.history(context.spyg, 'open', 40, '1d')
    
    # Retrieve SPY MACD data
    macda, signal, hist = talib.MACD(prices, fastperiod=12,slowperiod=26,signalperiod=9)
    macd = macda[-1] - signal[-1]
    
    # Calculate how much vix moved the previous day
    if (context.vix <> -1) : 
        vix_ratio = last_vix/context.vix -1
    else :
        vix_ratio = 0
    context.vix = last_vix
    
    xiv_history = data.history(context.xiv, 'price', 2, '1d')  
    
    xiv_ratio = xiv_history[1]/xiv_history[0] - 1
    
    # Setting thresholds
    threshold_vix_too_low = 10.76   # 0 
    threshold_vix_200ma_ratio_low = 0.79  # 0 
    threshold_xiv = -0.049          # 1
    threshold_vxv_xiv = 0.87        # 2
    threshold_uvxy = 0.049          # 3
    threshold_macd = -0.55          # 3
    threshold_vxv_uvxy = 1.3        # 4
    threshold_vix_high = 19.9       # 5
    threshold_vc_low = -0.148       # 6
    threshold_vc_high = 0.046       # 8
    threshold_vc_high_2 = -0.06     # 8
    threshold_xiv_ratio = -0.053    # 10
    threshold_uvxy_ratio = 0.08     # 11

    # 0
    if last_vix < threshold_vix_too_low and last_vix_200ma_ratio < threshold_vix_200ma_ratio_low: # if VIX is too low, invest in UVXY witht he hope of a spike
        target_sid = context.uvxy
    # 1        
    elif last_ratio < threshold_xiv: # if contango is high, invest in XIV to gain from decay
        target_sid = context.xiv
    
    # 2
    elif vix_vxv_ratio < threshold_vxv_xiv: # if short term vol is low compared to mid term, invest in XIV to gain from decay
        target_sid = context.xiv

    # 3
    elif last_ratio > threshold_uvxy and macd > threshold_macd: # if backwardation is high, invest in UVXY to gain from decay
        target_sid = context.uvxy

    # 4
    elif vix_vxv_ratio > threshold_vxv_uvxy: # if short term vol is high compared to mid term, invest in UVXY to gain from growth
        target_sid = context.uvxy

    # 5
    elif last_vix > threshold_vix_high: # if VIX is too high, invest in XIV expecting that VIX will drop
        target_sid = context.xiv

    # 6
    elif vix_ratio < threshold_vc_low: # Vix down sharply, invest in XIV expecting that futures curve gets pulled down
        target_sid = context.xiv

    # 7
    elif vix_ratio > threshold_vc_high: # Vix up sharply, invest in UVXY expecting that futures curve gets pulled up
        target_sid = context.uvxy

    # 8
    elif vix_ratio > threshold_vc_high_2: #have to think
        target_sid = context.xiv

    # 9
    else:
        target_sid = context.uvxy

    # 10
    if (target_sid == context.xiv and xiv_ratio < threshold_xiv_ratio) : 
        # indicators say XIV but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq 

    # 11
    elif (target_sid == context.uvxy and xiv_ratio > threshold_uvxy_ratio) :
        # indicators say UVXY but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq
    
    context.BigSignalShortVIX = True if context.xiv  is target_sid else False
    context.BigSignalLongVIX  = True if context.uvxy is target_sid else False
    context.BigSignalTQQQ     = True if context.tqqq is target_sid else False
    
def VIX_Mix(context, data):
    c = context
    
    if 0 < c.SellAndWait:
        c.SellAndWait -= 1
        return

    cancel_open_orders(context, data) # avoid confusion

    ### Determine how much to risk in Long VIX ###
    # Load historical data for the stocks  
    hist = data.history(c.vxx, ['high', 'low', 'close'], 15, '1d')  
    # Calculate the ATR for the stock  
    atr_14 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=14)[-1]  
    atr_3 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=3)[-1]
    c.VIX_HedgeLeverage = c.VIX_MaxHedgeLeverage if atr_3 <= atr_14 else c.VIX_MinHedgeLeverage

    #Gets Moving Average of VXX
    price_hist = data.history(c.vxx, 'price', c.AvgLength, '1d')
    c.vxxAvg = price_hist.mean()
    
    #get data for calculations
    n = 200
    vxx_prices = data.history(c.vxx, "price", n + 2, "1d")
    vxx_lows = data.history(c.vxx, "low", n + 2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.LengthWVF,center=False).max()
    
    #William's VIX Fix indicator a.k.a. the Synthetic VIX
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100
    
    # calculated smoothed WVF
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.LengthEMA1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.LengthEMA2)
    
    #Do some checks for cross overs. 
    if WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-1]:
        wvf_crossedSmoothedWVF1 = True
    else: 
        wvf_crossedSmoothedWVF1 = False
    #Same except for smoothed2 
    if WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-1]:
        wvf_crossedSmoothedWVF2 = True
    else: 
        wvf_crossedSmoothedWVF2 = False
    
    #Current price of vxx
    vxxPrice = data.current(c.vxx, 'price')
    
    #SignalShortVIX 
    if ( wvf_crossedSmoothedWVF1 and WVF[-1] < c.SmoothedWVF2[-1]) or (wvf_crossedSmoothedWVF2 and wvf_crossedSmoothedWVF1):
        SignalShortVIX = True
    elif ((vxxPrice > c.vxxAvg and vxx_prices[-2] < c.vxxAvg) or (WVF[-1] < c.SmoothedWVF2[-1] and WVF[-2] > c.SmoothedWVF2[-1])):
        SignalShortVIX = False
    else:
        SignalShortVIX = True

    if (c.BigSignalShortVIX and SignalShortVIX): # Agree ShortVIX
        c.ShortVIX    = True
        c.LongVIX     = False
        c.Agree       = True

    elif (c.BigSignalLongVIX and not SignalShortVIX): # Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = True

    elif (c.BigSignalLongVIX and SignalShortVIX): # Not Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = False

    for stock in c.portfolio.positions:
        if stock not in c.VIXstocks and stock not in c.SetAsideStocks:
            TarPer(context, data, stock, 0.00)

    ##
    # VIX_Mix only once until signal changes again
    # or
    # leverage drops too low
    ##

    l = c.account.leverage
    LevTooLow = True if (0.33 > l) or (0.90 < l < 1.05) else False
    p = c.portfolio.positions

    if c.BigSignalTQQQ:
        if LevTooLow or (c.XIV in p or c.UVXY in p):
            TarPer(context, data, c.XIV, 0.00)
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(1.00 / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)

    elif c.ShortVIX:
        if LevTooLow or (c.XIV not in p):
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(c.SetAsideLeverageTotal / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)
            c.BoughtShortVIX = False
            c.PriceXIV = 0.00

    elif c.LongVIX:
        if LevTooLow or (c.UVXY not in p):
            TarPer(context, data, c.XIV, 0.00)
            for stock in c.SetAsideStocks:
                TarPer(context, data, stock, 0.00)
            c.BoughtLongVIX = False
            c.PriceUVXY = 0.00

    # Record / log stuff I want to know
    c.XIVprice  = data.current(c.XIV, 'price')
    c.UVXYprice = data.current(c.UVXY, 'price')
    TQQQprice = data.current(c.tqqq, 'price')
    #record(XIV  = c.XIVprice)
    #record(UVXY = c.UVXYprice)
    #record(TQQQ = TQQQprice)
    BigSignal = 'NoBigSignal'
    BigSignal = 'ShortVIX' if c.BigSignalShortVIX else BigSignal
    BigSignal = ' LongVIX' if c.BigSignalLongVIX  else BigSignal
    BigSignal = '    TQQQ' if c.BigSignalTQQQ     else BigSignal
    SyntheticVIX = 'NoSyntheticVIX'
    SyntheticVIX = 'ShortVIX' if c.ShortVIX else SyntheticVIX
    SyntheticVIX = ' LongVIX' if c.LongVIX  else SyntheticVIX
    log.info('BigSignal / SyntheticVIX: {} / {}     VIX: {:.2f}     XIV: {:.2f}     UVXY: {:.2f}     TQQQ: {:.2f}'
        .format(BigSignal, SyntheticVIX, c.VIXprice, c.XIVprice, c.UVXYprice, TQQQprice)
    )

def update_indices(context, data):
    context.fetch_failed = False
    context.vix_vals = unpack_from_data(context, data, 'v')    
    context.vxv_vals = unpack_from_data(context, data, 'vxv')  
    context.vx1_vals = unpack_from_data(context, data, 'v1')
    context.vx2_vals = unpack_from_data(context, data, 'v2')

def fix_close(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%m/%d/%Y')))
    df = df.sort_values(by='Date', ascending=True)
    return df

def fix_closeVX(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%Y-%m-%d')))
    df = df.sort_values(by='Date', ascending=True)
    return df


def subsequent_trading_date(date):
    tdays = tradingcalendar.trading_days
    last_date = pd.to_datetime(date)
    last_dt = tradingcalendar.canonicalize_datetime(last_date)
    next_dt = tdays[tdays.searchsorted(last_dt) + 1]
    return next_dt

def add_last_bar(df):
    last_date = df.index[-1]
    subsequent_date = subsequent_trading_date(last_date)
    blank_row = pd.Series({}, index=df.columns, name=subsequent_date)
    # add today, and shift all previous data up to today. This 
    # should result in the same data frames as in backtest
    df = df.append(blank_row).shift(1).dropna(how='all')
    return df

def shift_data(df):
    df = add_last_bar(df)
    df.fillna(method='ffill') 
    df['PrevCloses'] = my_rolling_apply_series(df['Close'], to_csv_str, History)
    dates = pd.Series(df.index)
    dates.index = df.index
    df['PrevDates'] = my_rolling_apply_series(dates, to_csv_str, History)
    return df

def unpack_from_data(context, data, sym):
    try:
        v = data.current(sym, 'PrevCloses')
        i = data.current(sym, 'PrevDates')
        return from_csv_strs(i,v,True).apply(float)
    except:
        log.warn("Unable to unpack historical {s} data.".format(s=sym))
        context.fetch_failed = True

def addFieldsVIX(df):
    df = fix_close(df,'VIX Close')
    df['200ma'] = df['Close'].rolling(200).mean()
    df['200ma Ratio'] = df['Close'] / df['200ma']

    return df

def addFieldsVXV(df):
    df.rename(columns={'Unnamed: 0': 'Date'}, inplace=True)
    df = fix_close(df,'CLOSE')
    return df

def addFieldsVX1(df):
    df = fix_closeVX(df,'F1')
    return df

def addFieldsVX2(df):
    df = fix_closeVX(df,'F2')
    return df

# convert a series of values to a comma-separated string of said values
def to_csv_str(s):
    return functools.reduce(lambda x,y: x+','+y, pd.Series(s).apply(str))

# a specific instance of rolling apply, for Series of any type (not just numeric,
# ala pandas.rolling_apply), where the index of the series is set to the indices
# of the last elements of each subset
def my_rolling_apply_series(s_in, f, n):
    s_out = pd.Series([f(s_in[i:i+n]) for i in range(0,len(s_in)-(n-1))]) 
    s_out.index = s_in.index[n-1:]
    return s_out

# reconstitutes a Series from two csv-encoded strings, one of the index, one of the values
def from_csv_strs(x, y, idx_is_date):
    s = pd.Series(y.split(','),index=x.split(','))
    if (idx_is_date):
        s.index = s.index.map(lambda x: pd.Timestamp(x))
    return s

def pvr(context, data):
    ''' Custom chart and/or logging of profit_vs_risk returns and related information from https://www.quantopian.com/posts/pvr#569784bda73e9bf2b7000180
    '''  
    #import time  
    #from datetime import datetime  
    #from pytz import timezone      # Python will only do once, makes this portable.  
                                   #   Move to top of algo for better efficiency.  
    c = context  # Brevity is the soul of wit -- Shakespeare [for readability]  
    if 'pvr' not in c:

        # For real money, you can modify this to total cash input minus any withdrawals  
        manual_cash = c.portfolio.starting_cash  
        time_zone   = 'US/Central'   # Optionally change to your own time zone for wall clock time

        c.pvr = {  
            'options': {  
                # # # # # # # # # #  Options  # # # # # # # # # #  
                'logging'         : 0,    # Info to logging window with some new maximums  
                'log_summary'     : 126,  # Summary every x days. 252/yr

                'record_pvr'      : 1,    # Profit vs Risk returns (percentage)  
                'record_pvrp'     : 0,    # PvR (p)roportional neg cash vs portfolio value  
                'record_cash'     : 1,    # Cash available  
                'record_max_lvrg' : 0,    # Maximum leverage encountered  
                'record_risk_hi'  : 0,    # Highest risk overall  
                'record_shorting' : 0,    # Total value of any shorts  
                'record_max_shrt' : 0,    # Max value of shorting total  
                'record_cash_low' : 0,    # Any new lowest cash level  
                'record_q_return' : 0,    # Quantopian returns (percentage)  
                'record_pnl'      : 1,    # Profit-n-Loss  
                'record_risk'     : 1,    # Risked, max cash spent or shorts beyond longs+cash  
                'record_leverage' : 0,    # End of day leverage (context.account.leverage)  
                # All records are end-of-day or the last data sent to chart during any day.  
                # The way the chart operates, only the last value of the day will be seen.  
                # # # # # # # # #  End options  # # # # # # # # #  
            },  
            'pvr'        : 0,      # Profit vs Risk returns based on maximum spent  
            'cagr'       : 0,  
            'max_lvrg'   : 0,  
            'max_shrt'   : 0,  
            'risk_hi'    : 0,  
            'days'       : 0.0,  
            'date_prv'   : '',  
            'date_end'   : get_environment('end').date(),  
            'cash_low'   : manual_cash,  
            'cash'       : manual_cash,  
            'start'      : manual_cash,  
            'tz'         : time_zone,  
            'begin'      : time.time(),  # For run time  
            'run_str'    : '{} to {}  ${}  {} {}'.format(get_environment('start').date(), get_environment('end').date(), int(manual_cash), datetime.now(timezone(time_zone)).strftime("%Y-%m-%d %H:%M"), time_zone)  
        }  
        if c.pvr['options']['record_pvrp']: c.pvr['options']['record_pvr'] = 0 # if pvrp is active, straight pvr is off  
        if get_environment('arena') not in ['backtest', 'live']: c.pvr['options']['log_summary'] = 1 # Every day when real money  
        log.info(c.pvr['run_str'])  
    p = c.pvr ; o = c.pvr['options'] ; pf = c.portfolio ; pnl = pf.portfolio_value - p['start']  
    def _pvr(c):  
        p['cagr'] = ((pf.portfolio_value / p['start']) ** (1 / (p['days'] / 252.))) - 1  
        ptype = 'PvR' if o['record_pvr'] else 'PvRp'  
        log.info('{} {} %/day   cagr {}   Portfolio value {}   PnL {}'.format(ptype, '%.4f' % (p['pvr'] / p['days']), '%.3f' % p['cagr'], '%.0f' % pf.portfolio_value, '%.0f' % pnl))  
        log.info('  Profited {} on {} activated/transacted for PvR of {}%'.format('%.0f' % pnl, '%.0f' % p['risk_hi'], '%.1f' % p['pvr']))  
        log.info('  QRet {} PvR {} CshLw {} MxLv {} RskHi {} MxShrt {}'.format('%.2f' % (100 * pf.returns), '%.2f' % p['pvr'], '%.0f' % p['cash_low'], '%.2f' % p['max_lvrg'], '%.0f' % p['risk_hi'], '%.0f' % p['max_shrt']))  
    def _minut():  
        dt = get_datetime().astimezone(timezone(p['tz']))  
        return str((dt.hour * 60) + dt.minute - 570).rjust(3)  # (-570 = 9:31a)  
    date = get_datetime().date()  
    if p['date_prv'] != date:  
        p['date_prv'] = date  
        p['days'] += 1.0  
    do_summary = 0  
    if o['log_summary'] and p['days'] % o['log_summary'] == 0 and _minut() == '100':  
        do_summary = 1              # Log summary every x days  
    if do_summary or date == p['date_end']:  
        p['cash'] = pf.cash  
    elif p['cash'] == pf.cash and not o['logging']: return  # for speed

    shorts = sum([z.amount * z.last_sale_price for s, z in pf.positions.items() if z.amount < 0])  
    new_key_hi = 0                  # To trigger logging if on.  
    cash       = pf.cash  
    cash_dip   = int(max(0, p['start'] - cash))  
    risk       = int(max(cash_dip, -shorts))

    if o['record_pvrp'] and cash < 0:   # Let negative cash ding less when portfolio is up.  
        cash_dip = int(max(0, cash_dip * p['start'] / pf.portfolio_value))  
        # Imagine: Start with 10, grows to 1000, goes negative to -10, should not be 200% risk.

    if int(cash) < p['cash_low']:             # New cash low  
        new_key_hi = 1  
        p['cash_low'] = int(cash)             # Lowest cash level hit  
        if o['record_cash_low']: record(CashLow = p['cash_low'])

    if c.account.leverage > p['max_lvrg']:  
        new_key_hi = 1  
        p['max_lvrg'] = c.account.leverage    # Maximum intraday leverage  
        if o['record_max_lvrg']: record(MaxLv   = p['max_lvrg'])

    if shorts < p['max_shrt']:  
        new_key_hi = 1  
        p['max_shrt'] = shorts                # Maximum shorts value  
        if o['record_max_shrt']: record(MxShrt  = p['max_shrt'])

    if risk > p['risk_hi']:  
        new_key_hi = 1  
        p['risk_hi'] = risk                   # Highest risk overall  
        if o['record_risk_hi']:  record(RiskHi  = p['risk_hi'])

    # Profit_vs_Risk returns based on max amount actually invested, long or short  
    if p['risk_hi'] != 0: # Avoid zero-divide  
        p['pvr'] = 100 * pnl / p['risk_hi']  
        ptype = 'PvRp' if o['record_pvrp'] else 'PvR'  
        if o['record_pvr'] or o['record_pvrp']: record(**{ptype: p['pvr']})

    if o['record_shorting']: record(Shorts = shorts)             # Shorts value as a positve  
    if o['record_leverage']: record(Lvrg   = c.account.leverage) # Leverage  
    if o['record_cash']    : record(Cash   = cash)               # Cash  
    if o['record_risk']    : record(Risk   = risk)  # Amount in play, maximum of shorts or cash used  
    if o['record_q_return']: record(QRet   = 100 * pf.returns)  
    if o['record_pnl']     : record(PnL    = pnl)                # Profit|Loss

    if o['logging'] and new_key_hi:  
        log.info('{}{}{}{}{}{}{}{}{}{}{}{}'.format(_minut(),  
            ' Lv '     + '%.1f' % c.account.leverage,  
            ' MxLv '   + '%.2f' % p['max_lvrg'],  
            ' QRet '   + '%.1f' % (100 * pf.returns),  
            ' PvR '    + '%.1f' % p['pvr'],  
            ' PnL '    + '%.0f' % pnl,  
            ' Cash '   + '%.0f' % cash,  
            ' CshLw '  + '%.0f' % p['cash_low'],  
            ' Shrt '   + '%.0f' % shorts,  
            ' MxShrt ' + '%.0f' % p['max_shrt'],  
            ' Risk '   + '%.0f' % risk,  
            ' RskHi '  + '%.0f' % p['risk_hi']  
        ))  
    if do_summary: _pvr(c)  
    if get_datetime() == get_environment('end'):   # Summary at end of run  
        _pvr(c) ; elapsed = (time.time() - p['begin']) / 60  # minutes  
        log.info( '{}\nRuntime {} hr {} min'.format(p['run_str'], int(elapsed / 60), '%.1f' % (elapsed % 60)))

def handle_data(context, data): 
    pvr(context, data)
    c = context
    if c.ShowMaxLev:
        if c.account.leverage > c.mx_lvrg:  
            c.mx_lvrg = c.account.leverage  
            record(mx_lvrg = c.mx_lvrg)    # Record maximum leverage encountered

    ##
    # Buy XIV
    ##
    if c.ShortVIX and not c.BoughtShortVIX and not c.SellAndWait:
        PriceXIV = data.current(c.XIV, 'price')
        if not c.PriceXIV: c.PriceXIV = PriceXIV
        if PriceXIV < c.PriceXIV:
            c.PriceXIV = PriceXIV
        elif PriceXIV > 1.0025 * c.PriceXIV:
            c.BoughtShortVIX = True
            TarPer(context, data, c.XIV, c.VIX_GrowthLeverage)

    ##
    # Buy UVXY
    ##
    if c.LongVIX and not c.BoughtLongVIX and not c.SellAndWait:
        PriceUVXY = data.current(c.UVXY, 'price')
        if not c.PriceUVXY: c.PriceUVXY = PriceUVXY
        if PriceUVXY < c.PriceUVXY:
            c.PriceUVXY = PriceUVXY
        elif PriceUVXY > 1.005 * c.PriceUVXY:
            c.BoughtLongVIX = True
            TarPer(context, data, c.UVXY, c.VIX_HedgeLeverage)

    ##
    # RogueTrader here and in RogueTrader scheduled function
    ##
    if c.RogueTrader and not c.SellAndWait:
        for position in c.portfolio.positions.itervalues():
            if (position.sid in c.VIXstocks) or (position.sid in c.SetAsideStocks):
                if position.amount == 0:
                    if position.asset.symbol in c.stops: del c.stops[position.asset.symbol]
                    continue
                elif position.asset.symbol not in c.stops:
                    stoploss= c.stoploss if position.amount > 0 else -c.stoploss
                    c.stops[position.asset.symbol]=position.last_sale_price*(1-stoploss)
                    #log.info(' ! I have added '+str(position.asset.symbol)+' to Stops @ '+str((position.last_sale_price)*(1-stoploss)))
                elif c.stops[position.asset.symbol] < position.last_sale_price*(1- c.stoploss) and position.amount > 0:
                    c.stops[position.asset.symbol]=position.last_sale_price*(1- c.stoploss)
                    #log.info(' ! I have updated '+str(position.asset.symbol)+'- (Long) to stop @ '+str((position.last_sale_price)*(1- c.stoploss)))
                elif c.stops[position.asset.symbol] > position.last_sale_price and position.amount > 0:
                    #sell
                    log.info(' ! '+str(position.asset.symbol)+'- (Long) has hit stoploss @ '+str(position.last_sale_price))
                    if get_open_orders(position.sid): cancel_open_orders_for(context, data, position.sid)
                    c.stoppedout.append(position.asset.symbol)
                    TarPer(context, data, position.sid, 0.00)
     
                ##
                # Sell and Wait
                ##
                if (
                        (position.sid is c.XIV and 0 < position.amount)
                        and
                        (10.76 < c.vix < 12) and (position.last_sale_price > 1.013 * c.XIVprice)
                ):
                    c.SellAndWait = 1
                elif (
                        (position.sid is c.UVXY and 0 < position.amount)
                        and
                        (position.last_sale_price > 1.40 * c.UVXYprice)
                ):
                    c.SellAndWait = 3

        ##
        # Sell and Wait
        ##
        if 0 < c.SellAndWait:
            for stock in c.portfolio.positions:
                    if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                        cancel_open_orders_for(context, data, stock)
                        TarPer(context, data, stock, 0.00)

def CherryPickerClose(context,data):    
    
    c = context
    vxx_prices = data.history(c.VXX, "high", c.wvf_length*2, "1d")
    vxx_lows = data.history(c.VXX, "low", c.wvf_length*2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.wvf_length, center=False).max()
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100

    rsi = talib.RSI(vxx_prices, timeperiod=c.rsi_length)
    
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.ema1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.ema2)
    
    ## BUY RULES
    #if WVF crosses over smoothwvf1 and wvf < smoothwvf2
    if (
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] < c.SmoothedWVF2[-1])
        or
        (c.SmoothedWVF1[-2] < c.SmoothedWVF2[-2] and c.SmoothedWVF1[-1] > c.SmoothedWVF2[-1])
        or
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-2])
    ):
        c.sell = False
        for stock in c.portfolio.positions:
            if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                if stock is not c.XIV:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 0.00)
                else:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 1.00)
      
    ## SELL RULES
    if c.portfolio.positions[c.XIV].amount > 0:
        #if rsi crosses over rsi_trigger
        if rsi[-2] < c.rsi_trigger and rsi[-1] > c.rsi_trigger:
            c.sell = True
            
        #if wvf crosses under smoothwvf2: sell
        elif WVF[-2] > c.SmoothedWVF2[-2] and WVF[-1] < c.SmoothedWVF2[-1]:
            c.sell = True

        else:
            c.sell = False
There was a runtime error.
50 responses

I was comparing this and the previous algorithm (without extreme vetting ) and noticed that consistently this algorithm had substantially higher leverage swings.

Besides just setting leverage to a certain value ( context.account.leverage , which still provides some swings), in theory what other ways can you control leverage?

I imagine a text book would say alter your (long value + abs(short_value)) / context.portfolio.portfolio_value ratio. Although, I feel like there would still be a lot of underlying variables that also cause leverage swings.

With Robinhood accounts, selling short is not currently allowed. So that is not an option. Not sure about other methods.

I imagined that would play a factor.

Does it have something to do with trading volume of the stock and the time delay between bid and purchase?

This version may not be as profitable long term as much as Robin Hood VIX Mix Rogue Trader. At least that is what back testing shows. If that worries you, then stick with Rogue Trader.

Oh, I am not trading. I was just wondering. Don't worry about me. :)

When the low volume stock is bought, you will get rejected sell limit orders, because it may cause Pattern Day Trader. The fix for that is to have $25,000 or more in your trading account. Again, if these are issues that concern you, probably stick with Rogue Trader.

Also, I am still working on tweaking position sizing and ordering to have fewer rejected orders.

Still a work in progress. I think there will be less rejected buy orders now. I added a couple of lines to TarPer function to limit the size of the order.
Because this is a work in progress, you may want to remain with Rogue Trader.

Clone Algorithm
380
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
from datetime import datetime  
import functools
import itertools
from itertools import cycle
import math
import numpy as np
import pandas as pd
from pytz import timezone      
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.factors import SimpleMovingAverage, AverageDollarVolume
from quantopian.pipeline.filters.morningstar import IsPrimaryShare
import re
from scipy import stats
import talib
import time
from zipline.utils import tradingcalendar

DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT = 0.20
History = 128

def initialize(context):

    ##
    # ExtremeVetting
    ##

    context.MaxCandidates=390 #6.5*60
    context.EveryThisManyMinutes=15
    context.MaxBuyOrdersAtOnce=context.EveryThisManyMinutes
    context.MyLeastPrice=2.00
    context.MyMostPrice=5.00
    context.MyRetreatPrice=context.MyLeastPrice
    context.MyRetreatAge=3
    context.MyDaysPerPennyReduction=0.33
    context.MyMinPurchase=1000
    context.MyMaxPurchase=25000
    context.EV_BuyFactor=.90
    context.SellFactor=1.08

    # over simplistic tracking of position age
    context.age={}
    print len(context.portfolio.positions)

    # ExtremeVetting
    EveryThisManyMinutes=context.EveryThisManyMinutes
    TradingDayHours=6.5
    TradingDayMinutes=int(TradingDayHours*60)
    for minutez in xrange(
        0, 
        TradingDayMinutes, 
        EveryThisManyMinutes
    ):
        if minutez >= 1:
            schedule_function(ExtremeVetting, date_rules.every_day(), time_rules.market_open(minutes=minutez))
        else:
            schedule_function(ExtremeVetting, date_rules.every_day(), time_rules.market_open())

    # Create our pipeline and attach it to our algorithm.
    my_pipe = make_pipeline(context)
    attach_pipeline(my_pipe, 'my_pipeline')

    ##
    # CherryPicker
    ##

    context.rsi_length = 3
    context.rsi_trigger = 50
    context.wvf_length = 100
    context.ema1 = 10
    context.ema2 = 30
    context.sell = False

    ##
    # Not CherryPicker Not ExtremeVetting
    ##
    
    vixUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv'
    vxvUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vxvdailyprices.csv'
    nokoUrl = 'http://52.15.233.150/noko.csv'  
    
    fetch_csv(nokoUrl, 
              symbol='v1', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX1, 
              post_func=shift_data)
    
    fetch_csv(nokoUrl, 
              symbol='v2', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX2, 
              post_func=shift_data)

    fetch_csv(vixUrl, 
              symbol='v', 
              skiprows=1,
              date_column='Date', 
              pre_func=addFieldsVIX,
              post_func=shift_data)

    fetch_csv(vxvUrl, 
              symbol='vxv', 
              skiprows=2,
              date_column='Date', 
              pre_func=addFieldsVXV,
              post_func=shift_data)

    context.xiv = sid(40516)
    context.tqqq = sid(39214)
    context.uvxy = sid(41969)
    context.spyg = sid(22009)
    
    context.vix = -1
    context.xiv_day = 0
    set_benchmark(context.xiv) # ALPHA and BETA will be different
    set_slippage(myVolumeShareSlippage(volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT, price_impact=0.0))
    set_commission(commission.PerTrade(cost=0.00))
    
    context.SetAsideLeverageTotal = 0.20 # 100% allocate when BigSignalTQQQ
    context.VIX_GrowthLeverage    = 1 - context.SetAsideLeverageTotal
    context.VIX_MinHedgeLeverage  = context.VIX_HedgeLeverage  = 0.666
    context.VIX_MaxHedgeLeverage  = 1.00 # if certain conditions are met
    context.ShowMaxLev            = True

    # 3x NASDAQ nonfinancial, generally profitable
    context.SetAsideStocks = symbols('TQQQ')

    context.PriceXIV = context.PriceUVXY = 0.00
    context.BoughtShortVIX = context.BoughtLongVIX = False
    context.XIV       = symbol('XIV')
    context.UVXY      = symbol('UVXY') # approx 8% weekly erosion, bigger spikes
    context.VIXstocks = (context.XIV, context.UVXY)
    context.LongVIX  = False  # no decisions until one of three conditions exists
    context.ShortVIX = False  # no decisions until one of three conditions exists
    # not necessary to set BigSignal variables because they get set by MoreSignals function early every day
    
    # apparently highly successful VIX signals
    schedule_function(CherryPickerOpen, date_rules.every_day(), time_rules.market_open(), False)
    schedule_function(MoreSignals, date_rules.every_day(), time_rules.market_open(minutes = 2))
    schedule_function(VIX_Mix, date_rules.every_day(), time_rules.market_open(minutes = 4))
    schedule_function(RogueTrader, date_rules.every_day(),time_rules.market_open(minutes = 60))
    schedule_function(cancel_open_orders, date_rules.every_day(), time_rules.market_close())    
    schedule_function(RecordVars, date_rules.every_day(), time_rules.market_close())    
    schedule_function(CherryPickerClose, date_rules.every_day(), time_rules.market_close(), False)

    #VXX used for strategy to buy XIV
    context.VXX = context.vxx = sid(38054) # VXX

    #Editable values to tweak backtest
    context.AvgLength = 20
    context.LengthWVF = 100
    context.LengthEMA1 = 10
    context.LengthEMA2 = 30
    
    #internal variables to store data
    context.vxxAvg = 0 
    context.SmoothedWVF1 = 0
    context.SmoothedWVF2 = 0
    context.vxxLow = 0
    context.vxxHigh = 0
    
    #Internal stop variables
    # context.stoploss is set in RogueTrader
    context.stoploss = 0.50
    context.stops         = {}
    context.stoppedout    = []
    context.SellAndWait   = 0

class myVolumeShareSlippage(slippage.SlippageModel):
    """Model slippage as a function of the volume of shares traded.
    """

    def __init__(self, volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT,
                 price_impact=0.1):

        self.volume_limit = volume_limit
        self.price_impact = price_impact

        slippage.SlippageModel.__init__(self)

    def process_order(self, data, order):
        volume = data.current(order.asset, "volume")

        max_volume = self.volume_limit * volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return None, None

        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return None, None

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / volume,
                           self.volume_limit)

        price = data.current(order.asset, "close")

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * price
        impacted_price = price + simulated_impact

        if order.limit:
            # this is tricky! if an order with a limit price has reached
            # the limit price, we will try to fill the order. do not fill
            # these shares if the impacted price is worse than the limit
            # price. return early to avoid creating the transaction.

            # buy order is worse if the impacted price is greater than
            # the limit price. sell order is worse if the impacted price
            # is less than the limit price
            if (order.direction > 0 and impacted_price > order.limit) or \
                    (order.direction < 0 and impacted_price < order.limit):
                return None, None
            
            # For marketable limit orders the price is 'impacted_price'
            # (that is current price + slippage) but for non-marketable
            # limit order the price must be the limit price.
            # To put it simple, if the market "goes through" the level
            # of a limit order (non-marketable) we have to use the limit
            # price, otherwise the 'impacted_price'
            # To disinguish between marketable and non-marketable limit
            # order we can use the following good approximation:
            # if both open and close price are below/above (buy/sell)
            # the limit price the order is markettable
            # if open price is above (or below for sell) limit price
            # and close price is below (or above for sell) limit pirce,
            # then the order is non-marketable
            
            open_price = data.current(order.asset, "open")
            # Note: no need to check for close price if we are here
            non_marketable = (order.direction > 0 and open_price > order.limit) or \
                             (order.direction < 0 and open_price < order.limit)
                
            if non_marketable:
                impacted_price = order.limit
                
            #print '%d limit %f open %f close %f marketable %s final price %f' % (order.direction, order.limit, open_price, price, not non_marketable, impacted_price)

        return (
            impacted_price,
            math.copysign(cur_volume, order.direction)
        )

def make_pipeline(context):
    """
    Create our pipeline.
    """

    # Filter for primary share equities. IsPrimaryShare is a built-in filter.
    primary_share = IsPrimaryShare()

    # Equities listed as common stock (as opposed to, say, preferred stock).
    # 'ST00000001' indicates common stock.
    common_stock = morningstar.share_class_reference.security_type.latest.eq('ST00000001')

    # Non-depositary receipts. Recall that the ~ operator inverts filters,
    # turning Trues into Falses and vice versa
    not_depositary = ~morningstar.share_class_reference.is_depositary_receipt.latest

    # Equities not trading over-the-counter.
    not_otc = ~morningstar.share_class_reference.exchange_id.latest.startswith('OTC')

    # Not when-issued equities.
    not_wi = ~morningstar.share_class_reference.symbol.latest.endswith('.WI')

    # Equities without LP in their name, .matches does a match using a regular
    # expression
    not_lp_name = ~morningstar.company_reference.standard_name.latest.matches('.* L[. ]?P.?$')

    # Equities with a null value in the limited_partnership Morningstar
    # fundamental field.
    not_lp_balance_sheet = morningstar.balance_sheet.limited_partnership.latest.isnull()

    # Equities whose most recent Morningstar market cap is not null have
    # fundamental data and therefore are not ETFs.
    have_market_cap = morningstar.valuation.market_cap.latest.notnull()

    # At least a certain price
    price = USEquityPricing.close.latest
    AtLeastPrice   = (price >= context.MyLeastPrice)
    AtMostPrice    = (price <= context.MyMostPrice)

    # Filter for stocks that pass all of our previous filters.
    tradeable_stocks = (
        primary_share
        & common_stock
        & not_depositary
        & not_otc
        & not_wi
        & not_lp_name
        & not_lp_balance_sheet
        & have_market_cap
        & AtLeastPrice
        & AtMostPrice
    )

    LowVar=6
    HighVar=40

    log.info('\nAlgorithm initialized variables:\n context.MaxCandidates %s \n LowVar %s \n HighVar %s'
        % (context.MaxCandidates, LowVar, HighVar)
    )

    # High dollar volume filter.
    base_universe = AverageDollarVolume(
        window_length=20,
        mask=tradeable_stocks
    ).percentile_between(LowVar, HighVar)

    # Short close price average.
    ShortAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=3,
        mask=base_universe
    )

    # Long close price average.
    LongAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=45,
        mask=base_universe
    )

    percent_difference = (ShortAvg - LongAvg) / LongAvg

    # Filter to select securities to long.
    stocks_worst = percent_difference.bottom(context.MaxCandidates)
    securities_to_trade = (stocks_worst)

    return Pipeline(
        columns={
            'stocks_worst': stocks_worst
        },
        screen=(securities_to_trade),
    )

def my_compute_weights(context):
    """
    Compute ordering weights.
    """
    # Compute even target weights for our long positions and short positions.
    stocks_worst_weight = 1.00/len(context.stocks_worst)

    return stocks_worst_weight

def before_trading_start(context, data):
    # Gets our pipeline output every day.
    context.output = pipeline_output('my_pipeline')
    context.stocks_worst = context.output[context.output['stocks_worst']].index.tolist()
    context.stocks_worst_weight = my_compute_weights(context)
    context.MyCandidate = cycle(context.stocks_worst)

    for stock in context.portfolio.positions:
        if stock in context.age:
            context.age[stock] += 1
        else:
            context.age[stock] = 1
    for stock in context.age:
        if stock not in context.portfolio.positions:
            context.age[stock] = 0

    context.RogueTrader = False # Not True until RogueTrader scheduled function runs

    context.mx_lvrg  = 0 # reset for recording daily max leverage

    # To help determine previous signal when start algo in live trade Robinhood
    if not context.ShortVIX and not context.LongVIX: # Maybe we can figure it out
        context.ShortVIX = True if 0 < context.portfolio.positions[context.XIV].amount  else False
        context.LongVIX  = True if 0 < context.portfolio.positions[context.UVXY].amount else False
        if context.ShortVIX and context.LongVIX: # Do no harm
            context.ShortVIX = context.LongVIX = False

def RecordVars(context, data):
    
    # handling this in handle_data now to show mx_lvrg
    if not context.ShowMaxLev:
        record(Leverage=context.account.leverage)
        pass

def CherryPickerOpen(context,data):
    c = context
    if c.sell:
        c.sell = False
        if c.portfolio.positions[c.XIV].amount > 0: 
            cancel_open_orders_for(context, data, c.XIV)
            TarPer(context, data, c.XIV, 0.00)
            
def RogueTrader(context, data):

    c = context
    c.RogueTrader = True # Not True until RogueTrader scheduled function runs

    cancel_open_orders(context, data)

    ##
    # Limit sell and Stop loss orders
    ##
    for stock in c.portfolio.positions:

        # Set stoploss
        c.stoploss = 0.21 if stock is c.UVXY else 0.035

        # Set LimitPrice for first order
        RemainingFactor  = 0.50 if stock is c.UVXY else 0.22
        MaxOrders        = 20   if stock is c.UVXY else 3
        if stock is c.UVXY:
            LimitPriceFactor = 1.06 if c.Agree else 1.05
        else:
            LimitPriceFactor = 1.04
        LimitPrice       = LimitPriceFactor * c.portfolio.positions[stock].cost_basis

        SharesRemaining = int(RemainingFactor * c.portfolio.positions[stock].amount)
        SharesPerOrder  = min(SharesRemaining, max(100, int(SharesRemaining / MaxOrders)))
        
        while 0 < SharesRemaining:

            order(stock, -SharesPerOrder, style=LimitOrder(LimitPrice))
            
            SharesRemaining -= SharesPerOrder
            SharesPerOrder = min(SharesRemaining, SharesPerOrder)
            LimitPrice *= LimitPriceFactor 
        if stock.symbol in c.stops: del c.stops[stock.symbol]
        
def TarPer(context, data, stock, TargetPercent):

    if DataCanTrade(context, data, stock):

        if 0 == TargetPercent:
            order_target_percent(stock, 0.00)
        else:
            # Always want money available to withdraw 
            # and also try to prevent margin related order rejections
            PV = context.portfolio.portfolio_value
            DoNotSpend = 2000 # 200 Cushion plus cash for withdrawals
            RhMargin = 24000.00 # Set to 0 if you do not have Robinhood Gold
            MaxLeverage = 1.33 - .12 # Hard Limit for leverage minus seemingly necessary cushion
            MaxLeverage = min(MaxLeverage, max(MaxLeverage, context.account.leverage))
            RhMargin = min(RhMargin, PV * (MaxLeverage - 1))
            RhPV = PV + RhMargin - DoNotSpend  
            RhCash = RhPV - context.portfolio.positions_value
            amount = context.portfolio.positions[stock].amount
            price = data.current(stock, 'price')
            PosValue   = float(amount * price)
            TarValue   = float(RhPV * TargetPercent)
            DiffValue  = float(TarValue - PosValue)
            DiffValue  = min(DiffValue, RhCash)
            DiffAmount = int(DiffValue / price)
            DiffAmount = 0 if 0 > DiffAmount and 0 == amount else DiffAmount
            order(stock, DiffAmount)

        if stock.symbol in context.stops: del context.stops[stock.symbol]

def DataCanTrade(context, data, stock):

    try:
        if data.can_trade(stock):
            return True
        else:
            return False
    except:
        return False

def ExtremeVetting(context, data):
    c = context
    cash = c.portfolio.cash
    PValue = c.portfolio.portfolio_value

    cancel_open_buy_orders(context, data)

    # Order sell at profit target in hope that somebody actually buys it
    for stock in c.portfolio.positions:
        if not get_open_orders(stock):
            StockShares = c.portfolio.positions[stock].amount
            CurrPrice = float(data.current([stock], 'price'))
            CostBasis = float(c.portfolio.positions[stock].cost_basis)
            SellPrice = float(make_div_by_05(CostBasis*c.SellFactor, buy=False))
            if np.isnan(SellPrice):
                pass # probably best to wait until nan goes away
            elif (
                stock in c.age 
                and c.MyRetreatAge<=c.age[stock] 
                and (
                    c.MyRetreatPrice>CurrPrice
                    or CostBasis>CurrPrice
                )
            ):
                SellPrice = float(
                    CostBasis-(
                        c.age[stock]/(100.00*c.MyDaysPerPennyReduction)
                    )
                )
                SellPrice = .50 if .50 > SellPrice else SellPrice
                SellPrice = float(make_div_by_05(SellPrice, buy=False))
                order(stock, -StockShares,
                    style=LimitOrder(SellPrice)
                )
            else:
                order(stock, -StockShares,
                    style=LimitOrder(SellPrice)
                )

    WeightFactor = .33 if cash > .33 * PValue else 1
    WeightThisBuyOrder=float(WeightFactor * 1.00 / c.MaxBuyOrdersAtOnce)
    MaxBuyOrdersAtOnce = 1 if cash < c.MyMinPurchase * c.MaxBuyOrdersAtOnce else c.MaxBuyOrdersAtOnce        
    for ThisBuyOrder in range(MaxBuyOrdersAtOnce):
        stock = c.MyCandidate.next()
        PHshort = data.history([stock], 'price', 5, '1d')
        PHshortAvg = float(PHshort.mean())
        PHlong = data.history([stock], 'price', 40, '1d')
        PHlongAvg = float(PHlong.mean())
        CurrPrice = float(data.current([stock], 'price'))
        if PHshortAvg < PHlongAvg * c.EV_BuyFactor:
            if cash >= c.MyMinPurchase * MaxBuyOrdersAtOnce:
                if c.MyMinPurchase > WeightThisBuyOrder*cash:
                    Purchase=c.MyMinPurchase
                elif c.MyMaxPurchase < WeightThisBuyOrder*cash:
                    Purchase=c.MyMaxPurchase
                else:
                    Purchase=WeightThisBuyOrder*cash
                StockSharesToOwn = int(Purchase/CurrPrice)
                StockValueTarget = StockSharesToOwn * CurrPrice
                StockTarPer = StockValueTarget / PValue
                TarPer(context, data, stock, StockTarPer)

#if cents not divisible by .05, round down if buy, round up if sell
def make_div_by_05(s, buy=False):
    s *= 20.00
    s =  math.floor(s) if buy else math.ceil(s)
    s /= 20.00
    return s

def cancel_open_buy_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
            if 0<order.amount: #it is a buy order
                cancel_order(order)

def cancel_open_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            cancel_order(order)
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
    
def cancel_open_orders_for(context, data, security):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            if stock is security:
                if order.amount < context.portfolio.positions[stock].amount:
                    cancel_order(order)
                    #message = 'Canceling order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                else: # Do NOT want to cancel stop loss order
                    #message = 'NOT Canceling stop loss order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                    pass

def MoreSignals(context, data):  

    update_indices(context, data)     
    last_vix = context.VIXprice = data.current('v', 'Close')
    last_vx1 = data.current('v1','Close')  
    last_vx2 = data.current('v2','Close')      
    last_vxv = data.current('vxv', 'Close')
    last_vix_200ma_ratio = data.current('v', '200ma Ratio')
           
    # Calculating the gap between spot vix and the first month vix future
    last_ratio_v_v1 = last_vix/last_vx1

    # Calculating the contango ratio of the front and second month VIX Futures 
    last_ratio_v1_v2 = last_vx1/last_vx2

    # Blending the previous two ratios together using a weighted average
    ratio_weight = 0.7
    last_ratio = (ratio_weight*last_ratio_v_v1) + ((1-ratio_weight)*last_ratio_v1_v2) - 1
    
    vix_vxv_ratio = last_vix/last_vxv
    
    # Retrieve SPY prices for technical indicators
    prices = data.history(context.spyg, 'open', 40, '1d')
    
    # Retrieve SPY MACD data
    macda, signal, hist = talib.MACD(prices, fastperiod=12,slowperiod=26,signalperiod=9)
    macd = macda[-1] - signal[-1]
    
    # Calculate how much vix moved the previous day
    if (context.vix <> -1) : 
        vix_ratio = last_vix/context.vix -1
    else :
        vix_ratio = 0
    context.vix = last_vix
    
    xiv_history = data.history(context.xiv, 'price', 2, '1d')  
    
    xiv_ratio = xiv_history[1]/xiv_history[0] - 1
    
    # Setting thresholds
    threshold_vix_too_low = 10.76   # 0 
    threshold_vix_200ma_ratio_low = 0.79  # 0 
    threshold_xiv = -0.049          # 1
    threshold_vxv_xiv = 0.87        # 2
    threshold_uvxy = 0.049          # 3
    threshold_macd = -0.55          # 3
    threshold_vxv_uvxy = 1.3        # 4
    threshold_vix_high = 19.9       # 5
    threshold_vc_low = -0.148       # 6
    threshold_vc_high = 0.046       # 8
    threshold_vc_high_2 = -0.06     # 8
    threshold_xiv_ratio = -0.053    # 10
    threshold_uvxy_ratio = 0.08     # 11

    # 0
    if last_vix < threshold_vix_too_low and last_vix_200ma_ratio < threshold_vix_200ma_ratio_low: # if VIX is too low, invest in UVXY witht he hope of a spike
        target_sid = context.uvxy
    # 1        
    elif last_ratio < threshold_xiv: # if contango is high, invest in XIV to gain from decay
        target_sid = context.xiv
    
    # 2
    elif vix_vxv_ratio < threshold_vxv_xiv: # if short term vol is low compared to mid term, invest in XIV to gain from decay
        target_sid = context.xiv

    # 3
    elif last_ratio > threshold_uvxy and macd > threshold_macd: # if backwardation is high, invest in UVXY to gain from decay
        target_sid = context.uvxy

    # 4
    elif vix_vxv_ratio > threshold_vxv_uvxy: # if short term vol is high compared to mid term, invest in UVXY to gain from growth
        target_sid = context.uvxy

    # 5
    elif last_vix > threshold_vix_high: # if VIX is too high, invest in XIV expecting that VIX will drop
        target_sid = context.xiv

    # 6
    elif vix_ratio < threshold_vc_low: # Vix down sharply, invest in XIV expecting that futures curve gets pulled down
        target_sid = context.xiv

    # 7
    elif vix_ratio > threshold_vc_high: # Vix up sharply, invest in UVXY expecting that futures curve gets pulled up
        target_sid = context.uvxy

    # 8
    elif vix_ratio > threshold_vc_high_2: #have to think
        target_sid = context.xiv

    # 9
    else:
        target_sid = context.uvxy

    # 10
    if (target_sid == context.xiv and xiv_ratio < threshold_xiv_ratio) : 
        # indicators say XIV but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq 

    # 11
    elif (target_sid == context.uvxy and xiv_ratio > threshold_uvxy_ratio) :
        # indicators say UVXY but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq
    
    context.BigSignalShortVIX = True if context.xiv  is target_sid else False
    context.BigSignalLongVIX  = True if context.uvxy is target_sid else False
    context.BigSignalTQQQ     = True if context.tqqq is target_sid else False
    
def VIX_Mix(context, data):
    c = context
    
    if 0 < c.SellAndWait:
        c.SellAndWait -= 1
        return

    cancel_open_orders(context, data) # avoid confusion

    ### Determine how much to risk in Long VIX ###
    # Load historical data for the stocks  
    hist = data.history(c.vxx, ['high', 'low', 'close'], 15, '1d')  
    # Calculate the ATR for the stock  
    atr_14 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=14)[-1]  
    atr_3 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=3)[-1]
    c.VIX_HedgeLeverage = c.VIX_MaxHedgeLeverage if atr_3 <= atr_14 else c.VIX_MinHedgeLeverage

    #Gets Moving Average of VXX
    price_hist = data.history(c.vxx, 'price', c.AvgLength, '1d')
    c.vxxAvg = price_hist.mean()
    
    #get data for calculations
    n = 200
    vxx_prices = data.history(c.vxx, "price", n + 2, "1d")
    vxx_lows = data.history(c.vxx, "low", n + 2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.LengthWVF,center=False).max()
    
    #William's VIX Fix indicator a.k.a. the Synthetic VIX
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100
    
    # calculated smoothed WVF
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.LengthEMA1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.LengthEMA2)
    
    #Do some checks for cross overs. 
    if WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-1]:
        wvf_crossedSmoothedWVF1 = True
    else: 
        wvf_crossedSmoothedWVF1 = False
    #Same except for smoothed2 
    if WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-1]:
        wvf_crossedSmoothedWVF2 = True
    else: 
        wvf_crossedSmoothedWVF2 = False
    
    #Current price of vxx
    vxxPrice = data.current(c.vxx, 'price')
    
    #SignalShortVIX 
    if ( wvf_crossedSmoothedWVF1 and WVF[-1] < c.SmoothedWVF2[-1]) or (wvf_crossedSmoothedWVF2 and wvf_crossedSmoothedWVF1):
        SignalShortVIX = True
    elif ((vxxPrice > c.vxxAvg and vxx_prices[-2] < c.vxxAvg) or (WVF[-1] < c.SmoothedWVF2[-1] and WVF[-2] > c.SmoothedWVF2[-1])):
        SignalShortVIX = False
    else:
        SignalShortVIX = True

    if (c.BigSignalShortVIX and SignalShortVIX): # Agree ShortVIX
        c.ShortVIX    = True
        c.LongVIX     = False
        c.Agree       = True

    elif (c.BigSignalLongVIX and not SignalShortVIX): # Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = True

    elif (c.BigSignalLongVIX and SignalShortVIX): # Not Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = False

    for stock in c.portfolio.positions:
        if stock not in c.VIXstocks and stock not in c.SetAsideStocks:
            TarPer(context, data, stock, 0.00)

    ##
    # VIX_Mix only once until signal changes again
    # or
    # leverage drops too low
    ##

    l = c.account.leverage
    LevTooLow = True if (0.33 > l) or (0.90 < l < 1.05) else False
    p = c.portfolio.positions

    if c.BigSignalTQQQ:
        if LevTooLow or (c.XIV in p or c.UVXY in p):
            TarPer(context, data, c.XIV, 0.00)
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(1.00 / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)

    elif c.ShortVIX:
        if LevTooLow or (c.XIV not in p):
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(c.SetAsideLeverageTotal / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)
            c.BoughtShortVIX = False
            c.PriceXIV = 0.00

    elif c.LongVIX:
        if LevTooLow or (c.UVXY not in p):
            TarPer(context, data, c.XIV, 0.00)
            for stock in c.SetAsideStocks:
                TarPer(context, data, stock, 0.00)
            c.BoughtLongVIX = False
            c.PriceUVXY = 0.00

    # Record / log stuff I want to know
    c.XIVprice  = data.current(c.XIV, 'price')
    c.UVXYprice = data.current(c.UVXY, 'price')
    TQQQprice = data.current(c.tqqq, 'price')
    #record(XIV  = c.XIVprice)
    #record(UVXY = c.UVXYprice)
    #record(TQQQ = TQQQprice)
    BigSignal = 'NoBigSignal'
    BigSignal = 'ShortVIX' if c.BigSignalShortVIX else BigSignal
    BigSignal = ' LongVIX' if c.BigSignalLongVIX  else BigSignal
    BigSignal = '    TQQQ' if c.BigSignalTQQQ     else BigSignal
    SyntheticVIX = 'NoSyntheticVIX'
    SyntheticVIX = 'ShortVIX' if c.ShortVIX else SyntheticVIX
    SyntheticVIX = ' LongVIX' if c.LongVIX  else SyntheticVIX
    log.info('BigSignal / SyntheticVIX: {} / {}     VIX: {:.2f}     XIV: {:.2f}     UVXY: {:.2f}     TQQQ: {:.2f}'
        .format(BigSignal, SyntheticVIX, c.VIXprice, c.XIVprice, c.UVXYprice, TQQQprice)
    )

def update_indices(context, data):
    context.fetch_failed = False
    context.vix_vals = unpack_from_data(context, data, 'v')    
    context.vxv_vals = unpack_from_data(context, data, 'vxv')  
    context.vx1_vals = unpack_from_data(context, data, 'v1')
    context.vx2_vals = unpack_from_data(context, data, 'v2')

def fix_close(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%m/%d/%Y')))
    df = df.sort_values(by='Date', ascending=True)
    return df

def fix_closeVX(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%Y-%m-%d')))
    df = df.sort_values(by='Date', ascending=True)
    return df


def subsequent_trading_date(date):
    tdays = tradingcalendar.trading_days
    last_date = pd.to_datetime(date)
    last_dt = tradingcalendar.canonicalize_datetime(last_date)
    next_dt = tdays[tdays.searchsorted(last_dt) + 1]
    return next_dt

def add_last_bar(df):
    last_date = df.index[-1]
    subsequent_date = subsequent_trading_date(last_date)
    blank_row = pd.Series({}, index=df.columns, name=subsequent_date)
    # add today, and shift all previous data up to today. This 
    # should result in the same data frames as in backtest
    df = df.append(blank_row).shift(1).dropna(how='all')
    return df

def shift_data(df):
    df = add_last_bar(df)
    df.fillna(method='ffill') 
    df['PrevCloses'] = my_rolling_apply_series(df['Close'], to_csv_str, History)
    dates = pd.Series(df.index)
    dates.index = df.index
    df['PrevDates'] = my_rolling_apply_series(dates, to_csv_str, History)
    return df

def unpack_from_data(context, data, sym):
    try:
        v = data.current(sym, 'PrevCloses')
        i = data.current(sym, 'PrevDates')
        return from_csv_strs(i,v,True).apply(float)
    except:
        log.warn("Unable to unpack historical {s} data.".format(s=sym))
        context.fetch_failed = True

def addFieldsVIX(df):
    df = fix_close(df,'VIX Close')
    df['200ma'] = df['Close'].rolling(200).mean()
    df['200ma Ratio'] = df['Close'] / df['200ma']

    return df

def addFieldsVXV(df):
    df.rename(columns={'Unnamed: 0': 'Date'}, inplace=True)
    df = fix_close(df,'CLOSE')
    return df

def addFieldsVX1(df):
    df = fix_closeVX(df,'F1')
    return df

def addFieldsVX2(df):
    df = fix_closeVX(df,'F2')
    return df

# convert a series of values to a comma-separated string of said values
def to_csv_str(s):
    return functools.reduce(lambda x,y: x+','+y, pd.Series(s).apply(str))

# a specific instance of rolling apply, for Series of any type (not just numeric,
# ala pandas.rolling_apply), where the index of the series is set to the indices
# of the last elements of each subset
def my_rolling_apply_series(s_in, f, n):
    s_out = pd.Series([f(s_in[i:i+n]) for i in range(0,len(s_in)-(n-1))]) 
    s_out.index = s_in.index[n-1:]
    return s_out

# reconstitutes a Series from two csv-encoded strings, one of the index, one of the values
def from_csv_strs(x, y, idx_is_date):
    s = pd.Series(y.split(','),index=x.split(','))
    if (idx_is_date):
        s.index = s.index.map(lambda x: pd.Timestamp(x))
    return s

def pvr(context, data):
    ''' Custom chart and/or logging of profit_vs_risk returns and related information from https://www.quantopian.com/posts/pvr#569784bda73e9bf2b7000180
    '''  
    #import time  
    #from datetime import datetime  
    #from pytz import timezone      # Python will only do once, makes this portable.  
                                   #   Move to top of algo for better efficiency.  
    c = context  # Brevity is the soul of wit -- Shakespeare [for readability]  
    if 'pvr' not in c:

        # For real money, you can modify this to total cash input minus any withdrawals  
        manual_cash = c.portfolio.starting_cash  
        time_zone   = 'US/Central'   # Optionally change to your own time zone for wall clock time

        c.pvr = {  
            'options': {  
                # # # # # # # # # #  Options  # # # # # # # # # #  
                'logging'         : 0,    # Info to logging window with some new maximums  
                'log_summary'     : 126,  # Summary every x days. 252/yr

                'record_pvr'      : 1,    # Profit vs Risk returns (percentage)  
                'record_pvrp'     : 0,    # PvR (p)roportional neg cash vs portfolio value  
                'record_cash'     : 1,    # Cash available  
                'record_max_lvrg' : 0,    # Maximum leverage encountered  
                'record_risk_hi'  : 0,    # Highest risk overall  
                'record_shorting' : 0,    # Total value of any shorts  
                'record_max_shrt' : 0,    # Max value of shorting total  
                'record_cash_low' : 0,    # Any new lowest cash level  
                'record_q_return' : 0,    # Quantopian returns (percentage)  
                'record_pnl'      : 1,    # Profit-n-Loss  
                'record_risk'     : 1,    # Risked, max cash spent or shorts beyond longs+cash  
                'record_leverage' : 0,    # End of day leverage (context.account.leverage)  
                # All records are end-of-day or the last data sent to chart during any day.  
                # The way the chart operates, only the last value of the day will be seen.  
                # # # # # # # # #  End options  # # # # # # # # #  
            },  
            'pvr'        : 0,      # Profit vs Risk returns based on maximum spent  
            'cagr'       : 0,  
            'max_lvrg'   : 0,  
            'max_shrt'   : 0,  
            'risk_hi'    : 0,  
            'days'       : 0.0,  
            'date_prv'   : '',  
            'date_end'   : get_environment('end').date(),  
            'cash_low'   : manual_cash,  
            'cash'       : manual_cash,  
            'start'      : manual_cash,  
            'tz'         : time_zone,  
            'begin'      : time.time(),  # For run time  
            'run_str'    : '{} to {}  ${}  {} {}'.format(get_environment('start').date(), get_environment('end').date(), int(manual_cash), datetime.now(timezone(time_zone)).strftime("%Y-%m-%d %H:%M"), time_zone)  
        }  
        if c.pvr['options']['record_pvrp']: c.pvr['options']['record_pvr'] = 0 # if pvrp is active, straight pvr is off  
        if get_environment('arena') not in ['backtest', 'live']: c.pvr['options']['log_summary'] = 1 # Every day when real money  
        log.info(c.pvr['run_str'])  
    p = c.pvr ; o = c.pvr['options'] ; pf = c.portfolio ; pnl = pf.portfolio_value - p['start']  
    def _pvr(c):  
        p['cagr'] = ((pf.portfolio_value / p['start']) ** (1 / (p['days'] / 252.))) - 1  
        ptype = 'PvR' if o['record_pvr'] else 'PvRp'  
        log.info('{} {} %/day   cagr {}   Portfolio value {}   PnL {}'.format(ptype, '%.4f' % (p['pvr'] / p['days']), '%.3f' % p['cagr'], '%.0f' % pf.portfolio_value, '%.0f' % pnl))  
        log.info('  Profited {} on {} activated/transacted for PvR of {}%'.format('%.0f' % pnl, '%.0f' % p['risk_hi'], '%.1f' % p['pvr']))  
        log.info('  QRet {} PvR {} CshLw {} MxLv {} RskHi {} MxShrt {}'.format('%.2f' % (100 * pf.returns), '%.2f' % p['pvr'], '%.0f' % p['cash_low'], '%.2f' % p['max_lvrg'], '%.0f' % p['risk_hi'], '%.0f' % p['max_shrt']))  
    def _minut():  
        dt = get_datetime().astimezone(timezone(p['tz']))  
        return str((dt.hour * 60) + dt.minute - 570).rjust(3)  # (-570 = 9:31a)  
    date = get_datetime().date()  
    if p['date_prv'] != date:  
        p['date_prv'] = date  
        p['days'] += 1.0  
    do_summary = 0  
    if o['log_summary'] and p['days'] % o['log_summary'] == 0 and _minut() == '100':  
        do_summary = 1              # Log summary every x days  
    if do_summary or date == p['date_end']:  
        p['cash'] = pf.cash  
    elif p['cash'] == pf.cash and not o['logging']: return  # for speed

    shorts = sum([z.amount * z.last_sale_price for s, z in pf.positions.items() if z.amount < 0])  
    new_key_hi = 0                  # To trigger logging if on.  
    cash       = pf.cash  
    cash_dip   = int(max(0, p['start'] - cash))  
    risk       = int(max(cash_dip, -shorts))

    if o['record_pvrp'] and cash < 0:   # Let negative cash ding less when portfolio is up.  
        cash_dip = int(max(0, cash_dip * p['start'] / pf.portfolio_value))  
        # Imagine: Start with 10, grows to 1000, goes negative to -10, should not be 200% risk.

    if int(cash) < p['cash_low']:             # New cash low  
        new_key_hi = 1  
        p['cash_low'] = int(cash)             # Lowest cash level hit  
        if o['record_cash_low']: record(CashLow = p['cash_low'])

    if c.account.leverage > p['max_lvrg']:  
        new_key_hi = 1  
        p['max_lvrg'] = c.account.leverage    # Maximum intraday leverage  
        if o['record_max_lvrg']: record(MaxLv   = p['max_lvrg'])

    if shorts < p['max_shrt']:  
        new_key_hi = 1  
        p['max_shrt'] = shorts                # Maximum shorts value  
        if o['record_max_shrt']: record(MxShrt  = p['max_shrt'])

    if risk > p['risk_hi']:  
        new_key_hi = 1  
        p['risk_hi'] = risk                   # Highest risk overall  
        if o['record_risk_hi']:  record(RiskHi  = p['risk_hi'])

    # Profit_vs_Risk returns based on max amount actually invested, long or short  
    if p['risk_hi'] != 0: # Avoid zero-divide  
        p['pvr'] = 100 * pnl / p['risk_hi']  
        ptype = 'PvRp' if o['record_pvrp'] else 'PvR'  
        if o['record_pvr'] or o['record_pvrp']: record(**{ptype: p['pvr']})

    if o['record_shorting']: record(Shorts = shorts)             # Shorts value as a positve  
    if o['record_leverage']: record(Lvrg   = c.account.leverage) # Leverage  
    if o['record_cash']    : record(Cash   = cash)               # Cash  
    if o['record_risk']    : record(Risk   = risk)  # Amount in play, maximum of shorts or cash used  
    if o['record_q_return']: record(QRet   = 100 * pf.returns)  
    if o['record_pnl']     : record(PnL    = pnl)                # Profit|Loss

    if o['logging'] and new_key_hi:  
        log.info('{}{}{}{}{}{}{}{}{}{}{}{}'.format(_minut(),  
            ' Lv '     + '%.1f' % c.account.leverage,  
            ' MxLv '   + '%.2f' % p['max_lvrg'],  
            ' QRet '   + '%.1f' % (100 * pf.returns),  
            ' PvR '    + '%.1f' % p['pvr'],  
            ' PnL '    + '%.0f' % pnl,  
            ' Cash '   + '%.0f' % cash,  
            ' CshLw '  + '%.0f' % p['cash_low'],  
            ' Shrt '   + '%.0f' % shorts,  
            ' MxShrt ' + '%.0f' % p['max_shrt'],  
            ' Risk '   + '%.0f' % risk,  
            ' RskHi '  + '%.0f' % p['risk_hi']  
        ))  
    if do_summary: _pvr(c)  
    if get_datetime() == get_environment('end'):   # Summary at end of run  
        _pvr(c) ; elapsed = (time.time() - p['begin']) / 60  # minutes  
        log.info( '{}\nRuntime {} hr {} min'.format(p['run_str'], int(elapsed / 60), '%.1f' % (elapsed % 60)))

def handle_data(context, data): 
    pvr(context, data)
    c = context
    if c.ShowMaxLev:
        if c.account.leverage > c.mx_lvrg:  
            c.mx_lvrg = c.account.leverage  
            record(mx_lvrg = c.mx_lvrg)    # Record maximum leverage encountered

    ##
    # Buy XIV
    ##
    if c.ShortVIX and not c.BoughtShortVIX and not c.SellAndWait:
        PriceXIV = data.current(c.XIV, 'price')
        if not c.PriceXIV: c.PriceXIV = PriceXIV
        if PriceXIV < c.PriceXIV:
            c.PriceXIV = PriceXIV
        elif PriceXIV > 1.0025 * c.PriceXIV:
            c.BoughtShortVIX = True
            TarPer(context, data, c.XIV, c.VIX_GrowthLeverage)

    ##
    # Buy UVXY
    ##
    if c.LongVIX and not c.BoughtLongVIX and not c.SellAndWait:
        PriceUVXY = data.current(c.UVXY, 'price')
        if not c.PriceUVXY: c.PriceUVXY = PriceUVXY
        if PriceUVXY < c.PriceUVXY:
            c.PriceUVXY = PriceUVXY
        elif PriceUVXY > 1.005 * c.PriceUVXY:
            c.BoughtLongVIX = True
            TarPer(context, data, c.UVXY, c.VIX_HedgeLeverage)

    ##
    # RogueTrader here and in RogueTrader scheduled function
    ##
    if c.RogueTrader and not c.SellAndWait:
        for position in c.portfolio.positions.itervalues():
            if (position.sid in c.VIXstocks) or (position.sid in c.SetAsideStocks):
                if position.amount == 0:
                    if position.asset.symbol in c.stops: del c.stops[position.asset.symbol]
                    continue
                elif position.asset.symbol not in c.stops:
                    stoploss= c.stoploss if position.amount > 0 else -c.stoploss
                    c.stops[position.asset.symbol]=position.last_sale_price*(1-stoploss)
                    #log.info(' ! I have added '+str(position.asset.symbol)+' to Stops @ '+str((position.last_sale_price)*(1-stoploss)))
                elif c.stops[position.asset.symbol] < position.last_sale_price*(1- c.stoploss) and position.amount > 0:
                    c.stops[position.asset.symbol]=position.last_sale_price*(1- c.stoploss)
                    #log.info(' ! I have updated '+str(position.asset.symbol)+'- (Long) to stop @ '+str((position.last_sale_price)*(1- c.stoploss)))
                elif c.stops[position.asset.symbol] > position.last_sale_price and position.amount > 0:
                    #sell
                    log.info(' ! '+str(position.asset.symbol)+'- (Long) has hit stoploss @ '+str(position.last_sale_price))
                    if get_open_orders(position.sid): cancel_open_orders_for(context, data, position.sid)
                    c.stoppedout.append(position.asset.symbol)
                    TarPer(context, data, position.sid, 0.00)
     
                ##
                # Sell and Wait
                ##
                if (
                        (position.sid is c.XIV and 0 < position.amount)
                        and
                        (10.76 < c.vix < 12) and (position.last_sale_price > 1.013 * c.XIVprice)
                ):
                    c.SellAndWait = 1
                elif (
                        (position.sid is c.UVXY and 0 < position.amount)
                        and
                        (position.last_sale_price > 1.40 * c.UVXYprice)
                ):
                    c.SellAndWait = 3

        ##
        # Sell and Wait
        ##
        if 0 < c.SellAndWait:
            for stock in c.portfolio.positions:
                    if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                        cancel_open_orders_for(context, data, stock)
                        TarPer(context, data, stock, 0.00)

def CherryPickerClose(context,data):    
    
    c = context
    vxx_prices = data.history(c.VXX, "high", c.wvf_length*2, "1d")
    vxx_lows = data.history(c.VXX, "low", c.wvf_length*2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.wvf_length, center=False).max()
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100

    rsi = talib.RSI(vxx_prices, timeperiod=c.rsi_length)
    
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.ema1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.ema2)
    
    ## BUY RULES
    #if WVF crosses over smoothwvf1 and wvf < smoothwvf2
    if (
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] < c.SmoothedWVF2[-1])
        or
        (c.SmoothedWVF1[-2] < c.SmoothedWVF2[-2] and c.SmoothedWVF1[-1] > c.SmoothedWVF2[-1])
        or
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-2])
    ):
        c.sell = False
        for stock in c.portfolio.positions:
            if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                if stock is not c.XIV:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 0.00)
                else:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 1.00)
      
    ## SELL RULES
    if c.portfolio.positions[c.XIV].amount > 0:
        #if rsi crosses over rsi_trigger
        if rsi[-2] < c.rsi_trigger and rsi[-1] > c.rsi_trigger:
            c.sell = True
            
        #if wvf crosses under smoothwvf2: sell
        elif WVF[-2] > c.SmoothedWVF2[-2] and WVF[-1] < c.SmoothedWVF2[-1]:
            c.sell = True

        else:
            c.sell = False
There was a runtime error.

I could not tell whether a limit order being used for buying low volume stocks. The spread could be too big for them.

I was comparing this and the previous algorithm (without extreme
vetting ) and noticed that consistently this algorithm had
substantially higher leverage swings.

Besides just setting leverage to a certain value ( context.account.leverage, which still provides some swings), in
theory what other ways can you control leverage?

I imagine a text book would say alter your (long value + abs(short_value)) / context.portfolio.portfolio_value ratio.
Although, I feel like there would still be a lot of underlying
variables that also cause leverage swings.

https://www.quantopian.com/lectures/leverage

Not sure how I missed this. Obviously this will not work with all these additional stocks involved.
All my low volume stocks sold at 9:34 market time. I removed the following code in VIX_Mix function:

    for stock in c.portfolio.positions:  
        if stock not in c.VIXstocks and stock not in c.SetAsideStocks:  
            TarPer(context, data, stock, 0.00)


Sorry, another one needed in Initialize.
context.Agree = False

Clone Algorithm
380
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
from datetime import datetime  
import functools
import itertools
from itertools import cycle
import math
import numpy as np
import pandas as pd
from pytz import timezone      
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.factors import SimpleMovingAverage, AverageDollarVolume
from quantopian.pipeline.filters.morningstar import IsPrimaryShare
import re
from scipy import stats
import talib
import time
from zipline.utils import tradingcalendar

DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT = 0.20
History = 128

def initialize(context):

    ##
    # ExtremeVetting
    ##

    context.MaxCandidates=390 #6.5*60
    context.EveryThisManyMinutes=15
    context.MaxBuyOrdersAtOnce=context.EveryThisManyMinutes
    context.MyLeastPrice=2.00
    context.MyMostPrice=5.00
    context.MyRetreatPrice=context.MyLeastPrice
    context.MyRetreatAge=3
    context.MyDaysPerPennyReduction=0.33
    context.MyMinPurchase=1000
    context.MyMaxPurchase=25000
    context.EV_BuyFactor=.90
    context.SellFactor=1.08

    # over simplistic tracking of position age
    context.age={}
    print len(context.portfolio.positions)

    # ExtremeVetting
    EveryThisManyMinutes=context.EveryThisManyMinutes
    TradingDayHours=6.5
    TradingDayMinutes=int(TradingDayHours*60)
    for minutez in xrange(
        0, 
        TradingDayMinutes, 
        EveryThisManyMinutes
    ):
        if minutez >= 1:
            schedule_function(ExtremeVetting, date_rules.every_day(), time_rules.market_open(minutes=minutez))
        else:
            schedule_function(ExtremeVetting, date_rules.every_day(), time_rules.market_open())

    # Create our pipeline and attach it to our algorithm.
    my_pipe = make_pipeline(context)
    attach_pipeline(my_pipe, 'my_pipeline')

    ##
    # CherryPicker
    ##

    context.rsi_length = 3
    context.rsi_trigger = 50
    context.wvf_length = 100
    context.ema1 = 10
    context.ema2 = 30
    context.sell = False

    ##
    # Not CherryPicker Not ExtremeVetting
    ##
    
    vixUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv'
    vxvUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vxvdailyprices.csv'
    nokoUrl = 'http://52.15.233.150/noko.csv'  
    
    fetch_csv(nokoUrl, 
              symbol='v1', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX1, 
              post_func=shift_data)
    
    fetch_csv(nokoUrl, 
              symbol='v2', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX2, 
              post_func=shift_data)

    fetch_csv(vixUrl, 
              symbol='v', 
              skiprows=1,
              date_column='Date', 
              pre_func=addFieldsVIX,
              post_func=shift_data)

    fetch_csv(vxvUrl, 
              symbol='vxv', 
              skiprows=2,
              date_column='Date', 
              pre_func=addFieldsVXV,
              post_func=shift_data)

    context.xiv = sid(40516)
    context.tqqq = sid(39214)
    context.uvxy = sid(41969)
    context.spyg = sid(22009)
    
    context.vix = -1
    context.xiv_day = 0
    set_benchmark(context.xiv) # ALPHA and BETA will be different
    set_slippage(myVolumeShareSlippage(volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT, price_impact=0.0))
    set_commission(commission.PerTrade(cost=0.00))
    
    context.SetAsideLeverageTotal = 0.20 # 100% allocate when BigSignalTQQQ
    context.VIX_GrowthLeverage    = 1 - context.SetAsideLeverageTotal
    context.VIX_MinHedgeLeverage  = context.VIX_HedgeLeverage  = 0.666
    context.VIX_MaxHedgeLeverage  = 1.00 # if certain conditions are met
    context.Agree                 = False
    context.ShowMaxLev            = True

    # 3x NASDAQ nonfinancial, generally profitable
    context.SetAsideStocks = symbols('TQQQ')

    context.PriceXIV = context.PriceUVXY = 0.00
    context.BoughtShortVIX = context.BoughtLongVIX = False
    context.XIV       = symbol('XIV')
    context.UVXY      = symbol('UVXY') # approx 8% weekly erosion, bigger spikes
    context.VIXstocks = (context.XIV, context.UVXY)
    context.LongVIX  = False  # no decisions until one of three conditions exists
    context.ShortVIX = False  # no decisions until one of three conditions exists
    # not necessary to set BigSignal variables because they get set by MoreSignals function early every day
    
    # apparently highly successful VIX signals
    schedule_function(CherryPickerOpen, date_rules.every_day(), time_rules.market_open(), False)
    schedule_function(MoreSignals, date_rules.every_day(), time_rules.market_open(minutes = 2))
    schedule_function(VIX_Mix, date_rules.every_day(), time_rules.market_open(minutes = 4))
    schedule_function(RogueTrader, date_rules.every_day(),time_rules.market_open(minutes = 60))
    schedule_function(cancel_open_orders, date_rules.every_day(), time_rules.market_close())    
    schedule_function(RecordVars, date_rules.every_day(), time_rules.market_close())    
    schedule_function(CherryPickerClose, date_rules.every_day(), time_rules.market_close(), False)

    #VXX used for strategy to buy XIV
    context.VXX = context.vxx = sid(38054) # VXX

    #Editable values to tweak backtest
    context.AvgLength = 20
    context.LengthWVF = 100
    context.LengthEMA1 = 10
    context.LengthEMA2 = 30
    
    #internal variables to store data
    context.vxxAvg = 0 
    context.SmoothedWVF1 = 0
    context.SmoothedWVF2 = 0
    context.vxxLow = 0
    context.vxxHigh = 0
    
    #Internal stop variables
    # context.stoploss is set in RogueTrader
    context.stoploss = 0.50
    context.stops         = {}
    context.stoppedout    = []
    context.SellAndWait   = 0

class myVolumeShareSlippage(slippage.SlippageModel):
    """Model slippage as a function of the volume of shares traded.
    """

    def __init__(self, volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT,
                 price_impact=0.1):

        self.volume_limit = volume_limit
        self.price_impact = price_impact

        slippage.SlippageModel.__init__(self)

    def process_order(self, data, order):
        volume = data.current(order.asset, "volume")

        max_volume = self.volume_limit * volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return None, None

        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return None, None

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / volume,
                           self.volume_limit)

        price = data.current(order.asset, "close")

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * price
        impacted_price = price + simulated_impact

        if order.limit:
            # this is tricky! if an order with a limit price has reached
            # the limit price, we will try to fill the order. do not fill
            # these shares if the impacted price is worse than the limit
            # price. return early to avoid creating the transaction.

            # buy order is worse if the impacted price is greater than
            # the limit price. sell order is worse if the impacted price
            # is less than the limit price
            if (order.direction > 0 and impacted_price > order.limit) or \
                    (order.direction < 0 and impacted_price < order.limit):
                return None, None
            
            # For marketable limit orders the price is 'impacted_price'
            # (that is current price + slippage) but for non-marketable
            # limit order the price must be the limit price.
            # To put it simple, if the market "goes through" the level
            # of a limit order (non-marketable) we have to use the limit
            # price, otherwise the 'impacted_price'
            # To disinguish between marketable and non-marketable limit
            # order we can use the following good approximation:
            # if both open and close price are below/above (buy/sell)
            # the limit price the order is markettable
            # if open price is above (or below for sell) limit price
            # and close price is below (or above for sell) limit pirce,
            # then the order is non-marketable
            
            open_price = data.current(order.asset, "open")
            # Note: no need to check for close price if we are here
            non_marketable = (order.direction > 0 and open_price > order.limit) or \
                             (order.direction < 0 and open_price < order.limit)
                
            if non_marketable:
                impacted_price = order.limit
                
            #print '%d limit %f open %f close %f marketable %s final price %f' % (order.direction, order.limit, open_price, price, not non_marketable, impacted_price)

        return (
            impacted_price,
            math.copysign(cur_volume, order.direction)
        )

def make_pipeline(context):
    """
    Create our pipeline.
    """

    # Filter for primary share equities. IsPrimaryShare is a built-in filter.
    primary_share = IsPrimaryShare()

    # Equities listed as common stock (as opposed to, say, preferred stock).
    # 'ST00000001' indicates common stock.
    common_stock = morningstar.share_class_reference.security_type.latest.eq('ST00000001')

    # Non-depositary receipts. Recall that the ~ operator inverts filters,
    # turning Trues into Falses and vice versa
    not_depositary = ~morningstar.share_class_reference.is_depositary_receipt.latest

    # Equities not trading over-the-counter.
    not_otc = ~morningstar.share_class_reference.exchange_id.latest.startswith('OTC')

    # Not when-issued equities.
    not_wi = ~morningstar.share_class_reference.symbol.latest.endswith('.WI')

    # Equities without LP in their name, .matches does a match using a regular
    # expression
    not_lp_name = ~morningstar.company_reference.standard_name.latest.matches('.* L[. ]?P.?$')

    # Equities with a null value in the limited_partnership Morningstar
    # fundamental field.
    not_lp_balance_sheet = morningstar.balance_sheet.limited_partnership.latest.isnull()

    # Equities whose most recent Morningstar market cap is not null have
    # fundamental data and therefore are not ETFs.
    have_market_cap = morningstar.valuation.market_cap.latest.notnull()

    # At least a certain price
    price = USEquityPricing.close.latest
    AtLeastPrice   = (price >= context.MyLeastPrice)
    AtMostPrice    = (price <= context.MyMostPrice)

    # Filter for stocks that pass all of our previous filters.
    tradeable_stocks = (
        primary_share
        & common_stock
        & not_depositary
        & not_otc
        & not_wi
        & not_lp_name
        & not_lp_balance_sheet
        & have_market_cap
        & AtLeastPrice
        & AtMostPrice
    )

    LowVar=6
    HighVar=40

    log.info('\nAlgorithm initialized variables:\n context.MaxCandidates %s \n LowVar %s \n HighVar %s'
        % (context.MaxCandidates, LowVar, HighVar)
    )

    # High dollar volume filter.
    base_universe = AverageDollarVolume(
        window_length=20,
        mask=tradeable_stocks
    ).percentile_between(LowVar, HighVar)

    # Short close price average.
    ShortAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=3,
        mask=base_universe
    )

    # Long close price average.
    LongAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=45,
        mask=base_universe
    )

    percent_difference = (ShortAvg - LongAvg) / LongAvg

    # Filter to select securities to long.
    stocks_worst = percent_difference.bottom(context.MaxCandidates)
    securities_to_trade = (stocks_worst)

    return Pipeline(
        columns={
            'stocks_worst': stocks_worst
        },
        screen=(securities_to_trade),
    )

def my_compute_weights(context):
    """
    Compute ordering weights.
    """
    # Compute even target weights for our long positions and short positions.
    stocks_worst_weight = 1.00/len(context.stocks_worst)

    return stocks_worst_weight

def before_trading_start(context, data):
    # Gets our pipeline output every day.
    context.output = pipeline_output('my_pipeline')
    context.stocks_worst = context.output[context.output['stocks_worst']].index.tolist()
    context.stocks_worst_weight = my_compute_weights(context)
    context.MyCandidate = cycle(context.stocks_worst)

    for stock in context.portfolio.positions:
        if stock in context.age:
            context.age[stock] += 1
        else:
            context.age[stock] = 1
    for stock in context.age:
        if stock not in context.portfolio.positions:
            context.age[stock] = 0

    context.RogueTrader = False # Not True until RogueTrader scheduled function runs

    context.mx_lvrg  = 0 # reset for recording daily max leverage

    # To help determine previous signal when start algo in live trade Robinhood
    if not context.ShortVIX and not context.LongVIX: # Maybe we can figure it out
        context.ShortVIX = True if 0 < context.portfolio.positions[context.XIV].amount  else False
        context.LongVIX  = True if 0 < context.portfolio.positions[context.UVXY].amount else False
        if context.ShortVIX and context.LongVIX: # Do no harm
            context.ShortVIX = context.LongVIX = False

def RecordVars(context, data):
    
    # handling this in handle_data now to show mx_lvrg
    if not context.ShowMaxLev:
        record(Leverage=context.account.leverage)
        pass

def CherryPickerOpen(context,data):
    c = context
    if c.sell:
        c.sell = False
        if c.portfolio.positions[c.XIV].amount > 0: 
            cancel_open_orders_for(context, data, c.XIV)
            TarPer(context, data, c.XIV, 0.00)
            
def RogueTrader(context, data):

    c = context
    c.RogueTrader = True # Not True until RogueTrader scheduled function runs

    cancel_open_orders(context, data)

    ##
    # Limit sell and Stop loss orders
    ##
    for stock in c.portfolio.positions:

        # Set stoploss
        c.stoploss = 0.21 if stock is c.UVXY else 0.035

        # Set LimitPrice for first order
        RemainingFactor  = 0.50 if stock is c.UVXY else 0.22
        MaxOrders        = 20   if stock is c.UVXY else 3
        if stock is c.UVXY:
            LimitPriceFactor = 1.06 if c.Agree else 1.05
        else:
            LimitPriceFactor = 1.04
        LimitPrice       = LimitPriceFactor * c.portfolio.positions[stock].cost_basis

        SharesRemaining = int(RemainingFactor * c.portfolio.positions[stock].amount)
        SharesPerOrder  = min(SharesRemaining, max(100, int(SharesRemaining / MaxOrders)))
        
        while 0 < SharesRemaining:

            order(stock, -SharesPerOrder, style=LimitOrder(LimitPrice))
            
            SharesRemaining -= SharesPerOrder
            SharesPerOrder = min(SharesRemaining, SharesPerOrder)
            LimitPrice *= LimitPriceFactor 
        if stock.symbol in c.stops: del c.stops[stock.symbol]
        
def TarPer(context, data, stock, TargetPercent):

    if DataCanTrade(context, data, stock):

        if 0 == TargetPercent:
            order_target_percent(stock, 0.00)
        else:
            # Always want money available to withdraw 
            # and also try to prevent margin related order rejections
            PV = context.portfolio.portfolio_value
            DoNotSpend = 2000 # 200 Cushion plus cash for withdrawals
            RhMargin = 24000.00 # Set to 0 if you do not have Robinhood Gold
            MaxLeverage = 1.33 - .12 # Hard Limit for leverage minus seemingly necessary cushion
            MaxLeverage = min(MaxLeverage, max(MaxLeverage, context.account.leverage))
            RhMargin = min(RhMargin, PV * (MaxLeverage - 1))
            RhPV = PV + RhMargin - DoNotSpend  
            RhCash = RhPV - context.portfolio.positions_value
            amount = context.portfolio.positions[stock].amount
            price = data.current(stock, 'price')
            PosValue   = float(amount * price)
            TarValue   = float(RhPV * TargetPercent)
            DiffValue  = float(TarValue - PosValue)
            DiffValue  = min(DiffValue, RhCash)
            DiffAmount = int(DiffValue / price)
            DiffAmount = 0 if 0 > DiffAmount and 0 == amount else DiffAmount
            order(stock, DiffAmount)

        if stock.symbol in context.stops: del context.stops[stock.symbol]

def DataCanTrade(context, data, stock):

    try:
        if data.can_trade(stock):
            return True
        else:
            return False
    except:
        return False

def ExtremeVetting(context, data):
    c = context
    cash = c.portfolio.cash
    PValue = c.portfolio.portfolio_value

    cancel_open_buy_orders(context, data)

    # Order sell at profit target in hope that somebody actually buys it
    for stock in c.portfolio.positions:
        if not get_open_orders(stock):
            StockShares = c.portfolio.positions[stock].amount
            CurrPrice = float(data.current([stock], 'price'))
            CostBasis = float(c.portfolio.positions[stock].cost_basis)
            SellPrice = float(make_div_by_05(CostBasis*c.SellFactor, buy=False))
            if np.isnan(SellPrice):
                pass # probably best to wait until nan goes away
            elif (
                stock in c.age 
                and c.MyRetreatAge<=c.age[stock] 
                and (
                    c.MyRetreatPrice>CurrPrice
                    or CostBasis>CurrPrice
                )
            ):
                SellPrice = float(
                    CostBasis-(
                        c.age[stock]/(100.00*c.MyDaysPerPennyReduction)
                    )
                )
                SellPrice = .50 if .50 > SellPrice else SellPrice
                SellPrice = float(make_div_by_05(SellPrice, buy=False))
                order(stock, -StockShares,
                    style=LimitOrder(SellPrice)
                )
            else:
                order(stock, -StockShares,
                    style=LimitOrder(SellPrice)
                )

    WeightFactor = .33 if cash > .33 * PValue else 1
    WeightThisBuyOrder=float(WeightFactor * 1.00 / c.MaxBuyOrdersAtOnce)
    MaxBuyOrdersAtOnce = 1 if cash < c.MyMinPurchase * c.MaxBuyOrdersAtOnce else c.MaxBuyOrdersAtOnce        
    for ThisBuyOrder in range(MaxBuyOrdersAtOnce):
        stock = c.MyCandidate.next()
        PHshort = data.history([stock], 'price', 5, '1d')
        PHshortAvg = float(PHshort.mean())
        PHlong = data.history([stock], 'price', 40, '1d')
        PHlongAvg = float(PHlong.mean())
        CurrPrice = float(data.current([stock], 'price'))
        if PHshortAvg < PHlongAvg * c.EV_BuyFactor:
            if cash >= c.MyMinPurchase * MaxBuyOrdersAtOnce:
                if c.MyMinPurchase > WeightThisBuyOrder*cash:
                    Purchase=c.MyMinPurchase
                elif c.MyMaxPurchase < WeightThisBuyOrder*cash:
                    Purchase=c.MyMaxPurchase
                else:
                    Purchase=WeightThisBuyOrder*cash
                StockSharesToOwn = int(Purchase/CurrPrice)
                StockValueTarget = StockSharesToOwn * CurrPrice
                StockTarPer = StockValueTarget / PValue
                TarPer(context, data, stock, StockTarPer)

#if cents not divisible by .05, round down if buy, round up if sell
def make_div_by_05(s, buy=False):
    s *= 20.00
    s =  math.floor(s) if buy else math.ceil(s)
    s /= 20.00
    return s

def cancel_open_buy_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
            if 0<order.amount: #it is a buy order
                cancel_order(order)

def cancel_open_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            cancel_order(order)
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
    
def cancel_open_orders_for(context, data, security):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            if stock is security:
                if order.amount < context.portfolio.positions[stock].amount:
                    cancel_order(order)
                    #message = 'Canceling order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                else: # Do NOT want to cancel stop loss order
                    #message = 'NOT Canceling stop loss order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                    pass

def MoreSignals(context, data):  

    update_indices(context, data)     
    last_vix = context.VIXprice = data.current('v', 'Close')
    last_vx1 = data.current('v1','Close')  
    last_vx2 = data.current('v2','Close')      
    last_vxv = data.current('vxv', 'Close')
    last_vix_200ma_ratio = data.current('v', '200ma Ratio')
           
    # Calculating the gap between spot vix and the first month vix future
    last_ratio_v_v1 = last_vix/last_vx1

    # Calculating the contango ratio of the front and second month VIX Futures 
    last_ratio_v1_v2 = last_vx1/last_vx2

    # Blending the previous two ratios together using a weighted average
    ratio_weight = 0.7
    last_ratio = (ratio_weight*last_ratio_v_v1) + ((1-ratio_weight)*last_ratio_v1_v2) - 1
    
    vix_vxv_ratio = last_vix/last_vxv
    
    # Retrieve SPY prices for technical indicators
    prices = data.history(context.spyg, 'open', 40, '1d')
    
    # Retrieve SPY MACD data
    macda, signal, hist = talib.MACD(prices, fastperiod=12,slowperiod=26,signalperiod=9)
    macd = macda[-1] - signal[-1]
    
    # Calculate how much vix moved the previous day
    if (context.vix <> -1) : 
        vix_ratio = last_vix/context.vix -1
    else :
        vix_ratio = 0
    context.vix = last_vix
    
    xiv_history = data.history(context.xiv, 'price', 2, '1d')  
    
    xiv_ratio = xiv_history[1]/xiv_history[0] - 1
    
    # Setting thresholds
    threshold_vix_too_low = 10.76   # 0 
    threshold_vix_200ma_ratio_low = 0.79  # 0 
    threshold_xiv = -0.049          # 1
    threshold_vxv_xiv = 0.87        # 2
    threshold_uvxy = 0.049          # 3
    threshold_macd = -0.55          # 3
    threshold_vxv_uvxy = 1.3        # 4
    threshold_vix_high = 19.9       # 5
    threshold_vc_low = -0.148       # 6
    threshold_vc_high = 0.046       # 8
    threshold_vc_high_2 = -0.06     # 8
    threshold_xiv_ratio = -0.053    # 10
    threshold_uvxy_ratio = 0.08     # 11

    # 0
    if last_vix < threshold_vix_too_low and last_vix_200ma_ratio < threshold_vix_200ma_ratio_low: # if VIX is too low, invest in UVXY witht he hope of a spike
        target_sid = context.uvxy
    # 1        
    elif last_ratio < threshold_xiv: # if contango is high, invest in XIV to gain from decay
        target_sid = context.xiv
    
    # 2
    elif vix_vxv_ratio < threshold_vxv_xiv: # if short term vol is low compared to mid term, invest in XIV to gain from decay
        target_sid = context.xiv

    # 3
    elif last_ratio > threshold_uvxy and macd > threshold_macd: # if backwardation is high, invest in UVXY to gain from decay
        target_sid = context.uvxy

    # 4
    elif vix_vxv_ratio > threshold_vxv_uvxy: # if short term vol is high compared to mid term, invest in UVXY to gain from growth
        target_sid = context.uvxy

    # 5
    elif last_vix > threshold_vix_high: # if VIX is too high, invest in XIV expecting that VIX will drop
        target_sid = context.xiv

    # 6
    elif vix_ratio < threshold_vc_low: # Vix down sharply, invest in XIV expecting that futures curve gets pulled down
        target_sid = context.xiv

    # 7
    elif vix_ratio > threshold_vc_high: # Vix up sharply, invest in UVXY expecting that futures curve gets pulled up
        target_sid = context.uvxy

    # 8
    elif vix_ratio > threshold_vc_high_2: #have to think
        target_sid = context.xiv

    # 9
    else:
        target_sid = context.uvxy

    # 10
    if (target_sid == context.xiv and xiv_ratio < threshold_xiv_ratio) : 
        # indicators say XIV but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq 

    # 11
    elif (target_sid == context.uvxy and xiv_ratio > threshold_uvxy_ratio) :
        # indicators say UVXY but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq
    
    context.BigSignalShortVIX = True if context.xiv  is target_sid else False
    context.BigSignalLongVIX  = True if context.uvxy is target_sid else False
    context.BigSignalTQQQ     = True if context.tqqq is target_sid else False
    
def VIX_Mix(context, data):
    c = context
    
    if 0 < c.SellAndWait:
        c.SellAndWait -= 1
        return

    cancel_open_orders(context, data) # avoid confusion

    ### Determine how much to risk in Long VIX ###
    # Load historical data for the stocks  
    hist = data.history(c.vxx, ['high', 'low', 'close'], 15, '1d')  
    # Calculate the ATR for the stock  
    atr_14 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=14)[-1]  
    atr_3 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=3)[-1]
    c.VIX_HedgeLeverage = c.VIX_MaxHedgeLeverage if atr_3 <= atr_14 else c.VIX_MinHedgeLeverage

    #Gets Moving Average of VXX
    price_hist = data.history(c.vxx, 'price', c.AvgLength, '1d')
    c.vxxAvg = price_hist.mean()
    
    #get data for calculations
    n = 200
    vxx_prices = data.history(c.vxx, "price", n + 2, "1d")
    vxx_lows = data.history(c.vxx, "low", n + 2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.LengthWVF,center=False).max()
    
    #William's VIX Fix indicator a.k.a. the Synthetic VIX
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100
    
    # calculated smoothed WVF
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.LengthEMA1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.LengthEMA2)
    
    #Do some checks for cross overs. 
    if WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-1]:
        wvf_crossedSmoothedWVF1 = True
    else: 
        wvf_crossedSmoothedWVF1 = False
    #Same except for smoothed2 
    if WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-1]:
        wvf_crossedSmoothedWVF2 = True
    else: 
        wvf_crossedSmoothedWVF2 = False
    
    #Current price of vxx
    vxxPrice = data.current(c.vxx, 'price')
    
    #SignalShortVIX 
    if ( wvf_crossedSmoothedWVF1 and WVF[-1] < c.SmoothedWVF2[-1]) or (wvf_crossedSmoothedWVF2 and wvf_crossedSmoothedWVF1):
        SignalShortVIX = True
    elif ((vxxPrice > c.vxxAvg and vxx_prices[-2] < c.vxxAvg) or (WVF[-1] < c.SmoothedWVF2[-1] and WVF[-2] > c.SmoothedWVF2[-1])):
        SignalShortVIX = False
    else:
        SignalShortVIX = True

    if (c.BigSignalShortVIX and SignalShortVIX): # Agree ShortVIX
        c.ShortVIX    = True
        c.LongVIX     = False
        c.Agree       = True

    elif (c.BigSignalLongVIX and not SignalShortVIX): # Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = True

    elif (c.BigSignalLongVIX and SignalShortVIX): # Not Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = False

    ##
    # VIX_Mix only once until signal changes again
    # or
    # leverage drops too low
    ##

    l = c.account.leverage
    LevTooLow = True if (0.33 > l) or (0.90 < l < 1.05) else False
    p = c.portfolio.positions

    if c.BigSignalTQQQ:
        if LevTooLow or (c.XIV in p or c.UVXY in p):
            TarPer(context, data, c.XIV, 0.00)
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(1.00 / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)

    elif c.ShortVIX:
        if LevTooLow or (c.XIV not in p):
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(c.SetAsideLeverageTotal / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)
            c.BoughtShortVIX = False
            c.PriceXIV = 0.00

    elif c.LongVIX:
        if LevTooLow or (c.UVXY not in p):
            TarPer(context, data, c.XIV, 0.00)
            for stock in c.SetAsideStocks:
                TarPer(context, data, stock, 0.00)
            c.BoughtLongVIX = False
            c.PriceUVXY = 0.00

    # Record / log stuff I want to know
    c.XIVprice  = data.current(c.XIV, 'price')
    c.UVXYprice = data.current(c.UVXY, 'price')
    TQQQprice = data.current(c.tqqq, 'price')
    #record(XIV  = c.XIVprice)
    #record(UVXY = c.UVXYprice)
    #record(TQQQ = TQQQprice)
    BigSignal = 'NoBigSignal'
    BigSignal = 'ShortVIX' if c.BigSignalShortVIX else BigSignal
    BigSignal = ' LongVIX' if c.BigSignalLongVIX  else BigSignal
    BigSignal = '    TQQQ' if c.BigSignalTQQQ     else BigSignal
    SyntheticVIX = 'NoSyntheticVIX'
    SyntheticVIX = 'ShortVIX' if c.ShortVIX else SyntheticVIX
    SyntheticVIX = ' LongVIX' if c.LongVIX  else SyntheticVIX
    log.info('BigSignal / SyntheticVIX: {} / {}     VIX: {:.2f}     XIV: {:.2f}     UVXY: {:.2f}     TQQQ: {:.2f}'
        .format(BigSignal, SyntheticVIX, c.VIXprice, c.XIVprice, c.UVXYprice, TQQQprice)
    )

def update_indices(context, data):
    context.fetch_failed = False
    context.vix_vals = unpack_from_data(context, data, 'v')    
    context.vxv_vals = unpack_from_data(context, data, 'vxv')  
    context.vx1_vals = unpack_from_data(context, data, 'v1')
    context.vx2_vals = unpack_from_data(context, data, 'v2')

def fix_close(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%m/%d/%Y')))
    df = df.sort_values(by='Date', ascending=True)
    return df

def fix_closeVX(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%Y-%m-%d')))
    df = df.sort_values(by='Date', ascending=True)
    return df


def subsequent_trading_date(date):
    tdays = tradingcalendar.trading_days
    last_date = pd.to_datetime(date)
    last_dt = tradingcalendar.canonicalize_datetime(last_date)
    next_dt = tdays[tdays.searchsorted(last_dt) + 1]
    return next_dt

def add_last_bar(df):
    last_date = df.index[-1]
    subsequent_date = subsequent_trading_date(last_date)
    blank_row = pd.Series({}, index=df.columns, name=subsequent_date)
    # add today, and shift all previous data up to today. This 
    # should result in the same data frames as in backtest
    df = df.append(blank_row).shift(1).dropna(how='all')
    return df

def shift_data(df):
    df = add_last_bar(df)
    df.fillna(method='ffill') 
    df['PrevCloses'] = my_rolling_apply_series(df['Close'], to_csv_str, History)
    dates = pd.Series(df.index)
    dates.index = df.index
    df['PrevDates'] = my_rolling_apply_series(dates, to_csv_str, History)
    return df

def unpack_from_data(context, data, sym):
    try:
        v = data.current(sym, 'PrevCloses')
        i = data.current(sym, 'PrevDates')
        return from_csv_strs(i,v,True).apply(float)
    except:
        log.warn("Unable to unpack historical {s} data.".format(s=sym))
        context.fetch_failed = True

def addFieldsVIX(df):
    df = fix_close(df,'VIX Close')
    df['200ma'] = df['Close'].rolling(200).mean()
    df['200ma Ratio'] = df['Close'] / df['200ma']

    return df

def addFieldsVXV(df):
    df.rename(columns={'Unnamed: 0': 'Date'}, inplace=True)
    df = fix_close(df,'CLOSE')
    return df

def addFieldsVX1(df):
    df = fix_closeVX(df,'F1')
    return df

def addFieldsVX2(df):
    df = fix_closeVX(df,'F2')
    return df

# convert a series of values to a comma-separated string of said values
def to_csv_str(s):
    return functools.reduce(lambda x,y: x+','+y, pd.Series(s).apply(str))

# a specific instance of rolling apply, for Series of any type (not just numeric,
# ala pandas.rolling_apply), where the index of the series is set to the indices
# of the last elements of each subset
def my_rolling_apply_series(s_in, f, n):
    s_out = pd.Series([f(s_in[i:i+n]) for i in range(0,len(s_in)-(n-1))]) 
    s_out.index = s_in.index[n-1:]
    return s_out

# reconstitutes a Series from two csv-encoded strings, one of the index, one of the values
def from_csv_strs(x, y, idx_is_date):
    s = pd.Series(y.split(','),index=x.split(','))
    if (idx_is_date):
        s.index = s.index.map(lambda x: pd.Timestamp(x))
    return s

def pvr(context, data):
    ''' Custom chart and/or logging of profit_vs_risk returns and related information from https://www.quantopian.com/posts/pvr#569784bda73e9bf2b7000180
    '''  
    #import time  
    #from datetime import datetime  
    #from pytz import timezone      # Python will only do once, makes this portable.  
                                   #   Move to top of algo for better efficiency.  
    c = context  # Brevity is the soul of wit -- Shakespeare [for readability]  
    if 'pvr' not in c:

        # For real money, you can modify this to total cash input minus any withdrawals  
        manual_cash = c.portfolio.starting_cash  
        time_zone   = 'US/Central'   # Optionally change to your own time zone for wall clock time

        c.pvr = {  
            'options': {  
                # # # # # # # # # #  Options  # # # # # # # # # #  
                'logging'         : 0,    # Info to logging window with some new maximums  
                'log_summary'     : 126,  # Summary every x days. 252/yr

                'record_pvr'      : 1,    # Profit vs Risk returns (percentage)  
                'record_pvrp'     : 0,    # PvR (p)roportional neg cash vs portfolio value  
                'record_cash'     : 1,    # Cash available  
                'record_max_lvrg' : 0,    # Maximum leverage encountered  
                'record_risk_hi'  : 0,    # Highest risk overall  
                'record_shorting' : 0,    # Total value of any shorts  
                'record_max_shrt' : 0,    # Max value of shorting total  
                'record_cash_low' : 0,    # Any new lowest cash level  
                'record_q_return' : 0,    # Quantopian returns (percentage)  
                'record_pnl'      : 1,    # Profit-n-Loss  
                'record_risk'     : 1,    # Risked, max cash spent or shorts beyond longs+cash  
                'record_leverage' : 0,    # End of day leverage (context.account.leverage)  
                # All records are end-of-day or the last data sent to chart during any day.  
                # The way the chart operates, only the last value of the day will be seen.  
                # # # # # # # # #  End options  # # # # # # # # #  
            },  
            'pvr'        : 0,      # Profit vs Risk returns based on maximum spent  
            'cagr'       : 0,  
            'max_lvrg'   : 0,  
            'max_shrt'   : 0,  
            'risk_hi'    : 0,  
            'days'       : 0.0,  
            'date_prv'   : '',  
            'date_end'   : get_environment('end').date(),  
            'cash_low'   : manual_cash,  
            'cash'       : manual_cash,  
            'start'      : manual_cash,  
            'tz'         : time_zone,  
            'begin'      : time.time(),  # For run time  
            'run_str'    : '{} to {}  ${}  {} {}'.format(get_environment('start').date(), get_environment('end').date(), int(manual_cash), datetime.now(timezone(time_zone)).strftime("%Y-%m-%d %H:%M"), time_zone)  
        }  
        if c.pvr['options']['record_pvrp']: c.pvr['options']['record_pvr'] = 0 # if pvrp is active, straight pvr is off  
        if get_environment('arena') not in ['backtest', 'live']: c.pvr['options']['log_summary'] = 1 # Every day when real money  
        log.info(c.pvr['run_str'])  
    p = c.pvr ; o = c.pvr['options'] ; pf = c.portfolio ; pnl = pf.portfolio_value - p['start']  
    def _pvr(c):  
        p['cagr'] = ((pf.portfolio_value / p['start']) ** (1 / (p['days'] / 252.))) - 1  
        ptype = 'PvR' if o['record_pvr'] else 'PvRp'  
        log.info('{} {} %/day   cagr {}   Portfolio value {}   PnL {}'.format(ptype, '%.4f' % (p['pvr'] / p['days']), '%.3f' % p['cagr'], '%.0f' % pf.portfolio_value, '%.0f' % pnl))  
        log.info('  Profited {} on {} activated/transacted for PvR of {}%'.format('%.0f' % pnl, '%.0f' % p['risk_hi'], '%.1f' % p['pvr']))  
        log.info('  QRet {} PvR {} CshLw {} MxLv {} RskHi {} MxShrt {}'.format('%.2f' % (100 * pf.returns), '%.2f' % p['pvr'], '%.0f' % p['cash_low'], '%.2f' % p['max_lvrg'], '%.0f' % p['risk_hi'], '%.0f' % p['max_shrt']))  
    def _minut():  
        dt = get_datetime().astimezone(timezone(p['tz']))  
        return str((dt.hour * 60) + dt.minute - 570).rjust(3)  # (-570 = 9:31a)  
    date = get_datetime().date()  
    if p['date_prv'] != date:  
        p['date_prv'] = date  
        p['days'] += 1.0  
    do_summary = 0  
    if o['log_summary'] and p['days'] % o['log_summary'] == 0 and _minut() == '100':  
        do_summary = 1              # Log summary every x days  
    if do_summary or date == p['date_end']:  
        p['cash'] = pf.cash  
    elif p['cash'] == pf.cash and not o['logging']: return  # for speed

    shorts = sum([z.amount * z.last_sale_price for s, z in pf.positions.items() if z.amount < 0])  
    new_key_hi = 0                  # To trigger logging if on.  
    cash       = pf.cash  
    cash_dip   = int(max(0, p['start'] - cash))  
    risk       = int(max(cash_dip, -shorts))

    if o['record_pvrp'] and cash < 0:   # Let negative cash ding less when portfolio is up.  
        cash_dip = int(max(0, cash_dip * p['start'] / pf.portfolio_value))  
        # Imagine: Start with 10, grows to 1000, goes negative to -10, should not be 200% risk.

    if int(cash) < p['cash_low']:             # New cash low  
        new_key_hi = 1  
        p['cash_low'] = int(cash)             # Lowest cash level hit  
        if o['record_cash_low']: record(CashLow = p['cash_low'])

    if c.account.leverage > p['max_lvrg']:  
        new_key_hi = 1  
        p['max_lvrg'] = c.account.leverage    # Maximum intraday leverage  
        if o['record_max_lvrg']: record(MaxLv   = p['max_lvrg'])

    if shorts < p['max_shrt']:  
        new_key_hi = 1  
        p['max_shrt'] = shorts                # Maximum shorts value  
        if o['record_max_shrt']: record(MxShrt  = p['max_shrt'])

    if risk > p['risk_hi']:  
        new_key_hi = 1  
        p['risk_hi'] = risk                   # Highest risk overall  
        if o['record_risk_hi']:  record(RiskHi  = p['risk_hi'])

    # Profit_vs_Risk returns based on max amount actually invested, long or short  
    if p['risk_hi'] != 0: # Avoid zero-divide  
        p['pvr'] = 100 * pnl / p['risk_hi']  
        ptype = 'PvRp' if o['record_pvrp'] else 'PvR'  
        if o['record_pvr'] or o['record_pvrp']: record(**{ptype: p['pvr']})

    if o['record_shorting']: record(Shorts = shorts)             # Shorts value as a positve  
    if o['record_leverage']: record(Lvrg   = c.account.leverage) # Leverage  
    if o['record_cash']    : record(Cash   = cash)               # Cash  
    if o['record_risk']    : record(Risk   = risk)  # Amount in play, maximum of shorts or cash used  
    if o['record_q_return']: record(QRet   = 100 * pf.returns)  
    if o['record_pnl']     : record(PnL    = pnl)                # Profit|Loss

    if o['logging'] and new_key_hi:  
        log.info('{}{}{}{}{}{}{}{}{}{}{}{}'.format(_minut(),  
            ' Lv '     + '%.1f' % c.account.leverage,  
            ' MxLv '   + '%.2f' % p['max_lvrg'],  
            ' QRet '   + '%.1f' % (100 * pf.returns),  
            ' PvR '    + '%.1f' % p['pvr'],  
            ' PnL '    + '%.0f' % pnl,  
            ' Cash '   + '%.0f' % cash,  
            ' CshLw '  + '%.0f' % p['cash_low'],  
            ' Shrt '   + '%.0f' % shorts,  
            ' MxShrt ' + '%.0f' % p['max_shrt'],  
            ' Risk '   + '%.0f' % risk,  
            ' RskHi '  + '%.0f' % p['risk_hi']  
        ))  
    if do_summary: _pvr(c)  
    if get_datetime() == get_environment('end'):   # Summary at end of run  
        _pvr(c) ; elapsed = (time.time() - p['begin']) / 60  # minutes  
        log.info( '{}\nRuntime {} hr {} min'.format(p['run_str'], int(elapsed / 60), '%.1f' % (elapsed % 60)))

def handle_data(context, data): 
    pvr(context, data)
    c = context
    if c.ShowMaxLev:
        if c.account.leverage > c.mx_lvrg:  
            c.mx_lvrg = c.account.leverage  
            record(mx_lvrg = c.mx_lvrg)    # Record maximum leverage encountered

    ##
    # Buy XIV
    ##
    if c.ShortVIX and not c.BoughtShortVIX and not c.SellAndWait:
        PriceXIV = data.current(c.XIV, 'price')
        if not c.PriceXIV: c.PriceXIV = PriceXIV
        if PriceXIV < c.PriceXIV:
            c.PriceXIV = PriceXIV
        elif PriceXIV > 1.0025 * c.PriceXIV:
            c.BoughtShortVIX = True
            TarPer(context, data, c.XIV, c.VIX_GrowthLeverage)

    ##
    # Buy UVXY
    ##
    if c.LongVIX and not c.BoughtLongVIX and not c.SellAndWait:
        PriceUVXY = data.current(c.UVXY, 'price')
        if not c.PriceUVXY: c.PriceUVXY = PriceUVXY
        if PriceUVXY < c.PriceUVXY:
            c.PriceUVXY = PriceUVXY
        elif PriceUVXY > 1.005 * c.PriceUVXY:
            c.BoughtLongVIX = True
            TarPer(context, data, c.UVXY, c.VIX_HedgeLeverage)

    ##
    # RogueTrader here and in RogueTrader scheduled function
    ##
    if c.RogueTrader and not c.SellAndWait:
        for position in c.portfolio.positions.itervalues():
            if (position.sid in c.VIXstocks) or (position.sid in c.SetAsideStocks):
                if position.amount == 0:
                    if position.asset.symbol in c.stops: del c.stops[position.asset.symbol]
                    continue
                elif position.asset.symbol not in c.stops:
                    stoploss= c.stoploss if position.amount > 0 else -c.stoploss
                    c.stops[position.asset.symbol]=position.last_sale_price*(1-stoploss)
                    #log.info(' ! I have added '+str(position.asset.symbol)+' to Stops @ '+str((position.last_sale_price)*(1-stoploss)))
                elif c.stops[position.asset.symbol] < position.last_sale_price*(1- c.stoploss) and position.amount > 0:
                    c.stops[position.asset.symbol]=position.last_sale_price*(1- c.stoploss)
                    #log.info(' ! I have updated '+str(position.asset.symbol)+'- (Long) to stop @ '+str((position.last_sale_price)*(1- c.stoploss)))
                elif c.stops[position.asset.symbol] > position.last_sale_price and position.amount > 0:
                    #sell
                    log.info(' ! '+str(position.asset.symbol)+'- (Long) has hit stoploss @ '+str(position.last_sale_price))
                    if get_open_orders(position.sid): cancel_open_orders_for(context, data, position.sid)
                    c.stoppedout.append(position.asset.symbol)
                    TarPer(context, data, position.sid, 0.00)
     
                ##
                # Sell and Wait
                ##
                if (
                        (position.sid is c.XIV and 0 < position.amount)
                        and
                        (10.76 < c.vix < 12) and (position.last_sale_price > 1.013 * c.XIVprice)
                ):
                    c.SellAndWait = 1
                elif (
                        (position.sid is c.UVXY and 0 < position.amount)
                        and
                        (position.last_sale_price > 1.40 * c.UVXYprice)
                ):
                    c.SellAndWait = 3

        ##
        # Sell and Wait
        ##
        if 0 < c.SellAndWait:
            for stock in c.portfolio.positions:
                    if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                        cancel_open_orders_for(context, data, stock)
                        TarPer(context, data, stock, 0.00)

def CherryPickerClose(context,data):    
    
    c = context
    vxx_prices = data.history(c.VXX, "high", c.wvf_length*2, "1d")
    vxx_lows = data.history(c.VXX, "low", c.wvf_length*2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.wvf_length, center=False).max()
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100

    rsi = talib.RSI(vxx_prices, timeperiod=c.rsi_length)
    
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.ema1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.ema2)
    
    ## BUY RULES
    #if WVF crosses over smoothwvf1 and wvf < smoothwvf2
    if (
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] < c.SmoothedWVF2[-1])
        or
        (c.SmoothedWVF1[-2] < c.SmoothedWVF2[-2] and c.SmoothedWVF1[-1] > c.SmoothedWVF2[-1])
        or
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-2])
    ):
        c.sell = False
        for stock in c.portfolio.positions:
            if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                if stock is not c.XIV:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 0.00)
                else:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 1.00)
      
    ## SELL RULES
    if c.portfolio.positions[c.XIV].amount > 0:
        #if rsi crosses over rsi_trigger
        if rsi[-2] < c.rsi_trigger and rsi[-1] > c.rsi_trigger:
            c.sell = True
            
        #if wvf crosses under smoothwvf2: sell
        elif WVF[-2] > c.SmoothedWVF2[-2] and WVF[-1] < c.SmoothedWVF2[-1]:
            c.sell = True

        else:
            c.sell = False
There was a runtime error.

I posted my version of XIV Shotgun at https://www.quantopian.com/posts/xiv-shotgun-trading-inverse-vix-with-wvf

It includes TarPer function and margin. Hopefully it just works, so I don't have to fix it.

I am live trading Robin Hood VIX Mix Rogue Trader at this moment. I have temporarily abandoned Robin Hood VIX Mix Extreme Vetting which is still a work in progress.

Do NOT get too excited. I am back live trading Robin Hood VIX Mix Extreme Vetting. It is still a work in progress. However, it does have a more reasonable feel to it.

The micro cap low volume stocks are gone, finito, fired, no longer a part of my family. The ExtremeVetting function uses Q500 worst performers.

There is a significant drop, apparently, in Max DD. This is much improved over the previous version.

Clone Algorithm
380
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
from datetime import datetime  
import functools
import itertools
from itertools import cycle
import math
import numpy as np
import pandas as pd
from pytz import timezone      
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.factors import SimpleMovingAverage, AverageDollarVolume
from quantopian.pipeline.filters import Q500US
import re
from scipy import stats
import talib
import time
from zipline.utils import tradingcalendar

DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT = 0.20
History = 128

def initialize(context):

    ##
    # ExtremeVetting
    ##

    context.MaxCandidates=5
    context.MaxBuyOrdersAtOnce=context.MaxCandidates
    context.MyLeastPrice=20.00
    context.MyMostPrice=2000.00
    context.MyMinPurchase=1000
    context.MyMaxPurchase=2500
    context.EV_BuyFactor=.90

    # over simplistic tracking of position age
    context.age={}
    print len(context.portfolio.positions)

    # ExtremeVetting
    schedule_function(ExtremeVetting, date_rules.every_day(), time_rules.market_open(minutes=45))

    # Create our pipeline and attach it to our algorithm.
    my_pipe = make_pipeline(context)
    attach_pipeline(my_pipe, 'my_pipeline')

    ##
    # CherryPicker
    ##

    context.rsi_length = 3
    context.rsi_trigger = 50
    context.wvf_length = 100
    context.ema1 = 10
    context.ema2 = 30
    context.sell = False

    ##
    # Not CherryPicker Not ExtremeVetting
    ##
    
    vixUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv'
    vxvUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vxvdailyprices.csv'
    nokoUrl = 'http://52.15.233.150/noko.csv'  
    
    fetch_csv(nokoUrl, 
              symbol='v1', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX1, 
              post_func=shift_data)
    
    fetch_csv(nokoUrl, 
              symbol='v2', 
              date_column='Date', 
              date_format='%Y-%m-%d', 
              pre_func=addFieldsVX2, 
              post_func=shift_data)

    fetch_csv(vixUrl, 
              symbol='v', 
              skiprows=1,
              date_column='Date', 
              pre_func=addFieldsVIX,
              post_func=shift_data)

    fetch_csv(vxvUrl, 
              symbol='vxv', 
              skiprows=2,
              date_column='Date', 
              pre_func=addFieldsVXV,
              post_func=shift_data)

    context.xiv = sid(40516)
    context.tqqq = sid(39214)
    context.uvxy = sid(41969)
    context.spyg = sid(22009)
    
    context.vix = -1
    context.xiv_day = 0
    set_benchmark(context.xiv) # ALPHA and BETA will be different
    set_slippage(myVolumeShareSlippage(volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT, price_impact=0.0))
    set_commission(commission.PerTrade(cost=0.00))
    
    context.SetAsideLeverageTotal = 0.20 # 100% allocate when BigSignalTQQQ
    context.VIX_GrowthLeverage    = 1 - context.SetAsideLeverageTotal
    context.VIX_MinHedgeLeverage  = context.VIX_HedgeLeverage  = 0.666
    context.VIX_MaxHedgeLeverage  = 1.00 # if certain conditions are met
    context.Agree                 = False
    context.ShowMaxLev            = True

    # 3x NASDAQ nonfinancial, generally profitable
    context.SetAsideStocks = symbols('TQQQ')

    context.PriceXIV = context.PriceUVXY = 0.00
    context.BoughtShortVIX = context.BoughtLongVIX = False
    context.XIV       = symbol('XIV')
    context.UVXY      = symbol('UVXY') # approx 8% weekly erosion, bigger spikes
    context.VIXstocks = (context.XIV, context.UVXY)
    context.LongVIX  = False  # no decisions until one of three conditions exists
    context.ShortVIX = False  # no decisions until one of three conditions exists
    # not necessary to set BigSignal variables because they get set by MoreSignals function early every day
    
    # apparently highly successful VIX signals
    schedule_function(CherryPickerOpen, date_rules.every_day(), time_rules.market_open(), False)
    schedule_function(MoreSignals, date_rules.every_day(), time_rules.market_open(minutes = 2))
    schedule_function(VIX_Mix, date_rules.every_day(), time_rules.market_open(minutes = 4))
    schedule_function(RogueTrader, date_rules.every_day(),time_rules.market_open(minutes = 60))
    schedule_function(cancel_open_orders, date_rules.every_day(), time_rules.market_close())    
    schedule_function(RecordVars, date_rules.every_day(), time_rules.market_close())    
    schedule_function(CherryPickerClose, date_rules.every_day(), time_rules.market_close(), False)

    #VXX used for strategy to buy XIV
    context.VXX = context.vxx = sid(38054) # VXX

    #Editable values to tweak backtest
    context.AvgLength = 20
    context.LengthWVF = 100
    context.LengthEMA1 = 10
    context.LengthEMA2 = 30
    
    #internal variables to store data
    context.vxxAvg = 0 
    context.SmoothedWVF1 = 0
    context.SmoothedWVF2 = 0
    context.vxxLow = 0
    context.vxxHigh = 0
    
    #Internal stop variables
    # context.stoploss is set in RogueTrader
    context.stoploss = 0.50
    context.stops         = {}
    context.stoppedout    = []
    context.SellAndWait   = 0

class myVolumeShareSlippage(slippage.SlippageModel):
    """Model slippage as a function of the volume of shares traded.
    """

    def __init__(self, volume_limit=DEFAULT_VOLUME_SLIPPAGE_BAR_LIMIT,
                 price_impact=0.1):

        self.volume_limit = volume_limit
        self.price_impact = price_impact

        slippage.SlippageModel.__init__(self)

    def process_order(self, data, order):
        volume = data.current(order.asset, "volume")

        max_volume = self.volume_limit * volume

        # price impact accounts for the total volume of transactions
        # created against the current minute bar
        remaining_volume = max_volume - self.volume_for_bar
        if remaining_volume < 1:
            # we can't fill any more transactions
            return None, None

        # the current order amount will be the min of the
        # volume available in the bar or the open amount.
        cur_volume = int(min(remaining_volume, abs(order.open_amount)))

        if cur_volume < 1:
            return None, None

        # tally the current amount into our total amount ordered.
        # total amount will be used to calculate price impact
        total_volume = self.volume_for_bar + cur_volume

        volume_share = min(total_volume / volume,
                           self.volume_limit)

        price = data.current(order.asset, "close")

        simulated_impact = volume_share ** 2 \
            * math.copysign(self.price_impact, order.direction) \
            * price
        impacted_price = price + simulated_impact

        if order.limit:
            # this is tricky! if an order with a limit price has reached
            # the limit price, we will try to fill the order. do not fill
            # these shares if the impacted price is worse than the limit
            # price. return early to avoid creating the transaction.

            # buy order is worse if the impacted price is greater than
            # the limit price. sell order is worse if the impacted price
            # is less than the limit price
            if (order.direction > 0 and impacted_price > order.limit) or \
                    (order.direction < 0 and impacted_price < order.limit):
                return None, None
            
            # For marketable limit orders the price is 'impacted_price'
            # (that is current price + slippage) but for non-marketable
            # limit order the price must be the limit price.
            # To put it simple, if the market "goes through" the level
            # of a limit order (non-marketable) we have to use the limit
            # price, otherwise the 'impacted_price'
            # To disinguish between marketable and non-marketable limit
            # order we can use the following good approximation:
            # if both open and close price are below/above (buy/sell)
            # the limit price the order is markettable
            # if open price is above (or below for sell) limit price
            # and close price is below (or above for sell) limit pirce,
            # then the order is non-marketable
            
            open_price = data.current(order.asset, "open")
            # Note: no need to check for close price if we are here
            non_marketable = (order.direction > 0 and open_price > order.limit) or \
                             (order.direction < 0 and open_price < order.limit)
                
            if non_marketable:
                impacted_price = order.limit
                
            #print '%d limit %f open %f close %f marketable %s final price %f' % (order.direction, order.limit, open_price, price, not non_marketable, impacted_price)

        return (
            impacted_price,
            math.copysign(cur_volume, order.direction)
        )

def make_pipeline(context):
    """
    Create our pipeline.
    """

    # Absolutely must be profitable
    profitable = morningstar.valuation_ratios.ev_to_ebitda.latest > 0  

    # At least a certain price
    price = USEquityPricing.close.latest
    AtLeastPrice   = (price >= context.MyLeastPrice)
    AtMostPrice    = (price <= context.MyMostPrice)

    # Filter for stocks that pass all of our previous filters.
    tradeable_stocks = (
        Q500US()
        & profitable
        & AtLeastPrice
        & AtMostPrice
    )

    LowVar=6
    HighVar=40

    log.info('\nAlgorithm initialized variables:\n context.MaxCandidates %s \n LowVar %s \n HighVar %s'
        % (context.MaxCandidates, LowVar, HighVar)
    )

    # High dollar volume filter.
    base_universe = AverageDollarVolume(
        window_length=20,
        mask=tradeable_stocks
    ).percentile_between(LowVar, HighVar)

    # Short close price average.
    ShortAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=3,
        mask=base_universe
    )

    # Long close price average.
    LongAvg = SimpleMovingAverage(
        inputs=[USEquityPricing.close],
        window_length=45,
        mask=base_universe
    )

    percent_difference = (ShortAvg - LongAvg) / LongAvg

    # Filter to select securities to long.
    stocks_worst = percent_difference.bottom(context.MaxCandidates)
    securities_to_trade = (stocks_worst)

    return Pipeline(
        columns={
            'stocks_worst': stocks_worst
        },
        screen=(securities_to_trade),
    )

def my_compute_weights(context):
    """
    Compute ordering weights.
    """
    # Compute even target weights for our long positions and short positions.
    stocks_worst_weight = 0.00 if 1>len(context.stocks_worst) else 1.00/len(context.stocks_worst)

    return stocks_worst_weight

def before_trading_start(context, data):
    # Gets our pipeline output every day.
    context.output = pipeline_output('my_pipeline')
    context.stocks_worst = context.output[context.output['stocks_worst']].index.tolist()
    context.stocks_worst_weight = my_compute_weights(context)
    context.MyCandidate = cycle(context.stocks_worst)

    for stock in context.portfolio.positions:
        if stock in context.age:
            context.age[stock] += 1
        else:
            context.age[stock] = 1
    for stock in context.age:
        if stock not in context.portfolio.positions:
            context.age[stock] = 0

    context.RogueTrader = False # Not True until RogueTrader scheduled function runs

    context.mx_lvrg  = 0 # reset for recording daily max leverage

    # To help determine previous signal when start algo in live trade Robinhood
    if not context.ShortVIX and not context.LongVIX: # Maybe we can figure it out
        context.ShortVIX = True if 0 < context.portfolio.positions[context.XIV].amount  else False
        context.LongVIX  = True if 0 < context.portfolio.positions[context.UVXY].amount else False
        if context.ShortVIX and context.LongVIX: # Do no harm
            context.ShortVIX = context.LongVIX = False

def RecordVars(context, data):
    
    # handling this in handle_data now to show mx_lvrg
    if not context.ShowMaxLev:
        record(Leverage=context.account.leverage)
        pass

def CherryPickerOpen(context,data):
    c = context
    if c.sell:
        c.sell = False
        if c.portfolio.positions[c.XIV].amount > 0: 
            cancel_open_orders_for(context, data, c.XIV)
            TarPer(context, data, c.XIV, 0.00)
            
def RogueTrader(context, data):

    c = context
    c.RogueTrader = True # Not True until RogueTrader scheduled function runs

    cancel_open_orders(context, data)

    ##
    # Limit sell and Stop loss orders
    ##
    for stock in c.portfolio.positions:

        # Set stoploss
        c.stoploss = 0.21 if stock is c.UVXY else 0.035

        # Set LimitPrice for first order
        RemainingFactor  = 0.50 if stock is c.UVXY else 0.22
        MaxOrders        = 20   if stock is c.UVXY else 3
        if stock is c.UVXY:
            LimitPriceFactor = 1.06 if c.Agree else 1.05
        else:
            LimitPriceFactor = 1.04
        LimitPrice       = LimitPriceFactor * c.portfolio.positions[stock].cost_basis

        SharesRemaining = int(RemainingFactor * c.portfolio.positions[stock].amount)
        SharesPerOrder  = min(SharesRemaining, max(100, int(SharesRemaining / MaxOrders)))
        
        while 0 < SharesRemaining:

            order(stock, -SharesPerOrder, style=LimitOrder(LimitPrice))
            
            SharesRemaining -= SharesPerOrder
            SharesPerOrder = min(SharesRemaining, SharesPerOrder)
            LimitPrice *= LimitPriceFactor 
        if stock.symbol in c.stops: del c.stops[stock.symbol]
        
def TarPer(context, data, stock, TargetPercent):

    if DataCanTrade(context, data, stock):

        if 0 == TargetPercent:
            order_target_percent(stock, 0.00)
        else:
            # Always want money available to withdraw 
            # and also try to prevent margin related order rejections
            PV = context.portfolio.portfolio_value
            DoNotSpend = 2000 # 200 Cushion plus cash for withdrawals
            RhMargin = 24000.00 # Set to 0 if you do not have Robinhood Gold
            MaxLeverage = 1.33 - .12 # Hard Limit for leverage minus seemingly necessary cushion
            MaxLeverage = min(MaxLeverage, max(MaxLeverage, context.account.leverage))
            RhMargin = min(RhMargin, PV * (MaxLeverage - 1))
            RhPV = PV + RhMargin - DoNotSpend  
            RhCash = RhPV - context.portfolio.positions_value
            amount = context.portfolio.positions[stock].amount
            price = data.current(stock, 'price')
            PosValue   = float(amount * price)
            TarValue   = float(RhPV * TargetPercent)
            DiffValue  = float(TarValue - PosValue)
            DiffValue  = min(DiffValue, RhCash)
            DiffAmount = int(DiffValue / price)
            DiffAmount = 0 if 0 > DiffAmount and 0 == amount else DiffAmount
            order(stock, DiffAmount)

        if stock.symbol in context.stops: del context.stops[stock.symbol]

def DataCanTrade(context, data, stock):

    try:
        if data.can_trade(stock):
            return True
        else:
            return False
    except:
        return False

def ExtremeVetting(context, data):
    c = context
    cash = c.portfolio.cash
    PValue = c.portfolio.portfolio_value

    cancel_open_buy_orders(context, data)

    WeightFactor = .33 if cash > .33 * PValue else 1
    WeightThisBuyOrder=float(WeightFactor * 1.00 / c.MaxBuyOrdersAtOnce)
    MaxBuyOrdersAtOnce = 1 if cash < c.MyMinPurchase * c.MaxBuyOrdersAtOnce else c.MaxBuyOrdersAtOnce  
    try:
        for ThisBuyOrder in range(MaxBuyOrdersAtOnce):
            stock = c.MyCandidate.next()
            PHshort = data.history([stock], 'price', 5, '1d')
            PHshortAvg = float(PHshort.mean())
            PHlong = data.history([stock], 'price', 40, '1d')
            PHlongAvg = float(PHlong.mean())
            CurrPrice = float(data.current([stock], 'price'))
            if PHshortAvg < PHlongAvg * c.EV_BuyFactor:
                if cash >= c.MyMinPurchase * MaxBuyOrdersAtOnce:
                    if c.MyMinPurchase > WeightThisBuyOrder*cash:
                        Purchase=c.MyMinPurchase
                    elif c.MyMaxPurchase < WeightThisBuyOrder*cash:
                        Purchase=c.MyMaxPurchase
                    else:
                        Purchase=WeightThisBuyOrder*cash
                    StockSharesToOwn = int(Purchase/CurrPrice)
                    StockValueTarget = StockSharesToOwn * CurrPrice
                    StockTarPer = StockValueTarget / PValue
                    TarPer(context, data, stock, StockTarPer)
    except: pass

#if cents not divisible by .05, round down if buy, round up if sell
def make_div_by_05(s, buy=False):
    s *= 20.00
    s =  math.floor(s) if buy else math.ceil(s)
    s /= 20.00
    return s

def cancel_open_buy_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
            if 0<order.amount: #it is a buy order
                cancel_order(order)

def cancel_open_orders(context, data):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            cancel_order(order)
            #message = 'Canceling order of {amount} shares in {stock}'
            #log.info(message.format(amount=order.amount, stock=stock))
    
def cancel_open_orders_for(context, data, security):
    oo = get_open_orders()
    if len(oo) == 0:
        return
    for stock, orders in oo.iteritems():
        for order in orders:
            if stock is security:
                if order.amount < context.portfolio.positions[stock].amount:
                    cancel_order(order)
                    #message = 'Canceling order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                else: # Do NOT want to cancel stop loss order
                    #message = 'NOT Canceling stop loss order of {amount} shares in {stock}'
                    #log.info(message.format(amount=order.amount, stock=stock))
                    pass

def MoreSignals(context, data):  

    update_indices(context, data)     
    last_vix = context.VIXprice = data.current('v', 'Close')
    last_vx1 = data.current('v1','Close')  
    last_vx2 = data.current('v2','Close')      
    last_vxv = data.current('vxv', 'Close')
    last_vix_200ma_ratio = data.current('v', '200ma Ratio')
           
    # Calculating the gap between spot vix and the first month vix future
    last_ratio_v_v1 = last_vix/last_vx1

    # Calculating the contango ratio of the front and second month VIX Futures 
    last_ratio_v1_v2 = last_vx1/last_vx2

    # Blending the previous two ratios together using a weighted average
    ratio_weight = 0.7
    last_ratio = (ratio_weight*last_ratio_v_v1) + ((1-ratio_weight)*last_ratio_v1_v2) - 1
    
    vix_vxv_ratio = last_vix/last_vxv
    
    # Retrieve SPY prices for technical indicators
    prices = data.history(context.spyg, 'open', 40, '1d')
    
    # Retrieve SPY MACD data
    macda, signal, hist = talib.MACD(prices, fastperiod=12,slowperiod=26,signalperiod=9)
    macd = macda[-1] - signal[-1]
    
    # Calculate how much vix moved the previous day
    if (context.vix <> -1) : 
        vix_ratio = last_vix/context.vix -1
    else :
        vix_ratio = 0
    context.vix = last_vix
    
    xiv_history = data.history(context.xiv, 'price', 2, '1d')  
    
    xiv_ratio = xiv_history[1]/xiv_history[0] - 1
    
    # Setting thresholds
    threshold_vix_too_low = 10.76   # 0 
    threshold_vix_200ma_ratio_low = 0.79  # 0 
    threshold_xiv = -0.049          # 1
    threshold_vxv_xiv = 0.87        # 2
    threshold_uvxy = 0.049          # 3
    threshold_macd = -0.55          # 3
    threshold_vxv_uvxy = 1.3        # 4
    threshold_vix_high = 19.9       # 5
    threshold_vc_low = -0.148       # 6
    threshold_vc_high = 0.046       # 8
    threshold_vc_high_2 = -0.06     # 8
    threshold_xiv_ratio = -0.053    # 10
    threshold_uvxy_ratio = 0.08     # 11

    # 0
    if last_vix < threshold_vix_too_low and last_vix_200ma_ratio < threshold_vix_200ma_ratio_low: # if VIX is too low, invest in UVXY witht he hope of a spike
        target_sid = context.uvxy
    # 1        
    elif last_ratio < threshold_xiv: # if contango is high, invest in XIV to gain from decay
        target_sid = context.xiv
    
    # 2
    elif vix_vxv_ratio < threshold_vxv_xiv: # if short term vol is low compared to mid term, invest in XIV to gain from decay
        target_sid = context.xiv

    # 3
    elif last_ratio > threshold_uvxy and macd > threshold_macd: # if backwardation is high, invest in UVXY to gain from decay
        target_sid = context.uvxy

    # 4
    elif vix_vxv_ratio > threshold_vxv_uvxy: # if short term vol is high compared to mid term, invest in UVXY to gain from growth
        target_sid = context.uvxy

    # 5
    elif last_vix > threshold_vix_high: # if VIX is too high, invest in XIV expecting that VIX will drop
        target_sid = context.xiv

    # 6
    elif vix_ratio < threshold_vc_low: # Vix down sharply, invest in XIV expecting that futures curve gets pulled down
        target_sid = context.xiv

    # 7
    elif vix_ratio > threshold_vc_high: # Vix up sharply, invest in UVXY expecting that futures curve gets pulled up
        target_sid = context.uvxy

    # 8
    elif vix_ratio > threshold_vc_high_2: #have to think
        target_sid = context.xiv

    # 9
    else:
        target_sid = context.uvxy

    # 10
    if (target_sid == context.xiv and xiv_ratio < threshold_xiv_ratio) : 
        # indicators say XIV but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq 

    # 11
    elif (target_sid == context.uvxy and xiv_ratio > threshold_uvxy_ratio) :
        # indicators say UVXY but it just dropped overnight, so go for TQQQ
        target_sid = context.tqqq
    
    context.BigSignalShortVIX = True if context.xiv  is target_sid else False
    context.BigSignalLongVIX  = True if context.uvxy is target_sid else False
    context.BigSignalTQQQ     = True if context.tqqq is target_sid else False
    
def VIX_Mix(context, data):
    c = context
    
    if 0 < c.SellAndWait:
        c.SellAndWait -= 1
        return

    cancel_open_orders(context, data) # avoid confusion

    ### Determine how much to risk in Long VIX ###
    # Load historical data for the stocks  
    hist = data.history(c.vxx, ['high', 'low', 'close'], 15, '1d')  
    # Calculate the ATR for the stock  
    atr_14 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=14)[-1]  
    atr_3 = talib.ATR(hist['high'],  
                    hist['low'],  
                    hist['close'],  
                    timeperiod=3)[-1]
    c.VIX_HedgeLeverage = c.VIX_MaxHedgeLeverage if atr_3 <= atr_14 else c.VIX_MinHedgeLeverage

    #Gets Moving Average of VXX
    price_hist = data.history(c.vxx, 'price', c.AvgLength, '1d')
    c.vxxAvg = price_hist.mean()
    
    #get data for calculations
    n = 200
    vxx_prices = data.history(c.vxx, "price", n + 2, "1d")
    vxx_lows = data.history(c.vxx, "low", n + 2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.LengthWVF,center=False).max()
    
    #William's VIX Fix indicator a.k.a. the Synthetic VIX
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100
    
    # calculated smoothed WVF
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.LengthEMA1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.LengthEMA2)
    
    #Do some checks for cross overs. 
    if WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-1]:
        wvf_crossedSmoothedWVF1 = True
    else: 
        wvf_crossedSmoothedWVF1 = False
    #Same except for smoothed2 
    if WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-1]:
        wvf_crossedSmoothedWVF2 = True
    else: 
        wvf_crossedSmoothedWVF2 = False
    
    #Current price of vxx
    vxxPrice = data.current(c.vxx, 'price')
    
    #SignalShortVIX 
    if ( wvf_crossedSmoothedWVF1 and WVF[-1] < c.SmoothedWVF2[-1]) or (wvf_crossedSmoothedWVF2 and wvf_crossedSmoothedWVF1):
        SignalShortVIX = True
    elif ((vxxPrice > c.vxxAvg and vxx_prices[-2] < c.vxxAvg) or (WVF[-1] < c.SmoothedWVF2[-1] and WVF[-2] > c.SmoothedWVF2[-1])):
        SignalShortVIX = False
    else:
        SignalShortVIX = True

    if (c.BigSignalShortVIX and SignalShortVIX): # Agree ShortVIX
        c.ShortVIX    = True
        c.LongVIX     = False
        c.Agree       = True

    elif (c.BigSignalLongVIX and not SignalShortVIX): # Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = True

    elif (c.BigSignalLongVIX and SignalShortVIX): # Not Agree LongVIX
        c.ShortVIX    = False
        c.LongVIX     = True
        c.Agree       = False

    ##
    # VIX_Mix only once until signal changes again
    # or
    # leverage drops too low
    ##

    l = c.account.leverage
    LevTooLow = True if (0.33 > l) or (0.90 < l < 1.05) else False
    p = c.portfolio.positions

    if c.BigSignalTQQQ:
        if LevTooLow or (c.XIV in p or c.UVXY in p):
            TarPer(context, data, c.XIV, 0.00)
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(1.00 / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)

    elif c.ShortVIX:
        if LevTooLow or (c.XIV not in p):
            TarPer(context, data, c.UVXY, 0.00)
            SetAsideStocks = c.SetAsideStocks
            SetAsideLeveragePositions = len(SetAsideStocks)
            for stock in SetAsideStocks:
                if not DataCanTrade(context, data, stock):
                    SetAsideStocks.remove(stock)
                    SetAsideLeveragePositions -= 1
            SetAsideLeverage = float(c.SetAsideLeverageTotal / SetAsideLeveragePositions) if 0 < SetAsideLeveragePositions else 0.00
            for stock in SetAsideStocks:
                TarPer(context, data, stock, SetAsideLeverage)
            c.BoughtShortVIX = False
            c.PriceXIV = 0.00

    elif c.LongVIX:
        if LevTooLow or (c.UVXY not in p):
            TarPer(context, data, c.XIV, 0.00)
            for stock in c.SetAsideStocks:
                TarPer(context, data, stock, 0.00)
            c.BoughtLongVIX = False
            c.PriceUVXY = 0.00

    # Record / log stuff I want to know
    c.XIVprice  = data.current(c.XIV, 'price')
    c.UVXYprice = data.current(c.UVXY, 'price')
    TQQQprice = data.current(c.tqqq, 'price')
    #record(XIV  = c.XIVprice)
    #record(UVXY = c.UVXYprice)
    #record(TQQQ = TQQQprice)
    BigSignal = 'NoBigSignal'
    BigSignal = 'ShortVIX' if c.BigSignalShortVIX else BigSignal
    BigSignal = ' LongVIX' if c.BigSignalLongVIX  else BigSignal
    BigSignal = '    TQQQ' if c.BigSignalTQQQ     else BigSignal
    SyntheticVIX = 'NoSyntheticVIX'
    SyntheticVIX = 'ShortVIX' if c.ShortVIX else SyntheticVIX
    SyntheticVIX = ' LongVIX' if c.LongVIX  else SyntheticVIX
    log.info('BigSignal / SyntheticVIX: {} / {}     VIX: {:.2f}     XIV: {:.2f}     UVXY: {:.2f}     TQQQ: {:.2f}'
        .format(BigSignal, SyntheticVIX, c.VIXprice, c.XIVprice, c.UVXYprice, TQQQprice)
    )

def update_indices(context, data):
    context.fetch_failed = False
    context.vix_vals = unpack_from_data(context, data, 'v')    
    context.vxv_vals = unpack_from_data(context, data, 'vxv')  
    context.vx1_vals = unpack_from_data(context, data, 'v1')
    context.vx2_vals = unpack_from_data(context, data, 'v2')

def fix_close(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%m/%d/%Y')))
    df = df.sort_values(by='Date', ascending=True)
    return df

def fix_closeVX(df,closeField):
    df = df.rename(columns={closeField:'Close'})
    # remove spurious asterisks
    df['Date'] = df['Date'].apply(lambda dt: re.sub('\*','',dt))
    # convert date column to timestamps
    df['Date'] = df['Date'].apply(lambda dt: pd.Timestamp(datetime.strptime(dt,'%Y-%m-%d')))
    df = df.sort_values(by='Date', ascending=True)
    return df


def subsequent_trading_date(date):
    tdays = tradingcalendar.trading_days
    last_date = pd.to_datetime(date)
    last_dt = tradingcalendar.canonicalize_datetime(last_date)
    next_dt = tdays[tdays.searchsorted(last_dt) + 1]
    return next_dt

def add_last_bar(df):
    last_date = df.index[-1]
    subsequent_date = subsequent_trading_date(last_date)
    blank_row = pd.Series({}, index=df.columns, name=subsequent_date)
    # add today, and shift all previous data up to today. This 
    # should result in the same data frames as in backtest
    df = df.append(blank_row).shift(1).dropna(how='all')
    return df

def shift_data(df):
    df = add_last_bar(df)
    df.fillna(method='ffill') 
    df['PrevCloses'] = my_rolling_apply_series(df['Close'], to_csv_str, History)
    dates = pd.Series(df.index)
    dates.index = df.index
    df['PrevDates'] = my_rolling_apply_series(dates, to_csv_str, History)
    return df

def unpack_from_data(context, data, sym):
    try:
        v = data.current(sym, 'PrevCloses')
        i = data.current(sym, 'PrevDates')
        return from_csv_strs(i,v,True).apply(float)
    except:
        log.warn("Unable to unpack historical {s} data.".format(s=sym))
        context.fetch_failed = True

def addFieldsVIX(df):
    df = fix_close(df,'VIX Close')
    df['200ma'] = df['Close'].rolling(200).mean()
    df['200ma Ratio'] = df['Close'] / df['200ma']

    return df

def addFieldsVXV(df):
    df.rename(columns={'Unnamed: 0': 'Date'}, inplace=True)
    df = fix_close(df,'CLOSE')
    return df

def addFieldsVX1(df):
    df = fix_closeVX(df,'F1')
    return df

def addFieldsVX2(df):
    df = fix_closeVX(df,'F2')
    return df

# convert a series of values to a comma-separated string of said values
def to_csv_str(s):
    return functools.reduce(lambda x,y: x+','+y, pd.Series(s).apply(str))

# a specific instance of rolling apply, for Series of any type (not just numeric,
# ala pandas.rolling_apply), where the index of the series is set to the indices
# of the last elements of each subset
def my_rolling_apply_series(s_in, f, n):
    s_out = pd.Series([f(s_in[i:i+n]) for i in range(0,len(s_in)-(n-1))]) 
    s_out.index = s_in.index[n-1:]
    return s_out

# reconstitutes a Series from two csv-encoded strings, one of the index, one of the values
def from_csv_strs(x, y, idx_is_date):
    s = pd.Series(y.split(','),index=x.split(','))
    if (idx_is_date):
        s.index = s.index.map(lambda x: pd.Timestamp(x))
    return s

def pvr(context, data):
    ''' Custom chart and/or logging of profit_vs_risk returns and related information from https://www.quantopian.com/posts/pvr#569784bda73e9bf2b7000180
    '''  
    #import time  
    #from datetime import datetime  
    #from pytz import timezone      # Python will only do once, makes this portable.  
                                   #   Move to top of algo for better efficiency.  
    c = context  # Brevity is the soul of wit -- Shakespeare [for readability]  
    if 'pvr' not in c:

        # For real money, you can modify this to total cash input minus any withdrawals  
        manual_cash = c.portfolio.starting_cash  
        time_zone   = 'US/Central'   # Optionally change to your own time zone for wall clock time

        c.pvr = {  
            'options': {  
                # # # # # # # # # #  Options  # # # # # # # # # #  
                'logging'         : 0,    # Info to logging window with some new maximums  
                'log_summary'     : 126,  # Summary every x days. 252/yr

                'record_pvr'      : 1,    # Profit vs Risk returns (percentage)  
                'record_pvrp'     : 0,    # PvR (p)roportional neg cash vs portfolio value  
                'record_cash'     : 1,    # Cash available  
                'record_max_lvrg' : 0,    # Maximum leverage encountered  
                'record_risk_hi'  : 0,    # Highest risk overall  
                'record_shorting' : 0,    # Total value of any shorts  
                'record_max_shrt' : 0,    # Max value of shorting total  
                'record_cash_low' : 0,    # Any new lowest cash level  
                'record_q_return' : 0,    # Quantopian returns (percentage)  
                'record_pnl'      : 1,    # Profit-n-Loss  
                'record_risk'     : 1,    # Risked, max cash spent or shorts beyond longs+cash  
                'record_leverage' : 0,    # End of day leverage (context.account.leverage)  
                # All records are end-of-day or the last data sent to chart during any day.  
                # The way the chart operates, only the last value of the day will be seen.  
                # # # # # # # # #  End options  # # # # # # # # #  
            },  
            'pvr'        : 0,      # Profit vs Risk returns based on maximum spent  
            'cagr'       : 0,  
            'max_lvrg'   : 0,  
            'max_shrt'   : 0,  
            'risk_hi'    : 0,  
            'days'       : 0.0,  
            'date_prv'   : '',  
            'date_end'   : get_environment('end').date(),  
            'cash_low'   : manual_cash,  
            'cash'       : manual_cash,  
            'start'      : manual_cash,  
            'tz'         : time_zone,  
            'begin'      : time.time(),  # For run time  
            'run_str'    : '{} to {}  ${}  {} {}'.format(get_environment('start').date(), get_environment('end').date(), int(manual_cash), datetime.now(timezone(time_zone)).strftime("%Y-%m-%d %H:%M"), time_zone)  
        }  
        if c.pvr['options']['record_pvrp']: c.pvr['options']['record_pvr'] = 0 # if pvrp is active, straight pvr is off  
        if get_environment('arena') not in ['backtest', 'live']: c.pvr['options']['log_summary'] = 1 # Every day when real money  
        log.info(c.pvr['run_str'])  
    p = c.pvr ; o = c.pvr['options'] ; pf = c.portfolio ; pnl = pf.portfolio_value - p['start']  
    def _pvr(c):  
        p['cagr'] = ((pf.portfolio_value / p['start']) ** (1 / (p['days'] / 252.))) - 1  
        ptype = 'PvR' if o['record_pvr'] else 'PvRp'  
        log.info('{} {} %/day   cagr {}   Portfolio value {}   PnL {}'.format(ptype, '%.4f' % (p['pvr'] / p['days']), '%.3f' % p['cagr'], '%.0f' % pf.portfolio_value, '%.0f' % pnl))  
        log.info('  Profited {} on {} activated/transacted for PvR of {}%'.format('%.0f' % pnl, '%.0f' % p['risk_hi'], '%.1f' % p['pvr']))  
        log.info('  QRet {} PvR {} CshLw {} MxLv {} RskHi {} MxShrt {}'.format('%.2f' % (100 * pf.returns), '%.2f' % p['pvr'], '%.0f' % p['cash_low'], '%.2f' % p['max_lvrg'], '%.0f' % p['risk_hi'], '%.0f' % p['max_shrt']))  
    def _minut():  
        dt = get_datetime().astimezone(timezone(p['tz']))  
        return str((dt.hour * 60) + dt.minute - 570).rjust(3)  # (-570 = 9:31a)  
    date = get_datetime().date()  
    if p['date_prv'] != date:  
        p['date_prv'] = date  
        p['days'] += 1.0  
    do_summary = 0  
    if o['log_summary'] and p['days'] % o['log_summary'] == 0 and _minut() == '100':  
        do_summary = 1              # Log summary every x days  
    if do_summary or date == p['date_end']:  
        p['cash'] = pf.cash  
    elif p['cash'] == pf.cash and not o['logging']: return  # for speed

    shorts = sum([z.amount * z.last_sale_price for s, z in pf.positions.items() if z.amount < 0])  
    new_key_hi = 0                  # To trigger logging if on.  
    cash       = pf.cash  
    cash_dip   = int(max(0, p['start'] - cash))  
    risk       = int(max(cash_dip, -shorts))

    if o['record_pvrp'] and cash < 0:   # Let negative cash ding less when portfolio is up.  
        cash_dip = int(max(0, cash_dip * p['start'] / pf.portfolio_value))  
        # Imagine: Start with 10, grows to 1000, goes negative to -10, should not be 200% risk.

    if int(cash) < p['cash_low']:             # New cash low  
        new_key_hi = 1  
        p['cash_low'] = int(cash)             # Lowest cash level hit  
        if o['record_cash_low']: record(CashLow = p['cash_low'])

    if c.account.leverage > p['max_lvrg']:  
        new_key_hi = 1  
        p['max_lvrg'] = c.account.leverage    # Maximum intraday leverage  
        if o['record_max_lvrg']: record(MaxLv   = p['max_lvrg'])

    if shorts < p['max_shrt']:  
        new_key_hi = 1  
        p['max_shrt'] = shorts                # Maximum shorts value  
        if o['record_max_shrt']: record(MxShrt  = p['max_shrt'])

    if risk > p['risk_hi']:  
        new_key_hi = 1  
        p['risk_hi'] = risk                   # Highest risk overall  
        if o['record_risk_hi']:  record(RiskHi  = p['risk_hi'])

    # Profit_vs_Risk returns based on max amount actually invested, long or short  
    if p['risk_hi'] != 0: # Avoid zero-divide  
        p['pvr'] = 100 * pnl / p['risk_hi']  
        ptype = 'PvRp' if o['record_pvrp'] else 'PvR'  
        if o['record_pvr'] or o['record_pvrp']: record(**{ptype: p['pvr']})

    if o['record_shorting']: record(Shorts = shorts)             # Shorts value as a positve  
    if o['record_leverage']: record(Lvrg   = c.account.leverage) # Leverage  
    if o['record_cash']    : record(Cash   = cash)               # Cash  
    if o['record_risk']    : record(Risk   = risk)  # Amount in play, maximum of shorts or cash used  
    if o['record_q_return']: record(QRet   = 100 * pf.returns)  
    if o['record_pnl']     : record(PnL    = pnl)                # Profit|Loss

    if o['logging'] and new_key_hi:  
        log.info('{}{}{}{}{}{}{}{}{}{}{}{}'.format(_minut(),  
            ' Lv '     + '%.1f' % c.account.leverage,  
            ' MxLv '   + '%.2f' % p['max_lvrg'],  
            ' QRet '   + '%.1f' % (100 * pf.returns),  
            ' PvR '    + '%.1f' % p['pvr'],  
            ' PnL '    + '%.0f' % pnl,  
            ' Cash '   + '%.0f' % cash,  
            ' CshLw '  + '%.0f' % p['cash_low'],  
            ' Shrt '   + '%.0f' % shorts,  
            ' MxShrt ' + '%.0f' % p['max_shrt'],  
            ' Risk '   + '%.0f' % risk,  
            ' RskHi '  + '%.0f' % p['risk_hi']  
        ))  
    if do_summary: _pvr(c)  
    if get_datetime() == get_environment('end'):   # Summary at end of run  
        _pvr(c) ; elapsed = (time.time() - p['begin']) / 60  # minutes  
        log.info( '{}\nRuntime {} hr {} min'.format(p['run_str'], int(elapsed / 60), '%.1f' % (elapsed % 60)))

def handle_data(context, data): 
    pvr(context, data)
    c = context
    if c.ShowMaxLev:
        if c.account.leverage > c.mx_lvrg:  
            c.mx_lvrg = c.account.leverage  
            record(mx_lvrg = c.mx_lvrg)    # Record maximum leverage encountered

    ##
    # Buy XIV
    ##
    if c.ShortVIX and not c.BoughtShortVIX and not c.SellAndWait:
        PriceXIV = data.current(c.XIV, 'price')
        if not c.PriceXIV: c.PriceXIV = PriceXIV
        if PriceXIV < c.PriceXIV:
            c.PriceXIV = PriceXIV
        elif PriceXIV > 1.0025 * c.PriceXIV:
            c.BoughtShortVIX = True
            TarPer(context, data, c.XIV, c.VIX_GrowthLeverage)

    ##
    # Buy UVXY
    ##
    if c.LongVIX and not c.BoughtLongVIX and not c.SellAndWait:
        PriceUVXY = data.current(c.UVXY, 'price')
        if not c.PriceUVXY: c.PriceUVXY = PriceUVXY
        if PriceUVXY < c.PriceUVXY:
            c.PriceUVXY = PriceUVXY
        elif PriceUVXY > 1.005 * c.PriceUVXY:
            c.BoughtLongVIX = True
            TarPer(context, data, c.UVXY, c.VIX_HedgeLeverage)

    ##
    # RogueTrader here and in RogueTrader scheduled function
    ##
    if c.RogueTrader and not c.SellAndWait:
        for position in c.portfolio.positions.itervalues():
            if (position.sid in c.VIXstocks) or (position.sid in c.SetAsideStocks):
                if position.amount == 0:
                    if position.asset.symbol in c.stops: del c.stops[position.asset.symbol]
                    continue
                elif position.asset.symbol not in c.stops:
                    stoploss= c.stoploss if position.amount > 0 else -c.stoploss
                    c.stops[position.asset.symbol]=position.last_sale_price*(1-stoploss)
                    #log.info(' ! I have added '+str(position.asset.symbol)+' to Stops @ '+str((position.last_sale_price)*(1-stoploss)))
                elif c.stops[position.asset.symbol] < position.last_sale_price*(1- c.stoploss) and position.amount > 0:
                    c.stops[position.asset.symbol]=position.last_sale_price*(1- c.stoploss)
                    #log.info(' ! I have updated '+str(position.asset.symbol)+'- (Long) to stop @ '+str((position.last_sale_price)*(1- c.stoploss)))
                elif c.stops[position.asset.symbol] > position.last_sale_price and position.amount > 0:
                    #sell
                    log.info(' ! '+str(position.asset.symbol)+'- (Long) has hit stoploss @ '+str(position.last_sale_price))
                    if get_open_orders(position.sid): cancel_open_orders_for(context, data, position.sid)
                    c.stoppedout.append(position.asset.symbol)
                    TarPer(context, data, position.sid, 0.00)
     
                ##
                # Sell and Wait
                ##
                if (
                        (position.sid is c.XIV and 0 < position.amount)
                        and
                        (10.76 < c.vix < 12) and (position.last_sale_price > 1.013 * c.XIVprice)
                ):
                    c.SellAndWait = 1
                elif (
                        (position.sid is c.UVXY and 0 < position.amount)
                        and
                        (position.last_sale_price > 1.40 * c.UVXYprice)
                ):
                    c.SellAndWait = 3

        ##
        # Sell and Wait
        ##
        if 0 < c.SellAndWait:
            for stock in c.portfolio.positions:
                    if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                        cancel_open_orders_for(context, data, stock)
                        TarPer(context, data, stock, 0.00)

def CherryPickerClose(context,data):    
    
    c = context
    vxx_prices = data.history(c.VXX, "high", c.wvf_length*2, "1d")
    vxx_lows = data.history(c.VXX, "low", c.wvf_length*2, "1d")
    vxx_highest = vxx_prices.rolling(window = c.wvf_length, center=False).max()
    WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100

    rsi = talib.RSI(vxx_prices, timeperiod=c.rsi_length)
    
    c.SmoothedWVF1 = talib.EMA(WVF, timeperiod=c.ema1) 
    c.SmoothedWVF2 = talib.EMA(WVF, timeperiod=c.ema2)
    
    ## BUY RULES
    #if WVF crosses over smoothwvf1 and wvf < smoothwvf2
    if (
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] < c.SmoothedWVF2[-1])
        or
        (c.SmoothedWVF1[-2] < c.SmoothedWVF2[-2] and c.SmoothedWVF1[-1] > c.SmoothedWVF2[-1])
        or
        (WVF[-1] > c.SmoothedWVF1[-1] and WVF[-2] < c.SmoothedWVF1[-2] and WVF[-1] > c.SmoothedWVF2[-1] and WVF[-2] < c.SmoothedWVF2[-2])
    ):
        c.sell = False
        for stock in c.portfolio.positions:
            if (stock in c.VIXstocks) or (stock in c.SetAsideStocks):
                if stock is not c.XIV:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 0.00)
                else:
                    cancel_open_orders_for(context, data, stock)
                    TarPer(context, data, stock, 1.00)
      
    ## SELL RULES
    if c.portfolio.positions[c.XIV].amount > 0:
        #if rsi crosses over rsi_trigger
        if rsi[-2] < c.rsi_trigger and rsi[-1] > c.rsi_trigger:
            c.sell = True
            
        #if wvf crosses under smoothwvf2: sell
        elif WVF[-2] > c.SmoothedWVF2[-2] and WVF[-1] < c.SmoothedWVF2[-1]:
            c.sell = True

        else:
            c.sell = False
There was a runtime error.

I think your drop in DD is due to a portion of your portfolio that's not making any gains/losses: The extreme vetting portion. I removed all the VIX trading and profits/losses were basically nonone. You'd be better off putting that portion into SHY/cash or someting.

Great job.

I turned off my live trade algo. For obvious reasons, I gotta stop relying on it. For now I am going to try to adjust to doing manual trades with the paper trade as a guide. As a small benefit, the paper trade seems to never die, from what I've experienced. Also, the paper trade still shows the current price, fifteen minute delayed I think.

How does everyone feel about live trading being shutdown. What are everyone's plans?

@nick I've been manually trading XIV and VXX. I watch the paper trades of this algo and a number of others, but mostly just to confirm my own hunches. Most of the volatility algos I'm watching are down over the past few weeks. My manual trades are significantly up -- might just be luck. Key is to have stop losses in place. For the most part these volatility algorithms are more crippled by the quantopian platform than they get anything out of it. Will be really easy to get them up and running on my local machine.

Probably not the best place to express how you feel about it, there's a whole thread for that

https://www.quantopian.com/posts/phasing-out-brokerage-integrations

People are also discussing what next there and here: https://www.quantopian.com/posts/questionnaire-for-quantopian-live-brokerage-traders

The more people coordinating on a single thread, the easier it will be to figure out.

@Charles, why have you stopped it? In backtesting it has managed well the big recent spikes in volatility. Do you see a significant difference between real trade and backtest?

@Viridian, since mid March, many vola algos that were making good money drastically reduced the positive results. The low volatility regime and market trendless changed the intraday pattern. This is hurting many volatility algos. I stopped them and am now doing the same as you, manual trade.

Any word on if paper trading will be phased out as well on Quantopian?

@Jay
I doubt it. That is one method that they / we do out of sample testing, I think.

@Charles
Any thoughts about moving this/just the vixmix over to IBridgePy or Zipline-live? Have been running this live with a small position on InteractiveBrokers where the data seems to perform better. It would be a shame to see it go in a month just because live-trading ends on this site.

@Charles

Have you thought about moving to Quantconnect, Zipline-live, or any other alternatives?

Edit: ibridgepy might be a viable option, which you can view right here:
https://www.quantopian.com/posts/ibridgepy-setup#59a596becd58cd0010212a1d

@everyone
All options are on the table. I may be a bit slow to change over to anything. I just now today, finished moving from a 5 bedroom to a 2 bedroom. I am exhausted. I have a lot of distractions going on right now. Not outright ignoring all of this. Simply don't have much energy / time to devote to it at this moment.

slight update: I asked Rh for help / direction on viable options for live trading algo traders such as myself. Waiting for response from Rh.

@charles

I’ve been using a electron based desktop client for robinhood for some time.

I’m currently trying to find some time to take the python robinhood api and couple it to your algos.

I’m a JavaScript developer so it’ll probably be painful to get working.

Do you know if or how these algos could run on a local machine.

From the looks of things, it’s pretty simple to hook into robinhoods api. Unfortunately I only discovered your work after the shutdown and am determined to get a solution up and running. If you have any suggestions on if this code will run locally, I’ll start an implementation.

I’ll start researching as I’m sure it’s straight forward to run this algo on my own machine?

If anyone is interested in joining me, I’ll create a repo. As I said, I don’t write python

No meaningful update from Rh yet.

However, here is my update as to my status. This algo broke when noko.csv stopped being provided by another Q user. I did attempt to adjust this algo to work without noko.csv. The results were not satisfactory. I found another algo which is not currently broken which I am using instead. It is Rolando Retana version of Kory Hoang algo Ballistic XIV https://www.quantopian.com/posts/ballistic-xiv-slash-vxx-my-best-long-xiv-slash-vxx-strategy-to-date#perf-599cda91b97574555fccd7a0

I am able to get Robinhood running in Android emulator Jar of Beans. However, I am not actually using that actively.

I am using:
the above mentioned algo as live paper trade 15 minute delay
PyAutoGUI
Google Chrome extension Little John

My setup is crude. I work on it a little each day. I am doing manual trades until the automation is reliable. I think I will have the automation running by tomorrow trading hours. I am using I3 Window Manager in Ubuntu Linux on my laptop. PyAutoGUI can work on whatever setup you have. I enjoy Linux, Python, and programming. I do not currently have a job except driving for Uber. So I have more time to do this stuff, which I do enjoy, so I am not in a hurry to get another regular job. Right now I am living off of stocks and Uber. My budget is a poor man budget more than ever now. But I love the freedom to spend more time with my wife, who does need my frequent help because of her medical problems.

Some news to me there, thx.
I spend ~97%+ time toward the fund but my Robinhood algo, modified early CWitt code quadrupled in 10 months, would have placed serious $$ in it soon.

I like your approach
Im actually using your algo from another RH vetting thread you have
My main question is how are you actually running the algo which will callback to PyAutoGUI?

Seeing as you know python, check these out
https://github.com/Jamonek/Robinhood
https://github.com/Bekt/robinhood-client
https://github.com/able900/robinhood

My plan is to pretty much use this api to trigger the trades, but i dont know how you get them running locally

Im also thinking of writing a chrome extension which watches the live trade run in quantopain, then posts to a node server which will execute the python commands

Id appreciate any help and would gladly share my work with you :) your algos have backtested beautifully.
Next week ill be running it against the market and seeing what results spit out of quant. If theres something there, then im going to likely run a chrome extension to forward the algo trades to RH

@Blue, Glad to hear you are doing well with one of my algos still! There are plenty of them that do not rely on noko.csv. This algo would get even better returns I believe than the one I am using. But I will have to figure out how to unbreak this algo later. I attempted to fix it, but the returns were destroyed. So for now I punted.

@Everybody else, I finished my automation. It is crude and custom to my situation, but I believe it stands a pretty good chance of being reliable, so I don't have to watch it every minute. It is running on my laptop. And like I said earlier, I am using the Q live 15 minute delayed paper trade with my own PyAutoGUI automation watching it for buys and sells. Because of the 15 minute delay, I set buys to a slightly adjusted limit price. But sells are market orders. We shall see how well it works tomorrow morning. I missed out on a big gain Friday because I didn't do what it said to do. When will I learn?

@Zack, your implementation ideas sound promising. I am using what I feel comfortable with at this point. We shall see how it does this week.

Thanks Charles

I’ll keep you informed of my progress as well. Thank you for you algos and input into the existing challenges we now face.

I am finding more success directly using the Robinhood API reference at https://github.com/sanko/Robinhood/blob/master/ .
There is something extra nice about being able to execute an order exactly with all the parameters I want.

So, it looks like I will use a combination of:
Ubuntu Linux
i3 Window Manager
Google Chrome or Chromium
GNOME Terminal
Monkey Studio
Python3
PyAutoGUI
TCL Expect
Robinhood API reference at https://github.com/sanko/Robinhood/blob/master/
Paper trade Rolando Retana version of Kory Hoang algo Ballistic XIV https://www.quantopian.com/posts/ballistic-xiv-slash-vxx-my-best-long-xiv-slash-vxx-strategy-to-date#perf-599cda91b97574555fccd7a0

Hey Chris

I’m glad you are finding some success :)
I myself have also made some headway. For the sake of documenting this, as well as any input from the community - here is where I’m at.

I wanted a way to keep track of today’s trades and I want to also see yesterday’s.

Problem is, the order table uses a virtual dom and only loads a couple orders.

I’ve developed a extension which pretty much tricks the virtualDom into showing all data. After deciphering their codebase I was able to locate a few global functions which gives me access to the entire web application. With this I am able to load all the trades I’ve done. Their developers store most of their constructors in memory which make accessing script instances extremely hard. I’m considering creating service workers to proxy the applications scripts back onto itself, allowing me to essentially rewrite their frontend and take full control of Quantopians paper trading platform. I would like to move to direct websocket communication, which is pretty simple but I need to replicate Qs sid to stock name. The Json comes back without the stock symbol. There’s another function which translates it that I need to gain access to. I must admit, that table has some terrible performance, extending the amount of rows to and running all their updates on that table is painful. Once the table is loaded, I use mutation observers on the DOM to spot changes, then patch them into my persisted object, which goes back to RH for synchronization.

I’ve noticed a couple forms hidden inside. Along with some iframes, I’ll need more time to investigate but with access to their models along with watiching what chatter happens between frames, I may be able to create a more robust api on both ends.

I iterate over orders in the table and construct a object with a key that’s hashed uniquely based on the data. Now that I have the trades. I run a server which intercepts the object.

On the server side (which might just be another service worker in chrome) I do a call to robinhoods api, and get my trade history there. Pretty much synchronize the trades and make sure that Robinhood is placing the same orders as Q. If there’s a new trade in the order book that’s not in RH, I push a new order to the api.

I have noticed that some Robinhood trades are executed but they are not on Q. I’m looking at setting an exclusion list Incase I want to manually trade something. But if a limit order Q places that is later cancelled because it wasn’t filled. But filled in RH, I track that independently until it’s profitable, then sell it programmatically.

Once I get enough understanding, I should be able to actually pass data back into the python algorithm and make modifications there, such as if I deposit more money or bought a stock that I want to track with the algo. I doubt they will allow cross origin requests, but it should be fairly simple to transcode their authentication into some headers. I’ve done this before to issue local sessions from a remote host with great success.

One of your Q algos places many limit orders, most are cancelled, I do want to try and minimize the amount of queries I do to RH and Q, to avoid suspicious activity. I’m considering some persistent layer that can query endpoints less frequent. Firebase might be an option just because I can asynchronously write and read elsewhere, changing the databse would indirectly execute a RH command.

Digging further into how Q runs. I discovered some websockets and a whole bunch of code. Things that may be beneficial to us, but will not mention them publicly. Luckily, the compilers that are used to build the web app are pretty bad, there’s enough obsfucated code but the manner it’s mangled makes it easy to reverse.

I’m not a fan of this delay of 15 min. Your algo does place limit orders though, so in some cases they appear before being filled, letting me forward them to RH with no profit loss. However, I wonder if it’s possible to use Robinhood as the data source? I can get the endpoint and historical data. With that we would have up to data info. Even mess with the dates so that it appears 15 min behind. I also might have found the golden goose, but need to pick the data apart.

For right now I built a chrome extension. But likely will move to a headless solution that I can host in the cloud for continuous trading. If you, or anyone else is interested in working together on some solutions, or discoveries I may or may not have found under the hood. Be it python algo work, zipline, or JavaScript. [email protected]

Just realized that your name was autocorrected. Apologies.

My time is extremely limited, but am hoping to have a full implementation by this weekend. I do however see more potential lurking inside the codebase, but I’ll need to see how secure their indirect socket to server communication is.

Sounds promising Zack!

I think I finally got my automation wrapper (around the paper trade Ballistic XIV algo mentioned above) running without any showstopper bugs. I am buying at slight discounted limit price and selling at slight padded limit price to attempt to compensate for the apparent disadvantage of 15 minute delayed paper trading. We shall see if this is profitable over the next couple of weeks.

I have also got my chrome extension stable, I’ll be testing it today to see if the my new cacheing system works.

Monday it trades without a problem

Any updates on this guys? I would love to join the development side of things with Python/Javascript.

So far it looks to be profitable the way I am doing it, at least long term, which is what I am aiming for. I've been making small tweaks to my automation wrapper daily. Today, this week actually, is probably a good test. The main thing I like about this method is that I can control it more reliably and customize it according to my needs. Depending on how I fare this week with the larger swings in volatility, I may need to make some more adjustments.

As I said before, this is running in an environment and with software tools that I am comfortable with. It may not work for others. If anyone is seriously interested in using my code in their own environment, I am willing, within reason, to assist. Of course, money helps to motivate me.

I am confident that, even if I end up losing some money short term, long term will trend profitable. This setup feels like I have more influence over my destiny. I hesitate to say "control over my destiny" because so many things out of my control can happen. I think it is good to never forget that.

@Charles If you're still around, would love an update

I tried cloning the latest version of this algo and got the following error "Exception: Could not connect to http://52.15.233.150/noko.csv"

Does anyone know content description of NOKO.CSV and format?
If it's straight forward maybe I can make it available to the community.

@Mike It seems to be working well. I have tweaked the parameters of my automation wrapper a few times, including before market open today. The paper trade on Quantopian has been running since 10/11/2017. The paper trade at this moment made 3.71% return. The 2 or 3 down periods have been a bit difficult for this algorithm to make a profit. Even so, it is a profit. Long term, it tends to do well. My real return was noticeably better, 20.39%. No guarantee of future results. I did benefit from a particularly good period of growth in TQQQ, about 8% return during a very short term. For about the last month or so though, I have only been in XIV. When I get my balance firmly above $25,000 again, then I will probably add TQQQ and UVXY strategies again. Also, keep in mind that I am only using the underlying Quantopian paper trading for buy / sell signals. But I am, in effect, changing the behavior by not buying and selling the same as the algo does.

@chandra Look at https://www.quantopian.com/posts/deployed-two-xiv-slash-uvxy-slash-tqqq-strategies-for-paper-trading-dot-dot-dot-will-make-it-live-trading-after-a-month#59b4530c8c942b00108e556f Honver Lam should be able to answer your question. I believe he was providing the noko.csv resource for the rest of us.

@Charles, Do you have a blog that we can follow? can you share how to build automation wrapper between Quantopian and Robinhood?

@Jeff, I do have a blog at http://charlesweldonwitt.blogspot.com/ . I have not updated it in a while and I have not yet put anything related to algorithmic trading on there. I am currently adding cryptocurrency trading to my automation, so that will keep me busy for a while while I tweak that.

For anybody that checks out the blog. I have retired from audiobook narration. That turned out to be a labor of love because the author was dying and wanted to see and hear his work published as an audiobook.

@Charles, it might be a good idea to manager your blog. Reader can donate and after you gain enough traffic, you can make money by commercials.

@Charles, I tested the algorithm that trades non-liquid stocks. It seems it works very well for small marketcap stocks with low liquidity while it does not work for mid or large CAPs. I wonder what is the fundamental reason that the algo works

It seems it works very well for small marketcap stocks with low liquidity while it does not work for mid or large CAPs

Likely answer is that micro-caps and small-caps are too small for hedge funds to trade, and so there are more market inefficiencies to take advantage of.