| Overall Statistics |
|
Total Trades 3 Average Win 0% Average Loss 0% Compounding Annual Return -25.738% Drawdown 0.600% Expectancy 0 Net Profit -0.464% Sharpe Ratio -6.68 Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.184 Beta 0.198 Annual Standard Deviation 0.029 Annual Variance 0.001 Information Ratio -3.661 Tracking Error 0.037 Treynor Ratio -0.985 Total Fees $4.06 |
### <summary>
### Basic template algorithm simply initializes the date range and cash. This is a skeleton
### framework you can use for designing an algorithm.
### </summary>
import numpy as np
import pandas as pd
import scipy
import sys
from datetime import datetime, timedelta
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Indicators")
AddReference("QuantConnect.Common")
import statsmodels.api as sm
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Data import *
from QuantConnect.Indicators import *
from QuantConnect.Orders import *
from QuantConnect.Securities import *
from System.Collections.Generic import List
from scipy.optimize import minimize
#import matplotlib.pyplot as plt # only works in Notebook
import decimal
from System.Collections import *
RESEARCHMODE= False # set this to False to toggle for simulated or live trading
VERBOSEMODE= True # set thi
VERBOSEMODE2= True # set thi
class BasicTemplateAlgorithm(QCAlgorithm):
def Initialize(self):
# Set the cash we'd like to use for our backtest
# This is ignored in live trading
self.SetCash(100000)
self.excess_liquidity = decimal.Decimal(50000.00)
# Start and end dates for the backtest.
# These are ignored in live trading.
self.SetStartDate(2017,11,05)
self.SetEndDate(2017,11,12)
self.benchmark = self.AddEquity("SPY",Resolution.Minute).Symbol #used for references to scheduling
strbench = self.benchmark.ToString() # must be in string format
self.bullish_stock = self.AddEquity("TQQQ", Resolution.Minute).Symbol
self.bearish_stock = self.AddEquity("TMF", Resolution.Minute).Symbol
self.small_cap_stock = self.AddEquity("TNA", Resolution.Minute).Symbol
self.mid_cap_stock = self.AddEquity("IJH", Resolution.Minute).Symbol
self.vxx = self.AddEquity("VXX", Resolution.Minute).Symbol
self.xiv= self.AddEquity("XIV", Resolution.Minute).Symbol
self.spy = self.AddEquity("TQQQ", Resolution.Minute).Symbol
self.shortSpy = self.AddEquity("TLT", Resolution.Minute).Symbol
self.stocks = [self.bullish_stock,
self.bearish_stock,
self.small_cap_stock,
self.mid_cap_stock,
self.xiv]
self.skippedSecurities = [
self.AddEquity("AGG", Resolution.Minute).Symbol,
self.AddEquity("TIPS", Resolution.Minute).Symbol
]
self.permanentStocks= [
self.AddEquity("AGG", Resolution.Minute).Symbol,
self.AddEquity("TIPS", Resolution.Minute).Symbol,
self.AddEquity("TLT", Resolution.Minute).Symbol,
self.AddEquity("SDY", Resolution.Minute).Symbol
]
self.boughtPermanent = False
#set up variables to calculate margin
self.day= datetime.today().day
self.timestep=0
self.margin_req=0
self.totalShorts=0
self.totalLongs=0
self.cash=0
self.weightsp = { self.permanentStocks[0]: 0.50 , self.permanentStocks[1]: 0.10,self.permanentStocks[2]: 0.20,self.permanentStocks[3]: 0.20,}
self.track_orders = 1 # toggle on|off
self.n = 0
self.s = np.zeros_like(self.stocks)
self.x0 = np.zeros_like(self.stocks)
self.x1 = 1.0*np.ones_like(self.stocks)/len(self.stocks)
self.eps = 0.01
self.tol = 1.0e-6 #assume convergence is 10 time SLSQP ftol of 1e-6
self.valid_constraint_count = 0
self.opt_pass_count = 0
self.run_count = 0
self.eps_vals = []
self.portvalue = self.Portfolio.get_TotalPortfolioValue()
self.RISK_LEVEL = 1.85
self.is_first_of_week = False
self.is_trading_day = False
self.rebalance_threshhold = 500
self.OTHER_MIX = 0.10 # place this as percentage of non-permanent portfolio that you WANT invested in this strategy.
# this is percentage of 1-self.permanentRatio. 1.00 = 100% into aggressive strategy
self.permanentRatio= 0.90 # store percentage of portfolio dedicated to permanent positioins and excluded from this algo
self.waits_max = 3 # trading days
self.profit_threshhold = 0.3 # percentage terms 1.0 = 1 pct
self.enableProfitTaking = True
self.account_leverage = self.Portfolio.TotalAbsoluteHoldingsCost / self.Portfolio.TotalPortfolioValue
self.mx_lvrg = 0
# stop losses according to rising intraday threshhold
self.loss_threshhold = 20.00 # percentage terms 1.0 = 1 pct
self.enableLossLimiting= False
# makes sure at least one position is short at all times. (for quantopian contest rules)
self.alwaysShort = True
self.short_stock = self.AddEquity("SQQQ", Resolution.Minute)
self.maxprice = {} # Keys are symbols, values are lists of prices.
for s in self.stocks:
self.maxprice[s] = 00
if self.account_leverage > self.mx_lvrg:
self.mx_lvrg = self.account_leverage
self.current_holdings = [] # used to manage portfolio
self.waits = {} # used to delay repetitive actions
self.total_trades =0
self.sliceTime = datetime.today()
try:
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(10, 0), Action(self.buyPermanent))
self.Schedule.On(self.DateRules.MonthStart(strbench),self.TimeRules.AfterMarketOpen(strbench,20), Action(self.refreshPermanent))
except:
self.Log('An unknown error occurred trying to Initialize.' + str(sys.exc_info()[0]) )
def addStock(self,s,pct):
# sometimes we mistakenly call the stock by its object, not by its Symbol property because of borrowed code
# this catches that and adjusts for it.
if VERBOSEMODE: self.Log('line 192 addStock reached')
try:
if hasattr(s,'Symbol'):
sym = s.Symbol
else:
#make sure we are an equity already
if not isinstance(s,Securities.Equity.Equity):
sym = self.AddEquity(s,Resolution.Minute).Symbol
else:
sym = s
self.SetHoldings(sym,pct)
return True
except:
if VERBOSEMODE: self.Log('An unknown error occurred trying to optimize the portfolio within allocate.', sys.exc_info()[0])
return False
def OnData(self,slice):
try:
self.data = slice
if (False in [slice.ContainsKey(x) for x in self.stocks]) \
and (False in [slice.ContainsKey(x) for x in self.permanentStocks]) \
and (False in [slice.ContainsKey(x) for x in self.skippedSecurities]) :
if VERBOSEMODE: self.Log('exiting OnData no valid stocks in current data stream')
return
self.sliceTime = slice.Time
if self.sliceTime.weekday()<> 1 : #tuesday is day 1
self.is_trading_day = False
if self.sliceTime.weekday()<> 0 : # monday
self.is_first_of_week = False
#if VERBOSEMODE:self.Log("line number 193 is_trading_day {} is_first_of_week {} weekday {} n date {} {}:{} ".format( self.is_trading_day, self.is_first_of_week,self.sliceTime.weekday(), self.sliceTime.day,self.sliceTime.hour,self.sliceTime.minute))
except:
self.Log('An unknown error occurred in OnData'), sys.exc_info()[0]
return
def refreshPermanent(self):
self.boughtPermanent = False
self.buyPermanent
def buyPermanent(self):
try:
if not self.boughtPermanent:
for stock in self.permanentStocks:
sym = self.symbolAsString(stock)
if VERBOSEMODE2:self.Log("line number 198 stock {}".format(stock))
if self.Securities[sym].Holdings :
if VERBOSEMODE2:self.Log('permanentRatio symbol {} permanentRatio is {} weightsp[stock] is {} ' .format(sym,self.permanentRatio, self.weightsp[stock]))
adjustedWeight= self.permanentRatio * self.weightsp[stock]
if VERBOSEMODE2:self.Log('adjustedWeight is {}' .format(adjustedWeight))
self.place_order(sym,adjustedWeight,False)
self.boughtPermanent= True
except:
self.Log('An unknown error occurred in buyPermanent function.' + str(sys.exc_info()[0]) )
return False
def set_is_first_of_week(self):
#if datetime.today().weekday() == 0: # Monday
self.is_first_of_week = True
self.is_trading_day = False
#else:
#self.is_first_of_week = False
if VERBOSEMODE:self.Log("line number 232 is_first_of_week date {} {}:{} ".format( self.sliceTime.day,self.sliceTime.hour,self.sliceTime.minute))
def set_is_trading_day(self):
self.is_trading_day = True
self.is_first_of_week = False
if VERBOSEMODE:self.Log("line number 307 is_trading_day date {} {}:{} ".format( self.sliceTime.day,self.sliceTime.hour,self.sliceTime.minute))
def record_leverage(self):
print("Total leverage: %d" % self.account_leverage)
def place_order(self, stock, percent,liquidateExisting=False, resolution=None):
try:
if VERBOSEMODE: self.Log('line 309 placeOrder reached')
if resolution is None:
resolution = Resolution.Minute
if VERBOSEMODE: self.Log("reached line 313. liquidateExisting now set to {}". format(liquidateExisting) )
sym = self.symbolAsString(stock)
shares = self.get_desired_allocation( sym, percent)
current_shares = self.Portfolio[sym].Quantity
if VERBOSEMODE: self.Log(" line 319 found shares for symbol {} of {}". format(sym,current_shares))
needShares = shares != current_shares
if VERBOSEMODE: self.Log("reached line 321 need shares? {}".format(needShares))
if shares != current_shares:
# allowing predetermined period to first elapse
if self.waits.has_key(stock) :
if self.waits[stock] > 0:
if VERBOSEMODE: self.Log("Waiting for stock to wake up from hibernation {}".format(stock) )
return False
else:
self.total_trades += 1
if isinstance(percent,decimal.Decimal) :
pct=round(percent,4)
else:
pct = round(decimal.Decimal(percent),4)
if VERBOSEMODE2: self.Log(" line 264 allocating symbol {} pct used {} for fraction {} ". format(sym,pct,percent))
if not self.Securities[sym].Holdings :
if VERBOSEMODE: self.Log('line 265 not found {} in holdings. Adding equity ' .format(sym))
self.AddEquity(sym,resolution)
if VERBOSEMODE2: self.Log('line 272 would set symbol {} to percent {}' .format(sym,pct))
self.SetHoldings(sym,pct,liquidateExisting)
amt = self.Portfolio[sym].Quantity
if VERBOSEMODE2: self.Log('line 273 successfully set holding for symbol {} pct {} at {}:{} ' .format(sym,pct,self.sliceTime.hour,self.sliceTime.minute))
if VERBOSEMODE2: self.Log('line 276 immediately after quantity is {}' .format(amt))
return True
except:
self.Log('An unknown error occurred in place_order function for stock {} error:{}' .format(sym, sys.exc_info()[0]) )
return False
def get_desired_allocation(self, stock, percent):
if VERBOSEMODE: self.Log('line 358 getting needed shares for symbol {} percent {}' .format(stock,percent))
sym= self.symbolAsString(stock)
pct = decimal.Decimal(percent)
current_price =self.Securities[sym].Price
if current_price == 0: #avoid division by 0
if VERBOSEMODE: self.Log('line 291 current_price for symbol {} is {}' .format(sym,current_price))
return 0
shares = int((self.Portfolio.TotalPortfolioValue * pct)/current_price)
if VERBOSEMODE: self.Log('line 369 needed shares for symbol {} are {}' .format(sym,shares))
return shares
def get_holding_size(self, stock):
try:
if VERBOSEMODE: self.Log('line 333 get_holding_size reached')
sym = self.symbolAsString(stock)
return ( self.Portfolio[sym].Quantity * self.Portfolio[sym].AveragePrice) / self.Portfolio.TotalPortfolioValue
except:
self.Log('An unknown error occurred reading results of get_holding_size.{}'.format( sys.exc_info()[0]))
return
def allocate(self):
if VERBOSEMODE: self.Log('line 340 allocate reached at date{} hour {} minute {}'.format(self.sliceTime.day,self.sliceTime.hour,self.sliceTime.minute))
try:
if not hasattr(self,"run_count"):
self.run_count = 1
else:
self.run_count += 1
if RESEARCHMODE:
period = 17 # * 390
prices = self.get_history_from_list(self.stocks,period,Resolution.Minute, 'close').dropna()#.bfill().ffill()
else:
period = 17 * 390
prices = self.get_history_from_list(self.stocks,period,Resolution.Minute, 'close').dropna()#.bfill().ffill()
if VERBOSEMODE: self.Log('line 354 in allocate prices are {}'. format(prices))
ret = prices.pct_change()[1:].as_matrix()
if VERBOSEMODE: self.Log("price pct change as matrix is {} line 395". format( ret))
ret_mean = prices.pct_change().mean()
ret_std = prices.pct_change().std()
ret_norm = ret_mean/ret_std
ret_norm = ret_norm.as_matrix()
ret_norm_max = np.max(ret_norm)
eps_factor = 0.9 if ret_norm_max >0 else 1.0
self.eps = eps_factor*ret_norm_max
bnds = []
limits = [0,1]
for stock in self.stocks:
bnds.append(limits)
bnds = tuple(tuple(x) for x in bnds)
if VERBOSEMODE: self.Log("line 419 bnds is {} ". format( bnds))
cons = ({'type': 'eq', 'fun': lambda x: np.sum(x)-1.0},
{'type': 'ineq', 'fun': lambda x: np.dot(x,ret_norm)-self.eps})
if VERBOSEMODE: self.Log("line 22 cons is {} ". format(cons))
if VERBOSEMODE: self.Log("before minimize line 428 self.variance {}| self.x1 {} | self.jac_variance {} is " .format(self.variance,self.x1,self.jac_variance))
res = minimize(self.variance, self.x1, args=ret,jac=self.jac_variance, method='SLSQP', bounds=bnds, constraints=cons)
if VERBOSEMODE: self.Log("res is {} " .format( res))
except:
if VERBOSEMODE: self.Log('An unknown error occurred trying to optimize the portfolio within allocate.', sys.exc_info()[0])
return
try:
allocation = np.copy(self.x0)
if res.success: # if SLSQP declares success
if self.opt_pass_count is None:
self.opt_pass_count =1
else:
self.opt_pass_count += 1
weighted_ret_norm = np.dot(res.x,ret_norm)
w_ret_constraint = weighted_ret_norm - self.eps + self.tol
if VERBOSEMODE: self.Log("w_ret_constraint is {} ". format( w_ret_constraint))
if(w_ret_constraint > 0): # and constraint is actually met
self.valid_constraint_count += 1
allocation = res.x
allocation[allocation<0] = 0
denom = np.sum(allocation)
if denom > 0:
allocation = allocation/denom
msg = "{0} runs, {1} SLSQP passes, {2} constraints passed".format(
self.run_count, self.opt_pass_count,
self.valid_constraint_count)
if(self.run_count>1000):self.Log(msg)
else:
self.Log("constraint fail, SLSQP status = {0}".format(res.status))
pass
else:
self.Log("SLSQP fail, SLSQP status = {0}".format(res.status))
pass
self.n += 1 # increment number of allocations
self.s += allocation
except:
self.Log('An unknown error occurred reading results of optimize.{}'.format( sys.exc_info()[0]))
return
if VERBOSEMODE: self.Log( "allocation is now {}".format(allocation))
if self.alwaysShort:
self.reallocateToShort
if self.is_trading_day:
if VERBOSEMODE:self.Log("line number 482 is_trading_day set to True on {}: {}".format(self.is_trading_day,self.sliceTime.hour,self.sliceTime.minute))
self.trade()
else:
if VERBOSEMODE:self.Log("line number 485 set_is_trading_day set to False on {}: {}".format(self.sliceTime.hour,self.sliceTime.minute))
if VERBOSEMODE:self.Log("line number 442 _completed allocate function on {}: {}".format(self.sliceTime.hour,self.sliceTime.minute))
def GetShiftingWindows(self,thelist, size):
if VERBOSEMODE: self.Log('line 398 GetShiftingWindows reached')
return [ thelist[x:x+size] for x in range( len(thelist) - size + 1 ) ]
def reallocateToShort(self):
try:
if VERBOSEMODE: self.Log('line 405 reallocateToShort reached')
if self.n > 0 :
allocation = self.s
n=self.n
if VERBOSEMODE: self.Log( 'allocation in reallocateToShort is \n{} of type {} '.format(allocation, type(allocation)))
if VERBOSEMODE: self.Log( 'old allocation is \n{}'.format(n))
#find the biggest allocation
maxAl = allocation.max()
if VERBOSEMODE: print 'maxAl is \n',maxAl
lastPos = len(self.stocks)-1
doOnce = True
for i,stock in enumerate(self.stocks):
if allocation[i]==maxAl:
doOnce = False # so this is run only one time.
# this is stock we want. we are going to allocate 10% of its allocation to short its reverse etf (2 x negative = positive)
# to fulfill contest short requirements
previousShort = self.short_stock
if stock == self.bullish_stock:
self.short_stock = self.bearish_stock
elif stock == self.bearish_stock:
self.short_stock = self.bullish_stock
elif stock == (self.small_cap_stock or self.mid_cap_stock ):
self.short_stock = self.shortMidCap
elif stock == (self.xiv):
self.short_stock = self.vxx
if previousShort <> self.short_stock:
if VERBOSEMODE: print 'sell all positions of previousShort' , previousShort.Symbol
self.place_order(previousShort, 0) # don't want to keep holding other short
allocation[lastPos] = allocation[i] * 0.1 * -1 # how much to allocate to newly designated short position
if VERBOSEMODE: self.Log( 'shorting last position by this ratio{}' .format(allocation[lastPos]))
allocation[i]= allocation[i] + allocation[lastPos] # whichever was max allocation now get diminished by amount of allocation to short_stock
if VERBOSEMODE: self.Log('reducing max position to new lesser value of {}'. format(allocation[i]))
break
else:
return
except:
print('An unknown error occurred in reallocateToShort.'), sys.exc_info()[0]
return
def trade(self):
pass
def allocSPY (self):
pass
def variance(self,x,*args):
try:
p = np.squeeze(np.asarray(args))
print "p squeezed is " ,p
Acov = np.cov(p.T)
r = np.dot(x,np.dot(Acov,x))
#if VERBOSEMODE: self.Log( "Acov of p is {} result is {}".format( Acov,r))
return r
except:
print('An unknown error occurred trying to find variance.'), sys.exc_info()[0]
return 0.0
def jac_variance(self,x,*args):
try:
p = np.squeeze(np.asarray(args))
Acov = np.cov(p.T)
return 2*np.dot(Acov,x)
except:
self.Log('An unknown error occurred trying to find jacvariance.'), sys.exc_info()[0]
return 0.0
def update_newFrame(self):
try:
if VERBOSEMODE: self.Log('line 854 update_newFrame reached at date{} hour {} minute {}'.format(self.sliceTime.day,self.sliceTime.hour,self.sliceTime.minute))
self.cash = self.Portfolio.get_Cash()
self.portvalue = self.Portfolio.get_TotalPortfolioValue()
self.totalLongs=0
self.totalShorts=0
#if VERBOSEMODE: self.Log("line 861")
for s in self.Securities.Keys:
if VERBOSEMODE: self.Log(' looping through self.Securities.Keys symbol {} quantity:{} average price{} '. format(s,self.Portfolio[s].Quantity , self.Portfolio[s].AveragePrice))
if self.Portfolio[s].Quantity <0 :
self.totalShorts += (self.Portfolio[s].Quantity * self.Portfolio[s].AveragePrice)
else:
self.totalLongs += (self.Portfolio[s].Quantity * self.Portfolio[s].AveragePrice)
#if VERBOSEMODE: self.Log(' total longs {} total shorts {} ' . format(self.totalLongs , self.totalShorts))
self.update_portvals()
#Handle assigning the timestep number (1 day is 1 timestep)
if VERBOSEMODE: self.Log( 'got to 874')
if datetime.today().day <> self.day: #look for a new day
self.day=datetime.today().day
self.timestep += 1
#print ( "Cash: "+str(self.cash)+"; Margin Req: "+str(self.margin_req)+" Avail Cash:"+str(self.cash - self.margin_req) )
if VERBOSEMODE: self.Log(' excess liquidity {} ' . format(self.excess_liquidity))
if self.excess_liquidity < 0 :
self.generate_marginCall()
if VERBOSEMODE: self.Log('successfully ran update_newFrame')
except:
if VERBOSEMODE: self.Log('An unknown error occurred in update_newFrame.'), sys.exc_info()[0]
return
def wait(self, symbol=None, action=None):
try:
if VERBOSEMODE: self.Log("reached line 365 in wait for symbol {}" .format(symbol) )
self.waits
except NameError as e:
if VERBOSEMODE: self.Log('A Name error occurred in wait .{} \ncreating waits array'. format(e) )
self.waits = {}
return
except:
if VERBOSEMODE: self.Log('A known error occurred in wait.{}'. format(sys.exc_info()[0]) )
if VERBOSEMODE and symbol is not None: self.Log("reached line 369 creating waits array for symbol {}" .format(symbol) )
self.waits = {}
return
try:
if symbol and action:
if action == 1:
self.waits[symbol] = 1 # start wait
elif action == 0:
del self.waits[symbol] # end wait
else:
for symbol in self.waits.copy():
if self.waits[symbol] > self.waits_max:
del self.waits[symbol]
else:
self.waits[symbol] += 1 # increment
if VERBOSEMODE: self.Log("reached line 378 {}" .format(self.waits[symbol]) )
except:
if VERBOSEMODE: self.Log('An unknown error occurred in wait.{}'. format(sys.exc_info()[0]) )
def generate_marginCall(self):
try:
#This function should be coded to address margin calls
self.Log("Margin call imminent so reallocating: Cash: {} Margin Requirement: {} Excess Margin:" .format(self.cash,self.margin_req,self.total_equity - self.margin_req))
self.Log("Margin Remaining per QC object {} ".format(self.Securities.MarginRemaining))
#following causes a reallocation immediately
self.is_trading_day = True
self.allocate()
except:
if VERBOSEMODE: self.Log('An unknown error occurred in generate_marginCall {}'. format(sys.exc_info()[0]) )
def update_portvals(self):
try:
if VERBOSEMODE: self.Log('line 821 update_portvals reached at date{} hour {} minute {}'.format(self.sliceTime.day,self.sliceTime.hour,self.sliceTime.minute))
#Update account information when this function is called
self.total_equity = self.cash + self.portvalue
if self.total_equity == 0:
self.pct_invested = 0
else:
self.pct_invested = (self.totalLongs-self.totalShorts) / self.total_equity
self.pct_cash = self.cash / self.total_equity
if VERBOSEMODE: self.Log('self.pct_cash is {}'. format(self.pct_cash))
#self.margin_req = abs(self.totalShorts * self.maint_margin)
self.margin_req = abs(decimal.Decimal(self.totalLongs) * 0.5 + decimal.Decimal(self.totalShorts) * 0.3 )
if VERBOSEMODE: self.Log('self.margin_req is {}'. format(self.margin_req))
self.excess_liquidity = decimal.Decimal(self.total_equity) - decimal.Decimal(self. margin_req)
if VERBOSEMODE: self.Log('self.excess_liquidity is {}'. format(self.excess_liquidity))
if VERBOSEMODE: self.Log('successfully ran update portvals')
except:
if VERBOSEMODE: self.Log('An unknown error occurred in update_portvals.'), sys.exc_info()[0]
def take_profit(self): # Close some positions to take profit
if VERBOSEMODE: self.Log('line 800 reached at date{} hour {} minute {}'.format(self.sliceTime.day,self.sliceTime.hour,self.sliceTime.minute))
pass
def LimitOrder(self,sym,pct,limitprice):
#replace this later with REAL limit order which will take absolute value not a percentage
self.SetHoldings(sym,pct,True)
def limit_losses(self):
pass
def slope(self,in_list): # Return slope of regression line. [Make sure this list contains no nans]
return sm.OLS(in_list, sm.add_constant(range(-len(in_list) + 1, 1))).fit().params[-1] # slope
def get_history_by_symbol(self,symbol,period,resolution=None,attr=None):
# what makes fetching history so complicated is that for some functions QC requires a string, for others a symbol
# even though these funcitons are closely related.
# history is fetched with Symbol type, Securities and Portfolio enumerations with string type. Latter are needed
# to check if that symbol is already part of the searchable universe
if VERBOSEMODE: self.Log('line 1051 get_history_by_symbol reached')
if RESEARCHMODE is None:
self.Log('fatal error you must specify RESEARCHMODE as global variable so this function works in Research')
return None
emptyDF = pd.DataFrame() #creates a new dataframe that's empty
if VERBOSEMODE: self.Log('line 1054 created dataframe')
try:
#quantopian s history method allows symbol as object or string but not QC so we need to always
# convert to symbol before calling history method to streamline compatibility
try:
if isinstance(symbol,str):
sym = symbol
if RESEARCHMODE:
qb = QuantBook()
symbol = qb.AddEquity(sym).Symbol
else:
symbol = self.AddEquity(sym).Symbol
else:
# must be in Symbol format already, so create a string variant
sym= str(symbol)
if VERBOSEMODE: self.Log('line 1063 after transformation in get_history_by_symbol types are sym:symbol {}{}'. format(type(sym),type(symbol)))
except:
if VERBOSEMODE: self.Log('An unknown error occurred trying to convert a symbol to a string type is {} Exiting '. format(type(symbol)))
return
if attr is None:
attr = "close"
if resolution is None:
resolution = "Resolution.Daily"
if RESEARCHMODE:
# fails if I try to empty existing QB by setting to None
history = qb.History(period, resolution)
else:
#history will not work if this symbol not already in Portfolio object of 'self'
try:
amt = self.Portfolio[sym].Quantity
if VERBOSEMODE: self.Log('line 1080 found symbol {} with quantity {}'.format(sym,amt) )
except:
self.AddEquity(sym,resolution)
if VERBOSEMODE: self.Log('line 1085 added symbol {} to universe as no quantity found'.format(sym) )
if VERBOSEMODE: self.Log('line 1101 testing history for symbol {} of type {} period {} resolution {}'.format(sym,type(symbol),period,resolution) )
try:
history = self.History(symbol,period,resolution) # watchout here you need Symbol not string 'sym'
if VERBOSEMODE: self.Log('line 1088 reached after fetching history of length {}'. format(len(history)) )
if len(history) == 0:
if VERBOSEMODE: self.Log('line 1181 no values found for history of symbol {}'. format(sym) )
return emptyDF
except:
self.Log('An unknown error occurred trying get history by_symbol line 1107' + str(sys.exc_info()[0]) )
df_history = history[attr].unstack(level=0).dropna()
if VERBOSEMODE: self.Log('line 1096 in get_history_by_symbol succesffully created df_history of type {}'. format(type(df_history)) )
return df_history
except NameError as e:
self.Log('A Name error occurred trying get history by_symbol.{}' .format(e) )
except:
self.Log('An unknown error occurred trying get history by_symbol.' + str(sys.exc_info()[0]) )
return emptyDF
def get_history_from_list(self,stocklist,period,resolution = None, attr = None):
if VERBOSEMODE: self.Log('line 1012 get_history_from_list reached')
try:
emptyDF = pd.DataFrame() #creates a new dataframe that's empty
if VERBOSEMODE: self.Log('line 1115 able to create empty dataframe')
if RESEARCHMODE is None:
self.Log('fatal error you must specify RESEARCHMODE as global variable')
return None
if attr is None:
attr = "close"
if resolution is None:
resolution = "Resolution.Daily"
if RESEARCHMODE:
qb = None # kill any exising instance to 'empty' symbollist
qb = QuantBook() # recreate it
qb.SetStartDate(self.StartDate)
for s in stocklist:
sym = s.ToString()
qb.AddEquity(sym,resolution) # adds equity to our newly created quantbook universe
history = qb.History(period, resolution)
else:
strlist= []
for s in stocklist:
strlist.append(s.ToString())
history = self.History(strlist,period, resolution)# will get all stocks in list of strings
if VERBOSEMODE: self.Log('line 1178 history from string list of type {}'. format(type(history) ))
df_history = history[attr].unstack(level=0).dropna()
if VERBOSEMODE: self.Log('line 1180 created df_history_from list of type {}'. format(type(df_history)) )
return df_history
except:
self.Log('An unknown error occurred trying get history from symbol.' + str(sys.exc_info()[0]) )
return emptyDF
def symbolAsString(self,symbol):
try:
if isinstance(symbol,Securities.Equity.Equity):
sym = symbol.Symbol.ToString()
else:
if isinstance(symbol,Symbol):
sym= str(symbol)
else:
sym = symbol
if VERBOSEMODE: self.Log("in symbolAsString successfully returned string {} ". format(sym))
return sym
except:
self.Log('An unknown error occurred trying symbolAsString.' + str(sys.exc_info()[0]) )
return ""
def final_reporting(self):
if is_date(2017, 1, 25):
print("Total trades: %d" % self.total_trades)
def record_leverage(self):
record(leverage = self.account.leverage)
record(mx_lvrg = self.mx_lvrg)
self.is_trading_day = False
self.is_first_of_week = False
def testHistory(self,sym,period,resolution):
try:
if RESEARCHMODE:
print 'researchmode enabled'
else:
try:
#make sure it exists in our securities list first
price = Securities[sym].Close
except:
equity=self.AddEquity(sym,resolution)
self.Log('line 1016 reached')
self.Log('line 1018 reached')
history = self.History(equity,period,resolution)
self.Log(str(history))
self.Log(str(len(history)))
self.Log('line 1022 reached')
df_history = history["close"].unstack(level=0).dropna()
return df_history
except :
self.Log('An unknown error occurred trying get history from list.' + str(sys.exc_info()[0]) )
def to_dataframe(data_c):
# Helper function to make a dataframe from the coarse object.
# Then we can use all the handy dataframe methods.
# Set the 'coerce_float' parameter to get meaningful datatypes
# otherwise all the fields will be un-useful generic objects.
data = [(
stock.Price,
stock.Volume,
stock.DollarVolume,
stock.HasFundamentalData)
for stock in data_c]
symbols = [stock.Symbol for stock in data_c ]
labels = ['price', 'volume', 'dollar_volume', 'has_fundamentals']
data_df = pd.DataFrame.from_records(
data,
index=symbols,
columns=labels,
coerce_float=True)
return data_df
# create and return list of all holdings
def getPortfolioHoldings(self):
# get the symbols of our holding stocks
holding_list = []
for i in self.Portfolio:
if i.Value.Invested:
holding_list.append(i.Value.Symbol)
return holding_list