Hello everyone.
I am usuing a schedule universe with monthly SPY constituents (read from dropbox), trying to backtest my strategy from 2014 to today. I'm allowing 20 open positions at a given time with (1/20)% buying power for each one.
csv = self.Download("file")
df = pd.read_csv(StringIO(csv))
# read constituents and prepare its list
....
random.shuffle(l)
self.constituents[index] = l
for x in self.constituents:
symbols.append(Symbol.Create(str(x), SecurityType.Equity, "USA"))
During the testing I have generated more UP direction insights (about 5k) than total trades (630), on average about 100 insights per month are generated. It is logicly possible that my strategly could take different trades based on different indexing of the insights list generated from the Alpha model.
I'm trying to shuffle the list so I can have different trades over my backtest period, but it seems the list is entering the Alpha Model in Alphabetic order even after shuffling.
I tried shuffling the symbolData dictionary in my Alpha model when 'OnSecuritiesChanged' is triggered so later on when they are accessed in the 'Update' insights are not generated in Alphabetic order, as follows:
def OnSecuritiesChanged(self, algorithm, changes):
'''Event fired each time the add/remove securities from the data feed.
Args:
algorithm: The algorithm instance that experienced the change in securities
changes: The security additions and removals from the algorithm'''
for removed in changes.RemovedSecurities:
pass
for added in changes.AddedSecurities:
sd = None
if not added.Symbol in self.symbolData:
sd = SymbolData(algorithm, added, self.fastPeriod, self.slowPeriod, self.resolution)
sd.emaFast = algorithm.EMA(added.Symbol, self.fastPeriod, self.resolution, self.field)
sd.emaFast.Updated += sd.EmaFastUpdated
sd.emaFastWindow = RollingWindow[IndicatorDataPoint](self.fastPeriod)
sd.emaSlow = algorithm.EMA(added.Symbol, self.slowPeriod, self.resolution, self.field)
sd.emaSlow.Updated += sd.EmaSlowUpdated
sd.emaSlowWindow = RollingWindow[IndicatorDataPoint](self.slowPeriod)
sd.high = algorithm.MAX(added.Symbol, self.highPeriod, self.resolution, self.field)
sd.high.Updated += sd.HighUpdated
sd.highWindow = RollingWindow[IndicatorDataPoint](self.highPeriod)
maxPeriod = max(self.fastPeriod, self.slowPeriod, self.highPeriod, self.lookup)
# warmup our indicators by pushing history through the indicators
history = algorithm.History(added.Symbol, maxPeriod, self.resolution)
if history.empty:
continue
if 'close' in history:
history = history.close.unstack(0).squeeze()
if history.size < self.highPeriod:
# algorithm.Error(f"Not enough {added.Symbol} history!")
continue
for time, value in history.iteritems():
sd.emaFast.Update(time, value)
sd.emaSlow.Update(time, value)
sd.high.Update(time, value)
self.symbolData[added.Symbol] = sd
if self.shuffle:
shuff = list(self.symbolData.items())
random.shuffle(shuff)
self.symbolData = dict(shuff)
def Update(self, algorithm, data):
'''
Args:
algorithm: The algorithm instance
data: The new data available
Returns:
The new insights generated'''
insights = []
for key, sd in self.symbolData.items():
if not sd.Security.Invested:
# generate UP direction insights..
elif sd.Security.Invested:
# generate FLAT direction insights.
I just can not seem to get my backtest to perform different trades.
One thing that came to my mind is that in the Execution model, targets are beeing sorted by something called OrderByMarginImpact, but I can't find any relevant information about this method. I modified the ImmediateExecutionModel example to fit my needs as follows:
def Execute(self, algorithm, targets):
'''Executes market orders if the standard deviation of price is more
than the configured number of deviations in the favorable direction.
Args:
algorithm: The algorithm instance
targets: The portfolio targets'''
self.targetsCollection.AddRange(targets)
# for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call
if self.targetsCollection.Count > 0:
for target in self.targetsCollection.OrderByMarginImpact(algorithm):
symbol = target.Symbol
quan = target.Quantity
if self.useLimits:
tp, sl = self.CalculateLimits(algorithm, symbol)
# fetch our symbol data
data = self.symbolData.get(symbol, None)
if data is None: return
if quan > 0 and not data.Security.Invested and symbol not in self.orders:
self.orders[symbol] = True
if self.useLimits:
algorithm.StopLimitOrder(symbol, int(quan), sl, tp)
else:
# Market Order Asynchronously
algorithm.MarketOrder(symbol, int(quan), True)
data.q = int(quan)
elif quan < 0 and data.Security.Invested and self.orders.get(symbol):
algorithm.Liquidate(symbol)
self.targetsCollection.ClearFulfilled(algorithm)
Can anyone help me achieve my goal?
With appreciation,
Ido.
Derek Melchin
Hi Ido,
The execution model can place trades at each timestep in the algorithm. In the execution model above, the trades are sorted by margin impact. The source code for the OrderByMarginImpact method, along with some comments, is available here.
If the goal is to adjust the order of the trades at each timestep, we need to implement a different sorting method in the execution model.
Best,
Derek Melchin
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.
Ido Elmaliah
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!