30 internal class SymbolCapacity
35 public static TimeSpan CapacityEffectPeriod = TimeSpan.FromDays(30);
43 private const decimal _forexMinuteVolume = 25000000m;
51 private const decimal _cfdMinuteVolume = 200m;
52 private const decimal _fastTradingVolumeScalingFactor = 2m;
55 private readonly Symbol _symbol;
57 private decimal _previousVolume;
58 private DateTime? _previousTime;
60 private bool _isInternal;
61 private decimal _averageDollarVolume;
62 private decimal _resolutionScaleFactor;
63 private decimal _marketCapacityDollarVolume;
64 private bool _resetMarketCapacityDollarVolume;
65 private decimal _fastTradingVolumeDiscountFactor;
71 public int Trades {
get;
private set; }
81 public decimal SaleVolume {
get;
private set; }
89 public decimal MarketCapacityDollarVolume => _marketCapacityDollarVolume * _resolutionScaleFactor;
96 public SymbolCapacity(
IAlgorithm algorithm, Symbol symbol)
98 _algorithm = algorithm;
99 Security = _algorithm.Securities[symbol];
102 _isInternal = _algorithm
104 .SubscriptionDataConfigService
105 .GetSubscriptionDataConfigs(symbol, includeInternalConfigs:
true)
106 .All(config => config.IsInternalFeed);
114 public void OnOrderEvent(
OrderEvent orderEvent)
121 _fastTradingVolumeDiscountFactor = _fastTradingVolumeScalingFactor * ((decimal)((orderEvent.
UtcTime - (_previousOrderEvent?.UtcTime ?? orderEvent.
UtcTime.AddDays(-1))).TotalMinutes) / 390m);
122 _fastTradingVolumeDiscountFactor = _fastTradingVolumeDiscountFactor > 1 ? 1 : Math.Max(0.20m, _fastTradingVolumeDiscountFactor);
124 if (_resetMarketCapacityDollarVolume)
126 _marketCapacityDollarVolume = 0;
128 _resetMarketCapacityDollarVolume =
false;
132 _previousOrderEvent = orderEvent;
139 private bool IncludeMarketVolume(
Resolution resolution)
141 if (_previousOrderEvent ==
null)
146 var dollarVolumeScaleFactor = 6000000;
154 dollarVolumeScaleFactor = dollarVolumeScaleFactor / 60;
155 k = _averageDollarVolume != 0
156 ? dollarVolumeScaleFactor / _averageDollarVolume
159 var timeoutPeriod = k > 120 ? 120 : (int)Math.Max(5, (
double)k);
160 timeout = _previousOrderEvent.
UtcTime.AddMinutes(timeoutPeriod);
164 k = _averageDollarVolume != 0
165 ? dollarVolumeScaleFactor / _averageDollarVolume
168 var timeoutMinutes = k > 120 ? 120 : (int)Math.Max(1, (
double)k);
169 timeout = _previousOrderEvent.
UtcTime.AddMinutes(timeoutMinutes);
173 return _algorithm.UtcTime == _previousOrderEvent.
UtcTime.RoundUp(resolution.ToTimeSpan());
178 return _algorithm.UtcTime == _previousOrderEvent.
UtcTime ||
179 _algorithm.UtcTime.Date == _previousOrderEvent.
UtcTime.RoundUp(resolution.ToTimeSpan());
182 timeout = _previousOrderEvent.
UtcTime.AddHours(1);
186 return _algorithm.UtcTime <= timeout;
193 public bool UpdateMarketCapacity()
196 if (bar ==
null || bar.Volume == 0)
201 var utcTime = _algorithm.UtcTime;
202 var resolution = bar.Period.ToHigherResolutionEquivalent(
false);
204 var timeBetweenBars = (decimal)(utcTime - (_previousTime ?? utcTime)).TotalMinutes;
206 if (_previousTime ==
null || timeBetweenBars == 0)
208 _averageDollarVolume = conversionRate * bar.Close * bar.Volume;
212 _averageDollarVolume = ((bar.Close * conversionRate) * (bar.Volume + _previousVolume)) / timeBetweenBars;
215 _previousTime = utcTime;
216 _previousVolume = bar.Volume;
218 var includeMarketVolume = IncludeMarketVolume(resolution);
219 if (includeMarketVolume)
221 _resolutionScaleFactor = ResolutionScaleFactor(resolution);
226 return !includeMarketVolume;
237 if (_algorithm.CurrentSlice.Bars.TryGetValue(_symbol, out bar))
243 if (_algorithm.CurrentSlice.QuoteBars.TryGetValue(_symbol, out quote))
246 var volume = (quote.LastBidSize + quote.LastAskSize) / 2;
249 switch (_symbol.SecurityType)
252 volume = _forexMinuteVolume;
255 volume = _cfdMinuteVolume;
287 private static decimal ResolutionScaleFactor(
Resolution resolution)
314 _resetMarketCapacityDollarVolume =
true;
321 public bool ShouldRemove()