Hey Financial Freedom with Zheng Tian,
The problem is that you might try to get information from a symbol that does not have data yet. For this you can add this line:
if not data.ContainsKey(symbol) or not data.Bars.ContainsKey(symbol):
continue
#line 43
The other error is insufficient buying power. This has to do with the way you set up your strategy. Either lower the percentage in the holdings or change the number of symbols that you buy.
I attached your code with the added line and another version which takes the history request into the class and sorts/selects symbols from the values of the selection data. I also adjusted a few other things so it will give another result(only for testing purposes.
#region imports
from AlgorithmImports import *
#endregion
from Alphas.MacdAlphaModel import MacdAlphaModel
class WellDressedYellowGreenFish(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1) # Set Start Date
self.SetCash(5000) # Set Strategy Cash
#self.AddAlpha(MacdAlphaModel(12, 26, 9, MovingAverageType.Simple, Resolution.Daily))
self.SetBenchmark("SPY")
self.AddUniverse(self.CoarseSelectionFunction)
self.UniverseSettings.Resolution = Resolution.Daily
self.averages = { }
self.SetWarmUp(400)
self.n = 0
def CoarseSelectionFunction(self, universe):
selected = []
universe = sorted(universe, key=lambda c: c.DollarVolume, reverse=True)
universe = [c for c in universe if c.Price > 100][:100]
for coarse in universe:
symbol = coarse.Symbol
if symbol not in self.averages:
# 1. Call history to get an array of 200 days of history data
#history = self.History(symbol, 200, Resolution.Daily)
#2. Adjust SelectionData to pass in the history result
self.averages[symbol] = SelectionData(self, symbol)
self.averages[symbol].update(coarse.EndTime, coarse.AdjustedPrice)
symb = list(filter(lambda x: x.fast > x.mid and x.mid > x.slow, self.averages.values()))
#if self.averages[symbol].fast > self.averages[symbol].mid and self.averages[symbol].mid > self.averages[symbol].slow:
#selected.append(symbol)
self.Debug([x.symbol.Value for x in symb[:2]])
return [x.symbol for x in symb[:2]]
def OnData(self, data):
if self.IsWarmingUp:
return
for symbol, symbol_data in self.averages.items():
if not data.ContainsKey(symbol) or not data.Bars.ContainsKey(symbol):
continue
tolerance = 0.0015
holdings = self.Portfolio[symbol].Quantity if self.Portfolio.ContainsKey(symbol) else 0
signalDeltaPercent = (symbol_data.macd.Current.Value - symbol_data.macd.Signal.Current.Value)/symbol_data.macd.Fast.Current.Value
if holdings <= 0 and signalDeltaPercent > tolerance: # 0.01%
if self.n == 2: return
# longterm says buy as well
self.Debug(symbol.Value)
self.SetHoldings(symbol, 0.4)
self.n += 1
elif holdings >= 0 and signalDeltaPercent < -tolerance:
self.Liquidate(symbol)
self.n -= 1
class SelectionData:
#3. Update the constructor to accept a history array
def __init__(self, algorithm, symbol):
self.symbol = symbol
self.slow = ExponentialMovingAverage(200)
self.mid = ExponentialMovingAverage(13)
self.fast = ExponentialMovingAverage(5)
self.macd = MovingAverageConvergenceDivergence(50, 200, 9, MovingAverageType.Exponential)
history = algorithm.History(symbol, 200, Resolution.Daily)
#4. Loop over the history data and update the indicators
for bar in history.itertuples():
self.fast.Update(bar.Index[1], bar.close)
self.slow.Update(bar.Index[1], bar.close)
self.mid.Update(bar.Index[1], bar.close)
self.macd.Update(bar.Index[1], bar.close)
def is_ready(self):
return self.slow.IsReady and self.fast.IsReady and self.mid.IsReady
def update(self, time, price):
self.fast.Update(time, price)
self.mid.Update(time, price)
self.slow.Update(time, price)
self.macd.Update(time, price)
fast = self.fast.Current.Value
slow = self.slow.Current.Value
mid = self.mid.Current.Value
Please accept this answer if you're satisfied with my answer, hope it helps 😊
Â