Back to Community
"Futures not allowed for live trading" error upon attempt to paper trade or broker trade.

"Futures not allowed for live trading" error upon attempt to paper trade or broker trade. Could someone from Quantopian explain this. Targeted algorithm is not trading Futures, but instead is using them as an indicator to trade valid sids. Why this is not allowed? What particular hurdles are there? How this could be "fixed"?

Clone Algorithm
120
Loading...
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
import talib
from math import trunc  
from pytz import timezone      
import numpy as np
import pandas as pd
import datetime
import math
import time
import re
import functools
import itertools

from zipline.utils import tradingcalendar

#Max_Wager in $ we want to invest into this algorithm
Max_Wager = 0 #5000.
#Or set above Max_Wager to 0 and set Max_Wager_Percent, as percent of portfolio
Max_Wager_Percent = 40.

History = 128
# Setting thresholds
threshold_vix_too_low = 10.8 # first percentile, very rare case, very likely VIX will pop so we want to be in UVXY
    
threshold_xiv = -0.049 # 60th percentile, as we want to be primarily in XIV
threshold_uvxy = -threshold_xiv # symmetry 

threshold_vxv_xiv = 0.79 # first percentile, very rare case
threshold_vxv_uvxy = 2 - threshold_vxv_xiv # symmetry 
    
threshold_macd = -0.55 # first percentile, we want to pass 99% of the cases here
    
threshold_vix_high = 19.9 # 85th percentile, we are already going to be in XIV 60% of the time, so need to be careful
# no more than total 75% of the time in XIV
    
threshold_vix_low = 11.5 # 5th percentile, very rare case, may be VIX will pop so we want to be in UVXY

threshold_vc_low = -0.148 # 1.5th percentile, very rare, we are already going to be in XIV 60% of the time, so need to be careful
# no more than total 75% of the time in XIV
    
threshold_vc_high = 0.046 #80th percentile, we will hardly be in UVXY (actually 51 is 80th percentile)
# so we need to pick up some cases where which is biased towards UVXY to get to at least 15% of the time in UVXY

threshold_vc_low_2 = 0.0 #50th percentile, below this we go for UVXY in lieu of any other signals
threshold_vc_high_2 = -0.06 # testing this, this is fitted  

# relaxing condition to invest in XIV from 60th to 62nd percentile (~5%), absolute value also relaxes ~5% from -0.049 to -0.046
threshold_xiv_2 = -0.046 # 62th percentile
# this is to check for one last time if no signals have it, before we default to TQQQ
    
threshold_uvxy_2 = -0.008 # 85th percentile, taking a risk to invest in UVXY when there's hardly any contango or backwardation
# this is to check for one last time if no signals have it, before we default to TQQQ
    
threshold_xiv_ratio = -0.06 # first percentile
# if XIV has dropepd that much we probably don't want to be long XIVeven though other signals say yes, default to TQQQ
threshold_uvxy_ratio = -threshold_xiv_ratio # symmetry
# if XIV has gone up that much we probably don't want to be long UVXY even though other signals say yes, default to TQQQ

# Blending two V1 and V2 ratios  together using a weighted average
ratio_weight = 0.7

def initialize(context):
    
    vixUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv'
    vxvUrl = 'http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vxvdailyprices.csv'

    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.futures = continuous_future('VX')
    
    set_slippage(slippage.FixedSlippage(spread=0.0))
    
    schedule_function(my_rebalance, date_rules.every_day(), time_rules.market_open(hours = 0, minutes = 1))
    
def my_rebalance(context, data):  
    
    update_indices(context, data)     
    last_vix = data.current('v', 'Close')
    last_vxv = data.current('vxv', 'Close')

    cl_chain = data.current_chain(context.futures)
    front = cl_chain[0]
    second = cl_chain[1]

    last_vx1 = data.current(front, 'price')
    last_vx2 = data.current(second, 'price')
    
    log.info("%s %5.3f %s %5.3f Vix %5.3f Vxv %5.3f" %(front, last_vx1, second, last_vx2, last_vix, last_vxv))

    # Calculating the gap ratio 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
    # average of above 2 using ratio_weight (more to front month)
    last_ratio = (ratio_weight*last_ratio_v_v1) + ((1-ratio_weight)*last_ratio_v1_v2) - 1
    # VIX to VXV ratio
    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
   
    #change in XIV from previous day
    xiv_history = data.history(context.xiv, 'price', 2, '1d')  
    xiv_ratio = xiv_history[1]/xiv_history[0] - 1
                    
    if last_vix < threshold_vix_too_low: # if VIX is too low, invest in UVXY witht he hope of a spike
        log.info("CASE UVXY 0")
        target_sid = context.uvxy

    elif last_ratio < threshold_xiv: # if contango is high, invest in XIV to gain from decay
        log.info("CASE XIV 1")
        target_sid = context.xiv

    elif vix_vxv_ratio < threshold_vxv_xiv: # if short term vol is low compared to mid term, invest in XIV to gain from decay
        log.info("CASE XIV 2")
        target_sid = context.xiv

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

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

    elif last_vix > threshold_vix_high: # if VIX is too high, invest in XIV expecting that VIX will drop
        log.info("CASE XIV 5")
        target_sid = context.xiv
            
    elif last_vix < threshold_vix_low: # if VIX is too low, invest in XIV expecting that VIX will rise
        log.info("CASE UVXY 6")
        target_sid = context.uvxy

    elif vix_ratio < threshold_vc_low: # Vix down sharply, invest in XIV expecting that futures curve gets pulled down
        log.info("CASE XIV 7")
        target_sid = context.xiv
            
    elif vix_ratio > threshold_vc_high: # Vix up sharply, invest in UVXY expecting that futures curve gets pulled up
        log.info("CASE UVXY 8")
        target_sid = context.uvxy

    elif vix_ratio > threshold_vc_high_2: #have to think
        log.info("CASE XIV 9")
        target_sid = context.xiv
            
    elif vix_ratio < threshold_vc_low_2: # vix dropped. There are no other signals. in the absence of any signal, try UVXY
        log.info("CASE UVXY 10")
        target_sid = context.uvxy

    elif last_ratio < threshold_xiv_2: # before we give up on XIV and move to TQQQ let's relax the contango conditions a bit
        log.info("CASE XIV 11")
        target_sid = context.xiv

    elif last_ratio > threshold_uvxy_2: # before we give up on UVXY and move to TQQQ let's relax the backwardation conditions a bit
        log.info("CASE UVXY 12")
        target_sid = context.uvxy

    else:
        log.info("CASE TQQQ 13")
        target_sid = context.tqqq
        
    if (target_sid == context.xiv and xiv_ratio < threshold_xiv_ratio) : 
        # indicators say XIV but it just dropped overnight, so got for TQQQ
        log.info("CASE TQQQ 14")
        target_sid = context.tqqq 
        
    elif (target_sid == context.uvxy and xiv_ratio > threshold_uvxy_ratio) :
        # indicators say UVXY but it just dropped overnight, so got for TQQQ
        log.info("CASE TQQQ 15")
        target_sid = context.tqqq
    
    
    
    if target_sid not in context.portfolio.positions:
        
        Wager = Max_Wager
        if Wager == 0.:
            Wager = Max_Wager_Percent/100.*context.portfolio.portfolio_value
        Weight = Wager/context.portfolio.portfolio_value
        log.info("Wager %5.2f Weight %5.2f" %(Wager, Weight))
        
        order_target_percent(context.tqqq,0)
        order_target_percent(context.uvxy,0)
        order_target_percent(context.xiv,0)
        order_target_percent(target_sid, Weight)
        
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')  

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.datetime.strptime(dt,'%m/%d/%Y')))
    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):
    log.info("Pre-Shift")
    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):
    #log.info("VIX: Pre-Massage")
    df = fix_close(df,'VIX Close')
    #log.info("VIX: Post-Massage")
    return df

def addFieldsVXV(df):
    #log.info("VXV: Pre-Massage")
    df.rename(columns={'Unnamed: 0': 'Date'}, inplace=True)
    df = fix_close(df,'CLOSE')
    #log.info("VXV: Post-Massage")
    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
            
There was a runtime error.
1 response

I am not quite sure, but I believe they are still developing futures for live trading. Usually they don't implement stuff all at once.