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:
- Price > 20
- 2 < DividendYield < 15
- 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());
}
}
}
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!