This commit is contained in:
@@ -147,6 +147,7 @@ namespace MarketData.Services
|
|||||||
{
|
{
|
||||||
LocalPriceCache.GetInstance().Dispose();
|
LocalPriceCache.GetInstance().Dispose();
|
||||||
GBPriceCache.GetInstance().Dispose();
|
GBPriceCache.GetInstance().Dispose();
|
||||||
|
GLPriceCache.GetInstance().Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG,$"[RunService] Done, total took {profiler.End()}(ms)");
|
MDTrace.WriteLine(LogLevel.DEBUG,$"[RunService] Done, total took {profiler.End()}(ms)");
|
||||||
|
|||||||
@@ -162,55 +162,91 @@ namespace MarketData.Cache
|
|||||||
|
|
||||||
public void Add(PortfolioTrades portfolioTrades)
|
public void Add(PortfolioTrades portfolioTrades)
|
||||||
{
|
{
|
||||||
List<string> symbols = portfolioTrades.Symbols;
|
List<string> symbols = portfolioTrades.Symbols;
|
||||||
Dictionary<string, DateTime> minTradeDates = symbols.ToDictionary(sym => sym, sym => portfolioTrades.GetMinTradeDate(sym));
|
DateTime today = DateTime.Today;
|
||||||
|
|
||||||
Dictionary<string, DateTime> minCacheDates;
|
Dictionary<string, DateTime> minTradeDates = symbols.ToDictionary(symbol => symbol, symbol => portfolioTrades.GetMinTradeDate(symbol));
|
||||||
lock (thisLock)
|
|
||||||
{
|
|
||||||
minCacheDates = symbols.ToDictionary(sym => sym, sym => priceCache.ContainsKey(sym) ? priceCache[sym].MinDate : DateTime.MaxValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 =>
|
Dictionary<string, DateTime> minCacheDates;
|
||||||
{
|
lock (thisLock)
|
||||||
DateTime minTradeDate = minTradeDates[symbol];
|
|
||||||
DateTime minCacheDate = minCacheDates[symbol];
|
|
||||||
Prices prices = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (minCacheDate == DateTime.MaxValue)
|
minCacheDates = symbols.ToDictionary(symbol => symbol,symbol => priceCache.ContainsKey(symbol) ? priceCache[symbol].MinDate : DateTime.MaxValue);
|
||||||
{
|
}
|
||||||
prices = PricingDA.GetPrices(symbol, minTradeDate);
|
|
||||||
}
|
|
||||||
else if (minTradeDate < minCacheDate)
|
|
||||||
{
|
|
||||||
prices = PricingDA.GetPrices(symbol, minCacheDate, minTradeDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prices != null && prices.Count > 0)
|
ConcurrentDictionary<string, Prices> fetchedPrices = new ConcurrentDictionary<string, Prices>();
|
||||||
{
|
ConcurrentDictionary<string, Price> latestPrices = new ConcurrentDictionary<string, Price>();
|
||||||
fetchedPrices[symbol] = prices;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
MDTrace.WriteLine(LogLevel.DEBUG, $"Error fetching prices for {symbol}: {ex.Message}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
lock (thisLock)
|
Parallel.ForEach(symbols, new ParallelOptions { MaxDegreeOfParallelism = 8 }, symbol =>
|
||||||
{
|
|
||||||
foreach (KeyValuePair<string, Prices> kvp in fetchedPrices)
|
|
||||||
{
|
{
|
||||||
foreach (Price price in kvp.Value)
|
DateTime minTradeDate = minTradeDates[symbol];
|
||||||
{
|
DateTime minCacheDate = minCacheDates[symbol];
|
||||||
Add(price);
|
|
||||||
}
|
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)
|
public void Add(Prices prices)
|
||||||
|
|||||||
Reference in New Issue
Block a user