diff --git a/MarketData/MarketData/Services/MainService.cs b/MarketData/MarketData/Services/MainService.cs index 32e1879..d2f12b0 100755 --- a/MarketData/MarketData/Services/MainService.cs +++ b/MarketData/MarketData/Services/MainService.cs @@ -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)"); diff --git a/MarketData/MarketDataLib/Cache/GLPriceCache.cs b/MarketData/MarketDataLib/Cache/GLPriceCache.cs index 19ab997..99e7d1a 100644 --- a/MarketData/MarketDataLib/Cache/GLPriceCache.cs +++ b/MarketData/MarketDataLib/Cache/GLPriceCache.cs @@ -162,55 +162,91 @@ namespace MarketData.Cache public void Add(PortfolioTrades portfolioTrades) { - List symbols = portfolioTrades.Symbols; - Dictionary minTradeDates = symbols.ToDictionary(sym => sym, sym => portfolioTrades.GetMinTradeDate(sym)); + List symbols = portfolioTrades.Symbols; + DateTime today = DateTime.Today; - Dictionary minCacheDates; - lock (thisLock) - { - minCacheDates = symbols.ToDictionary(sym => sym, sym => priceCache.ContainsKey(sym) ? priceCache[sym].MinDate : DateTime.MaxValue); - } + Dictionary minTradeDates = symbols.ToDictionary(symbol => symbol, symbol => portfolioTrades.GetMinTradeDate(symbol)); - ConcurrentDictionary fetchedPrices = new ConcurrentDictionary(); + // Symbols that need an intraday refresh: + // - open positions (no close date), or + // *** REMOVED THIS - closed today (close price may still be settling) TODO ***** + HashSet mutableSymbols = new HashSet(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 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 fetchedPrices = new ConcurrentDictionary(); + ConcurrentDictionary latestPrices = new ConcurrentDictionary(); - lock (thisLock) - { - foreach (KeyValuePair 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 � 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)