|
Every so often, I will get an e-mail from someone asking me to show them a good example of Lambdas in action in C# 3.5. When I go looking for lambda samples, I usually find some pretty interesting ones, but by and large they are relatively simple and don't really show you the power of lambdas, nested lambdas, and using lambdas within other language extensions.
One of the most key things to remember is that a lambda is data. It can be passed around as a function parameter. Most people like to think of lambdas as strongly typed function pointers and, in that light, they can be pretty easy to understand. The sample I want to show you is a lambda implementation of a pretty typical financial algorithm, VWAP. VWAP (Volume Weighted Average Price) is really just a way of measuring the average price of a stock, but using the volume of the trades done in a time series as a weight. So, if you have 1 trade done for 500 shares @ $50, the VWAP is $50. Add to it 300 more shares done at $75, and your VWAP is much closer to 75 whereas a traditional average would be right at $62.50. To people trading stocks, the VWAP value is often more important than the unweighted average.
Anyway, here's a lambda that figures out the VWAP. It operates on any IEnumerable and actually takes 2 lambdas as parameters. These input parameters instruct the VWAP function how to find the property on an object containing the quantity, and the property on an object containing the price.
Func<IEnumerable,
Func<object, double>,
Func<object, double>,
double>
VWAP =
(series, priceSelector, volumeSelector) =>
{
int totalVolume = 0;
double totalWeightedPrice = 0.0;
foreach (object o in series)
{
double weightedPrice = priceSelector(o) * volumeSelector(o);
totalWeightedPrice += weightedPrice;
totalVolume += volumeSelector(o);
}
return totalWeightedPrice / totalVolume;
};
The syntax might actually look a little weird if you've never seen lambdas in C# before. In particular, priceSelector(o) and volumeSelector(o) give people trouble when seeing them for the first time. Both of those are actually lambdas, and what you're looking at is an invocation of the function pointer using o as an argument. These lambdas, as defined by VWAP, return a double value when passed an object. priceSelector returns a double value indicating the price stored on object o and volumeSelector returns a double value indicating the quantity stored on object o. You can see how this is used in a sample invocation of the lambda below:
double vwapResult = VWAP(allTicks,
source => ((Tick)source).Price,
source => ((Tick)source).Quantity);
The line:
source => ((Tick)source).Price
Can be roughly translated into, "for all values source, return source.Price where source is an instance of Tick". This is typically referred to as a selector or column selector lambda. You'll see stuff like this used extensively in LINQ, LINQ to SQL, and LINQ to Entities.
One of the things that really makes VWAP useful is that you can look at the VWAP throughout the course of the day. Wouldn't it be great if you could print to the console (or maybe render in a graph...) the VWAP value at the point each tick? Here's how you can invoke a lambda directly inside a language extension (in this case, ForEach):
allTicks.ForEach(
tick =>
{
Console.Writeline(
VWAP(allTicks.Take(allTicks.IndexOf(tick) + 1),
source => ((Tick)source).Price,
source => ((Tick)source).Quantity));
});
I realize it's a little densely packed in there, but it's basically just running a loop through all of the ticks received and computing the VWAP based on the list of ticks up to that point so far, showing you a progressive change in VWAP since market open (or whatever your starting point was).
Anyway, I hope this quick demo of some "real world" lambdas has helped moreso than some of the typical "Hello World" lambdas that might be floating around.
Excellent example! Feel free to keep them coming!
thanks very much, this helped me a lot to understand Lambda expressions.
Open, High, Low and Close for a given time persiod, say 15minutes. I have
been trying to create an app (using LINQ, but I think I will try with
Continuous LINQ now) to show price candles.
If you download the latest release of Continuous LINQ
(http://www.codeplex.com/clinq), you'll notice that version 1.1 includes a
stock monitor demo. This demo not only uses CLINQ queries for filtering the
book down to one symbol, but it is also using continuous aggregates (a new
feature in 1.1) to illustrate the current high, current low, current VWAP,
and even charts a VWAP-over-time line on the same graph as a
price-over-time line. I think this is right along the same lines as what
you're looking to do.