Hi,
This feels like a rookie issue but when I apply "security.Symbol.Value" on securities in Coarse/Fine universe selection, I obtained something like "AAME 0" instead of "AAME" like I expected. It happense for all the securities in the universe selection model. I am circumventing this problem by simply replacing " 0" with nothing using the replace function but I was wondering if there was something more elegant (probably related to how I might not be using "Symbol.Value" correctly. Thanks!
Han Ruobin
Edit: the replace function does not work. While the string ticker has been changed to "AAME", the error still persists when using the ticker as an input in the consolidate function. I have attached my algorithm for reference. The error is triggered by line 163.
Â
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(2021, 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): 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 list_to_remove = [sym for sym in self.history_dict.keys() if symbol not in micro_PSR_symbols] for sym in list_to_remove: del self.history_dict[sym] for sym in micro_PSR_symbols: if sym not in self.history_dict.keys(): self.history_dict[sym] = hist_window(self,sym) 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 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 = str(self.Symbol.Value).replace(" 0","") 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
Â
Shile Wen
Hi Han,
It is not possible to overwrite the the .Value field.Furthermore, the issue with the algorithm is that we are trying to consolidate Symbols within the Fine filter, however, we need to wait for these Symbols to be added to our universe first, thus, we need to put the consolidation logic in OnSecuritiesChanged. I've shown the fixes in the attached backtest.
Best,
Shile Wen
Han Ruobin
Thank you!
Han Ruobin
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!