Notebook

Bottom with Dynamic Exit

In [1]:
# Import Libraries
import math
import numpy as np
import talib as ta
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels import regression
import statsmodels.api as sm
from quantopian.interactive.data.quandl import yahoo_index_vix as vix
from pandas.core.generic import NDFrame
# import data operations
import odo as odo
from odo import odo
# For use in your algorithms via the pipeline API
from quantopian.pipeline.data.quandl import yahoo_index_vix
# For use in Quantopian Research, exploring interactively
from quantopian.interactive.data.quandl import yahoo_index_vix
In [87]:
def linreg(X,Y):
    # Running the linear regression
    X = sm.add_constant(X)
    model = regression.linear_model.OLS(Y, X).fit()
    a = model.params[0]
    b = model.params[1]
    X = X[:, 1]

    # Return summary of the regression and plot results
    X2 = np.linspace(X.min(), X.max(), 10000)
    Y_hat = X2 * b + a
    #plt.scatter(X, Y, alpha=0.3) # Plot the raw data
    plt.plot(X2, Y_hat, alpha=0.9);  # Add the regression line, colored in red
    plt.title('VIX after Bottom (Linear Regression)')
    return b
    #return model.summary()
In [12]:
vix_df = odo(vix, pd.DataFrame)
vix_df.index = vix_df.asof_date
symbol = "SPY"
start = "2004-01-01"
end = "2017-01-20"
prices = get_pricing(symbol, start_date=start, end_date=end, fields='close_price')
prices.index.tz = None
sym_date=list()
sym_prices=list()
sym_vixstartdate=list()
vixinc = dict()
vixdec = dict()
totals = dict()
vixper = dict()
previous=[30]
after=[0,1]
reg = [15]
rsi = ta.RSI(np.array(prices), timeperiod=14)
# define a bottom: no close price lower than bottom in the previous x days and next y days.
for y in after:
    for s in previous:
        for q in reg:
            vixincrease=0
            vixdecrease=0
            for i in range(len(prices.index)-q):
                for j in range(s+1):
                    if prices[i] < prices[i-j-1]:
                        continue
                    else: break
                if j == s:
                    for k in range(y+1):
                        if prices[i] < prices[i+k+1]:
                            continue
                        else: break
                    if k == y:
                        sym_prices.append(prices[i])
                        sym_date.append(prices.index[i])
                        sym_vixstartdate.append(prices.index[i+y])
                        b=linreg(range(q),vix_df.close.loc[prices.index[i+y:i+y+q]])
                        plt.xlabel('Days')
                        plt.ylabel('VIX')
                        plt.text(1, 90,'(Bottom: no close price lower than bottom in the previous ' + str(previous) +\
                                 ' days and next ' + str(y) + ' day)')
                        if b>0:
                            vixincrease=vixincrease+1
                        else:
                            vixdecrease=vixdecrease+1
                        plt.axis([None, None, 0, 100])
                        vixinc[(s,y,q)] = vixincrease
                        vixdec[(s,y,q)] = vixdecrease
                        totals[(s,y,q)] = vixinc[(s,y,q)]+vixdec[(s,y,q)]
                        vixper = {(s,y,q): float(vixdec[(s,y,q)])/totals[(s,y,q)] for (s,y,q) in totals}


sym_bottom_data = {
    'price': sym_prices,
    'date': sym_date,
    'vixstartdate': sym_vixstartdate
}
print 'percentage:', vixper, 'totals:', totals
percentage: {(30, 0, 15): 0.7378640776699029, (30, 1, 15): 0.7543859649122807} totals: {(30, 0, 15): 206, (30, 1, 15): 114}

MACD Calculation

In [13]:
# MACD Calculation
macd, macdsignal, macdhist = ta.MACD(prices, 12, 26, 9)

trigger = macd - macdsignal

# When the trigger is positive, or becomes positives, it was a bottom. Likewise, when it goes from positive to 
# negative, it represents a top.
In [14]:
symbol='SPY'
start = "2004-01-01"
end = "2017-01-20"
stock_spy = get_pricing(symbol, start_date=start, end_date=end, fields=['high', 'low', 'close_price'])
# Vix Fix calculated for the SPY
WVF = (stock_spy['high'].rolling(28).max() - stock_spy['low'])/stock_spy['high'].rolling(28).max()*100

