20 using System.Collections.Generic;
21 using System.Runtime.CompilerServices;
34 private static readonly IReadOnlyList<BaseData> _empty =
new List<BaseData>();
37 private DateTime _lastQuoteBarUpdate;
38 private DateTime _lastOHLCUpdate;
41 private readonly
object _locker =
new();
42 private IReadOnlyList<BaseData> _lastTickQuotes = _empty;
43 private IReadOnlyList<BaseData> _lastTickTrades = _empty;
44 private Dictionary<Type, IReadOnlyList<BaseData>> _dataByType;
46 private Dictionary<string, object> _properties;
51 public decimal
Price {
get;
private set; }
56 public decimal
Open {
get;
private set; }
61 public decimal
High {
get;
private set; }
66 public decimal
Low {
get;
private set; }
71 public decimal
Close {
get;
private set; }
86 public decimal
BidSize {
get;
private set; }
91 public decimal
AskSize {
get;
private set; }
96 public decimal
Volume {
get;
private set; }
110 if (_properties ==
null)
112 _properties =
new Dictionary<string, object>();
123 public void AddDataList(IReadOnlyList<BaseData> data, Type dataType,
bool? containsFillForwardData =
null)
125 var nonFillForwardData = data;
127 if (containsFillForwardData !=
false)
129 var dataFiltered =
new List<BaseData>(data.Count);
130 for (var i = 0; i < data.Count; i++)
132 var dataPoint = data[i];
133 if (!dataPoint.IsFillForward)
135 dataFiltered.Add(dataPoint);
138 nonFillForwardData = dataFiltered;
140 if (nonFillForwardData.Count != 0)
149 var last = data[data.Count - 1];
173 var tick = data as
Tick;
178 StoreDataPoint(data);
189 StoreDataPoint(data);
200 if ((_lastData ==
null
201 || _lastQuoteBarUpdate != data.
EndTime
204 && isDefaultDataType)
211 if (tick.Value != 0)
Price = tick.Value;
213 switch (tick.TickType)
216 if (tick.Quantity != 0)
Volume = tick.Quantity;
220 if (tick.BidPrice != 0)
BidPrice = tick.BidPrice;
221 if (tick.BidSize != 0)
BidSize = tick.BidSize;
223 if (tick.AskPrice != 0)
AskPrice = tick.AskPrice;
224 if (tick.AskSize != 0)
AskSize = tick.AskSize;
230 var bar = data as
IBar;
235 if ((_lastQuoteBarUpdate != data.
EndTime || _lastOHLCUpdate != data.
EndTime) && isDefaultDataType)
237 _lastOHLCUpdate = data.
EndTime;
238 if (bar.Open != 0)
Open = bar.Open;
239 if (bar.High != 0)
High = bar.High;
240 if (bar.Low != 0)
Low = bar.Low;
249 if (tradeBar !=
null)
251 if (tradeBar.Volume != 0)
Volume = tradeBar.Volume;
255 if (quoteBar !=
null)
257 _lastQuoteBarUpdate = quoteBar.
EndTime;
258 if (quoteBar.Ask !=
null && quoteBar.Ask.Close != 0)
AskPrice = quoteBar.Ask.Close;
259 if (quoteBar.Bid !=
null && quoteBar.Bid.Close != 0)
BidPrice = quoteBar.Bid.Close;
260 if (quoteBar.LastBidSize != 0)
BidSize = quoteBar.LastBidSize;
261 if (quoteBar.LastAskSize != 0)
AskSize = quoteBar.LastAskSize;
278 public void StoreData(IReadOnlyList<BaseData> data, Type dataType)
280 if (dataType == typeof(
Tick))
282 var tick = data[data.Count - 1] as
Tick;
286 _lastTickTrades = data;
289 _lastTickQuotes = data;
296 _dataByType ??=
new();
297 _dataByType[dataType] = data;
318 IReadOnlyList<BaseData> list;
319 if (!
TryGetValue(typeof(T), out list) || list.Count == 0)
323 return list[list.Count - 1] as T;
332 if (typeof(T) == typeof(
Tick))
334 return _lastTickTrades.Concat(_lastTickQuotes).Cast<T>();
339 if (_dataByType ==
null || !_dataByType.TryGetValue(typeof(T), out var list))
341 return new List<T>();
344 return list.Cast<T>();
370 _lastTickQuotes = _empty;
371 _lastTickTrades = _empty;
373 _lastOHLCUpdate =
default;
374 _lastQuoteBarUpdate =
default;
388 public bool TryGetValue(Type type, out IReadOnlyList<BaseData> data)
400 else if (type == typeof(
Tick))
402 var quote = _lastTickQuotes.LastOrDefault();
403 var trade = _lastTickTrades.LastOrDefault();
404 var isQuoteDefaultDataType = quote !=
null &&
SubscriptionManager.IsDefaultDataType(quote);
405 var isTradeDefaultDataType = trade !=
null &&
SubscriptionManager.IsDefaultDataType(trade);
409 if (isQuoteDefaultDataType && isTradeDefaultDataType)
411 data = quote.EndTime > trade.EndTime ? _lastTickQuotes : _lastTickTrades;
415 data = isQuoteDefaultDataType ? _lastTickQuotes : _lastTickTrades;
416 return data?.Count > 0;
420 return _dataByType !=
null && _dataByType.TryGetValue(type, out data);
423 [MethodImpl(MethodImplOptions.AggressiveInlining)]
424 private void StoreDataPoint(
BaseData data)
426 if (data.GetType() == typeof(
Tick))
428 var tick = data as
Tick;
432 _lastTickTrades =
new List<BaseData> { tick };
435 _lastTickQuotes =
new List<BaseData> { tick };
443 _dataByType ??=
new();
445 IReadOnlyList<BaseData> list;
446 if (!_dataByType.TryGetValue(data.GetType(), out list))
448 list =
new List<BaseData> { data };
449 _dataByType[data.GetType()] = list;
455 ((List<BaseData>)list)[0] = data;
472 sourceToShare._dataByType ??=
new();
473 if (targetToModify._dataByType !=
null)
475 lock (targetToModify._locker)
477 lock (sourceToShare._locker)
479 foreach (var kvp
in targetToModify._dataByType)
481 sourceToShare._dataByType.TryAdd(kvp.Key, kvp.Value);
486 targetToModify._dataByType = sourceToShare._dataByType;
487 targetToModify._lastTickTrades = sourceToShare._lastTickTrades;
488 targetToModify._lastTickQuotes = sourceToShare._lastTickQuotes;
494 internal void ApplySplit(
Split split)
508 Action<BaseData> scale = data => data.Scale((target, factor, _) => target * factor, 1 / split.
SplitFactor, split.
SplitFactor, decimal.Zero);
509 _dataByType?.Values.DoForEach(x => x.DoForEach(scale));
510 _lastTickQuotes.DoForEach(scale);
511 _lastTickTrades.DoForEach(scale);