Hi all,

I have a mean-reversion algo that's running using pylivetrader, it's doing well, but the backtesting from modifying on Quantopian and then modifying locally etc... QuantConnect is appealing because of all the reasons you're all here. 

There's a lot in the filtering, but the first 2 filtrations are a SMA of the volume; the 50 day being over 50,000, and then  current closing price being over the SMA-150 of closing.

I'm starting simple with just the SMA volume. I don't seem to get any results back - though now the logging limit (I've upgraded) has just screwed me so I'm losing the day because the logs are so limited.

 

private class SelectionData
{
private readonly Symbol _symbol;
private readonly QCAlgorithm _algorithm;

public readonly SimpleMovingAverage SMAClosing;
public readonly SimpleMovingAverage SMAVolume;
public readonly RelativeStrengthIndex RSI;
public readonly NormalizedAverageTrueRange NormalizedATR;

public SelectionData(QCAlgorithm algorithm, Symbol symbol)
{
_algorithm = algorithm;
_symbol = symbol;

RSI = new RelativeStrengthIndex(4);
SMAClosing = new SimpleMovingAverage(150);
SMAVolume = new SimpleMovingAverage(50);
NormalizedATR = new NormalizedAverageTrueRange(10);
}

public bool Update(DateTime time, decimal closePrice, decimal volume)
{
//_algorithm.Log($"symbol={_symbol.Value}, dt: {time}, close={closePrice}, volume={volume}");
return RSI.Update(time, closePrice)
&& SMAClosing.Update(time, closePrice)
&& SMAVolume.Update(time, volume);
}
}

public override void Initialize()
{
UniverseSettings.Resolution = Resolution.Daily;

SetStartDate(2020, 01, 01);
SetEndDate(2020, 04, 20);
SetCash(10000);
SetWarmUp(TimeSpan.FromDays(200));
SetBrokerageModel(BrokerageName.Alpaca);

AddUniverse(CoarseSelectionFunction, FineSelectionFunction);
}

public IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse)
{
// Moving above the 150 day SMA
return (from cf in coarse
let sel = _selection.GetOrAdd(cf.Symbol, sym => new SelectionData(this, cf.Symbol))
where cf.HasFundamentalData && cf.AdjustedPrice > 1
where sel.Update(cf.EndTime, cf.AdjustedPrice, cf.Volume)
where sel.SMAVolume > 50000
select cf.Symbol)
.Take(100);
}

private IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine)
{
return fine
.Where(f => f.SecurityReference.IsPrimaryShare)
.Select(x => x.Symbol);
}

 

That's some of the code I'm using.

- How often does Initialize() run? 

- The docs or examples don't seem to address the best way of doing this kind of filtering. As you can see in my `SelectionData` class, there are more elements I want to screen the initial list of symbols on. There's more filtering but that will be in a scheduled buy/sell that runs daily.

I'm trying to now use a different way; which is:

private List<SecurityFilter> _securities = new List<SecurityFilter>();
private SecurityChanges _changes = SecurityChanges.None;

/// <summary>
///
/// </summary>
private struct SecurityFilter {
public Security Security;
public SimpleMovingAverage Volume;
}

public override void Initialize()
{
UniverseSettings.Resolution = Resolution.Daily;

SetStartDate(2020, 04, 01);
SetEndDate(2020, 04, 20);
SetCash(10000);
SetBrokerageModel(BrokerageName.Alpaca);

SetWarmUp(TimeSpan.FromDays(200));
AddUniverse(CoarseSelectionFunction, FineSelectionFunction);
}

/// <summary>
/// https://www.quantconnect.com/docs/algorithm-reference/universes#Universes-Coarse-Universe-Selection
/// https://www.quantconnect.com/forum/discussion/1515/question-about-universe-history/p1
/// </summary>
/// <param name="coarse"></param>
/// <returns></returns>
private IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse)
{
return (from cf in coarse
where cf.HasFundamentalData && cf.AdjustedPrice > 1
select cf.Symbol)
.Take(100);
}

private IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine)
{
return fine
.Where(f => f.SecurityReference.IsPrimaryShare)
.Select(x => x.Symbol);
}

// this event fires whenever we have changes to our universe
public override void OnSecuritiesChanged(SecurityChanges changes)
{
_changes = changes;

if (changes.AddedSecurities.Count > 0) {
AddSecurities(changes.AddedSecurities);
}
}

/// <summary>
///
/// </summary>
/// <param name="securities"></param>
private void AddSecurities(IEnumerable<Security> securities)
{
var securityFilters = new List<SecurityFilter>();
foreach (var s in securities) {
var ef = new SecurityFilter {
Security = s,
Volume = new SimpleMovingAverage(50),
};

var history = History(ef.Security.Symbol, 200, Resolution.Daily);
foreach (var hist in history) {
ef.Volume.Update(hist.EndTime, hist.Volume);
}

securityFilters.Add(ef);
}

_securities = securityFilters
.Where(
f => f.Volume > 500000
)
.OrderBy(f => f.Volume)
.Take(10)
.ToList();

Debug($"Added securities: {securities}");
}

But now because I have no logs, I guess I'm losing the weekend.

Is there a list of best practices?

Thanks!