Hi everyone,

I've been encountering some issues with error messages similar to the following: Insufficient buying power to complete order (Value:7270.56), Reason: Id: 1233, Initial Margin: 7274.64, Free Margin: 4408.0538.

I thought that it might be caused by slippage since the order will only be excuted the next day. In addition, it targets microcap equities so there is a high chance that the default margin would be insufficient to account for the ask/bid spread. To test if these were indeed the issues, I set the following:

self.Settings.FreePortfolioValuePercentage = 0.6

I believe this means that the cash buffer is set to 60% (correct me if I'm wrong). However, the error still persisted.

Digging around a bit, I found out that apparently Algorithm.Settings.FreePortfolioValuePercentage sets the buffer cash value to a static value, so the cash buffer percentage does not follow the growth in portfolio value. The details of the issue can be found in the link here:

https://github.com/QuantConnect/Lean/issues/4104

I tried to reassign the cash buffer value on every rebalancing cycle (3 months) in the OnSecuritiesChanged function using two different methods, neither of which worked. I would really appreciate it if anyone could help me. Thank you!  

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(2011, 2, 28) 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.Daily self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) self.lastmonth = -1 self.lastday = -1 self.monthinterval = 1 self.Symbols = None self.tobeliquidated = None self.numsecurities = 25 #self.SetWarmUp(timedelta(365)) def CoarseSelectionFunction(self,coarse): if self.IsWarmingUp: return if self.lastmonth == -1 or self.Time.month != self.lastmonth: self.lastmonth = self.Time.month self.lastday = self.Time.day return [x.Symbol for x in coarse if x.HasFundamentalData] else: return Universe.Unchanged def FineSelectionFunction(self,fine): #momo_dict = {} 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] #sorting by momentum for i in micro_PSR: hist = self.History(i.Symbol, 180 * self.monthinterval + 1, Resolution.Daily) if 'close' not in list(hist.columns): self.Debug(f'{i.Symbol.Value} DOES NOT HAVE "close". List of headers: {list(hist.columns)}') continue close_list = hist['close'].tolist() #self.Error(f'{i.Symbol.Value} INDICES: {[col for col in hist.columns]}') if len(close_list) == 180 *self.monthinterval + 1: #self.Debug(f'LENGTH IS: {len(close_list)}') curr_price = close_list[-1] price_6M = close_list[0] price_2M = close_list[60*self.monthinterval] price_1M = close_list[30*self.monthinterval] #if i.Symbol.Value == "TOPS": # self.Log(f'CURRENT PRICE: {curr_price}, BASELINE PRICE: {baseline_price}') momo_1M = curr_price/price_1M momo_2M = curr_price/price_2M/2 momo_6M = curr_price/price_6M/6 if momo_1M > momo_2M and momo_2M > momo_6M: security_momo_list.append([i.Symbol,momo_1M]) security_momo_list_sorted = sorted(security_momo_list,key = lambda i : i[1],reverse = True) output = [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] self.Symbols = output return output def OnSecuritiesChanged(self, changes): self.tobeliquidated = [security.Symbol for security in changes.RemovedSecurities] for sym in self.tobeliquidated: self.Liquidate(sym) #self.Settings.FreePortfolioValuePercentage = 0.6 self.Settings.FreePortfolioValue = self.Settings.FreePortfolioValuePercentage * self.Portfolio.TotalHoldingsValue for sym in self.Symbols: self.SetHoldings(str(sym),1/self.numsecurities) return