9#include <algotradelib/src/network/rate_limit.hpp>
27 using duration = std::chrono::nanoseconds;
28 using rep = duration::rep;
29 using period = duration::period;
30 using time_point = std::chrono::time_point<WalkClock, duration>;
33 static time_point now() {
return time_point{}; }
39std::chrono::nanoseconds ms(
long long count) {
40 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(count));
44long long as_ms(std::chrono::nanoseconds value) {
45 return std::chrono::duration_cast<std::chrono::milliseconds>(value).count();
49int argument(
int argc,
char** argv,
int index,
int fallback) {
53 const int value = std::atoi(argv[index]);
54 return value >= 0 ? value : fallback;
58void print_allowances(
const RateLimitBudget& budget) {
59 std::cout <<
"budget: burst=" << budget.burst_ <<
" per_second=" << budget.per_second_
60 <<
" trading_reserve=" << budget.trading_reserve_ <<
'\n';
61 std::cout <<
" interval between admissions: " << as_ms(Bucket(budget).interval()) <<
"ms\n";
62 for (
const auto group : {
64 RateLimitGroup::TRADING,
65 RateLimitGroup::ACCOUNT,
66 RateLimitGroup::MARKET_DATA,
67 RateLimitGroup::REFERENCE,
70 <<
" burst allowance " <<
usable_burst(budget, group) <<
'\n';
75void print_reserve(
const RateLimitBudget& budget) {
76 Bucket bucket(budget);
77 const auto now = WalkClock::now();
78 const int polling =
usable_burst(budget, RateLimitGroup::MARKET_DATA);
79 const int trading =
usable_burst(budget, RateLimitGroup::TRADING);
82 while (bucket.try_acquire(now, polling)) {
86 std::cout <<
"\na saturated polling loop spends " << spent <<
" request(s) immediately\n";
87 std::cout <<
" its next request waits " << as_ms(bucket.delay_until(now, polling)) <<
"ms\n";
88 std::cout <<
" a cancellation waits " << as_ms(bucket.delay_until(now, trading)) <<
"ms";
89 std::cout <<
" with " << bucket.available(now, trading) <<
" reserved slot(s) left\n";
93void print_corrections(
const RateLimitBudget& budget) {
94 std::cout <<
"\nreactions to a broker refusal\n";
97 shared.hold(std::chrono::seconds(1));
98 std::cout <<
" shared cap reached: allowance unchanged at " << shared.budget().per_second_
99 <<
"/s, admission held\n";
102 reported.shrink(2, 2, std::chrono::seconds(1));
103 std::cout <<
" broker reported its allowance: adopted " << reported.budget().per_second_
106 std::cout <<
" broker reported no allowance: allowance unchanged, admission held\n";
107 std::cout <<
" (KIS states none, so its budget stays as configured and its"
108 <<
" refusals are counted)\n";
112void print_sustained(
const RateLimitBudget& budget) {
113 Bucket bucket(budget);
114 const auto start = WalkClock::now();
115 const int polling =
usable_burst(budget, RateLimitGroup::MARKET_DATA);
118 for (
long long step = 0; step < 1000; step += 5) {
119 if (bucket.try_acquire(start + ms(step), polling)) {
123 std::cout <<
"\none second of polling as fast as allowed: " << admitted <<
" request(s)\n";
128int main(
int argc,
char** argv) {
130 RateLimitBudget budget;
131 budget.burst_ = argument(argc, argv, 1, budget.burst_);
132 budget.per_second_ = argument(argc, argv, 2, budget.per_second_);
133 budget.trading_reserve_ = argument(argc, argv, 3, budget.trading_reserve_);
135 print_allowances(budget);
136 print_reserve(budget);
137 print_sustained(budget);
138 print_corrections(budget);
140 }
catch (
const std::exception& exception) {
141 std::cerr <<
"example failed: " << exception.what() <<
'\n';
A rate limiter (the generic cell rate algorithm) that computes when a request may go; it neither wait...
The rate limiter of one connection (one app key): a RateLimitBucket on the steady clock,...
RateLimitGroup
The traffic class of a request, for rate limiting and queue priority. The broker adapter that builds ...
constexpr int usable_burst(const RateLimitBudget &budget, RateLimitGroup group) noexcept
Returns how much of the burst a traffic class may use.
constexpr std::string_view rate_limit_group_name(RateLimitGroup group) noexcept
Returns a lowercase name for a traffic class, such as "market_data", for logs.
void start(S &strategy, Ctx &context)
Calls strategy.on_start(context) if the strategy declares on_start; otherwise does nothing.
The request rate a connection may use.