17 using System.Collections.Generic;
64 .GetSubscriptionDataConfigs(asset.
Symbol)
65 .IsExtendedMarketHours()))
71 var tradeBar = GetBestEffortTradeBar(asset, order.
Time);
74 if (tradeBar ==
null)
return fill;
84 var askCurrent = GetBestEffortAskPrice(asset, order.
Time, out var fillMessage);
89 fill.FillPrice = Math.Min(askCurrent, order.
LimitPrice);
91 fill.Message = fillMessage;
102 var bidCurrent = GetBestEffortBidPrice(asset, order.
Time, out var fillMessage);
107 fill.FillPrice = Math.Max(bidCurrent, order.
LimitPrice);
109 fill.Message = fillMessage;
136 var slip = asset.
SlippageModel.GetSlippageApproximation(asset, order);
138 var fillMessage =
string.Empty;
144 fill.FillPrice = GetBestEffortAskPrice(asset, order.
Time, out fillMessage) + slip;
148 fill.FillPrice = GetBestEffortBidPrice(asset, order.
Time, out fillMessage) - slip;
154 fill.Message = fillMessage;
193 var tradeBar = GetBestEffortTradeBar(asset, order.
Time);
196 if (tradeBar ==
null)
return fill;
206 var slip = asset.
SlippageModel.GetSlippageApproximation(asset, order);
211 fill.FillPrice = tradeBar.Open - slip;
226 var slip = asset.
SlippageModel.GetSlippageApproximation(asset, order);
231 fill.FillPrice = tradeBar.Open + slip;
271 .GetSubscriptionDataConfigs(asset.
Symbol)
272 .IsExtendedMarketHours()))
282 if (pricesEndTime <= order.
Time)
return fill;
302 fill.FillPrice = Math.Min(prices.High, order.
LimitPrice);
324 fill.FillPrice = Math.Max(prices.Low, order.
LimitPrice);
376 .GetSubscriptionDataConfigs(asset.
Symbol)
377 .IsExtendedMarketHours()))
383 var tradeBar = GetBestEffortTradeBar(asset, order.
Time);
386 if (tradeBar ==
null)
return fill;
404 fill.FillPrice = tradeBar.Open;
423 fill.FillPrice = tradeBar.Open;
454 var endTime = DateTime.MinValue;
458 if (subscribedTypes.Contains(typeof(
Tick)))
460 var primaryExchangeCode = ((
Equity)asset).PrimaryExchange.Code;
465 .OrderBy(x => x.EndTime).ToList();
470 !
string.IsNullOrWhiteSpace(x.SaleCondition) &&
471 x.ExchangeCode == primaryExchangeCode &&
472 (x.ParsedSaleCondition & openTradeTickFlags) != 0 &&
487 tick = trades.LastOrDefault() ?? asset.
Cache.GetAll<
Tick>().LastOrDefault();
488 if ((tick?.EndTime.TimeOfDay - previousOpen)?.TotalMinutes < 1)
496 endTime = tick?.EndTime ?? endTime;
500 fill.FillPrice = tick.Price;
503 else if (subscribedTypes.Contains(typeof(
TradeBar)))
506 if (tradeBar !=
null)
509 if (tradeBar.Time < localOrderTime)
return fill;
518 fill.FillPrice = tradeBar.Open;
526 if (localOrderTime >= endTime)
return fill;
545 var slip = asset.
SlippageModel.GetSlippageApproximation(asset, order);
547 var bestEffortMessage =
"";
553 if (fill.FillPrice == 0)
555 fill.FillPrice = GetBestEffortAskPrice(asset, order.
Time, out bestEffortMessage);
556 fill.Message += bestEffortMessage;
559 fill.FillPrice += slip;
562 if (fill.FillPrice == 0)
564 fill.FillPrice = GetBestEffortBidPrice(asset, order.
Time, out bestEffortMessage);
565 fill.Message += bestEffortMessage;
568 fill.FillPrice -= slip;
599 if (subscribedTypes.Contains(typeof(
Tick)))
601 var primaryExchangeCode = ((
Equity)asset).PrimaryExchange.Code;
605 .Where(x => x.TickType ==
TickType.Trade)
606 .OrderBy(x => x.EndTime).ToList();
611 !
string.IsNullOrWhiteSpace(x.SaleCondition) &&
612 x.ExchangeCode == primaryExchangeCode
613 && (x.ParsedSaleCondition & closeTradeTickFlags) != 0);
621 tick = trades.LastOrDefault() ?? asset.
Cache.GetAll<
Tick>().LastOrDefault();
626 if ((tick?.EndTime - nextMarketClose)?.TotalMinutes < 1)
641 fill.FillPrice = tick.Price;
650 else if (subscribedTypes.Contains(typeof(
TradeBar)))
660 var slip = asset.
SlippageModel.GetSlippageApproximation(asset, order);
662 var bestEffortMessage =
"";
668 if (fill.FillPrice == 0)
670 fill.FillPrice = GetBestEffortAskPrice(asset, order.
Time, out bestEffortMessage);
671 fill.Message += bestEffortMessage;
674 fill.FillPrice += slip;
677 if (fill.FillPrice == 0)
679 fill.FillPrice = GetBestEffortBidPrice(asset, order.
Time, out bestEffortMessage);
680 fill.Message += bestEffortMessage;
683 fill.FillPrice -= slip;
702 .GetSubscriptionDataConfigs(asset.
Symbol)
703 .ToHashSet(x => x.Type);
705 if (subscribedTypes.Count == 0)
707 throw new InvalidOperationException($
"Cannot perform fill for {asset.Symbol} because no data subscription were found.");
710 return subscribedTypes;
721 private decimal GetBestEffortAskPrice(
Security asset, DateTime orderTime, out
string message)
723 message =
string.Empty;
725 var bestEffortAskPrice = 0m;
733 List<Tick> ticks =
null;
734 var isTickSubscribed = subscribedTypes.Contains(typeof(
Tick));
736 if (isTickSubscribed)
738 ticks = asset.
Cache.GetAll<
Tick>().ToList();
740 var quote = ticks.LastOrDefault(x => x.TickType ==
TickType.Quote && x.AskPrice > 0);
743 if (quote.EndTime >= cutOffTime)
745 return quote.AskPrice;
749 bestEffortAskPrice = quote.AskPrice;
754 if (subscribedTypes.Contains(typeof(
QuoteBar)))
757 if (quoteBar !=
null && (baseData ==
null || quoteBar.EndTime > baseData.
EndTime))
759 if (quoteBar.EndTime >= cutOffTime)
761 return quoteBar.
Ask?.
Close ?? quoteBar.Close;
765 bestEffortAskPrice = quoteBar.Ask?.Close ?? quoteBar.Close;
766 message = Messages.EquityFillModel.FilledWithQuoteBarData(asset, quoteBar);
770 if (isTickSubscribed)
772 var trade = ticks.LastOrDefault(x => x.TickType ==
TickType.Trade);
773 if (trade !=
null && (baseData ==
null || trade.EndTime > baseData.
EndTime))
775 message = Messages.EquityFillModel.FilledWithTradeTickData(asset, trade);
777 if (trade.EndTime >= cutOffTime)
783 bestEffortAskPrice = trade.
Price;
787 if (subscribedTypes.Contains(typeof(
TradeBar)))
790 if (tradeBar !=
null && (baseData ==
null || tradeBar.EndTime > baseData.
EndTime))
792 message = Messages.EquityFillModel.FilledWithTradeBarData(asset, tradeBar);
794 if (tradeBar.EndTime >= cutOffTime)
796 return tradeBar.
Close;
800 bestEffortAskPrice = tradeBar.Close;
804 if (baseData !=
null)
806 return bestEffortAskPrice;
809 throw new InvalidOperationException(Messages.FillModel.NoMarketDataToGetAskPriceForFilling(asset, subscribedTypes));
820 private decimal GetBestEffortBidPrice(
Security asset, DateTime orderTime, out
string message)
822 message =
string.Empty;
824 var bestEffortBidPrice = 0m;
832 List<Tick> ticks =
null;
833 var isTickSubscribed = subscribedTypes.Contains(typeof(
Tick));
835 if (isTickSubscribed)
837 ticks = asset.
Cache.GetAll<
Tick>().ToList();
839 var quote = ticks.LastOrDefault(x => x.TickType ==
TickType.Quote && x.BidPrice > 0);
842 if (quote.EndTime >= cutOffTime)
844 return quote.BidPrice;
848 bestEffortBidPrice = quote.BidPrice;
849 message = Messages.EquityFillModel.FilledWithQuoteTickData(asset, quote);
853 if (subscribedTypes.Contains(typeof(
QuoteBar)))
856 if (quoteBar !=
null && (baseData ==
null || quoteBar.EndTime > baseData.
EndTime))
858 if (quoteBar.EndTime >= cutOffTime)
860 return quoteBar.
Bid?.
Close ?? quoteBar.Close;
864 bestEffortBidPrice = quoteBar.Bid?.Close ?? quoteBar.Close;
865 message = Messages.EquityFillModel.FilledWithQuoteBarData(asset, quoteBar);
869 if (isTickSubscribed)
871 var trade = ticks.LastOrDefault(x => x.TickType ==
TickType.Trade);
872 if (trade !=
null && (baseData ==
null || trade.EndTime > baseData.
EndTime))
874 message = Messages.EquityFillModel.FilledWithTradeTickData(asset, trade);
876 if (trade.EndTime >= cutOffTime)
882 bestEffortBidPrice = trade.
Price;
886 if (subscribedTypes.Contains(typeof(
TradeBar)))
889 if (tradeBar !=
null && (baseData ==
null || tradeBar.EndTime > baseData.
EndTime))
891 message = Messages.EquityFillModel.FilledWithTradeBarData(asset, tradeBar);
893 if (tradeBar.EndTime >= cutOffTime)
895 return tradeBar.
Close;
899 bestEffortBidPrice = tradeBar.Close;
903 if (baseData !=
null)
905 return bestEffortBidPrice;
908 throw new InvalidOperationException(Messages.FillModel.NoMarketDataToGetBidPriceForFilling(asset, subscribedTypes));
928 if (subscribedTypes.Contains(typeof(
Tick)))
931 var tradeHigh = decimal.MinValue;
932 var tradeLow = decimal.MaxValue;
934 var tradeVolume = 0m;
935 var startTimeUtc = DateTime.MinValue;
936 var endTimeUtc = DateTime.MinValue;
938 var trades = asset.
Cache.GetAll<
Tick>().Where(x => x.TickType ==
TickType.Trade).ToList();
941 foreach (var trade
in trades)
945 tradeOpen = trade.
Price;
946 startTimeUtc = trade.Time;
949 tradeHigh = Math.Max(tradeHigh, trade.Price);
950 tradeLow = Math.Min(tradeLow, trade.Price);
951 tradeClose = trade.Price;
952 tradeVolume += trade.Quantity;
953 endTimeUtc = trade.EndTime;
957 tradeOpen, tradeHigh, tradeLow, tradeClose, tradeVolume, endTimeUtc - startTimeUtc);
960 else if (subscribedTypes.Contains(typeof(
TradeBar)))
966 if (bestEffortTradeBar ==
null ||
972 return bestEffortTradeBar;
983 var prices =
PythonWrapper.GetPricesInternal(asset, direction);
984 return new Prices(prices.EndTime, prices.Current, prices.Open, prices.High, prices.Low, prices.Close);
997 var high = asset.
High;
998 var open = asset.
Open;
999 var close = asset.
Close;
1000 var current = asset.
Price;
1005 return new Prices(endTime, current, open, high, low, close);
1010 .GetSubscriptionDataConfigs(asset.
Symbol)
1011 .Select(x => x.Type).ToList();
1014 if (subscriptionTypes.Contains(typeof(
Tick)) && tick !=
null)
1019 return new Prices(tick.EndTime, price, 0, 0, 0, 0);
1026 return new Prices(tick.EndTime, price, 0, 0, 0, 0);
1032 if (subscriptionTypes.Contains(typeof(
QuoteBar)) && quoteBar !=
null)
1037 return new Prices(quoteBar.EndTime, bar);
1043 if (subscriptionTypes.Contains(typeof(
TradeBar)) && tradeBar !=
null)
1045 return new Prices(tradeBar);
1048 return new Prices(endTime, current, open, high, low, close);