Overall Statistics |
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 |
from QuantConnect import * from QuantConnect.Parameters import * from QuantConnect.Benchmarks import * from QuantConnect.Brokerages import * from QuantConnect.Util import * from QuantConnect.Interfaces import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Selection import * from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Algorithm.Framework.Portfolio import * from QuantConnect.Algorithm.Framework.Execution import * from QuantConnect.Algorithm.Framework.Risk import * from QuantConnect.Indicators import * from QuantConnect.Data import * from QuantConnect.Data.Consolidators import * from QuantConnect.Data.Custom import * from QuantConnect.Data.Fundamental import * from QuantConnect.Data.Market import * from QuantConnect.Data.UniverseSelection import * from QuantConnect.Notifications import * from QuantConnect.Orders import * from QuantConnect.Orders.Fees import * from QuantConnect.Orders.Fills import * from QuantConnect.Orders.Slippage import * from QuantConnect.Scheduling import * from QuantConnect.Securities import * from QuantConnect.Securities.Equity import * from QuantConnect.Securities.Forex import * from QuantConnect.Securities.Interfaces import * from datetime import date, datetime, timedelta from QuantConnect.Python import * from QuantConnect.Storage import * QCAlgorithmFramework = QCAlgorithm QCAlgorithmFrameworkBridge = QCAlgorithm import math import numpy as np import pandas as pd import scipy as sp class MicroGrowth(QCAlgorithm): def Initialize(self): #self.SetStartDate(2020, 2, 12) # Set Start Date self.SetStartDate(2019, 1,1) self.SetEndDate(2019, 3, 1) self.SetCash(100000) # Set Strategy Cash #self.Settings.FreePortfolioValuePercentage = 0.6 self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash) self.UniverseSettings.Resolution = Resolution.Hour self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) self.lasttime = None self.monthinterval = 1 self.periods = [30,60,180] self.rebalance_interval = timedelta(days = min(self.periods)) self.tohold = None self.tobeliquidated = None self.numsecurities = 25 self.SetWarmUp(timedelta(hours= 4)) self.debug_execution = False self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x))) self.history_dict = {} self.rebalance = False #self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.BeforeMarketClose("TSLA", 0), self.ClosingBar) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(minutes=10)), self.RebalancePortfolio) def RebalancePortfolio(self): return if self.IsWarmingUp: return if self.rebalance == True: self.rebalance = False # selected symbols will be found in Log self.Debug('\n\n\n'+f'========== NEW CYCLE ==========') # self.Debug(f'New Securities Added: {[security.Symbol.Value for security in changes.AddedSecurities]}') # self.Debug(f'Securities Removed{[security.Symbol.Value for security in changes.RemovedSecurities]}') self.Debug(f'PORTFOLIO CASH BEFORE LIQUIDATION: {self.Portfolio.Cash}') self.Debug(f'PORTFOLIO UNSETTLED CASH BEFORE LIQUIDATION: {self.Portfolio.UnsettledCash}') for sym in self.tobeliquidated: self.Liquidate(sym) self.Debug(f'PRE-LIQUIDATION: {[[sym.Value, self.Portfolio[sym].Quantity] for sym in self.tobeliquidated]}') #self.Settings.FreePortfolioValuePercentage = 0.6 #self.Settings.FreePortfolioValue = self.Settings.FreePortfolioValuePercentage * self.Portfolio.TotalHoldingsValue for sym in self.tohold: self.SetHoldings(str(sym),1/self.numsecurities) self.Debug(f'PRE-SET-QUANTITY: {[[sym.Value,self.Portfolio[sym].Quantity] for sym in self.tohold]}') self.Debug(f'EXPECTED CURRENT STATE: {sorted([sym.Value for sym in self.tohold])}') if self.debug_execution == False: self.debug_execution = True elif self.debug_execution == True: self.debug_execution = False self.Debug(f'========== {(self.Time - self.lasttime).seconds / 3600} HOURS AFTER ORDER IS EXECUTED ==========') self.Debug(f'POST-LIQUIDATION: {[[sym.Value, self.Portfolio[sym].Quantity] for sym in self.tobeliquidated]}') self.Debug(f'POST-SET-QUANTITY: {[[sym.Value,self.Portfolio[sym].Quantity] for sym in self.tohold]}') self.Debug(f'PORTFOLIO CASH AFTER REBALANCING: {self.Portfolio.Cash}') self.Debug(f'PORTFOLIO UNSETTLED CASH AFTER REBALANCING: {self.Portfolio.UnsettledCash}') self.Debug(f'ACTUAL CURRENT STATE: {sorted([x.Key.Value for x in self.Portfolio if x.Value.Invested])}') self.Debug(f'PORTFOLIO TOTAL HOLDINGS VALUE: {self.Portfolio.TotalHoldingsValue}') self.Debug(f'PORTFOLIO TOTAL EQUITY VALUE: {self.Portfolio.TotalPortfolioValue}') self.Debug(f'PORTFOLIO TOTAL (HOLDINGS - EQUITY) VALUE: {self.Portfolio.TotalHoldingsValue - self.Portfolio.TotalPortfolioValue}') def OnData(self, data): return def CoarseSelectionFunction(self,coarse): if self.IsWarmingUp: return if self.lasttime == None or self.Time-self.lasttime >= self.rebalance_interval: self.lasttime = self.Time self.rebalance = True return [x.Symbol for x in coarse if x.HasFundamentalData] else: return Universe.Unchanged def FineSelectionFunction(self,fine): security_momo_list = [] MKTCAP_dict = {} #exclude delisted and TOPS (due to split value issue) excluded_delisted = [i for i in fine if isinstance(i.SecurityReference.DelistingDate.date(),datetime) == False and i.Symbol.Value != "TOPS"] #filter by mkt_cap for i in fine: if isinstance(i.MarketCap,(float,int)) and i.MarketCap != 0: MKTCAP_dict[i]=i.MarketCap microcap = [i for i in excluded_delisted if isinstance(MKTCAP_dict.get(i),(int,float)) and MKTCAP_dict.get(i)>25e6 and MKTCAP_dict.get(i)<250e6] #filter by Price-to-Sales Ratio < 1 (defined to be null if result <= 0) micro_PSR = [i for i in microcap if isinstance(i.ValuationRatios.PSRatio,(float,int)) and i.ValuationRatios.PSRatio < 1 and i.ValuationRatios.PSRatio > 0] micro_PSR_symbols = [i.Symbol for i in micro_PSR] #sorting by momentum using rolling window security_momo_list = [[sym, self.history_dict[sym].get_crit_momo()] for sym in self.history_dict.keys() if self.history_dict[sym].eval_self_momo() == True] security_momo_list_sorted = sorted(security_momo_list,key = lambda i : i[1],reverse = True) self.tohold = [f[0] for f in security_momo_list_sorted[:self.numsecurities]] #self.Debug(f'{[f.Value for f in output]}') #output = [f[0] for f in security_momo_list] return micro_PSR_symbols def OnSecuritiesChanged(self, changed): for security in changed.AddedSecurities: sym = security.Symbol if sym not in self.history_dict: self.history_dict[sym] = hist_window(self,sym) for security in changed.RemovedSecurities: self.history_dict.pop(sym, None) class hist_window(): def __init__(self,algorithm,symbol,criterion_period = None): self.Symbol = symbol #self.Ticker = self.Symbol.Value self.periods=sorted(algorithm.periods) self.maxperiod = max(self.periods) self.Window = RollingWindow[TradeBar](self.maxperiod + 1) #periods quantified in days #period sorted in increasing length of period self.maxperiod = max(self.periods) if criterion_period == None: self.criterion_period = self.maxperiod else: self.criterion_period = criterion_period #in order of increasing recency, last element being most recent tradebar hist_bars = algorithm.History(self.Symbol, self.maxperiod+1, Resolution.Daily) for bar in hist_bars.itertuples(): tradebar = TradeBar(bar.Index[1], self.Symbol, bar.open, bar.high, bar.low, bar.close, bar.volume) self.Window.Add(tradebar) ticker = self.Symbol algorithm.Debug(f'TICKER: {ticker}') algorithm.Consolidate(ticker, timedelta(days=1), lambda x: self.Window.Add(x)) def get_momo(self, period): if self.Window.Count >= period: return self.Window[0].Close/self.Window[period].Close/period else: return None def get_crit_momo(self): return self.get_momo(self.criterion_period) def eval_self_momo(self): if self.get_momo(self.maxperiod) == None: return False for i in range(0,len(self.periods)-1): if self.get_momo(self.periods[i]) < self.get_momo(self.periods[i+1]): return False return True