This commit is contained in:
@@ -147,6 +147,7 @@ namespace MarketData.Services
|
||||
{
|
||||
LocalPriceCache.GetInstance().Dispose();
|
||||
GBPriceCache.GetInstance().Dispose();
|
||||
GLPriceCache.GetInstance().Dispose();
|
||||
}
|
||||
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,$"[RunService] Done, total took {profiler.End()}(ms)");
|
||||
|
||||
@@ -162,55 +162,91 @@ namespace MarketData.Cache
|
||||
|
||||
public void Add(PortfolioTrades portfolioTrades)
|
||||
{
|
||||
List<string> symbols = portfolioTrades.Symbols;
|
||||
Dictionary<string, DateTime> minTradeDates = symbols.ToDictionary(sym => sym, sym => portfolioTrades.GetMinTradeDate(sym));
|
||||
List<string> symbols = portfolioTrades.Symbols;
|
||||
DateTime today = DateTime.Today;
|
||||
|
||||
Dictionary<string, DateTime> minCacheDates;
|
||||
lock (thisLock)
|
||||
{
|
||||
minCacheDates = symbols.ToDictionary(sym => sym, sym => priceCache.ContainsKey(sym) ? priceCache[sym].MinDate : DateTime.MaxValue);
|
||||
}
|
||||
Dictionary<string, DateTime> minTradeDates = symbols.ToDictionary(symbol => symbol, symbol => portfolioTrades.GetMinTradeDate(symbol));
|
||||
|
||||
ConcurrentDictionary<string, Prices> fetchedPrices = new ConcurrentDictionary<string, Prices>();
|
||||
// Symbols that need an intraday refresh:
|
||||
// - open positions (no close date), or
|
||||
// *** REMOVED THIS - closed today (close price may still be settling) TODO *****
|
||||
HashSet<string> mutableSymbols = new HashSet<string>(symbols.Where(symbol => portfolioTrades.HasOpenPositions(symbol)));
|
||||
|
||||
Parallel.ForEach(symbols, new ParallelOptions { MaxDegreeOfParallelism = 8 }, symbol =>
|
||||
{
|
||||
DateTime minTradeDate = minTradeDates[symbol];
|
||||
DateTime minCacheDate = minCacheDates[symbol];
|
||||
Prices prices = null;
|
||||
|
||||
try
|
||||
Dictionary<string, DateTime> minCacheDates;
|
||||
lock (thisLock)
|
||||
{
|
||||
if (minCacheDate == DateTime.MaxValue)
|
||||
{
|
||||
prices = PricingDA.GetPrices(symbol, minTradeDate);
|
||||
}
|
||||
else if (minTradeDate < minCacheDate)
|
||||
{
|
||||
prices = PricingDA.GetPrices(symbol, minCacheDate, minTradeDate);
|
||||
}
|
||||
minCacheDates = symbols.ToDictionary(symbol => symbol,symbol => priceCache.ContainsKey(symbol) ? priceCache[symbol].MinDate : DateTime.MaxValue);
|
||||
}
|
||||
|
||||
if (prices != null && prices.Count > 0)
|
||||
{
|
||||
fetchedPrices[symbol] = prices;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, $"Error fetching prices for {symbol}: {ex.Message}");
|
||||
}
|
||||
});
|
||||
ConcurrentDictionary<string, Prices> fetchedPrices = new ConcurrentDictionary<string, Prices>();
|
||||
ConcurrentDictionary<string, Price> latestPrices = new ConcurrentDictionary<string, Price>();
|
||||
|
||||
lock (thisLock)
|
||||
{
|
||||
foreach (KeyValuePair<string, Prices> kvp in fetchedPrices)
|
||||
Parallel.ForEach(symbols, new ParallelOptions { MaxDegreeOfParallelism = 8 }, symbol =>
|
||||
{
|
||||
foreach (Price price in kvp.Value)
|
||||
{
|
||||
Add(price);
|
||||
}
|
||||
DateTime minTradeDate = minTradeDates[symbol];
|
||||
DateTime minCacheDate = minCacheDates[symbol];
|
||||
|
||||
try
|
||||
{
|
||||
// Historical fetch <20> only when cache is missing or incomplete
|
||||
Prices prices = null;
|
||||
if (minCacheDate == DateTime.MaxValue)
|
||||
{
|
||||
prices = PricingDA.GetPrices(symbol, minTradeDate);
|
||||
}
|
||||
else if (minTradeDate < minCacheDate)
|
||||
{
|
||||
prices = PricingDA.GetPrices(symbol, minCacheDate, minTradeDate);
|
||||
}
|
||||
|
||||
if (prices != null && prices.Count > 0)
|
||||
{
|
||||
fetchedPrices[symbol] = prices;
|
||||
}
|
||||
|
||||
// Intraday refresh open positions and positions closed today only
|
||||
if (mutableSymbols.Contains(symbol))
|
||||
{
|
||||
Price latestPrice = PricingDA.GetPrice(symbol);
|
||||
if (latestPrice != null)
|
||||
latestPrices[symbol] = latestPrice;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, $"Error fetching prices for {symbol}: {ex.Message}");
|
||||
}
|
||||
});
|
||||
|
||||
lock (thisLock)
|
||||
{
|
||||
// Historical prices idempotent, will not overwrite existing entries
|
||||
foreach (var kvp in fetchedPrices)
|
||||
{
|
||||
foreach (var price in kvp.Value)
|
||||
{
|
||||
Add(price);
|
||||
}
|
||||
}
|
||||
|
||||
// Latest prices unconditional overwrite to capture any intraday updates
|
||||
foreach (var kvp in latestPrices)
|
||||
{
|
||||
if (!priceCache.TryGetValue(kvp.Key, out var pricesByDate))
|
||||
{
|
||||
pricesByDate = new PricesByDate();
|
||||
priceCache[kvp.Key] = pricesByDate;
|
||||
}
|
||||
|
||||
if (pricesByDate.ContainsKey(kvp.Value.Date))
|
||||
pricesByDate.Remove(kvp.Value.Date);
|
||||
pricesByDate.Add(kvp.Value.Date, kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,
|
||||
$"[GLPriceCache:Add] Symbols: {symbols.Count}, Mutable: {mutableSymbols.Count}, " +
|
||||
$"Historical fetches: {fetchedPrices.Count}, Intraday updates: {latestPrices.Count}");
|
||||
}
|
||||
|
||||
public void Add(Prices prices)
|
||||
|
||||
Reference in New Issue
Block a user