Wednesday, April 22, 2009

Creating an Excel Add-In for Market Data - Part 2 - Market Data Provider Proxy

Last time we looked at just putting in place the basic infrastructure to support our RTD component. Now we dive in to the details of our actual market data provider implementation.

For this particular function, we need to find alternative data sources for our financial data because we don't want to necessarily depend on having Bloomberg available at all. There are plenty of good sources of free market data out there (usually delayed). Some good examples are Google Finance, Yahoo Finance, MSN Money, Level2StockQuotes.com, etc. Also, assuming you use some kind of broker that you deal with, they probably provide you real-time data as well - for example, I use Banc of America Investment Services to manage my IRA, and they provide real-time quotes when you are logged in with your account. So we'd like to have a plugin-layer where we can have multiple possible implementations, and it would be nice if we could actually have all of the implementations available, and ingelligently route between them based on priority, security type, availability of markets or even individual securities, or even query performance, load balancing, etc. So before we put specific market data provider adapters in place, we need a proxy-cache layer that can do this intelligent routing and management of our security universe.

We can start by defining a generic interface for any market data provider. For now let's assume we have only a synchronous model, and no actual asynchronous or event-based providers. Obviously if we wanted to properly plug in a real-time provider such as the Bloomberg tick event subscription, we would need to extend this further. We define a GetSecurityFieldValues() function to do the synchronous lookup, and for the purposes of our smart proxy functionality, we define a CanGetFieldForSecurityType() function.

public interface IMarketDataProvider
{
bool CanGetFieldForSecurityType(SecurityType type, string field);

decimal?[] GetSecurityFieldValues(Security security, string[] fields);
}


Then we define a simple proxy provider implementation:

public class MarketDataProxyProvider : IMarketDataProvider
{
private readonly IMarketDataProvider[] _providers;

public MarketDataProxyProvider(IMarketDataProvider[] providers)
{
_providers = providers;
}

public bool CanGetFieldForSecurityType(SecurityType type, string field)
{
return _providers.Any(provider => provider.CanGetFieldForSecurityType(type, field));
}

public decimal?[] GetSecurityFieldValues(Security security, string[] fields)
{
decimal?[] returnValues = new decimal?[fields.Length];
bool[] fieldsCovered = new bool[fields.Length];
foreach (IMarketDataProvider provider in _providers)
{
List fieldsToRetrieve = new List();
List fieldIndexes = new List();
for (int f = 0; f < fields.Length; f++)
{
if ((!fieldsCovered[f]) && provider.CanGetFieldForSecurityType(security.Type, fields[f]))
{
fieldsToRetrieve.Add(fields[f]);
fieldIndexes.Add(f);
fieldsCovered[f] = true;
}
}
if (fieldIndexes.Count > 0)
{
decimal?[] values = provider.GetSecurityFieldValues(security, fieldsToRetrieve.ToArray());
for (int f = 0; f < values.Length; f++)
returnValues[fieldIndexes[f]] = values[f];
}
if (fieldsCovered.All(fc => fc))
break;
}
return returnValues;
}
}


This is just a starting point, but it should give us the basic functionality to proxy for several providers. Some further work could be done to make this class dynamically configurable, and also possibly automatically adaptable to remember and re-prioritize providers based on prior performance.

No comments: