The idea is to call the universe selection once per week and filter the stocks using MFI
The criteria to add a stock to the universe is:

  1. Price > 20
  2. 2 < DividendYield < 15
  3. MFI > 60

As you know, MFI is a tradebar indicator, so I cannot use coarse.
The implementation reasoning is:

  • Add Universe is called every day, but if the week day is not Monday, it’ll return the same universe we have now
  • If the week day is Monday, I let the filter run, return 200 stock as maximum and I set a flag _universeSelectionCalled = true
  • Then in the OnData method if the flag _universeSelectionCalled is true I call the method RemoveStocksDontMeetWeeklyCriteria the applies the MFI filter.

But there is something plain wrong:

  • The RemoveStocksDontMeetWeeklyCriteria is never called.
  • The overridden OnSecuritiesChanged methos isn’t called neither.
  • The algorithm takes too long to run and ends ups throwing
Runtime Error: System.Exception: Execution Security Error: Memory Usage Maxed Out - 11264MB max, with last sample of 12998MB.

Any help will be much appreciated.
As I don’t have any working backtest, there is the code:

namespace QuantConnect
{
public class WeeklyCriteriaUniverse : QCAlgorithm
{
// holds our coarse fundamental indicators by symbol

private SecurityChanges _changes = SecurityChanges.None;
private IEnumerable<Symbol> _actualUniverse = Enumerable.Empty<Symbol>();
private bool _firstTime = true;

private bool _universeSelectionCalled = false;

public override void Initialize()
{
SetStartDate(year: 2013, month: 10, day: 08); //Set Start Date
SetEndDate(year: 2014, month: 10, day: 11); //Set End Date
SetCash(startingCash: 100000); //Set Strategy Cash

UniverseSettings.Resolution = Resolution.Daily;


AddUniverse(coarse =>
{
if (Time.DayOfWeek != DayOfWeek.Monday && !_firstTime) return _actualUniverse;
return coarse.Where(c => c.HasFundamentalData)
.OrderByDescending(c => c.DollarVolume)
.Select(c => c.Symbol)
.Take(200);
},
fine =>
{
if (Time.DayOfWeek != DayOfWeek.Monday && !_firstTime) return _actualUniverse;
Log(Time.ToString("F") + " - AddUniverse Called!");
_universeSelectionCalled = true;
return fine.Where(f => f.Price > 20 &&
f.ValuationRatios.TrailingDividendYield > 2 &&
f.ValuationRatios.TrailingDividendYield < 15)
.Select(f => f.Symbol);
}
);
}

public override void OnData(Slice slice)
{
if (_universeSelectionCalled)
{
// ToDO: Call remove from schelude
Log(Time.ToString("F") + " - RemoveStocksDontMeetWeeklyCriteria called.");
RemoveStocksDontMeetWeeklyCriteria();
}
}

private void RemoveStocksDontMeetWeeklyCriteria()
{
var stocksToRemove = new List<Symbol>();
foreach (var stock in Securities.Values)
{
var mfi = new MoneyFlowIndex(14);
foreach (var bar in History(stock.Symbol, TimeSpan.FromDays(16), Resolution.Daily))
{
mfi.Update(bar);
}
if (mfi < 60) stocksToRemove.Add(stock.Symbol);
}
Log(Time.ToString("F") + " - Stocks in universe: " + Securities.Count);
Log(Time.ToString("F") + " - Stocks to remove: " + stocksToRemove.Count);
Log(Time.ToString("F") + " - Stocks after removing : " + Securities.Count);
foreach (var symbol in stocksToRemove)
{
UniverseManager.Remove(symbol);
}
_firstTime = false;
_universeSelectionCalled = false;
_actualUniverse = Securities.Keys;
}


public override void OnSecuritiesChanged(SecurityChanges changes)
{
_changes = changes;
//TODO: check if changes is none.
Log(Time.ToString("F") + " - Stocks added to universe: " + changes.AddedSecurities.Count.ToString());
Log(Time.ToString("F") + " - Stocks removed from universe: " + changes.RemovedSecurities.Count.ToString());
}
}
}