As the title suggests, I've got indicators which are made from consolidated bars. They were created in a "for" loop as shown below. I need to be able to access the previous value of each indicator (I don't need a window full of them but that may be handy in the future).
In an example in the documentation you can assign a event handler to the consolidator, and inside the event I could modify the value of a dictionary called _prev5min, _prev10min, _prev30min etc etc.Thing is, I don't know how I can attach an event handler to work like this somehow inside the loop (I'd have to pass the value of 'minute' along with it I'm assuming).
The final goal is to do something like check if, between the previous x minute bar and the current one if the values of two indicators crossed. Checking the slope of the lines is also important (is it sloping up, or down) which is just using the previous value vs the current value.
I'm still fairly new to C# and trading algo's so excuse me if this idea isn't explained very well. Any help would be much apprecaited :)
foreach(var minute in new int[]{ 5, 10, 30, 60 })
{
// Create Consolidator
var consolidator = new QuoteBarConsolidator(TimeSpan.FromMinutes(minute));
// Create indicators
var adx = new AverageDirectionalIndex(thisTicker,14);
var rsi = new RelativeStrengthIndex(14);
var sma5 = new SimpleMovingAverage(10);
var sma20 = new SimpleMovingAverage(20);
// Register indicators to the consolidator to be updated at its frequency
RegisterIndicator(thisTicker, adx, consolidator);
RegisterIndicator(thisTicker, rsi, consolidator);
RegisterIndicator(thisTicker, sma5, consolidator);
RegisterIndicator(thisTicker, sma20, consolidator);
// Add the consolidator to the subscription manager to get updated with data from security
SubscriptionManager.AddConsolidator(thisTicker, consolidator);
// Add ADX, RSI, SMA5, SMA20 to Dictionaries
_adx.Add(minute, adx);
_rsi.Add(minute, rsi);
_sma5.Add(minute, sma5);
_sma20.Add(minute, sma20);;
}
JayJayD
The RollingWindow is the tool you are looking for.
In this example you can see the of the RollingWondow and how it is called everytime an indicator is updated usign the Updated event handler.
The log is quite borign because every value is repeated 5 times... but that means the indicators are workign fine.
Hope it helps.
Alexandre Catarino
This thread is a good oportunity to pull together information that is spread along some threads.
First, when we are working on several indicators for several timeframes, it would be necessary to save them on several dictionaries. In this case, we could create a class to hold all the information:
public class IndicatorSuite : BarIndicator { public AverageDirectionalIndex ADX; public RelativeStrengthIndex RSI; public SimpleMovingAverage FastSMA; public SimpleMovingAverage SlowSMA; public override bool IsReady { get { return ADX.IsReady && RSI.IsReady && FastSMA.IsReady && SlowSMA.IsReady; } } public IndicatorSuite(string name, int adxPeriod, int rsiPeriod, int fastSmaPeriod, int slowSmaPeriod) : base(name) { ADX = new AverageDirectionalIndex("", adxPeriod); RSI = new RelativeStrengthIndex(rsiPeriod); FastSMA = new SimpleMovingAverage(fastSmaPeriod); SlowSMA = new SimpleMovingAverage(slowSmaPeriod); } protected override decimal ComputeNextValue(IBaseDataBar input) { ADX.Update(input); RSI.Update(input.EndTime, input.Value); FastSMA.Update(input.EndTime, input.Value); SlowSMA.Update(input.EndTime, input.Value); return 0; } }
In this case, the class is a custom indicator that can be registered for automatic updates! In this example, ComputeNextValue is returning zero, but could return a combination of the internal indicator.
Like JJ said, we need to rely on RollingWindow to save previous states. Note that since we want to save states and not the indicator, we need to create a class to only hold the state. We can add the itens to the rolling window in an anonymous event handler:
// Updates the rolling window using an anonymous method consolidator.DataConsolidated += (s, bar) => { if (!suite.IsReady) return; // Uses a wrapper to save only the state of the indicator suite _window[bar.Period.Minutes].Add(new IndicatorSuiteState(suite)); };
At this point, we have one rolling window for every timeframe. Each rolling window has a series of a custom indicator that holds information of all indicators we are looking for our trading logic. For instance, if we want the previous moving average cross of the 30 minutes timeframe:
var win30 = _window[30]; // 30 min timeframe var prevWin30 = win30[1]; // Index 1, previous item. var crossOverLong = prevWin30.FastSMA > prevWin30.SlowSMA;
Please checkout the attached project for the full working example.
Andy Visser
JayJayD -- Your solution works great for everything except when I get into a situation like trying get the PositiveDirectionalIndex and NegativeDirectionalIndex of the previous ADX indicator. The rolling window is updated with the value for ADX but in doing to it seems it's left some of the other details of the indicator behind. Previously I was able to reference those values and would like to instead of trying to create two more windows for every time period of adx to hold the values. Any ideas?
JayJayD
I'm glad I helped.
Take a closer look to the RollingWindow definition, it has a generic, in the first case is an IndicatorDataPoint. That mean that the RollingWindows will store this type of object.
In this particular case you need two IndicatorDataPoint for each observation, in order to do that, one way is using an array of IndicatorDataPoint as RollingWindow generic (check the attached backtest). But point is that you can store anything in a RollingWindow.
Zentijr
The indicator suite is a great idea. But how would you adapt it to multiple symbols? I'm a very amature coder so can't quite see how I would roll this into a SymbolData style dictionary/class (ie like the multipleconsolidator example). Any tips on how to code this would be much appreciated.
Michael Manus
yes that is a very good idea.
quantconnect guys are using that in their example strategies:
MultipleSymbolConsolidationAlgorithm.cs
check the line 45: public readonly Dictionary<string, SymbolData> Data = new Dictionary<string, SymbolData>();
Zentijr
Michael- thanks I've seen that but think this is a little more complex? As an absolute amature, the issue I see is that the dictionary key in the one symbol example is keyed by minutes rather than symbols. So for multi symbols I think you somehow have to have a dictionary with string symbols, and dictionary of minutes and resulst of minutes ?
Michael Manus
hm when you google dictionaries you will see that the first thing (the string) is the key. In this example the symbol. Getting SymbolData for that symbol will give you Information like RollingWindow<TradeBar> Bars. The Bars hold a given amount of bars (RollingWindowSize = 10) for that symbol...........
https://www.dotnetperls.com/dictionary
as jayjayd above mentioned it....
James Candan
I'm not sure how one might do this in Python
// Here is where the RollingWindow is updated with the latest SMA observation. _sma.Updated += (object sender, IndicatorDataPoint updated) => { _window.Add(updated); };
Can someone offer up an example?
Andy Visser
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!