| 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