# Bollinger Bands
vfup, vfmid, vflow = ta.BBANDS(np.array(WVF),timeperiod=28,nbdevup=2, nbdevdn=2, matype=0)
plt.plot(vfup)
plt.plot(vfmid)
plt.plot(vflow)
plt.title('Williams Vix Fix and Bollinger Bands')
plt.xlabel('days')
plt.ylabel('Levels')
plt.grid(False);

When the WVF crosses the upper band, then it is time to sell the volatility, as it means the stock has reached lower bottom. On the contrary, when the WVF crosses the lower band, then it is time to buy as it means it market top, as it decreases the VIX will begin increasing.

The Vix Fix (Income Trader Volatility) ITV Indicator

http://www.nasdaq.com/article/the-award-winning-research-thats-led-to-a-100-win-rate-cm464581 This article shows how by adding a moving average to the WVF the signals improve. by adding the MA, the market action tells when the volatility had reached a short-term peak, allowing to balance the potential risks and rewards of option selling. The MA works in the same way the MACD works for any stock.

In [15]:
#Define the variables
fast   = 12
slow   = 26
signal = 9

#macd = ta.MACD(WVF, fastperiod = fast, slowperiod=slow, signalperiod=signal)
#plt.plot(macd);

shortma = pd.rolling_mean(WVF, fast)
longma  = pd.rolling_mean(WVF, slow)
macd    = shortma - longma
macdr   = macd.pct_change()[1:]
signal  = pd.rolling_mean(macd, signal)
trigger    = macd - signal
rtrigger = trigger.pct_change()[1:];

Dynamic Exit

Moving forward, everytime the entry criteria is met, that is, when the price at time t is the lowest in the time period [t-30:t], I will take a time series for 30 days and test every day for an exit signal to come (i.e. RSI>70). Once this happens, the time series will be crop to the time when the signal comes and run a regression on that time. Should no signal come, the biggest regression day-length will be 30 days.

In [142]:
vix_df = odo(vix, pd.DataFrame)
vix_df.index = vix_df.asof_date
symbol = "SPY"
start = "2004-01-01"
end = "2017-01-20"
prices = get_pricing(symbol, start_date=start, end_date=end, fields='close_price')
prices.index.tz = None
sym_date=list()
sym_prices=list()
sym_vixstartdate=list()
vixinc = dict()
vixdec = dict()
totals = dict()
vixper = dict()
selldays = dict()
previous=[30]
after=[0]
# define a bottom: no close price lower than bottom in the previous x days and next y days.
for y in after:
    for s in previous:
        R=np.array([0,]*30)
        #R = list() # Vector for the RSI Index
        vixincrease = 0
        vixdecrease = 0
        days        = 0
        for i in range(len(prices.index)-30):
            for j in range(s+1):
                if prices[i] < prices[i-j-1]:
                    continue
                else: break
            if j == s:
                for k in range(y+1):
                    if prices[i] < prices[i+k+1]:
                        continue
                    else: break
                if k == y:
                    sym_prices.append(prices[i])
                    sym_date.append(prices.index[i])
                    sym_vixstartdate.append(prices.index[i+y])
                    R=rsi[i+y+1:i+y+30+1] # RSI vector
                    # Count the number of days until the sell signal comes
                    RSI = []
                    for r in R:
                        if r < 70:
                            r = 1
                        else: break
                        RSI.append(r)
                    days = sum(RSI) + 1
                    selldays[(s,y)] = days
                    b=linreg(range(15),vix_df.close.loc[prices.index[i+y:i+y+15]])
                    plt.xlabel('Days')
                    plt.ylabel('VIX')
                    plt.grid(False)
                    plt.text(1, 90,'(Bottom: no close price lower than bottom in the previous ' + str(previous) +\
                             ' days and next ' + str(y) + ' day)')
                    if b>0:
                        vixincrease=vixincrease+1
                    else:
                        vixdecrease=vixdecrease+1
                    plt.axis([None, None, 0, 100])
                    vixinc[(s,y)] = vixincrease
                    vixdec[(s,y)] = vixdecrease
                    totals[(s,y)] = vixinc[(s,y)]+vixdec[(s,y)]
                    vixper = {(s,y): float(vixdec[(s,y)])/totals[(s,y)] for (s,y) in totals}


