Elke applicatie die met een crypto exchange praat, schrijft uiteindelijk dezelfde twee stukken loodgieterswerk. Het eerste herstelt je marktdata subscriptions nadat de socket is weggevallen. Het tweede vertraagt je REST calls zodat de exchange je niet afknijpt. Geen van beide is interessante code, in beide sluipen makkelijk subtiele fouten, en tot nu toe waren ze allebei de verantwoordelijkheid van de applicatie.
sgcWebSockets 2026.7 bouwt ze in. De exchange API clients kunnen hun eigen subscriptions opnieuw afspelen na een reconnect, en elke kant-en-klare REST client heeft nu een rate limiter aan clientzijde die begrenst hoeveel requests je in een tijdvenster verstuurt. Beide zijn opt-in en staan standaard uit, dus een upgrade verandert niets tot je ze aanzet.
De reconnect die je op niets geabonneerd achterlaat
De WatchDog is altijd goed geweest in het terughalen van de verbinding. Een kabel gaat eruit, een proxy loopt in een timeout, de exchange herstart een gateway, en een paar seconden later is de client weer verbonden. Dat deel werkt.
Wat niet terugkomt zijn je subscriptions. De exchange heeft er geen herinnering aan. Een nieuwe socket is een lege sessie, dus de trade en order book streams waar je op de oude socket om vroeg, bestaan simpelweg niet meer. Het symptoom is vervelend, want niets lijkt kapot: de client meldt Connected, er wordt geen fout opgeworpen, en de message events houden gewoon op met binnenkomen. Je grafiek loopt stilletjes achter.
De gebruikelijke oplossing is om zelf een lijst met subscriptions bij te houden en die vanuit OnConnect opnieuw af te spelen. Dat betekent elk symbool, elk kanaal en elke stream onthouden waar je om vroeg, en eraan denken die lijst bij te werken telkens als je ergens anders in de codebase een subscribe of unsubscribe doet. Het is boekhouding die niets met je strategie te maken heeft.
Automatische resubscribe aanzetten
De API clients weten al waarop je geabonneerd bent, want je hebt je via hen geabonneerd. In 2026.7 kunnen ze die lijst bewaren en na een reconnect zelf opnieuw afspelen. Het is één Boolean op het options object van de exchange, met de naam Resubscribe.
Hier is de handgeschreven versie die de meeste trading apps vandaag hebben, en wat daarvoor in de plaats komt:
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;
Met Resubscribe aan legt de client elke subscription vast op het moment dat je hem maakt, en nadat de WatchDog de socket heeft teruggehaald stuurt hij ze opnieuw op de verse sessie. Bij een unsubscribe verdwijnt de vermelding, dus een stream die je bewust hebt gesloten staat na de volgende reconnect niet ineens weer op uit de dood.
Het werkt samen met de WatchDog en vervangt hem niet. De WatchDog herstelt het transport, Resubscribe herstelt de sessie daarbovenop:
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;
De standaardwaarde is False. Bestaande applicaties die zich al met de hand opnieuw abonneren blijven precies werken zoals ze deden, zonder dubbele subscriptions, tot je je eigen code weggooit en de vlag zet.
Welke exchanges
Resubscribe zit op het options object van elke exchange client. Hij is beschikbaar op Binance, Bitfinex, Bitget, BitMEX, Bitstamp, Bybit, CEX, CEX Plus, Coinbase, Crypto.com, Deribit, Gate.io, Huobi, Kraken, KuCoin, MEXC en OKX, en op de sessiegebaseerde streaming feed van XTB. De property heet overal hetzelfde, dus de regel leest als Coinbase.Resubscribe, Bybit.Resubscribe, OKX.Resubscribe enzovoort, afhankelijk van welke component je op het formulier hebt gezet.
De Lightstreamer client, die door IG en andere brokers wordt gebruikt, doet intern hetzelfde. Na een rebind van de sessie heeft de server geen enkele registratie van de eerdere subscriptions, dus de client speelt ze zonder dat je erom vraagt opnieuw af vanuit zijn lokale verzameling.
Rate limits, vanaf de clientzijde
De andere helft van een trading app is de REST kant: een order plaatsen, een order annuleren, balansen laden, de symbolenlijst laden. Elke exchange publiceert een request budget voor die endpoints, meestal een aantal requests of een gewicht per minuut per IP of per key. Ga je eroverheen, dan krijg je een 429, en blijf je eroverheen gaan, dan krijg je een tijdelijke ban, wat een veel slechtere dag oplevert.
2026.7 voegt een rate limiter aan clientzijde toe aan TsgcHTTPAPI_client, zodat elke kant-en-klare REST client hem erft. Het is een schuivend venster: hooguit MaxRequests requests binnen elk venster van IntervalMs. Je configureert hem aan de hand van de gepubliceerde regels van de exchange, want de limiet van de exchange is de enige die telt:
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;
De klassieke manier om afgeknepen te worden is de burst bij het opstarten. De applicatie start, en waaiert uit om de symbolenlijst, de balansen, de open orders en de laatste candles voor veertig instrumenten te laden, allemaal in de eerste seconde. Daar is niets onredelijks aan, en de exchange telt het toch als veertig requests in één seconde. De limiter vlakt precies dat verkeerspatroon af, zonder dat je Sleep aanroepen door je initialisatiecode hoeft te strooien.
De limiter wordt lazy aangemaakt. Raak je RateLimit nooit aan, dan wordt er geen object gealloceerd en is het request pad byte voor byte wat het was, dus er valt niets te betalen als je hem niet gebruikt.
Wachten of weigeren
Als het budget voor het huidige venster op is, mag jij kiezen wat er met de volgende call gebeurt. Dat is Behavior, en het is een echte beslissing in plaats van een afstelknop.
rlbWait, de standaard, blokkeert de call tot er een slot vrijkomt en verstuurt hem dan. Dit is wat je wilt in een achtergrondproces dat historie inlaadt of posities reconcilieert. Het werk duurt iets langer en het komt allemaal af.
rlbReject werpt onmiddellijk EsgcHTTPRateLimit op en verstuurt niets. Dit is wat je wilt wanneer een late request erger is dan helemaal geen request. Een order die drie seconden nadat je besloot hem te versturen aankomt, kan een order zijn die je niet meer wilt, en die in een bewegende markt afvuren is erger dan luidruchtig falen:
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;
Een gangbare opzet is allebei, met twee componenten: rlbWait op de component die het bulkladen doet, en rlbReject op de component die orders plaatst, elk met zijn eigen budget.
Dit is niet de rate limiter aan serverzijde
Het is goed dit expliciet te maken, want de namen liggen dicht bij elkaar. sgcWebSockets 2026.5 leverde TsgcWSRateLimiter, en dat is een limiter aan de serverzijde: hij beschermt jouw server tegen jouw clients, door te begrenzen wat een inkomende verbinding je mag sturen. Die in dit artikel wijst de andere kant op. Het is een limiter aan de clientzijde die jou beschermt tegen de limieten van iemand anders, door te begrenzen wat jouw applicatie naar een exchange stuurt. Ze staan los van elkaar, en een applicatie die zowel server als exchange consument is, gebruikt met plezier allebei.
Niet alleen crypto
RateLimit woont op de basis HTTP API client, dus hij wordt geërfd door elke kant-en-klare REST client in de bibliotheek, niet alleen door de exchanges. De AI clients hebben request limieten van precies dezelfde soort, dus OpenAI, Anthropic en Gemini krijgen hem, en Stripe en de rest van de API integraties ook. De property zit op dezelfde plek met dezelfde vier instellingen:
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;
Zit je account op een tier met een laag plafond aan requests per minuut, dan is dit de goedkoopste manier om te voorkomen dat een parallelle batchjob eroverheen gaat.
Beschikbaarheid
Automatische resubscribe en de rate limiter aan clientzijde zijn beschikbaar in sgcWebSockets 2026.7 op Delphi 7 tot en met 13 en C++Builder, op Win32/Win64, Linux64, macOS, Android en iOS. Beide staan standaard uit, dus een upgrade is een drop-in.
Klanten met een actief abonnement kunnen de nieuwe build downloaden uit het klantengedeelte. Trial gebruikers kunnen het bijgewerkte installatieprogramma ophalen op esegece.com/products/websockets/download.
Vragen, feedback of hulp nodig bij het inbouwen hiervan in je trading app? Neem contact op, je krijgt antwoord van de mensen die de code hebben geschreven.
