Class OptionRequestGuard
- Namespace
- ATAS.DataFeedsCore
- Assembly
- ATAS.DataFeedsCore.dll
Connector-level limit on option requests that come past the budgeted options API.
The options API (OptionsSubscriptionService behind IOptionsDataProvider and the Options Board,
PLAT-5011) budgets its own subscriptions and lookups per connector and marks its connector calls with
EnterBudgetedScope(). Everything else that reaches a connector for options - a chart or DOM opened
on an option, or a third-party indicator that took the connector itself instead of the provider - is a
direct caller. Direct callers get a small allowance meant for a person opening option charts, not for a
program walking a whole option chain: at most MaxDirectOptions options held at once (an option
shared with the options API counts too), a token bucket for the subscribe requests they send to the broker (a
subscription restored after a reconnect costs a token too) and one for series/chain lookups. A request over the
allowance is refused locally and never reaches the broker. The unattended server hosts
(ReconnectOnFirstConnect) are our own infrastructure; the base connector does
not consult the guard for them.
The holdings are counted per origin and per subscription type, mirroring the connector's subscription
counter: the budgeted and the direct holders of one option are tracked apart, so a direct caller cannot ride
on a subscription of the options API and keep it after the API released it. The connector serialises the
guard with its own counter (see BaseConnector); the guard's own lock only protects its state.
Background: on 2026-09-28 Rithmic blocked clients of 8.0.15.271 that ran an indicator subscribing ~4 000 option strikes straight through the connector, around the budget of the options API, and re-subscribing all of them after every reconnect.
The scope is a guard against bugs, not a security boundary: indicators run in-process with full trust.
Added in ATAS 8.0.15.
public sealed class OptionRequestGuard
- Inheritance
-
objectOptionRequestGuard
- Extension Methods
Constructors
OptionRequestGuard(ILoggerSource, SubscriptionStatistics, TimeProvider)
Creates the guard of one connector.
public OptionRequestGuard(ILoggerSource logger, SubscriptionStatistics statistics, TimeProvider timeProvider)
Parameters
loggerILoggerSourceLog source for refusal reports.
statisticsSubscriptionStatisticsStatistics that count refused subscriptions and lookups.
timeProviderTimeProviderTime source of the rate limits and the report period.
Exceptions
- ArgumentNullException
An argument is null.
Fields
DirectLookupBurst
Largest burst of direct option series/chain lookups per connector.
public const int DirectLookupBurst = 10
Field Value
- int
DirectLookupRefillPerSecond
Sustained direct option series/chain lookups per second per connector (two per minute).
public const double DirectLookupRefillPerSecond = 0.03333333333333333
Field Value
- double
DirectSubscribeBurst
Largest burst of direct option subscribe requests per connector.
public const int DirectSubscribeBurst = 200
Field Value
- int
DirectSubscribeRefillPerSecond
Sustained direct option subscribe requests per second per connector (30 per minute).
public const double DirectSubscribeRefillPerSecond = 0.5
Field Value
- double
MaxDirectOptions
Options a direct caller may hold subscribed at once per connector.
public const int MaxDirectOptions = 200
Field Value
- int
Properties
DirectOptions
Options held by direct callers at the moment.
public int DirectOptions { get; }
Property Value
- int
IsBudgeted
The calls of the current thread are budgeted by their caller and pass unlimited.
public static bool IsBudgeted { get; }
Property Value
- bool
Methods
EnterBudgetedScope()
Marks the option connector calls of the current thread as already budgeted by the caller until the returned scope is disposed. Only for code that keeps its own per-connector budget (the options API) or whose volume is bounded by the account (position subscriptions). The scope must be entered and disposed on the same thread around the synchronous part of the call, for subscribes and unsubscribes alike.
public static OptionRequestGuard.BudgetedScope EnterBudgetedScope()
Returns
Release(Security)
The option has no active subscription left at the connector: every holding of it is forgotten and a direct place is given back.
public void Release(Security option)
Parameters
optionSecurity
Remove(Security, SubscriptionType)
The current caller unsubscribed the option from the types. The holding is taken from the caller's origin; types the origin does not hold are taken from the other one (a caller that subscribed and unsubscribes under different scopes).
public void Remove(Security option, SubscriptionType subscriptionTypes)
Parameters
optionSecuritysubscriptionTypesSubscriptionType
RemoveRejected(Security, SubscriptionType)
The broker rejected the registration of the types, reported on whatever thread: the holding is taken from the budgeted side first. When the options API and a direct caller share the option, the rejected request is the options API's more often than not, and a direct place is never given back on a guess.
public void RemoveRejected(Security option, SubscriptionType subscriptionTypes)
Parameters
optionSecuritysubscriptionTypesSubscriptionType
TryAdmitLookup(string, out Exception?)
Decides whether an option series or chain lookup may reach the broker.
public bool TryAdmitLookup(string request, out Exception? error)
Parameters
requeststringerrorException
Returns
- bool
TryAdmitResubscribe(Security, SubscriptionType, out Exception?)
Decides whether an option still counted as subscribed after a reconnect may be searched and subscribed at the broker again. An option held only inside budgeted scopes passes; an option a direct caller holds costs a direct token. A refused option is forgotten: the connector drops its subscription.
public bool TryAdmitResubscribe(Security option, SubscriptionType countedTypes, out Exception? error)
Parameters
optionSecurityThe option.
countedTypesSubscriptionTypeThe types the connector counts for the option; recorded as a direct holding when the guard does not know the option.
errorExceptionThe reason of a refusal.
Returns
- bool
TryAdmitSubscribe(Security, SubscriptionType, bool, out Exception?)
Decides whether the current caller may subscribe the option to the types and, when it may, records the holding under the caller's origin.
public bool TryAdmitSubscribe(Security option, SubscriptionType subscriptionTypes, bool sendsRequest, out Exception? error)
Parameters
optionSecurityThe option.
subscriptionTypesSubscriptionTypeThe types the caller subscribes to.
sendsRequestboolThe subscription sends a request to the broker (it adds a type nobody holds yet and the connector is connected); only such a subscription costs a token.
errorExceptionThe reason of a refusal.
Returns
- bool