sym_bottom_data = {
    'price': sym_prices,
    'date': sym_date,
    'vixstartdate': sym_vixstartdate
}
print 'percentage:', vixper, 'totals:', totals, 'Signal days:', selldays
percentage: {(30, 0): 0.7378640776699029} totals: {(30, 0): 206} Signal days: {(30, 0): 14}
In [108]:
#print days
#print selldays
print days
print R
len(R)
14
[ 50.61668824  53.82493369  60.43903607  61.66233557  59.9994215
  60.22926632  64.85423041  63.44483548  66.11651635  63.92649115
  68.0705926   69.0763575   69.56783089  71.51550638  65.84152975
  66.86130406  63.67608813  59.33152453  59.84736591  64.28073633
  66.62183663  73.74379248  74.8673459   77.39581035  75.76857488
  78.47947405  68.51409389  70.53961582  68.33721564  69.38849671]
Out[108]:
30
In [129]:
vix_df = odo(vix, pd.DataFrame)
vix_df.index = vix_df.asof_date
spy_df = odo(prices, pd.DataFrame)
symbol = "SPY"
start = "2004-01-01"
end = "2017-01-20"
prices = get_pricing(symbol, start_date=start, end_date=end, fields='close_price')
prices.index.tz = None
sym_date=list()
sym_prices=list()
sym_vixstartdate=list()
vixincrease=0
vixdecrease=0
previous=30
after=0
reg = [30]

rsi = ta.RSI(np.array(prices), timeperiod=14)
rsi_df = odo(rsi, pd.DataFrame)

for n in reg:
    A=np.array([0,]*n)
    B=np.array([0,]*n) # Vector for the SPY Prices to calculate the different indicators
    R=np.array([0,]*n) # Vector for the RSI Index
    # define a bottom: no close price lower than bottom in the previous x days and next y days.
    for i in range(n,len(prices.index)-n):
        for j in range(previous+1):
            if prices[i] < prices[i-j-1]:
                continue
            else: break
        if j == previous:
            for k in range(after+1):
                if prices[i] < prices[i+k+1]:
                    continue
                else: break
            if k == after:
                sym_prices.append(prices[i])
                sym_date.append(prices.index[i])
                sym_vixstartdate.append(prices.index[i+after])
                A=np.vstack([A,np.array(vix_df.close.loc[prices.index[i+after+1:i+after+n+1]])]) # VIX
                B=np.vstack([B,np.array(prices[prices.index[i+after+1:i+after+n+1]])]) # SPY Prices
                R=np.vstack([R,np.array(rsi[i+after+1:i+after+n+1])]) # RSI vector
                # Count the number of days until the sell signal comes
                Rlist = R.tolist()
                RSI = []
                for r in Rlist:
                    if r < 70:
                        r = 1
                    else: break
                    RSI.append(r)
                days = sum(RSI) + 1
                        
                
sym_bottom_data = {
    'price': sym_prices,
    'date': sym_date,
    'vixstartdate': sym_vixstartdate
}
sym_bottom_frame_data = pd.DataFrame(sym_bottom_data)
In [130]:
Alist = R.tolist()
days = np.array(range(30))

lisst = []
for i in Alist:
    if i[24]<200 and i[25]<200 and i[26]<200 and i[27]<200 and i[28]<200 and i[27]<200:
        lisst.append(i)

listo = []
for i in np.array(lisst):
    n = i/i[0]
    listo.append(n)
            
deflist = zip(*Alist)
plt.plot(deflist)
plt.grid(False)
plt.xlabel('Days')
plt.ylabel('VIX')
plt.title('VIX behaviour after bottom');
In [103]:
B = sum(listo[1:])/len(listo[1:])
plt.plot(B, color='red')
plt.grid(False)
plt.xlabel('Days')
plt.ylabel('VIX')
plt.title('VIX mean behaviour');
In [ ]: