Initial Commit
This commit is contained in:
259
MarketData/MarketDataLib/Cache/GBPriceCache.cs
Executable file
259
MarketData/MarketDataLib/Cache/GBPriceCache.cs
Executable file
@@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using MarketData.MarketDataModel;
|
||||
using MarketData.DataAccess;
|
||||
using MarketData.Utils;
|
||||
using System.Linq;
|
||||
using MarketData.Helper;
|
||||
using MarketData.Numerical;
|
||||
using System.Threading;
|
||||
|
||||
|
||||
// This cache is mainly used by the models. It is a short lived cache that gets cleared out every 2 minutes.
|
||||
// This cache will attempt to load a price from the database if it is found in the cache.
|
||||
namespace MarketData.Cache
|
||||
{
|
||||
public class GBPriceCache
|
||||
{
|
||||
private Thread cacheMonitorThread=null;
|
||||
private volatile bool threadRun=true;
|
||||
private Object thisLock=new Object();
|
||||
private Dictionary<String,PricesByDate> priceCache=new Dictionary<String,PricesByDate>(); // the main cache
|
||||
private Dictionary<String,Price> realTimePriceCache=new Dictionary<String,Price>(); // short lived cache of realtime prices gets cleared out every cacheRefreshAfter(ms)
|
||||
private Dictionary<String,bool> nullCache=new Dictionary<String,bool>();
|
||||
private DateGenerator dateGenerator=new DateGenerator();
|
||||
private static GBPriceCache priceCacheInstance=null;
|
||||
private int cacheRefreshAfter=120000; // the cache will be cleaned up after 2 minutes
|
||||
|
||||
protected GBPriceCache()
|
||||
{
|
||||
cacheMonitorThread=new Thread(new ThreadStart(ThreadProc));
|
||||
cacheMonitorThread.Start();
|
||||
}
|
||||
public static GBPriceCache GetInstance()
|
||||
{
|
||||
lock(typeof(GBPriceCache))
|
||||
{
|
||||
if(null==priceCacheInstance)
|
||||
{
|
||||
priceCacheInstance=new GBPriceCache();
|
||||
}
|
||||
return priceCacheInstance;
|
||||
}
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
priceCache=new Dictionary<String,PricesByDate>();
|
||||
realTimePriceCache=new Dictionary<String,Price>();
|
||||
nullCache=new Dictionary<String,bool>();
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
if(null==priceCacheInstance || false==threadRun)return;
|
||||
threadRun=false;
|
||||
if(null!=cacheMonitorThread)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("[GBPriceCache:Dispose]Thread state is '{0}'. Joining main thread...",Utility.ThreadStateToString(cacheMonitorThread)));
|
||||
cacheMonitorThread.Join(5000);
|
||||
this.cacheMonitorThread=null;
|
||||
}
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,"[GBPriceCache:Dispose] End.");
|
||||
priceCacheInstance=null;
|
||||
}
|
||||
}
|
||||
public void ClearCacheOnOrBefore(DateTime onOrBeforeDate,bool collect=false)
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,"Clearing GBPriceCache cache.");
|
||||
List<String> symbols=new List<String>(priceCache.Keys);
|
||||
foreach(String symbol in symbols)
|
||||
{
|
||||
PricesByDate pricesByDate=priceCache[symbol];
|
||||
List<DateTime> symbolDates=new List<DateTime>(pricesByDate.Keys);
|
||||
foreach(DateTime symbolDate in symbolDates)
|
||||
{
|
||||
if(symbolDate<onOrBeforeDate) pricesByDate.Remove(symbolDate);
|
||||
}
|
||||
}
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,"Calling garbage collector...");
|
||||
if(collect) GC.Collect();
|
||||
}
|
||||
}
|
||||
public Price GetPriceOrLatestAvailable(String symbol,DateTime date)
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
Price price=GetPrice(symbol,date);
|
||||
if(null!=price) return price;
|
||||
DateTime latestPricingDate=PricingDA.GetLatestDateOnOrBefore(symbol,date);
|
||||
price=GetPrice(symbol,latestPricingDate);
|
||||
if(null!=price) return price;
|
||||
price=PricingDA.GetPrice(symbol,latestPricingDate);
|
||||
if(null!=price) AddPrice(price);
|
||||
return price;
|
||||
}
|
||||
}
|
||||
public Price GetRealtimePrice(String symbol)
|
||||
{
|
||||
if(realTimePriceCache.ContainsKey(symbol)) return realTimePriceCache[symbol];
|
||||
Price price=MarketDataHelper.GetLatestPrice(symbol);
|
||||
if(null!=price)
|
||||
{
|
||||
realTimePriceCache.Add(symbol,price);
|
||||
}
|
||||
return price;
|
||||
}
|
||||
public Price GetPrice(String symbol,DateTime date)
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
date=date.Date;
|
||||
if(!ContainsPrice(symbol,date))
|
||||
{
|
||||
String key=symbol+Utility.DateTimeToStringMMHDDHYYYY(date);
|
||||
if(nullCache.ContainsKey(key)) return null;
|
||||
Price price=PricingDA.GetPrice(symbol,date);
|
||||
if(null==price)
|
||||
{
|
||||
nullCache.Add(key,true);
|
||||
return price;
|
||||
}
|
||||
AddPrice(price);
|
||||
}
|
||||
if(!priceCache.ContainsKey(symbol)) return null;
|
||||
PricesByDate pricesByDate=priceCache[symbol];
|
||||
if(!pricesByDate.ContainsKey(date.Date)) return null;
|
||||
return pricesByDate[date];
|
||||
}
|
||||
}
|
||||
|
||||
public Prices GetPrices(String symbol, DateTime earlierDate, DateTime laterDate)
|
||||
{
|
||||
DateGenerator dateGenerator = new DateGenerator();
|
||||
|
||||
if(laterDate<earlierDate)
|
||||
{
|
||||
DateTime tempDate = earlierDate;
|
||||
earlierDate = laterDate;
|
||||
laterDate=tempDate;
|
||||
}
|
||||
List<DateTime> datesList = dateGenerator.GenerateHistoricalDates(earlierDate, laterDate);
|
||||
datesList = datesList.Where(x => x >= earlierDate).ToList();
|
||||
return GetPrices(symbol, laterDate, datesList.Count);
|
||||
}
|
||||
|
||||
// The most recent price is returned at the lowest index
|
||||
public Prices GetPrices(String symbol,DateTime startDate,int dayCount)
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
List<DateTime> historicalDates=dateGenerator.GenerateHistoricalDates(startDate,dayCount+60);
|
||||
Prices prices=null;
|
||||
List<DateTime> missingDates=null;
|
||||
foreach(DateTime historicalDate in historicalDates)
|
||||
{
|
||||
if(!ContainsPrice(symbol,historicalDate))
|
||||
{
|
||||
String key=symbol+Utility.DateTimeToStringMMHDDHYYYY(historicalDate);
|
||||
if(nullCache.ContainsKey(key)) continue;
|
||||
if(null==missingDates)missingDates=new List<DateTime>();
|
||||
missingDates.Add(historicalDate);
|
||||
}
|
||||
}
|
||||
if(null!=missingDates)
|
||||
{
|
||||
DateTime minDate=(from DateTime date in missingDates select date).Min();
|
||||
DateTime maxDate=(from DateTime date in missingDates select date).Max();
|
||||
prices=PricingDA.GetPrices(symbol,maxDate,minDate);
|
||||
foreach(Price price in prices) AddPrice(price);
|
||||
prices=new Prices();
|
||||
foreach(DateTime historicalDate in historicalDates)
|
||||
{
|
||||
if(!ContainsPrice(symbol,historicalDate))
|
||||
{
|
||||
String key=symbol+Utility.DateTimeToStringMMHDDHYYYY(historicalDate);
|
||||
if(!nullCache.ContainsKey(key)) nullCache.Add(key,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!priceCache.ContainsKey(symbol)) continue;
|
||||
PricesByDate pricesByDate=priceCache[symbol];
|
||||
if(!pricesByDate.ContainsKey(historicalDate.Date)) continue;
|
||||
prices.Add(pricesByDate[historicalDate]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prices=new Prices();
|
||||
foreach(DateTime historicalDate in historicalDates)
|
||||
{
|
||||
if(!priceCache.ContainsKey(symbol)) continue;
|
||||
if(!priceCache[symbol].ContainsKey(historicalDate.Date))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
prices.Add((priceCache[symbol])[historicalDate]);
|
||||
}
|
||||
}
|
||||
return new Prices(prices.OrderByDescending(x => x.Date).ToList().Take(dayCount).ToList());
|
||||
}
|
||||
}
|
||||
private void AddPrice(Price price)
|
||||
{
|
||||
lock(thisLock)
|
||||
{
|
||||
if(null==price) return;
|
||||
PricesByDate pricesByDate=null;
|
||||
if(!priceCache.ContainsKey(price.Symbol))
|
||||
{
|
||||
pricesByDate=new PricesByDate();
|
||||
pricesByDate.Add(price.Date,price);
|
||||
priceCache.Add(price.Symbol,pricesByDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
pricesByDate=priceCache[price.Symbol];
|
||||
if(pricesByDate.ContainsKey(price.Date.Date)) return;
|
||||
pricesByDate.Add(price.Date.Date,price);
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool ContainsPrice(String symbol,DateTime date)
|
||||
{
|
||||
if(!priceCache.ContainsKey(symbol)) return false;
|
||||
PricesByDate pricesByDate=priceCache[symbol];
|
||||
if(!pricesByDate.ContainsKey(date.Date)) return false;
|
||||
return true;
|
||||
}
|
||||
private void ThreadProc()
|
||||
{
|
||||
int quantums=0;
|
||||
int quantumInterval=1000;
|
||||
while(threadRun)
|
||||
{
|
||||
Thread.Sleep(quantumInterval);
|
||||
if(!threadRun) break;
|
||||
quantums+=quantumInterval;
|
||||
if(quantums>cacheRefreshAfter)
|
||||
{
|
||||
quantums=0;
|
||||
lock(thisLock)
|
||||
{
|
||||
realTimePriceCache.Clear();
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,"Clearing GBPriceCache price cache.");
|
||||
}
|
||||
}
|
||||
}
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,"[GBPriceCache:ThreadProc]Thread ended.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user