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.
