Overall Statistics |
Total Trades 255 Average Win 0.08% Average Loss -0.11% Compounding Annual Return 85.691% Drawdown 0.500% Expectancy 0.530 Net Profit 5.397% Sharpe Ratio 12.762 Loss Rate 11% Win Rate 89% Profit-Loss Ratio 0.72 Alpha 0.474 Beta 0.002 Annual Standard Deviation 0.037 Annual Variance 0.001 Information Ratio 2.475 Tracking Error 0.056 Treynor Ratio 255.228 Total Fees $369.79 |
''' ChangeLog: 05/29/17 - creation of alpha generator #4 WVF with optimize 06/02/17 - Added new Quicksell logic to be more aggressive on non-daytrades 07/07/17 - Changed Exvet cash and weight calculation + formatting 07/15/17 - Removed RSI2, limited WVF to 20% weight 07/27/17 - Added Asset class rotation ACR 07/30/17 - Make Zscore algo look into past data, Normalized leverage to 1.0 07/30/17 - Changed Exvet pipeline to only look at top upward trending stocks 08/01/17 - lowered daytrade to 4.5% gain and lowered price to sell daytrades to -.02 (fixed reserve code) 08/15/17 - changed context variables to reset to prevent errors on restart 08/15/17 - daytrades limit price now max of current price or dayprice *.99 08/30/17 - Begin Import to QC. 09/03/17 - Modify SLSPQ to weekly with 2 month daily lookback 09/29/17 - First Live tests - Exvet 50 stocks, top 1M price change with top dollar volume ''' from clr import AddReference AddReference("System") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Common") from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Data.UniverseSelection import * import numpy as np import itertools from Manage_Modular import * from Utility_Functions import * from AlphaGenerator_SLSQP import * from AlphaGenerator_ZScore import * from AlphaGenerator_WVF_opt import * from AlphaGenerator_ACR import * from Exvet import * class Modexvet(QCAlgorithm): def Initialize(self): try: self.initialized return except: self.initialized = True """ Algo Settings """ self.allow_unlimited_daytrades = False #Enables unlimited day trading self.allow_unlimited_over25k = True #Enables daytrading once over 26k portfolio, turns daytrading off below 25.5k self.daytrade_limited = True #Enables lmited day trading (limit of 3, 5 day expiration per trade). """ QC Trading Settings """ StartDate = [int(x) for x in self.GetParameter("StartDate").split(',')] EndDate = [int(x) for x in self.GetParameter("EndDate").split(',')] self.SetCash(int(self.GetParameter("StartingCash"))) self.SetStartDate(StartDate[0],StartDate[1],StartDate[2]) self.SetEndDate(EndDate[0],EndDate[1],EndDate[2]) """ Initialization of all components of the algorithm """ self.Util = Utilities(self) #import utility functions self.Exvet = Exvet(self) #import Exvet self.AddEquity("SPY", Resolution.Minute) # creation of the portfolio manager self.p_manager = PortfolioManager_EquiWeight(self) # creation of market order execution handler self.exec_handler = ExecutionHandler_Market(self) # creation of alpha generator #1 if self.GetParameter("SLSQP") == "True": self.alpha_slsqp = AlphaGenerator_SLSQP(self) self.Log("SLSQP ACTIVE") self.p_manager.list_alpha.append(self.alpha_slsqp) # creation of alpha generator #2 if self.GetParameter("ZScore") == "True": self.alpha_zscore = AlphaGenerator_ZScore(self) self.Log("ZScore ACTIVE") self.p_manager.list_alpha.append(self.alpha_zscore) # creation of alpha generator #3 if self.GetParameter("WVF") == "True": self.alpha_WVF_opt = AlphaGenerator_WVF_opt(self) self.Log("WVF_OPT ACTIVE") self.p_manager.list_alpha.append(self.alpha_WVF_opt) self.Schedule.On(self.DateRules.Every([DayOfWeek.Friday]), self.TimeRules.BeforeMarketClose("SPY", 5), Action(self.alpha_WVF_opt.WVF_opt_reset)) # creation of alpha generator #4 if self.GetParameter("ACR") == "True": self.alpha_ACR = AlphaGenerator_ACR(self)#args self.Log("ACR ACTIVE") self.p_manager.list_alpha.append(self.alpha_ACR) """ Define The Fixed Universe for modular """ #Create a unique universe out of our combined asset lists self.securities = ["SPY"] self.securities += list(itertools.chain.from_iterable([alpha.stocks for alpha in self.p_manager.list_alpha])) self.securities = self.Util.Unique(self.securities) #self.Debug(str(self.securities)) self.consolidator = TradeBarConsolidator(1) self.consolidator.DataConsolidated += self.OnDataConsolidated self.SubscriptionManager.AddConsolidator("SPY", self.consolidator) for stock in self.securities: #self.Debug(str(stock)) if not stock == "SPY": self.AddEquity(stock, Resolution.Daily) """ Rebalance Schedule settings """ self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.Every(TimeSpan.FromMinutes(5)), Action(self.handle_tp)) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", -15), Action(self.my_before_trading)) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 1), Action(self.Util.cancel_open_orders)) ''' self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.Every(TimeSpan.FromMinutes(180)), Action(self.handle_exvet)) ''' self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 14), Action(self.handle_exvet)) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 59), Action(self.handle_exvet)) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 179), Action(self.handle_exvet)) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.AfterMarketOpen("SPY", 359), Action(self.handle_exvet)) """ Define the Exvet universe """ self.AddUniverse(self.Exvet.CoarseSelectionFunction,self.Exvet.FineSelectionFunction) """ Define risk management parameters """ self.max_leverage = 1.0 #highest combined leverage self.reserved = 0.0 #Tell algo to reserve (won't trade with) this amount of cash self.normalize = True #noramalize leverage (attempt to stay at max leverage always) self.max_exvet = 27500000 #$25000 maximum money that will be allocated to Exvet self.exvet_pct = 1.0 #30% of your portfolio will go to exvet until you reach max_exvet amount self.trail_stoppct = 0.10 #10% trailing stop """ Flags - Do not Change these! """ self.modular_rebal_needed = True self.calculated_alphas = False self.computed_portfolio = False self.before_trading_success = False self.exvet_sell_needed = True self.exvet_buy_needed = False self.tp_needed = True """ Data - Do not Change these! """ self.modular_leverage = 0.0 self.exvet_leverage = 0.0 self.bought = [] self.sold = [] self.reorder = [] self.tp = [] self.daytrades = [] self.age = {} self.max_price = {} self.stocks_long = [] self.previous = None self.buy_chunk = 0 if self.GetParameter("Exvet") == "False": self.exvet_pct = 0.0 """ DO NOT ORDER LIST """ self.TSPP = ["ACTG", "BBGI", "CGIX", "DTEA", "GEC", "JAKK", "MPVD", "OTEL", "SALM", "TLF", "ACY", "BBOX", "CHKE", "DVAX", "GFN", "JIVE", "MRIN", "OXBR", "SALT", "TNAV", "ADMP", "BBRG", "CHKR", "DVD", "GIFI", "JNP", "MRTX", "PCYO", "SANW", "TORM", "ADRO", "BBW", "CHMA", "DWCH", "GLBL", "JONE", "MRVC", "PDEX", "SBBP", "TRIL", "ADVM", "BCOV", "CLIR", "DXLG", "GLBR", "JTPY", "MSON", "PEIX", "SCLN", "TRST", "AETI", "BDE", "CLMT", "DXYN", "GLDD", "KFFB", "MTRX", "PER", "SCX", "TSRI", "AFMD", "BDSI", "CLRO", "DYNT", "GSOL", "KFS", "MX", "PES", "SGMO", "TTNP", "AGTC", "BKEP", "CLUB", "EACQ", "GTIM", "KIN", "NAII", "PESI", "SGOC", "TUES", "AHC", "BKMU", "CLWT", "ECT", "GV", "KMDA", "NATR", "PIH", "SHOR", "TWMC", "AKER", "BKS", "CNFR", "EDUC", "GVP", "KMPH", "NBY", "PKD", "SHOS", "TZOO", "ALDX", "BSQR", "COGT", "EGAN", "HBIO", "KND", "NDLS", "PLXP", "SIF", "UBFO", "AMRC", "BTN", "COVS", "EIGI", "HBM", "KNDI", "NDRO", "PMBC", "SIGM", "ULBI", "AMS", "BV", "CRBP", "EIGR", "HGT", "KODK", "NEOS", "PMTS", "SKIS", "UNAM", "APDN", "BVSN", "CRHM", "EMAN", "HIHO", "KONA", "NERV", "PNTR", "SNFCA", "UONE", "APT", "BYBK", "CRWS", "EMKR", "HIL", "KURA", "NL", "PPIH", "SPAR", "UONEK", "APWC", "CADC", "CSLT", "ENOC", "HLIT", "KVHI", "NOA", "PPSI", "SRNE", "USAT", "ARAY", "CALL", "CSTM", "ENZY", "HLTH", "LBIO", "NOG", "PRGX", "SSFN", "UUU", "ARCO", "CALX", "CTSO", "EPM", "HPJ", "LEE", "NR", "PRQR", "STAA", "VBLT", "ARCW", "CAW", "CVRR", "ERN", "HWCC", "LFGR", "NSSC", "PRTO", "STDY", "VCEL", "ARDX", "CBAK", "CVU", "ESXB", "HYGS", "LIFE", "NTEC", "RDNT", "STKL", "VHC", "ARTW", "CBMG", "CXDC", "ETM", "IIN", "LOAN", "NTIP", "REED", "STML", "VIRC", "ARTX", "CBMX", "CYAN", "EURN", "IMDZ", "LPSN", "NTP", "RELY", "SVBI", "VISI", "ASC", "CCO", "CYRN", "EVC", "INFU", "LQDT", "NTWK", "RFIL", "SYNC", "VOXX", "ASFI", "CDI", "DAC", "EVK", "INOD", "MATR", "NVGS", "RFP", "TA", "VSLR", "ASRV", "CDTX", "DAVE", "EVOL", "INTT", "MDCA", "NVIV", "RGLS", "TAC", "VTL", "AST", "CDXS", "DFBG", "EXFO", "IO", "MDLY", "OBAS", "RIC", "TACT", "VUZI", "AT", "CEMI", "DGII", "EZPW", "IOTS", "MDWD", "OCC", "RLH", "TCCO", "WAIR", "ATAX", "CEMP", "DGLY", "FORK", "IRMD", "MGIC", "OCIP", "RTIX", "TCON", "WMIH", "ATTO", "CETV", "DHX", "FRBK", "ISNS", "MITK", "OCX", "RWC", "TESO", "WSCI", "AWRE", "CFRX", "DHXM", "FSAM", "ITEK", "MLSS", "OFG", "RWLK", "TGH", "XELB", "AXSM", "CGEN", "DMTX", "FSIC", "ITUS", "MN", "OMN", "RXDX", "TIK", "XENE", "AXTI", "CGI", "DRAD", "FVE", "IVTY", "MOBL", "ONVI", "RYI", "TIPT", "ZAGG", "AAME", "AAV", "ABEO", "ABIO", "ABUS", "ACRX", ] """ Charting """ stockPlot = Chart('Data Graph') #stockPlot.AddSeries(Series('Leverage', SeriesType.Line, 0)) stockPlot.AddSeries(Series('Long', SeriesType.Line, 0)) stockPlot.AddSeries(Series('Short', SeriesType.Line, 0)) stockPlot.AddSeries(Series('Exvet_orders', SeriesType.Line, 0)) stockPlot.AddSeries(Series('Max ag', SeriesType.Line, 0)) stockPlot2 = Chart('Leverage') stockPlot2.AddSeries(Series('Leverage', SeriesType.Line, 0)) self.AddChart(stockPlot) def my_before_trading(self): self.Util.cancel_open_orders() #self.Log("before trading") portfolio = self.Portfolio portfolio_val_total = float(portfolio.TotalPortfolioValue) #Reset Daily Flags self.computed_portfolio = False self.modular_rebal_needed = True self.tp_needed = True self.exvet_sell_needed = True self.exvet_buy_needed = False self.exvet_buy_enabled = False self.calculated_alphas = False ''' #Dynamic cash reserve if portfolio_val_total >= 20000: self.reserved = 11240 #Tell algo to reserve (won't trade with) this amount of cash else: self.reserved = 0 #Tell algo to reserve (won't trade with) this amount of cash ''' #Adjust portions of modular and Exvet port_value = (portfolio_val_total - self.reserved) * self.max_leverage exvet_amt = min(self.exvet_pct * port_value,self.max_exvet) self.exvet_leverage = exvet_amt/port_value #self.modular_leverage = max(0.0,(self.max_leverage-self.exvet_leverage)) self.modular_leverage = max(0.0,((port_value-exvet_amt)/port_value)) #Enable day-trading if balance is >26000 and disable if less than 25500 (for safety) if self.allow_unlimited_over25k and portfolio_val_total >25000: self.allow_unlimited_daytrades = True elif self.allow_unlimited_over25k and portfolio_val_total <=25000: self.allow_unlimited_daytrades = False else: pass #Advance the age of all stocks held from yesterday positions = [i for i in portfolio.Keys if portfolio[i].Invested] for symbol in positions: if symbol.Value in self.securities: continue if symbol in self.age: self.age[symbol] += 1 elif not self.before_trading_success: self.age[symbol] = 2 else: self.age[symbol] = 1 self.age = {key: value for key, value in self.age.items() if key in positions} #Advance the age of all daytrades and remove daytrades 5 days old for i, item in enumerate(self.daytrades): self.daytrades[i] += 1 to_remove = [i for i, val in enumerate(self.daytrades) if val > 4] for index in reversed(to_remove): del self.daytrades[index] #Reset daily storage variables self.bought = [] self.sold = [] self.tp = [] self.reorder = [] self.buy_chunk = 0 #success self.before_trading_success = True """ Timed functions - These are spaced out for run-speed optimization """ #Run every 15 minutes def handle_tp(self): self.tp_needed = True self.exvet_buy_enabled = True def handle_exvet(self): #pass self.Util.my_record_vars() self.Util.cancel_open_orders() self.tp = [] self.exvet_sell_needed = True def OnDataConsolidated(self, sender, bar): #self.Debug(str(self.Time) + " > New Bar!") # if we have no changes, do nothing if not self.changes == SecurityChanges.None: for security in self.changes.RemovedSecurities: if security in self.stocks_long: self.stocks_long.remove(security) #Add securities to long list that meet our price criteria for security in self.changes.AddedSecurities: try: if not security in self.stocks_long and not str(security.Symbol.Value) in self.securities: history = self.History(security.Symbol, 1, Resolution.Daily) if history.empty: continue if (len(self.stocks_long) < self.Exvet.MaxOrders) and (history['close'][0] <= self.Exvet.MyMostPrice) and (history['close'][0] >= self.Exvet.MyLeastPrice): self.stocks_long.append(security) else: pass except: #failed to load security self.Debug("failed to load security") pass self.changes = SecurityChanges.None self.Debug("stocks Long = " + str(len(self.stocks_long))) #if before_trading_start has not run due to error: if not self.before_trading_success == True: self.my_before_trading() return #Reorder failed orders: if not self.reorder == []: self.Exvet.process_reorder() #Profit Taking/Stop Functions if self.tp_needed: self.Exvet.process_tp() #Rebalance when needed: #if self.exvet_buy_needed and self.exvet_buy_enabled: if self.exvet_buy_needed: if not self.exvet_pct == 0.0: self.Exvet.process_exvet_buy() if self.exvet_sell_needed: if not self.exvet_pct == 0.0: self.Exvet.process_exvet_sell() if self.modular_rebal_needed: self.Modular_Rebalance() #Handles Modular Rebalance, first it calculates alphas once per minute, once all are calculated it assembles the target_portfolio, then it executes orders until all orders are satisfied. def Modular_Rebalance(self): if not self.calculated_alphas: for alpha in np.setdiff1d(self.p_manager.list_alpha,self.p_manager.calculated): alpha.calculate_alpha() self.p_manager.calculated.append(alpha) return self.calculated_alphas = True self.p_manager.calculated = [] if not self.computed_portfolio: # compute new allocation each alpha would like for alpha in self.p_manager.list_alpha: alpha.compute_allocation() # compute new target portfolio self.p_manager.compute_target() # compute order strategy self.computed_portfolio = True target = self.p_manager.target_portfolio self.exec_handler.execute_orders(target) # this event fires whenever we have changes to our universe def OnSecuritiesChanged(self, changes): self.changes = changes
""" Misc/Utility Functions """ import numpy as np class Utilities(object): def __init__(self, data): self.data = data def Variance(self,x,*args): #Variance Function for SLSQP p = np.squeeze(np.asarray(args)) Acov = np.cov(p.T) return np.dot(x,np.dot(Acov,x)) def Jac_Variance(self,x,*args): #jac_variance Function for SLSQP p = np.squeeze(np.asarray(args)) Acov = np.cov(p.T) return 2*np.dot(Acov,x) def Unique(self,seq,idfun=None): # order preserving if idfun is None: def idfun(x): return x seen = {} result = [] for item in seq: marker = idfun(item) if marker in seen: continue seen[marker] = 1 result.append(item) return result def my_record_vars(self): #self.data.Debug("my_record_vars") account_leverage = float(self.data.Portfolio.TotalHoldingsValue) / float(self.data.Portfolio.TotalPortfolioValue) self.data.Plot('Leverage', 'Leverage', account_leverage) portfolio = self.data.Portfolio positions = portfolio.Keys pos = 0 short = 0 for symbol in positions: if not self.data.Securities.ContainsKey(symbol): continue if portfolio[symbol].IsLong: pos += 1 if portfolio[symbol].IsShort: short += 1 self.data.Plot('Data Graph', 'Long', pos) self.data.Plot('Data Graph', 'Short', short) max_age = 0 for symbol in self.data.age: if self.data.age[symbol] > max_age: max_age = self.data.age[symbol] self.data.Plot('Data Graph', 'Max age', max_age) def cancel_open_orders(self): #self.data.Debug("cancel_open_orders") oo = [order.Symbol for order in self.data.Transactions.GetOpenOrders()] if len(oo) == 0: return oo = self.Unique(oo) for symbol in oo: if not self.data.Securities.ContainsKey(symbol): return self.data.Transactions.CancelOpenOrders(symbol) def cancel_open_order(self, symbol): #self.data.Debug("cancel_open_order") if not self.data.Securities.ContainsKey(symbol): return oo = self.data.Transactions.GetOpenOrders(symbol) if len(oo) == 0: return self.data.Transactions.CancelOpenOrders(symbol) def chunks(self, listicle, n): """Yield successive n-sized chunks from l.""" for i in range(0, len(listicle), n): yield listicle[i:i + n] def get_gain(self, symbol): #self.data.Debug("get_gain") portfolio = self.data.Portfolio positions = [i for i in portfolio.Keys if portfolio[i].HoldStock] if symbol in positions: if not self.data.Securities.ContainsKey(symbol): return 0.0 return float(portfolio[symbol].UnrealizedProfitPercent) else: return 0.0 def process_trailing_stop(self): #self.data.Debug("process_trailing_stop") portfolio = self.data.Portfolio positions = [i for i in portfolio.Keys if portfolio[i].HoldStock] self.data.max_price = {symbol: value for symbol, value in self.data.max_price.items() if symbol in positions} for symbol in positions: if not self.data.Securities.ContainsKey(symbol): continue stock = str(symbol.Value) amount = int(portfolio[symbol].Quantity) if symbol in self.data.max_price.keys(): if not amount == 0: self.data.max_price[symbol] = max(0.0, self.data.max_price[symbol],float(portfolio[symbol].UnrealizedProfitPercent)) else: self.data.max_price[symbol] = 0.0 else: self.data.max_price[symbol] = float(portfolio[symbol].UnrealizedProfitPercent) #Get current gain gain = float(portfolio[symbol].UnrealizedProfitPercent) #close positions if (self.data.max_price[symbol] - gain) > self.data.trail_stoppct: if self.get_open_orders(symbol): self.cancel_open_order(symbol) continue if not amount == 0: self.data.sold.append(stock) self.data.Log("Sell Order " + str(stock) + " @ " + str(float(self.data.Securities[symbol].Price)) + " TRAILING STOP ORDER.") try: self.data.MarketOrder(symbol, -amount) except: self.data.Debug("trailing stop sell order failed") def get_open_orders(self, symbol=None): #self.data.Debug("get_open_orders") orders = False if symbol == None: if len(self.data.Transactions.GetOpenOrders()) > 0: orders = True else: if not self.data.Securities.ContainsKey(symbol): return orders if len(self.data.Transactions.GetOpenOrders(symbol)) > 0: orders = True return orders
from Utility_Functions import * import numpy as np """ Set up Modular Framework Classes """ #Alpha generator module is supposed to find edge on the market and ask the portfolio manager for allocation. class AlphaGenerator(object): def __init__(self): self.alloc = dict() # allocation wanted self.stocks = [] # positions associated to the strategy def compute_allocation(self): raise NotImplementedError() def calculate_alpha(self): raise NotImplementedError() #Execution Handler module takes care of the strategy to reach allocation once the portfolio manager gives a target allocation. class ExecutionHandler(object): #make orders def execute_orders(self, target_portfolio): raise NotImplementedError() #Portfolio manager module manages the portfolio on the chosen frequency. class PortfolioManager(object): def __init__(self): self.target_portfolio = dict() # target_portfolio self.list_alpha = [] # list of strategies self.calculated = [] # Which strategies have been calculated # computes the target portfolio def compute_target(self): raise NotImplementedError() """ Manage Modular Execution """ # PortfolioManagerEquiWeight gives equal dollar allocation to each alpha and builds a target portfolio class PortfolioManager_EquiWeight(PortfolioManager): def __init__(self, data): PortfolioManager.__init__(self) self.data = data def compute_target(self): # get number of alpha generators nb_alpha = max(1,len(self.list_alpha)) # clear target allocation for stock in self.data.securities: self.target_portfolio[stock] = 0 # for each alpha add allocation to the target for alpha in self.list_alpha: for stock in alpha.alloc: alloc_alpha = alpha.alloc[stock] / nb_alpha self.target_portfolio[stock] = self.target_portfolio[stock] + alloc_alpha #update the number of shares the alpha is responsible for #option to normalize target_portfolio to fill all availible leverage if self.data.normalize: original_wt = sum(np.abs(self.target_portfolio.values())) if original_wt > 0.0: factor = 1.0/original_wt else: factor = 0.0 for stock in self.target_portfolio: self.target_portfolio[stock] = self.target_portfolio[stock]*factor # ExecutionHandler_Market makes market orders to reach allocation class ExecutionHandler_Market(ExecutionHandler): def __init__(self, data): self.data = data ''' def execute_orders(self, target_portfolio): portfolio = self.data.Portfolio portfolio_val_total = float(portfolio.TotalPortfolioValue) port_val = (portfolio_val_total - self.data.reserved) * self.data.modular_leverage pos_val = float(portfolio.TotalHoldingsValue) cash = max(0.0,(port_val - pos_val)) for stock in target_portfolio: if self.data.Util.get_open_orders(stock): self.data.Debug("Open Orders, waiting") return for stock in self.data.securities: price = float(self.data.Securities[stock].Price) goal_val = port_val * min(1.0,target_portfolio[stock]) goal_shares = 0 if goal_val >= 0 and price > 0: goal_shares = np.floor(goal_val / price) if goal_val < 0 and price > 0: goal_shares = np.ceil(goal_val / price) current_shares = float(self.data.Portfolio[stock].Quantity) current_val = current_shares * price shares_to_buy = (goal_shares - current_shares) cost = np.abs(shares_to_buy) * price diff = 1.0 if not goal_val == 0: diff = np.abs((current_val-goal_val)/goal_val) if shares_to_buy > 1 and diff > .05: if (np.abs(goal_shares) < np.abs(current_shares)) or (cost < cash): self.data.MarketOrder(stock, shares_to_buy) msg = ''.join(["Ordering ",str(stock)," shares: ",str(shares_to_buy)]) #self.data.Log(msg) return else: self.data.modular_rebal_needed = True continue else: continue self.data.modular_rebal_needed = False for stock in self.data.securities: self.data.Log(str(stock) + ". Allocation = " + str(round(target_portfolio[stock]*100,1)) + "%") self.data.Log("Modular Execution Finished") ''' def execute_orders(self, target_portfolio): portfolio = self.data.Portfolio portfolio_val_total = float(portfolio.TotalPortfolioValue) port_value_adjusted = (portfolio_val_total - self.data.reserved) * self.data.max_leverage modular_leverage = (port_value_adjusted * self.data.modular_leverage)/portfolio_val_total sold = False for stock in self.data.securities: if self.data.Util.get_open_orders(stock): self.data.Debug("Open Orders on: " + str(stock) + ", waiting") self.data.modular_rebal_needed = True return current = float(self.data.Portfolio[stock].AbsoluteHoldingsValue) goal = (port_value_adjusted*target_portfolio[stock]) goal_pct = (modular_leverage*target_portfolio[stock]) amount = (goal-current) if amount < 0.0 and (abs(amount) > 1000 or goal_pct == 0.0): self.data.SetHoldings(stock, goal_pct) sold = True else: continue if sold: self.data.modular_rebal_needed = True return for stock in self.data.securities: current = float(self.data.Portfolio[stock].AbsoluteHoldingsValue) goal = (port_value_adjusted*target_portfolio[stock]) goal_pct = (modular_leverage*target_portfolio[stock]) amount = (goal-current) if amount > 0.0 and abs(amount) > 1000: self.data.SetHoldings(stock, goal_pct) else: continue for stock in self.data.securities: self.data.Log(str(stock) + ". Allocation = " + str(round(target_portfolio[stock]*100,1)) + "%") self.data.modular_rebal_needed = False self.data.Log("Modular Execution Finished")
from Manage_Modular import * from Utility_Functions import * import numpy as np import pandas as pd from scipy import optimize class AlphaGenerator_SLSQP(AlphaGenerator): def __init__(self, data): AlphaGenerator.__init__(self) self.data = data self.Util = Utilities(self.data) #SLSQP assets self.stocks = [ "SPY", "QQQ", "TLT", "TIP", "AGG", ] self.allocation = {} """ SLSQP parameters """ self.sqslp_days = 42 self.x1 = np.asarray([1.0/len(self.stocks) for i in self.stocks]) self.eps = 0.01 self.tol = float(1.0e-6) #assume convergence is 10 time SLSQP ftol of 1e-6 def compute_allocation(self): #self.data.Log("compute_allocation") for sid in self.allocation: self.alloc[sid] = self.allocation[sid] def calculate_alpha(self): prices = self.data.History(self.stocks, self.sqslp_days, Resolution.Daily)['close'].unstack(level=0) ret = prices.pct_change()[1:].values ret_mean = prices.pct_change().mean() ret_std = prices.pct_change().std() ret_norm = ret_mean/ret_std ret_norm = ret_norm.values 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] #[0,1] for long only [-1,1] for long/short for stock in self.stocks: bnds.append(limits) bnds = tuple(tuple(x) for x in bnds) cons = ({'type': 'eq', 'fun': lambda x: np.sum(x)-1.0}, {'type': 'ineq', 'fun': lambda x: np.dot(x,ret_norm)-self.eps}) res= optimize.minimize(self.Util.Variance, self.x1, args=ret,jac=self.Util.Jac_Variance, method='SLSQP',constraints=cons,bounds=bnds) if res.success: # if SLSQP declares success weighted_ret_norm = np.dot(res.x,ret_norm) w_ret_constraint = weighted_ret_norm - self.eps + self.tol if(w_ret_constraint > 0): # and constraint is actually met allocation = res.x allocation[allocation<0.0] = 0.0 #Remove to allow short factor=sum(np.abs(allocation)) if factor > 0: allocation = allocation/factor for i,stock in enumerate(self.stocks): self.allocation[stock] = allocation[i] self.data.WVF_opt_calculated = True else: self.data.Log("SLSQP: constraint fail, SLSQP status = {0}".format(res.status)) for i,stock in enumerate(self.stocks): self.allocation[stock] = 0.0 else: self.data.Log("SLSQP: SLSQP fail, SLSQP status = {0}".format(res.status)) for i,stock in enumerate(self.stocks): self.allocation[stock] = 0.0
from Manage_Modular import * from Utility_Functions import * import numpy as np import pandas as pd import math class AlphaGenerator_ZScore(AlphaGenerator): def __init__(self, data): AlphaGenerator.__init__(self) self.data = data #zscore assets self.stocks = [ "SPY", "TLT", "XLP", "XIV", ] """ zscore parameters """ self.fixed_wt_pct = 0.50 self.fixed_wt = { "XLP": 0.50, "TLT": 0.40, "XIV": 0.10, } self.vol_factor = 0.5 #TLT = .5, SPY = 1 self.ext_factor = 4.0 #move too extreme, leave asset self.lookback = 150 self.allocation = {} def compute_allocation(self): for sid in self.allocation: self.alloc[sid] = self.allocation[sid] def calculate_alpha(self): ''' for sid in self.stocks: if not self.data.data.ContainsKey(sid): self.data.Log("ZScore No data") return ''' history = self.data.History(['TLT'], self.lookback, Resolution.Daily) mean = history['close'].mean() sigma = history['close'].std() price = float(self.data.Securities['TLT'].Price) if sigma != 0.0: z = (price - mean) / sigma**self.vol_factor else: z = 0.0 if -self.ext_factor <= z <= self.ext_factor: tlt_target = 1.0/(1+math.exp(-1.2*z)) # Pure momentum adding 1 to the sin wave to prevent shorting else: tlt_target = 0.0 spy_target = (1.0-tlt_target) for sid in self.stocks: self.allocation[sid] = 0.0 if sid in self.fixed_wt: self.allocation[sid] += self.fixed_wt[sid] * self.fixed_wt_pct self.allocation["TLT"] += tlt_target * (1.0 - self.fixed_wt_pct) self.allocation["SPY"] += spy_target * (1.0 - self.fixed_wt_pct)
from Manage_Modular import * from Utility_Functions import * import numpy as np import pandas as pd from scipy import optimize class AlphaGenerator_WVF_opt(AlphaGenerator): def __init__(self, data): AlphaGenerator.__init__(self) self.data = data self.Util = Utilities(self.data) """ WVF parameters """ self.WFV_limit = 14 # (Kory used 14 but it becomes a bit too agressive) self.n = 28 self.WVF_opt_calculated = False self.allocation = {} #WVF_opt assets self.bull = "TQQQ" self.bear = "TMF" self.stocks = [ self.bull, self.bear, "XIV", ] self.vxx = self.data.AddEquity("VXX") """ WVF_SLSQP parameters """ self.sqslp_days = 17 self.x1 = np.asarray([1.0/len(self.stocks) for i in self.stocks]) self.eps = 0.01 self.tol = float(1.0e-6) #assume convergence is 10 time SLSQP ftol of 1e-6 """ SPY_FIX parameters """ self.period = 28 #"LookBack Period Standard Deviation High") self.bbl = 22 # "Bolinger Band Length") self.mult = 1.05 # "Bollinger Band Standard Devaition Up") self.lb = 22 # "Look Back Period Percentile High") self.ph = .90 # "Highest Percentile - 0.90=90%, 0.95=95%, 0.99=99%") # Criteria for Down Trend Definition for Filtered Pivots and Aggressive Filtered Pivots self.ltLB = 40 # Long-Term Look Back Current Bar Has To Close Below This Value OR Medium Term--Default=40") self.mtLB = 14 # Medium-Term Look Back Current Bar Has To Close Below This Value OR Long Term--Default=14") self.Str = 3 # Entry Price Action Strength--Close > X Bars Back---Default=3") def compute_allocation(self): #self.data.Log("compute_allocation") for sid in self.allocation: self.alloc[sid] = self.allocation[sid] def calculate_alpha(self): #self.data.Log("calculate_alpha") """ VOL_calculate """ history = self.data.History(["VXX"], int(self.n + 2), Resolution.Daily) vxx_prices = history.loc["VXX"]["close"][:-1] vxx_lows = history.loc["VXX"]["low"][:-1] vxx_highest = vxx_prices.rolling(window = self.n, center=False).max() # William's VIX Fix indicator a.k.a. the Synthetic VIX WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100 # Sell position when WVF crosses under 14 if(WVF[-2] > self.WFV_limit and WVF[-1] <= self.WFV_limit): self.allocation["XIV"] = 0.0 #self.data.Log("sell XIV") """ TMF_calculate """ history = self.data.History([self.bear], 200, Resolution.Daily) ma_tmf = history.loc[self.bear]["close"].mean() cp_tmf = float(self.data.Securities[self.bear].Price) if cp_tmf < ma_tmf: self.allocation[self.bear] = 0.0 """ Allocate stocks """ if not self.WVF_opt_calculated: self.WVF_opt_allocate() """ SPY_FIX calculate """ bullish_size = self.allocation[self.bull] bearish_size = self.allocation[self.bear] history = self.data.History([self.bull], int((2*self.period) + 2), Resolution.Daily) spy_close = history.loc[self.bull]["close"] spy_lows = history.loc[self.bull]["close"] spy_highest = spy_close.rolling(window = self.period).max() # Williams Vix Fix Formula WVF_s = ((spy_highest - spy_lows)/(spy_highest)) * 100 sDev = self.mult * np.std(WVF_s[-int(self.bbl):]) midLine = np.mean(WVF_s[-int(self.bbl):]) upperBand = midLine + sDev rangeHigh = (max(WVF_s[-int(self.lb):])) * self.ph spy_higher_then_Xdays_back = spy_close[-1] > spy_close[-int(self.Str)] spy_lower_then_longterm = spy_close[-1] < spy_close[-int(self.ltLB)] spy_lower_then_midterm = spy_close[-1] < spy_close[-int(self.mtLB)] # Alerts Criteria alert2 = not (WVF_s[-1] >= upperBand and WVF_s[-1] >= rangeHigh) and (WVF_s[-2] >= upperBand and WVF_s[-2] >= rangeHigh) spy_change = (alert2 or spy_higher_then_Xdays_back) and (spy_lower_then_longterm or spy_lower_then_midterm) if (spy_change and bearish_size > bullish_size) or (not spy_change and bullish_size > bearish_size): self.allocation[self.bear] = bullish_size self.allocation[self.bear] = bearish_size def WVF_opt_reset(self): #self.data.Log("WVF_opt_reset") self.WVF_opt_calculated = False def WVF_opt_allocate(self): #self.data.Log("WVF_opt_allocate") prices = self.data.History(self.stocks, self.sqslp_days, Resolution.Daily)['close'].unstack(level=0) ret = prices.pct_change()[1:].values ret_mean = prices.pct_change().mean() ret_std = prices.pct_change().std() ret_norm = ret_mean/ret_std ret_norm = ret_norm.values 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] #[0,1] for long only [-1,1] for long/short for stock in self.stocks: bnds.append(limits) bnds = tuple(tuple(x) for x in bnds) cons = ({'type': 'eq', 'fun': lambda x: np.sum(x)-1.0}, {'type': 'ineq', 'fun': lambda x: np.dot(x,ret_norm)-self.eps}) res= optimize.minimize(self.Util.Variance, self.x1, args=ret,jac=self.Util.Jac_Variance, method='SLSQP',constraints=cons,bounds=bnds) if res.success: # if SLSQP declares success weighted_ret_norm = np.dot(res.x,ret_norm) w_ret_constraint = weighted_ret_norm - self.eps + self.tol if(w_ret_constraint > 0): # and constraint is actually met allocation = res.x allocation[allocation<0] = 0 #Remove to allow short factor=sum(np.abs(allocation)) if factor > 0: allocation = allocation/factor for i,stock in enumerate(self.stocks): self.allocation[stock] = allocation[i] self.data.WVF_opt_calculated = True else: self.data.Log("WVF: constraint fail, SLSQP status = {0}".format(res.status)) for i,stock in enumerate(self.stocks): self.allocation[stock] = 0.0 else: self.data.Log("WVF: SLSQP fail, SLSQP status = {0}".format(res.status)) for i,stock in enumerate(self.stocks): self.allocation[stock] = 0.0
from Manage_Modular import * from Utility_Functions import * import numpy as np import pandas as pd import itertools class AlphaGenerator_ACR(AlphaGenerator): def __init__(self, data): AlphaGenerator.__init__(self) self.data = data self.Util = Utilities(self.data) self.ACR_assets = [ "VOE", "VDC", "XLP", "IJR", ] self.ACR_bonds = [ "TLT", "TIP", "DBC", "SHY", ] self.ACR_sectors = [ "XLB", #Materials "XLY", #Consumer Cyclical "XLF", #Financials "IYR", #ISHARES Real Estate "XLP", #Consumer Defensive "XLV", #Healthcare "XLU", #Utilities "XLE", #Energy "XLI", #Industrials "XLK", #Tech ] self.ACR_fixed = [ "SPY", ] for stock in self.ACR_sectors: self.data.AddEquity(stock) self.stocks = self.ACR_assets+self.ACR_bonds+self.ACR_fixed """ ACR (Asset Class Rotation) parameters """ self.ACR_sector_step = 13 #12% step change = all bonds if 9 of 11 sectors down self.ACR_asset_step = 20 #20% step change self.allocation = {} self.ACR_fixed_weight = [ 0.0, #SPY ] def compute_allocation(self): #self.data.Log("compute_allocation") for sid in self.allocation: self.alloc[sid] = self.allocation[sid] def calculate_alpha(self): for sid in self.stocks: if not sid in self.allocation: self.allocation[sid] = 0.0 ACR_assets_weight = np.zeros(len(self.ACR_assets)) ACR_bonds_data = pd.DataFrame(0, columns=['Weight','Ratio','20Day','60Day'],index=self.ACR_bonds) ACR_sectors_data = pd.DataFrame(0, columns=['Ratio','20Day','200Day'],index=self.ACR_sectors) """ Determine sector trends and calculate weight to assets/bonds """ ACR_sectors_data.loc[:,'20Day'] = self.data.History(self.ACR_sectors, 20, Resolution.Daily)["close"].unstack(level=0).mean() ACR_sectors_data.loc[:, '200Day'] = self.data.History(self.ACR_sectors, 200, Resolution.Daily)["close"].unstack(level=0).mean() ACR_sectors_data['Ratio'] = ACR_sectors_data['20Day']/ACR_sectors_data['200Day'] - 1 ACR_bonds_weight = len(ACR_sectors_data[ACR_sectors_data['Ratio'] < 0]) * self.ACR_sector_step/100.0 if ACR_bonds_weight > 1.0: ACR_bonds_weight = 1.0 ACR_bonds_weight = ACR_bonds_weight * (1-sum(self.ACR_fixed_weight)) """ Determine bond trends and which duration to be in """ if ACR_bonds_weight > 0.0: ACR_bonds_data.loc[:,'20Day'] = self.data.History(self.ACR_bonds, 20, Resolution.Daily)["close"].unstack(level=0).mean() ACR_bonds_data.loc[:, '60Day'] = self.data.History(self.ACR_bonds, 60, Resolution.Daily)["close"].unstack(level=0).mean() ACR_bonds_data['Ratio'] = ACR_bonds_data['20Day']/ACR_bonds_data['60Day'] - 1 ACR_bonds_data['Weight'] = 0 ACR_bonds_data.loc[ACR_bonds_data['Ratio'].idxmax(), 'Weight'] = ACR_bonds_weight #log.info(self.ACR_bonds_data) returns = self.data.History(self.ACR_assets, 126, Resolution.Daily)["close"].unstack(level=0).dropna().pct_change().dropna() + 1.0 """ Create portfolio combinations """ n = len(self.ACR_assets) steps = [x/100.0 for x in range(0,101,int(self.ACR_asset_step))] a = [steps for x in xrange(n)] b = list(itertools.product(*a)) x = [sum(i) for i in b] port = pd.DataFrame(b) port['Sum'] = x port = port[port.Sum == 1] del port['Sum'] """ Score and Weight portoflio """ port_returns = pd.DataFrame(np.dot(returns, port.T), index=returns.index) port_metrics = self.ACR_get_specs(port_returns) port_metrics = self.ACR_score(port_metrics) port_metrics['Z3'] = port_metrics.ZMean\ -port_metrics.ZSTD\ -port_metrics.ZDownSide\ +port_metrics.ZAnnualized\ -port_metrics.ZMax_Draw\ -port_metrics.ZSTD10\ +port_metrics.ZMean10\ +port_metrics.ZMinimum15 port_metrics = port_metrics.sort_values(by='Z3', ascending=False) portfolios = port portfolios.columns = list(returns.columns.values) best = pd.concat([pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()]).T]) #log.info(best.loc[:, (best != 0).any(axis=0)].T) best = pd.DataFrame(portfolios.iloc[port_metrics['Z3'].idxmax()]) #log.info(best) ACR_assets_weight = [i[0]*(1-ACR_bonds_weight-sum(self.ACR_fixed_weight)) for i in best.values] for x in range(n): self.allocation[self.ACR_assets[x]] = ACR_assets_weight[x] for stock in self.ACR_bonds: self.allocation[stock] = ACR_bonds_data.loc[stock, 'Weight'] for x in range(len(self.ACR_fixed)): self.allocation[self.ACR_fixed[x]] = self.ACR_fixed_weight[x] def ACR_drawdown(self, returns): mat = returns.cumprod().values [n, m] = np.shape(mat) maxes = np.maximum.accumulate(np.array(mat)) for i in range(0,n): for j in range(m): mat[i,j] = mat[i,j] / maxes[i,j] df = pd.DataFrame(mat) df[df > 1] = 1 return df def ACR_moving_returns(self, returns, w): mat = returns.values [n, m] = np.shape(mat) ret = np.zeros(shape = (n-w+1,m)) for i in range(w-1,n): for j in range(m): ret[i-w+1,j] = np.power(np.prod(mat[(i-w+1):i+1,j]),(1.0/w))- 1.0 return pd.DataFrame(ret) def ACR_get_specs(self, returns): metrics = pd.DataFrame((returns.mean()),columns=['Mean']) - 1.0 metrics['STD'] = pd.DataFrame((returns.std())) metrics['Annualized'] = np.power(returns.cumprod().values.tolist()[-1],1.0/len(returns))- 1.0 downside = returns.copy(deep=True) - 1 downside[downside > 0] = 0 downside = downside ** 2 metrics['DownSide'] = pd.DataFrame(downside.mean() ** 0.5) draw = self.ACR_drawdown(returns) metrics['Max_Draw'] = 1.0 - draw.min().values ret15 = self.ACR_moving_returns(returns,21) metrics['Minimum15'] = ret15.min().values ret10 = self.ACR_moving_returns(returns,21) metrics['Mean10'] = ret10.mean().values metrics['STD10'] = ret10.std().values return metrics def ACR_zscore(self, stocks, var, var_save): stocks[var_save] = (stocks[var] - stocks[var].mean())/stocks[var].std(ddof=0) return stocks def ACR_score(self, metrics): metrics = self.ACR_zscore(metrics, 'Mean', 'ZMean') metrics = self.ACR_zscore(metrics, 'STD', 'ZSTD') metrics = self.ACR_zscore(metrics, 'Annualized', 'ZAnnualized') metrics = self.ACR_zscore(metrics, 'DownSide', 'ZDownSide') metrics = self.ACR_zscore(metrics, 'Max_Draw', 'ZMax_Draw') metrics = self.ACR_zscore(metrics, 'Minimum15', 'ZMinimum15') metrics = self.ACR_zscore(metrics, 'STD10', 'ZSTD10') metrics = self.ACR_zscore(metrics, 'Mean10', 'ZMean10') return metrics
from Utility_Functions import * from QuantConnect.Data.UniverseSelection import * import numpy as np import pandas as pd """ Manage Exvet Execution """ class Exvet(object): def __init__(self, data): self.data = data """ Exvet parameters """ self.MyLeastPrice = 1.10 #1.10 #.7 Minimum stock price criteria self.MyMostPrice = 2.50 #2.49 #1.49Maximum stock price criteria self.LowVar = 0.06 #6 Bottom range percentile of DollarVolume universe self.HighVar = 0.40 #40 Top range percentile of DollarVolume universe self.rounding = True self.min_order = 200 self.MyFireSaleAge = 3 #3 Age at which stocks will be sold, regardless of profit/loss self.BuyFactor = .95 #.97 #.96Attempt to Buy stocks with this discount self.SellFactor = 1.03 #1.03 #1.02 Attempt to sell stocks with this profit self.DayFactor = 1.2 #1.05 Profit Threshold to attempt a daytrade sell, if daytrading is disabled it will still function as a "quick sell" threshold. self.Top_Stocks = 300 #150 self.MaxOrders = 50 #100 self.chunks = 10 #10 """ Temp variables - Do not modify """ self.exvet_buy_cash = 0.0 self.cash_used = 0.0 def process_exvet_sell(self): ### #Sell Logic ### if self.data.exvet_pct == 0.0: return #Order sell at profit target in hope that somebody actually buys it portfolio = self.data.Portfolio positions = [i for i in portfolio.Keys if portfolio[i].HoldStock] #self.data.Debug("positions(sell) = " + str(positions)) i = 0 #self.data.Debug("exvet sell ") for symbol in positions: if not self.data.Securities.ContainsKey(symbol): continue if i > self.chunks: return stock = str(symbol.Value) StockShares = int(portfolio[symbol].Quantity) CostBasis = float(portfolio[symbol].HoldingsCost)/StockShares price = float(self.data.Securities[symbol].Price) #Only buy Valid stocks that don't have open orders and respect daytrades. if not self.data.Util.get_open_orders(symbol) and not stock in self.data.bought and not stock in self.data.securities: if stock in self.data.TSPP or StockShares < 0: i +=1 try: self.data.MarketOrder(symbol, -StockShares) except: self.data.Debug("TSPP/short liquidation failed") continue SellPrice = CostBasis*self.SellFactor Quick_sell = (price*1.0)-.01 #if len(self.data.age.keys())>0: #self.data.Debug(str(self.data.age.keys()[0])) #if symbol in self.data.age.keys(): #age = self.data.age[symbol] #else: #age = 0 #self.data.Debug("age of " + str(symbol) + " = " + str(age)) too_old = (symbol in self.data.age and self.data.age[symbol]>=self.MyFireSaleAge and CostBasis>price) #high_profit = (price > (CostBasis*(self.SellFactor+.01))) high_profit = False try: if too_old or high_profit: #Profit Target has been greatly exceeded or stock held too long. Sell quickly. msg = "" if high_profit: #Log info why we sold it. self.data.LimitOrder(symbol, -StockShares, round((CostBasis*(self.SellFactor-.01)),2)) msg = ''.join(["Sell Limit Order ",str(stock)," @ ",str((CostBasis*(self.SellFactor-.01)))," Profit target exceeded."]) else: self.data.LimitOrder(symbol, -StockShares, round(Quick_sell,2)) msg = ''.join(["Sell Limit Order ",str(stock)," @ ",str(Quick_sell)," Held too long: ",str(self.data.age[symbol])," days."]) #self.data.Debug(msg) i +=1 self.data.Log(msg) if not self.data.allow_unlimited_daytrades: #mark as sold to prevent daytrades. self.data.sold.append(stock) else: #Attempt to sell at Profit target i +=1 self.data.LimitOrder(symbol, -StockShares, round(SellPrice,2)) msg = ''.join(["Sell Limit Order ",str(stock)," @ ",str(SellPrice)]) self.data.Log(msg) if not self.data.allow_unlimited_daytrades: #mark this as sold to prevent daytrades. self.data.sold.append(stock) except: self.data.Debug("exvet sell order failed") else: pass #flag for successful sell, move to buy logic self.data.exvet_sell_needed = False self.data.exvet_buy_needed = True def process_exvet_buy(self): ### #Buy Logic ### if self.data.exvet_pct == 0.0: return portfolio = self.data.Portfolio positions = [i for i in portfolio.Keys if portfolio[i].HoldStock] #self.data.Debug("positions = " + str(positions)) if self.data.buy_chunk == 0: port_val_total = float(portfolio.TotalPortfolioValue) port_val_adjusted = (port_val_total - self.data.reserved) * self.data.max_leverage num = 0 for sid in self.data.stocks_long: stock = str(sid.Symbol.Value) symbol = str(sid.Symbol) if not stock in self.data.sold and not sid.Invested and not stock in self.data.TSPP: num += 1 self.data.Plot('Data Graph', 'Exvet_orders', num) if num == 0: self.WeightThisBuyOrder = 0.0 else: self.WeightThisBuyOrder = min(.05,(1.0/num)) modular_used = 0.0 exvet_used = 0.0 for symbol in positions: stock = str(symbol.Value) if stock in self.data.securities: modular_used += float(portfolio[symbol].HoldingsValue) else: exvet_used += float(portfolio[symbol].HoldingsValue) exvet_val_max = port_val_adjusted * self.data.exvet_leverage #self.exvet_buy_cash = max(0.0,min(self.data.max_exvet,(exvet_val_max - exvet_used)*4.0)) self.exvet_buy_cash = max(0.0,min(self.data.max_exvet,(exvet_val_max - exvet_used))) self.cash_used = 0.0 stocks_chunk = [] try: stocks_chunk = list(self.data.Util.chunks(self.data.stocks_long,self.chunks))[self.data.buy_chunk] except: #flag for successful buy self.data.exvet_buy_needed = False self.data.buy_chunk = 0 return #Loop through candidates and place buy orders #self.data.Debug("chunk " + str(self.data.buy_chunk)) #history = self.data.History(stocks_chunk, 1, Resolution.Daily) #self.data.Debug(str(history)) for sid in stocks_chunk: stock = str(sid.Symbol.Value) symbol = str(sid.Symbol) if stock in self.data.TSPP or stock in self.data.securities: continue #self.data.Debug(stock_symbol + " in positions: " + str(stock_data in positions) + ". In data: " + str(self.data.Securities.ContainsKey(stock_data))) if not stock in self.data.sold and not sid.Invested and self.data.Securities.ContainsKey(symbol): price = float(self.data.Securities[symbol].Price) BuyPrice = price*self.BuyFactor if BuyPrice <= 0.0: continue StockShares = max(0,np.floor(self.WeightThisBuyOrder*self.exvet_buy_cash/BuyPrice)) if self.rounding == True: StockShares = round(StockShares, -2) if StockShares < self.min_order: continue cost = (BuyPrice*StockShares) if StockShares == 0 or ((self.cash_used + cost) >= self.exvet_buy_cash): continue self.cash_used += cost orders = 0 while StockShares > 0 and orders < 15: if StockShares == 300: BuyShares = 300 else: BuyShares = 200 msg = ''.join(["Buy Limit Order ",str(BuyShares)," shares of ",stock," @ ",str(BuyPrice)]) self.data.Log(msg) self.data.LimitOrder(symbol, BuyShares, round(BuyPrice,2)) StockShares -= BuyShares orders += 1 if not self.data.allow_unlimited_daytrades: #mark this as bought to prevent daytrades. self.data.bought.append(stock) self.data.buy_chunk += 1 #self.data.Debug("cash used " + str(self.cash_used)) #self.data.Debug("total cash " + str(self.exvet_buy_cash)) def process_tp(self): #self.data.Debug("TP ") self.data.tp_needed = False self.data.Util.process_trailing_stop() if self.data.exvet_pct == 0.0: return portfolio = self.data.Portfolio positions = [i for i in portfolio.Keys if portfolio[i].HoldStock] for symbol in positions: stock = str(symbol.Value) if stock in self.data.securities or not self.data.Securities.ContainsKey(symbol): continue try: gain = self.data.Util.get_gain(symbol) price = float(self.data.Securities[symbol].Price) StockShares = int(portfolio[symbol].Quantity) DayPrice = max(price,(float(portfolio[symbol].HoldingsCost)/StockShares*self.DayFactor))*.99 except: self.data.Debug("tp data failed") continue if gain > (self.DayFactor-1) and stock not in self.data.tp: if not self.data.allow_unlimited_daytrades: if stock in self.data.bought: if not self.data.daytrade_limited: continue else: if len(self.data.daytrades) >= 3: continue else: msg = ''.join(["Sell Limit Order ",str(stock)," @ ",str(DayPrice)," HIGH PROFIT LIMITED DAYTRADE."]) self.data.daytrades.append(0) #mark this as a daytrade. else: msg = ''.join(["Sell Limit Order ",str(stock)," @ ",str(DayPrice)," HIGH PROFIT SALE."]) else: msg = ''.join(["Sell Limit Order ",str(stock)," @ ",str(DayPrice)," HIGH PROFIT DAYTRADE."]) self.data.Log(msg) if self.data.Util.get_open_orders(symbol): self.data.reorder.append(symbol) self.data.Util.cancel_open_order(symbol) else: #Daytrade profit target has been exceeded. Sell quickly for high profit. try: self.data.LimitOrder(symbol, -StockShares, round(DayPrice,2)) except: self.data.Debug("failed TP limitorder") self.data.tp.append(stock) if not self.data.allow_unlimited_daytrades: self.data.sold.append(stock) #mark this as sold to prevent daytrades. def process_reorder(self): if self.data.exvet_pct == 0.0: return #self.data.Debug("process_reorder") portfolio = self.data.Portfolio positions = [i for i in portfolio.Keys if portfolio[i].HoldStock] for symbol in self.data.reorder: if not symbol in positions or not self.data.Securities.ContainsKey(symbol): continue #check to make sure we still own this stock DayPrice = float(portfolio[symbol].HoldingsCost)*self.DayFactor StockShares = int(portfolio[symbol].Quantity) try: self.data.LimitOrder(symbol, -StockShares, round(DayPrice,2)) except: self.data.Debug("reorder sell failed") self.data.reorder = [] """ DEFINE UNIVERSE """ ''' def CoarseSelectionFunction(self, coarse): if self.data.exvet_pct == 0.0: return [] selected = [x for x in coarse if (x.HasFundamentalData) and (float(x.Price) >= self.MyLeastPrice) and (float(x.Price) <= self.MyMostPrice)] #percentiles = selected.Percentile(self.LowVar,self.HighVar) DollarVolume = sorted(selected, key=lambda x: x.DollarVolume, reverse=True) #self.data.Log('initial select %d'%(len(DollarVolume))) upper = int(len(DollarVolume)*self.HighVar/100) lower = int(len(DollarVolume)*self.LowVar/100) brackets = DollarVolume[lower:upper] top = brackets[:self.Top_Stocks] #self.data.Log('top select %d'%(len(top))) return [x.Symbol for x in top] ''' def CoarseSelectionFunction(self, coarse): if self.data.exvet_pct == 0.0: return [] # First narrow the original coarse universe down to a managable level. init_select = [stock for stock in coarse if (stock.HasFundamentalData) and (float(stock.Price) >= self.MyLeastPrice) and (float(stock.Price) <= self.MyMostPrice)] # second convert the initial selection to a pandas dataframe. stock_symbols = [stock.Symbol for stock in init_select] stock_data = [(stock.DollarVolume,) for stock in init_select] column_names = ['dollar_volume'] # Use coerce parameter = True to convert data objects to numbers data_df = pd.DataFrame.from_records( stock_data, index=stock_symbols, columns=column_names, coerce_float=True) # Use pandas methods to select the assets we want # First find the values of dollar_volume at our desired bounds lower_percent = data_df.dollar_volume.quantile(self.LowVar) upper_percent = data_df.dollar_volume.quantile(self.HighVar) # Now simply query using those values # Filter for has_fundamentals to remove ETFs my_universe = (data_df. query('(dollar_volume >= @lower_percent) & (dollar_volume <= @upper_percent)')) # See how many securities are found in our universe self.data.Debug("{} potential securities found ".format(my_universe.shape[0])) # Expects a list of symbols returned return my_universe.index.tolist() def FineSelectionFunction(self, fine): if self.data.exvet_pct == 0.0: return [] filtered_fine = [x for x in fine if (x.ValuationRatios.PriceChange1M)] #self.data.Log('filtered_fine select %d'%(len(filtered_fine))) sortedByChange = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PriceChange1M, reverse=True) #sortedByChange = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PriceChange1M, reverse=False) # take the top entries from our sorted collection topFine = sortedByChange[:self.MaxOrders] self.data.Debug('Top select %d'%(len(topFine))) stocks = [x.Symbol for x in topFine] return stocks
''' Exvet_buy is ordering stocks that we already hold positions in, need to figure out why that isn't working and what other implications it might have (positions not registering) '''