Każda aplikacja rozmawiająca z giełdą kryptowalut kończy pisaniem tych samych dwóch kawałków instalacji wodno-kanalizacyjnej. Pierwszy przywraca subskrypcje danych rynkowych po zerwaniu gniazda. Drugi spowalnia wywołania REST, żeby giełda Cię nie zdławiła. Żaden z nich nie jest ciekawym kodem, oba łatwo napisać subtelnie źle i oba do tej pory były zostawiane aplikacji.
sgcWebSockets 2026.7 wbudowuje je w bibliotekę. Klienci API giełd potrafią odtworzyć własne subskrypcje po ponownym połączeniu, a każdy gotowy klient REST ma teraz limiter po stronie klienta, który ogranicza liczbę żądań wysyłanych w oknie czasowym. Oba są opcjonalne i domyślnie wyłączone, więc aktualizacja niczego nie zmienia, dopóki ich nie włączysz.
Ponowne połączenie, po którym nie masz żadnej subskrypcji
WatchDog zawsze dobrze radził sobie z przywracaniem połączenia. Ktoś wyciąga kabel, proxy przekracza limit czasu, giełda restartuje bramę, a kilka sekund później klient jest znowu połączony. Ta część działa.
Nie wracają natomiast Twoje subskrypcje. Giełda o nich nie pamięta. Nowe gniazdo to pusta sesja, więc strumienie transakcji i księgi zleceń, o które prosiłeś na starym gnieździe, po prostu już nie istnieją. Objaw jest paskudny, bo nic nie wygląda na zepsute: klient raportuje Connected, żaden błąd nie jest zgłaszany, a zdarzenia z wiadomościami po prostu przestają przychodzić. Twój wykres po cichu się dezaktualizuje.
Zwykłym obejściem jest prowadzenie własnej listy subskrypcji i odtwarzanie jej w OnConnect, co oznacza zapamiętywanie każdego symbolu, każdego kanału i każdego strumienia, o który prosiłeś, oraz pamiętanie o aktualizowaniu tej listy za każdym razem, gdy gdzieś indziej w kodzie coś subskrybujesz lub odsubskrybujesz. To księgowość, która nie ma nic wspólnego z Twoją strategią.
Włączanie automatycznej ponownej subskrypcji
Klienci API już wiedzą, co zasubskrybowałeś, bo subskrybowałeś przez nich. W 2026.7 potrafią zachować tę listę i sami ją odtworzyć po ponownym połączeniu. To pojedyncza wartość logiczna w obiekcie opcji giełdy, nazwana Resubscribe.
Oto ręcznie pisana wersja, którą ma dziś większość aplikacji tradingowych, i to, co ją zastępuje:
uses
sgcWebSocket, sgcWebSocket_API_Binance;
// Before: keep your own list and replay it on every reconnect.
procedure TForm1.OnBinanceConnect(Connection: TsgcWSConnection);
begin
sgcWSAPI_Binance1.SubscribeTrades('btcusdt');
sgcWSAPI_Binance1.SubscribeTicker('btcusdt');
sgcWSAPI_Binance1.SubscribeTrades('ethusdt');
// ... and every other symbol you had open, in the right order.
end;
// After: the API client replays them for you.
sgcWSAPI_Binance1.Binance.Resubscribe := True;
Gdy Resubscribe jest włączone, klient zapisuje każdą subskrypcję w chwili jej wykonania, a po tym, jak WatchDog przywróci gniazdo, wysyła je ponownie w nowej sesji. Odsubskrybowanie usuwa wpis, więc strumień, który celowo zamknąłeś, nie powstanie z martwych po następnym ponownym połączeniu.
Mechanizm współgra z WatchDogiem, a nie zastępuje go. WatchDog przywraca transport, a Resubscribe przywraca sesję na jego wierzchu:
uses
sgcWebSocket, sgcWebSocket_API_Kraken;
begin
sgcWebSocketClient1.WatchDog.Enabled := True;
sgcWebSocketClient1.WatchDog.Timeout := 5; // retry the socket every 5 seconds
sgcWSAPI_Kraken1.Client := sgcWebSocketClient1;
sgcWSAPI_Kraken1.Kraken.Resubscribe := True; // and restore the streams on top
sgcWebSocketClient1.Active := True;
sgcWSAPI_Kraken1.SubscribeTrade(['XBT/USD', 'ETH/USD']);
end;
Wartością domyślną jest False. Istniejące aplikacje, które już subskrybują ponownie ręcznie, działają dokładnie tak jak dotąd, bez zduplikowanych subskrypcji, dopóki nie usuniesz własnego kodu i nie ustawisz tej flagi.
Które giełdy
Resubscribe znajduje się w obiekcie opcji każdego klienta giełdy. Jest dostępne na Binance, Bitfinex, Bitget, BitMEX, Bitstamp, Bybit, CEX, CEX Plus, Coinbase, Crypto.com, Deribit, Gate.io, Huobi, Kraken, KuCoin, MEXC i OKX, a także w opartym na sesji strumieniu XTB. Właściwość zawsze nazywa się tak samo, więc linia brzmi Coinbase.Resubscribe, Bybit.Resubscribe, OKX.Resubscribe i tak dalej, w zależności od tego, który komponent upuściłeś na formularz.
Klient Lightstreamer, używany przez IG i innych brokerów, robi to samo wewnętrznie. Po ponownym powiązaniu sesji serwer nie pamięta wcześniejszych subskrypcji, więc klient odtwarza je z lokalnej kolekcji, bez proszenia go o to.
Limity żądań, od strony klienta
Druga połowa aplikacji tradingowej to strona REST: złóż zlecenie, anuluj zlecenie, wczytaj salda, wczytaj listę symboli. Każda giełda publikuje budżet żądań dla tych punktów końcowych, zwykle liczbę żądań lub wagę na minutę, na adres IP albo na klucz. Przekroczysz go i dostajesz 429, a jeśli będziesz przekraczać dalej, dostajesz czasowego bana, co jest dużo gorszym dniem.
2026.7 dodaje limiter po stronie klienta do TsgcHTTPAPI_client, więc dziedziczy go każdy gotowy klient REST. Działa jak okno przesuwne: co najwyżej MaxRequests żądań w każdym oknie IntervalMs. Konfigurujesz go na podstawie opublikowanych reguł giełdy, bo tylko limit giełdy ma znaczenie:
uses
sgcHTTP_API, sgcHTTP_API_Binance;
var
oBinance: TsgcHTTP_API_Binance_Rest;
begin
oBinance := TsgcHTTP_API_Binance_Rest.Create(nil);
try
oBinance.RateLimit.Enabled := True;
oBinance.RateLimit.IntervalMs := 60000; // one minute window
oBinance.RateLimit.MaxRequests := 1000; // stay under the published budget
oBinance.RateLimit.Behavior := rlbWait; // default
// Every request through this component now takes a slot first.
oBinance.GetAccountInformation;
finally
oBinance.Free;
end;
end;
Klasycznym sposobem na zdławienie samego siebie jest seria żądań przy starcie. Aplikacja się uruchamia i rozjeżdża się szeroko, żeby wczytać listę symboli, salda, otwarte zlecenia i ostatnie świece dla czterdziestu instrumentów, wszystko w pierwszej sekundzie. Nic w tym nierozsądnego, a giełda i tak liczy to jako czterdzieści żądań w jedną sekundę. Limiter wygładza dokładnie taki kształt ruchu, bez rozsypywania wywołań Sleep po kodzie inicjalizacji.
Limiter tworzony jest leniwie. Jeśli nigdy nie dotkniesz RateLimit, żaden obiekt nie jest alokowany, a ścieżka żądania jest bajt w bajt taka sama jak wcześniej, więc nie płacisz za nic, czego nie używasz.
Czekać albo odrzucić
Gdy budżet bieżącego okna zostanie wyczerpany, możesz wybrać, co stanie się z następnym wywołaniem. To właśnie Behavior, i jest to prawdziwa decyzja, a nie pokrętło do strojenia.
rlbWait, wartość domyślna, blokuje wywołanie do czasu zwolnienia się miejsca, a potem je wysyła. Tego chcesz w wątku roboczym w tle, który wczytuje historię albo uzgadnia pozycje. Praca trwa nieco dłużej i cała się kończy.
rlbReject natychmiast zgłasza EsgcHTTPRateLimit i nic nie wysyła. Tego chcesz, gdy spóźnione żądanie jest gorsze niż brak żądania. Zlecenie, które dociera trzy sekundy po tym, jak zdecydowałeś się je wysłać, może być zleceniem, którego już nie chcesz, a wystrzelenie go w ruchomy rynek jest gorsze niż głośna porażka:
uses
SysUtils, sgcHTTP_API, sgcHTTP_API_Binance;
begin
oBinance.RateLimit.Enabled := True;
oBinance.RateLimit.IntervalMs := 1000;
oBinance.RateLimit.MaxRequests := 10;
oBinance.RateLimit.Behavior := rlbReject;
try
oBinance.NewOrder('BTCUSDT', 'BUY', 'LIMIT', ...);
except
on E: EsgcHTTPRateLimit do
// Budget exhausted. Drop the order rather than send it stale.
LogWarning('rate limit hit, order not sent: ' + E.Message);
end;
end;
Częsta konfiguracja to oba naraz, w dwóch komponentach: rlbWait w komponencie, który wykonuje masowe wczytywanie, i rlbReject w komponencie, który składa zlecenia, każdy z własnym budżetem.
To nie jest limiter po stronie serwera
Warto powiedzieć to wprost, bo nazwy są zbliżone. sgcWebSockets 2026.5 dostarczyło TsgcWSRateLimiter, czyli limiter po stronie serwera: chroni on Twój serwer przed Twoimi klientami, ograniczając to, co połączenie przychodzące może do Ciebie wysłać. Ten z tego wpisu działa w drugą stronę. To limiter po stronie klienta, który chroni Ciebie przed limitami kogoś innego, ograniczając to, co Twoja aplikacja wysyła na giełdę. Są niezależne, a aplikacja, która jest jednocześnie serwerem i konsumentem danych giełdowych, spokojnie użyje obu.
Nie tylko kryptowaluty
RateLimit mieszka w bazowym kliencie HTTP API, więc dziedziczy go każdy gotowy klient REST w bibliotece, nie tylko giełdy. Klienci AI mają limity żądań dokładnie tego samego rodzaju, więc dostają go OpenAI, Anthropic i Gemini, a także Stripe i reszta integracji API. Właściwość jest w tym samym miejscu i ma te same cztery ustawienia:
uses
sgcHTTP_API, sgcHTTP_API_OpenAI;
begin
oOpenAI.RateLimit.Enabled := True;
oOpenAI.RateLimit.IntervalMs := 60000;
oOpenAI.RateLimit.MaxRequests := 500; // your tier's requests per minute
oOpenAI.RateLimit.Behavior := rlbWait;
end;
Jeśli Twoje konto jest na poziomie o niskim pułapie żądań na minutę, to najtańszy sposób, żeby równoległe zadanie wsadowe go nie przekroczyło.
Dostępność
Automatyczna ponowna subskrypcja i limiter po stronie klienta są dostępne w sgcWebSockets 2026.7 dla Delphi 7 do 13 i C++Builder, na Win32/Win64, Linux64, macOS, Android oraz iOS. Oba są domyślnie wyłączone, więc aktualizacja to prosta podmiana.
Klienci z aktywną subskrypcją mogą pobrać nową kompilację ze strefy klienta. Użytkownicy wersji próbnej mogą pobrać zaktualizowany instalator pod adresem esegece.com/products/websockets/download.
Pytania, opinie albo pomoc przy wpięciu tego w Twoją aplikację tradingową? Skontaktuj się z nami, odpowiedź otrzymasz od osób, które napisały ten kod.
