(I tried to filter for adx>30 and got no assets remaining - so I suspect i'm doing something wrong)
QUANTCONNECT COMMUNITY
(I tried to filter for adx>30 and got no assets remaining - so I suspect i'm doing something wrong)
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.
Alexandre Catarino
We can use any indicator to filter a universe provided that the universe data has all the information the indicator needs.
For instance, if we are using QuantConnect's built in universe data, Coarse Universe Selection:
class CoarseFundamental { public long Volume; // Traded shares public decimal DollarVolume; // Traded shares x Price public decimal Price; // Yesterday close price public Symbol Symbol; // Asset symbol }
we do not have OHLC data to compute an AverageDirectionalIndex (ADX) indicator.
In that case, we need to add the symbols to the universe first, compute the ADX, then select/rank the securities.
In the example below, after selecting the TOP10 DollarVolume symbols, I used History method to retrieve the latest 14 tradebars to compute ADX(14) and buy a security owhen its ADX is above 30.
Eyal netanel
Many thanks for this example and explanation. It seems a bit more complicated than I anticipated, but I'll have a fresh look when I'm less exhausted :-)
Thanks!
Eyal netanel
ok - so i guess what' confusing me is this:
On another example around here I saw an ini function siilar to this:
private class SelectionData { // class used to improve readability of the coarse selection function public readonly ExponentialMovingAverage Fast; public readonly ExponentialMovingAverage Slow; public readonly AverageDirectionalIndex adx; public SelectionData() { Fast = new ExponentialMovingAverage(9); Slow = new ExponentialMovingAverage(21); adx = new AverageDirectionalIndex("Daily",14); } public decimal ScaledDelta { // computes an object score of how much larger the fast is than the slow get { return (Fast - Slow)/((Fast + Slow)/2m); } // calculate: diff between the emas divided by their avg. } public decimal adxOutput { get { return adx; } } public bool Update(DateTime time, decimal value) { // updates the EMA indicators, returning true when they're both ready return Fast.Update(time, value) && Slow.Update(time, value); } } public override void Initialize() { // Initialise the data and resolution required, as well as the cash and start-end dates. UniverseSettings.Leverage = 2.0m; UniverseSettings.Resolution = Resolution.Daily; SetStartDate(2010, 01, 01); SetEndDate(2011, 01, 01); SetCash(25*1000); AddUniverse(coarse => { return (from cLong in coarse let avg = _averages.GetOrAdd(cLong.Symbol, sym => new SelectionData()) // grab the SelectionData instance for this symbol where avg.Update(cLong.EndTime, cLong.Price) // Update returns true when the indicators are ready, so don't accept until they are where avg.Fast > avg.Slow*(1 + Tolerance) // only pick symbols who have their fast ema over their slow ema ///where avg.adx > 30 where cLong.Price > 15 // only stocks with price > 15$ where cLong.Volume > 1000000 // orderby avg.adxOutput descending // prefer strong-trending symbols, as indicated by adx. select cLong.Symbol).Take(NumberOfSymbols); // we only need to return the symbol and return 'Count' symbols }); }
except for the adx-related lines. So I guess i had expected to be able to apply the indicator right in the initialization process (avg refers to getting fast and slow ema) while in your code it is done onData.
when I tried to apply it in the init, like it is already doing for EMA, it didn't work (meaning that no stocks were selected), which is why i commented out the where adx line.
Due to my poor knowledge in both c# and quantconnect, i am forced to ask - is it possible to somehow apply adx filtering in a way similar to how this code filters by ema, or does it have to be that ema be applied during init and adx during onData?
Alexandre Catarino
In order to update the ADX indicator in the code above, we would need to include following code in the SymbolData class:
// updates the indicators, returning true when they're all ready public bool Update(DateTime time, decimal value) { return Fast.Update(time, value) && // Updates EMA(9) Slow.Update(time, value) && // Updates EMA(21) adx.Update(/*TradeBar object here*/); // Updates ADX(14) }
However, you need to provide a tradebar to update the ADX, since the Average Directional Index (ADX) is tradebar indicator, meaning that we need at least 3 data points (high, low and closing price) to compute it.
This Update method is called inside the AddUniverse method:
AddUniverse(coarse => { return (from cLong in coarse /* ... */ // Update returns true when the indicators are ready, //so don't accept until they are where avg.Update(cLong.EndTime, cLong.Price) /* ... */ });
where cLong is a CoarseFundamental object:
class CoarseFundamental { public long Volume; // Traded shares public decimal DollarVolume; // Traded shares x Price public decimal Price; // Yesterday close price public Symbol Symbol; // Asset symbol }
As we can see, cLong does not have the required properties (open, high, low) to create a tradebar.
Therefore we need a custom universe that does, for example:
class CustomUniverse : BaseData { public Symbol Symbol; // Asset symbol public decimal Open; // Yesterday open price public decimal High; // Yesterday high price public decimal Low; // Yesterday low price public decimal Price; // Yesterday close price public long Volume; // Traded shares }
in order to have the following in the AddUniverse:
AddUniverse<CustomUniverse>("my-custom-universe", Resolution.Daily, data => { return (from cLong in data let bar = new TradeBar(Time, cLong.Symbol, cLong.Open, cLong.High, cLong.Low, cLong.Price, cLong.Volume, Resolution.Daily) /* ... */ // Update returns true when the indicators are ready, //so don't accept until they are where avg.Update(bar) /* ... */ });
Finally, SymbolData.Update would have to be edited to:
// updates the indicators, returning true when they're all ready public bool Update(TradeBar bar) { return Fast.Update(bar.EndTime, bar.Price) && // Updates EMA(9) Slow.Update(bar.EndTime, bar.Price) && // Updates EMA(21) adx.Update(bar); // Updates ADX(14) }
Eyal netanel
Thank you for this very detailed explanation!
As I'm working to integrate it with the rest of my code, I am getting "Argument 8: cannot convert from 'QuantConnect.Resolution' to 'System.TimeSpan?'"
for the "let bar = new TradeBar(Time, cLong.Symbol, cLong.Open, cLong.High, cLong.Low, cLong.Price, cLong.Volume, Resolution.Daily)" line.
This smells like a simple C# issue... but I don't know what to do with it.
Alexandre Catarino
Please use TimeSpan.FromDays(1):
AddUniverse<CustomUniverse>("my-custom-universe", Resolution.Daily, data => { return (from cLong in data let bar = new TradeBar(Time, cLong.Symbol, cLong.Open, cLong.High, cLong.Low, cLong.Price, cLong.Volume, TimeSpan.FromDays(1)) /* ... */ // Update returns true when the indicators are ready, //so don't accept until they are where avg.Update(bar) /* ... */ });
Eyal netanel
Thanks again for the big help - that seems to cut it and compilation kinda passes - but now I am running into an issue with the custom universe it seems.
After f​​​​ixing in the changes and derived changes to the best of my aunderstanding, I have this:
private class SelectionData { // class used to improve readability of the coarse selection function public readonly ExponentialMovingAverage Fast; public readonly ExponentialMovingAverage Slow; public readonly AverageDirectionalIndex adx; public SelectionData() { Fast = new ExponentialMovingAverage(9); Slow = new ExponentialMovingAverage(21); adx = new AverageDirectionalIndex("Daily",14); } public decimal ScaledDelta { // computes an object score of how much larger the fast is than the slow get { return (Fast - Slow)/((Fast + Slow)/2m); } // calculate: diff between the emas divided by their avg. } public decimal adxOutput { get { return adx; } } public bool Update(TradeBar bar) { // updates the indicators, returning true when they're all ready return Fast.Update(bar.EndTime, bar.Price) && // Updates EMA(9) Slow.Update(bar.EndTime, bar.Price) && // Updates EMA(21) adx.Update(bar); // Updates ADX(14) } } class CustomUniverse : BaseData { public Symbol Symbol; // Asset symbol public decimal Open; // Yesterday open price public decimal High; // Yesterday high price public decimal Low; // Yesterday low price public decimal Price; // Yesterday close price public long Volume; // Traded shares } public override void Initialize() { // Initialise the data and resolution required, as well as the cash and start-end dates. UniverseSettings.Leverage = 2.0m; UniverseSettings.Resolution = Resolution.Daily; SetStartDate(2010, 01, 01); SetEndDate(2011, 01, 01); SetCash(25*1000); AddUniverse<CustomUniverse>("my-custom-universe", Resolution.Daily, data => { return (from cLong in data let bar = new TradeBar(Time, cLong.Symbol, cLong.Open, cLong.High, cLong.Low, cLong.Price, cLong.Volume, TimeSpan.FromDays(1))//Resolution.Daily) let selector = new SelectionData() where selector.Update(bar) // Update returns true when the indicators are ready, so don't accept until they are where selector.Fast > selector.Slow*(1 + Tolerance) // only pick symbols who have their fast ema over their slow ema where selector.adx > 30 where cLong.Price > 15 // only stocks with price > 15$ where cLong.Volume > 1000000 // Volume > 100k orderby selector.adx descending // prefer strong-trending symbols, as indicated by adx. select cLong.Symbol).Take(NumberOfSymbols); // we only need to return the symbol and return 'Count' symbols }); }
Which passes compilation with no errors but with warnings such as:
'EmaCrossUniverseSelectionAlgorithm.CustomUniverse.Symbol' hides inherited member 'BaseData.Symbol'. Use the new keyword if hiding was intended.
and
Field 'EmaCrossUniverseSelectionAlgorithm.CustomUniverse.Volume' is never assigned to, and will always have its default value 0
Moving on to backtest despite the warnings, generates :
Failed to initialize algorithm: Initialize(): Please implement GetSource(SubscriptionDataConfig, DateTime, bool) on your custom data type: CustomUniverse
Am I missing some kind of a definition regarding the custom universe?
Alexandre Catarino
Here is a full example of a Custom Data Universe Algorithm.
Eyal Netanel
Sorry for the late followup but I was expanding my mind on another thread. One quick question though - does it mean that adx must work with an external source of data? or did I miss the point on this? I thought the QC data included all the O/H/L/C data. if it does - I still didn't understand how can i use it with ADX...
Jared Broad
Sorry Eyal, universe data does not have OHLC - just "C" close at the moment. If you'd like this you need to build the tradebar yourself or specify an external OHLC source.
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.
Eyal Netanel
By building the tradebar - what do you mean? how? up from the minute events, onData? I'm not sure how it's done. Is there a ready exacmple for that by any chance?
Esther Ng
Seems like there's a tutorial for this in 2017: https://www.quantconnect.com/tutorials/consolidating-data-build-bars/
Eyal netanel
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!