Intrinsic to collection change notifications, items can be notified by add, update and remove events. If ordering is supported a collection will support a move notification. Of course Dynamic Data supports these. Yet something which is often overlooked is data or functions of data are sometimes by necessity mutable. How can a collection which notifies respond to mutable changes?
To deal with this scenario, dynamic data introduces the concept of an Evaluate notification. This notification forms part of a change set and tells a consumer an item needs to be re-assessed or re-evaluated. This may effect things like filtering or sorting of an item. I feel a concrete example best illustrates this concept. Suppose we have the following function:
Func<Trade,bool> isNearToMarketPrice = trade => return Math.Abs(trade.PercentFromMarket) <= 1 %
Where PercentFromMarket is a calculation which is recalculated with each and every market data tick. Using standard linq a list of near to market trades can be retrieved as follows.
var nearToMaketTrades = myListOfTrades.Where(isNearToMarketPrice);
The manifest problem with this query is it pull based only and has no means of observing when the market price has been recalculated, or alternatively how can re-evaluation be forced. Based on practical experience of dealing with this kind problem I introduced multiple means of injecting the evaluate command into a dynamic data stream. Here I will use a filter controller illustrated in a previous blog and we will apply it to the trade service here.
In summary any of the controllers in dynamic data are used to inject commands and meta data into a stream. For this example we need a dynamic filter which is applied to a stream of trades.
//create a filter controller and set it's filter var filter = new FilterController<Trade>(); filter.Change(trade => Math.Abs(trade.PercentFromMarket) <= percentFromMarket()); //create a stream of live trades where the trade matches the above filter var filteredByPercent = myTradeService.Trades .Connect(trade=>trade.Status==TradeStatus.Live) .Synchronize(locker) .Filter(filter)
The filter controller has an overload to force re-evaluation.
filter.Revalue() // to reevaluate all // or filter.Reevaluate(Func<T,bool> itemSelector) //to re-evaluate selected items
The only missing element is when do we invoke re-evalulation. We have 2 choices. Either the service which calculates market prices provides a notification of trades which have been re-calculated or we poll on a period. Option 1 would be suitable for algo trading where everything must happen preferably with zero latency but for simplicity in the example we will poll as follows.
//re-evaluate filter periodically var reevaluator = Observable.Interval(TimeSpan.FromMilliseconds(250)) .Subscribe(_ => filter.Reevaluate());
And that is that. We have a live stream of trades, where closed trades are automatically filtered out from the source and the filter controller constantly re-applies to ensure only trades near to the market are included in the result. And as ever what is beginning to become my catch phrase – that is easy!
After wrapping the function into a cold observable, here’s the final code.
public IObservable<IChangeSet<Trade, long>> Query(Func<uint> percentFromMarket) { if (percentFromMarket == null) throw new ArgumentNullException("percentFromMarket"); return Observable.Create<IChangeSet<Trade, long>> (observer => { var locker = new object(); Func<Trade,bool> nearToMaketTrades = trade => Math.Abs(trade.PercentFromMarket) <= percentFromMarket(); var filter = new FilterController<Trade>(nearToMaketTrades); //re-evaluate filter periodically var reevaluator = Observable.Interval(TimeSpan.FromMilliseconds(250)) .Synchronize(locker) .Subscribe(_ => filter.Reevaluate()); //filter on live trades matching % specified var subscriber = _tradeService.Trades .Connect(trade=>trade.Status==TradeStatus.Live) .Synchronize(locker) .Filter(filter) .SubscribeSafe(observer); return new CompositeDisposable(subscriber, filter, reevaluator); }); }
This observable will form part of a future post where I want to build the foundation of an auto trading system.
But for now, in a few lines of code (see NearToMarketViewer.cs) we can put the data onto the screen.