Connector-level limit on option requests that come past the budgeted options API. More...
Classes | |
| struct | BudgetedScope |
| Ends the budgeted scope entered by EnterBudgetedScope. More... | |
Public Member Functions | |
| OptionRequestGuard (ILoggerSource logger, SubscriptionStatistics statistics, TimeProvider timeProvider) | |
| bool | TryAdmitSubscribe (Security option, SubscriptionType subscriptionTypes, bool sendsRequest, out Exception? error) |
| Decides whether the current caller may subscribe the option to the types and, when it may, records the holding under the caller's origin. | |
| void | Remove (Security option, SubscriptionType subscriptionTypes) |
| 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). | |
| void | RemoveRejected (Security option, SubscriptionType subscriptionTypes) |
| 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. | |
| bool | TryAdmitResubscribe (Security option, SubscriptionType countedTypes, out Exception? error) |
| 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. | |
| bool | TryAdmitLookup (string request, out Exception? error) |
| Decides whether an option series or chain lookup may reach the broker. | |
| void | Release (Security option) |
| The option has no active subscription left at the connector: every holding of it is forgotten and a direct place is given back. | |
Static Public Member Functions | |
| static BudgetedScope | 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. | |
Static Public Attributes | |
| const int | MaxDirectOptions = 200 |
| Options a direct caller may hold subscribed at once per connector. | |
| const int | DirectSubscribeBurst = 200 |
| Largest burst of direct option subscribe requests per connector. | |
| const double | DirectSubscribeRefillPerSecond = 0.5 |
| Sustained direct option subscribe requests per second per connector (30 per minute). | |
| const int | DirectLookupBurst = 10 |
| Largest burst of direct option series/chain lookups per connector. | |
| const double | DirectLookupRefillPerSecond = 1.0 / 30 |
| Sustained direct option series/chain lookups per second per connector (two per minute). | |
Properties | |
| static bool | IsBudgeted [get] |
| The calls of the current thread are budgeted by their caller and pass unlimited. | |
| int | DirectOptions [get] |
| Options held by direct callers at the moment. | |
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 (IDataFeedConnector.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.
| ATAS.DataFeedsCore.OptionRequestGuard.OptionRequestGuard | ( | ILoggerSource | logger, |
| SubscriptionStatistics | statistics, | ||
| TimeProvider | timeProvider | ||
| ) |
|
static |
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.
| void ATAS.DataFeedsCore.OptionRequestGuard.Release | ( | Security | option | ) |
The option has no active subscription left at the connector: every holding of it is forgotten and a direct place is given back.
| void ATAS.DataFeedsCore.OptionRequestGuard.Remove | ( | Security | option, |
| SubscriptionType | subscriptionTypes | ||
| ) |
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).
| void ATAS.DataFeedsCore.OptionRequestGuard.RemoveRejected | ( | Security | option, |
| SubscriptionType | subscriptionTypes | ||
| ) |
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.
| bool ATAS.DataFeedsCore.OptionRequestGuard.TryAdmitLookup | ( | string | request, |
| out Exception? | error | ||
| ) |
Decides whether an option series or chain lookup may reach the broker.
| bool ATAS.DataFeedsCore.OptionRequestGuard.TryAdmitResubscribe | ( | Security | option, |
| SubscriptionType | countedTypes, | ||
| out Exception? | error | ||
| ) |
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.
| option | The option. |
| countedTypes | The types the connector counts for the option; recorded as a direct holding when the guard does not know the option. |
| error | The reason of a refusal. |
| bool ATAS.DataFeedsCore.OptionRequestGuard.TryAdmitSubscribe | ( | Security | option, |
| SubscriptionType | subscriptionTypes, | ||
| bool | sendsRequest, | ||
| out Exception? | error | ||
| ) |
Decides whether the current caller may subscribe the option to the types and, when it may, records the holding under the caller's origin.
| option | The option. |
| subscriptionTypes | The types the caller subscribes to. |
| sendsRequest | The 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. |
| error | The reason of a refusal. |
|
static |
Largest burst of direct option series/chain lookups per connector.
|
static |
Sustained direct option series/chain lookups per second per connector (two per minute).
|
static |
Largest burst of direct option subscribe requests per connector.
|
static |
Sustained direct option subscribe requests per second per connector (30 per minute).
|
static |
Options a direct caller may hold subscribed at once per connector.
|
get |
Options held by direct callers at the moment.
|
staticget |
The calls of the current thread are budgeted by their caller and pass unlimited.