|
Volume Weighted Average Price is a financial figure that is often used as a gauge to determine a more realistic price for a given stock. It works by taking a history of ticks and for each stock, multiplying the quantity by the price (this is why it's called volume weighted). The final sum is then divided by the total quantity traded in the time series for that stock.
I was looking at the CLINQ implementation of continuous aggregates after I implemented a continuous standard deviation and realized that it was incredibly easy for individual application developers to build their own continuous aggregates that sit on top of the CLINQ framework. This way, you get to borrow all of the listening, monitoring, and listener-chaining functionality for free and just implement your own domain-specific aggregation logic.
Within CLINQ there is a new class called AggregateViewAdapter<T>. This class is responsible for listening to changes within a source collection and to changes within items in that collection. It also properly deals with subscribing to events from newly added objects in the collection and unsubscribing to removed objects. It also uses weak references to ease the burden on the garbage collector when using CLINQ. All of this functionality is done for you, leaving just the aggregation logic left to implement.
To show you how easy it is, here is the full source code for the ContinuousVwapMonitor class:
public class ContinuousVwapMonitor<T> :
AggregateViewAdapter<T> where T:INotifyPropertyChanged
{
private ContinuousValue<double> _output;
private Func<T, double> _priceSelector;
private Func<T, int> _qtySelector;
public ContinuousVwapMonitor(ObservableCollection<T> input,
Func<T, double> priceSelector,
Func<T, int> quantitySelector,
ContinuousValue<double> output)
: base(input)
{
_output = output;
_priceSelector = priceSelector;
_qtySelector = quantitySelector;
ReAggregate();
}
protected override void ReAggregate()
{
int count = Input.Count;
double weightedPrice = 0.0;
int totalQuantity = 0;
for (int x = 0; x < count; x++)
{
weightedPrice += _priceSelector(Input[x]) *
_qtySelector(Input[x]);
totalQuantity += _qtySelector(Input[x]);
}
double vwap = weightedPrice / totalQuantity;
SetCurrentValue<double>(_output, vwap);
}
}
As input to its constructor, this class takes a lambda function that selects a price value given a Tick model object, a lambda function that selects a quantity value given a Tick model object, the output value in terms of a ContinuousValue<double>, and the input collection. To get ContinuousVwap as an available option as an extension method on the ObservableCollection<T> class, you need to implement a quick language extension like this one:
public static class VwapExtender
{
public static ContinuousValue<double> ContinuousVwap<T>(
this ObservableCollection<T> input,
Func<T, double> priceSelector,
Func<T, int> quantitySelector) where T: INotifyPropertyChanged
{
ContinuousValue<double> output = new ContinuousValue<double>();
ContinuousVwapMonitor<T> vwapMonitor =
new ContinuousVwapMonitor<T>(input,
priceSelector, quantitySelector, output);
return output;
}
}
Now that you have extended ObservableCollection<T>, you can write Continuous Queries that also support Continuous Aggregates, giving you incredible power and flexibility in your UI, not to mention making your code easy to read, easy to build, easy to troubleshoot, and easy to maintain:
ContinuousCollection<Tick> appleTicks =
from tick in TickFeed.AllTicks
where tick.Symbol == "AAPL"
select tick;
ContinuousValue<double> appleVWAP = appleTicks.ContinuousVwap<Tick>(
tick => tick.Price,
tick => tick.Quantity);
Now you can place the appleVWAP value as a bound object anywhere in your WPF GUI and it will automatically update as your ticker feed updates, which causes your AAPL subset feed to update. All of that taken care of for you automatically. You can even use the scalar appleVWAP value to store a history of VWAP-over-time values by listening to the property changed event on the appleVWAP object:
appleVWAP.PropertyChanged += new PropertyChangedEventHandler(vwap_Changed);
....
void vwap_Changed(object sender, PropertyChangedEventArgs e)
{
_vwapHistory.AddItem((sender as ContinuousValue<double>).CurrentValue);
}
This VWAP history could be part of another ObservableCollection (which, to blow your mind, could also be queried using CLINQ!) which is then bound to a templated grid that converts the history into a line chart, plotting VWAP-over-time automatically.
Not only is CLINQ a powerful extension to LINQ, but extending CLINQ yourself with domain-specific logic is easy and can add tremendous value.