Feeds de criptomonedas que sobreviven a una reconexión, y un limitador de peticiones que evita que te bloqueen | eSeGeCe Blog

Feeds de criptomonedas que sobreviven a una reconexión, y un limitador de peticiones que evita que te bloqueen

· Componentes

Toda aplicación que habla con un exchange de criptomonedas acaba escribiendo las dos mismas piezas de fontanería. La primera restaura tus suscripciones de datos de mercado después de que se caiga el socket. La segunda ralentiza tus llamadas REST para que el exchange no te limite. Ninguna de las dos es código interesante, las dos son fáciles de hacer sutilmente mal, y hasta ahora las dos quedaban en manos de la aplicación.

sgcWebSockets 2026.7 las incorpora. Los clientes de API de los exchanges pueden reproducir sus propias suscripciones tras una reconexión, y todos los clientes REST ya preparados cuentan ahora con un limitador de peticiones en el cliente que limita cuántas peticiones envías en una ventana de tiempo. Ambos son opcionales y están desactivados por defecto, así que actualizar no cambia nada hasta que los activas.

La reconexión que te deja sin ninguna suscripción

El WatchDog siempre ha sido bueno recuperando la conexión. Alguien desenchufa un cable, un proxy agota su tiempo de espera, el exchange reinicia una pasarela, y unos segundos después el cliente vuelve a estar conectado. Esa parte funciona.

Lo que no vuelve son tus suscripciones. El exchange no guarda memoria de ellas. Un socket nuevo es una sesión en blanco, así que los streams de operaciones y de libro de órdenes que pediste en el socket anterior simplemente ya no existen. El síntoma es desagradable porque nada parece roto: el cliente informa de Connected, no se lanza ningún error, y los eventos de mensaje sencillamente dejan de llegar. Tu gráfico se queda obsoleto en silencio.

La solución habitual es mantener tu propia lista de suscripciones y reproducirla desde OnConnect, lo que implica recordar cada símbolo, cada canal y cada stream que pediste, y acordarte de actualizar esa lista cada vez que te suscribes o te das de baja en cualquier otro punto del código. Es una contabilidad que no tiene nada que ver con tu estrategia.

Activar la resuscripción automática

Los clientes de API ya saben a qué te suscribiste, porque te suscribiste a través de ellos. En 2026.7 pueden conservar esa lista y reproducirla ellos mismos tras una reconexión. Es un único Boolean en el objeto de opciones del exchange, llamado Resubscribe.

Esta es la versión artesanal que tienen hoy la mayoría de las aplicaciones de trading, y lo que la sustituye:

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;

Con Resubscribe activado, el cliente registra cada suscripción a medida que la haces, y después de que el WatchDog recupere el socket las vuelve a enviar en la sesión nueva. Darse de baja elimina la entrada, así que un stream que cerraste deliberadamente no resucita en la siguiente reconexión.

Se combina con el WatchDog en lugar de sustituirlo. El WatchDog restaura el transporte, Resubscribe restaura la sesión encima:

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;

El valor por defecto es False. Las aplicaciones existentes que ya se resuscriben a mano siguen funcionando exactamente igual, sin suscripciones duplicadas, hasta que borras tu propio código y activas la propiedad.

Qué exchanges

Resubscribe está en el objeto de opciones de cada cliente de exchange. Está disponible en Binance, Bitfinex, Bitget, BitMEX, Bitstamp, Bybit, CEX, CEX Plus, Coinbase, Crypto.com, Deribit, Gate.io, Huobi, Kraken, KuCoin, MEXC y OKX, y en el feed de streaming de XTB basado en sesión. La propiedad se escribe siempre igual, así que la línea queda como Coinbase.Resubscribe, Bybit.Resubscribe, OKX.Resubscribe y así sucesivamente, según el componente que hayas puesto en el formulario.

El cliente Lightstreamer, que utilizan IG y otros brókers, hace lo mismo internamente. Tras un rebind de sesión el servidor no tiene registro de las suscripciones anteriores, así que el cliente las reproduce desde su colección local sin que se lo pidas.

Límites de peticiones, desde el lado del cliente

La otra mitad de una aplicación de trading es el lado REST: colocar una orden, cancelar una orden, cargar los saldos, cargar la lista de símbolos. Todos los exchanges publican un presupuesto de peticiones para esos endpoints, normalmente un número de peticiones o un peso por minuto por IP o por clave. Si te pasas recibes un 429, y si sigues pasándote recibes un bloqueo temporal, que es un día mucho peor.

2026.7 añade un limitador de peticiones en el cliente a TsgcHTTPAPI_client, de modo que todos los clientes REST ya preparados lo heredan. Es una ventana deslizante: como mucho MaxRequests peticiones en cualquier ventana de IntervalMs. Lo configuras a partir de las reglas publicadas por el exchange, porque el límite del exchange es el único que importa:

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;

La forma clásica de acabar limitado es la ráfaga del arranque. La aplicación se inicia y se despliega para cargar la lista de símbolos, los saldos, las órdenes abiertas y las últimas velas de cuarenta instrumentos, todo en el primer segundo. Nada de eso es irrazonable, y aun así el exchange lo cuenta como cuarenta peticiones en un segundo. El limitador suaviza exactamente esa forma de tráfico sin que tengas que salpicar tu código de inicialización con llamadas a Sleep.

El limitador se crea de forma perezosa. Si nunca tocas RateLimit, no se reserva ningún objeto y la ruta de las peticiones es byte a byte la que era antes, así que no pagas nada por lo que no usas.

Esperar o rechazar

Cuando el presupuesto de la ventana actual se agota, puedes elegir qué le pasa a la siguiente llamada. Eso es Behavior, y es una decisión de verdad, más que un parámetro de ajuste.

rlbWait, el valor por defecto, bloquea la llamada hasta que se libera un hueco y entonces la envía. Es lo que quieres en un proceso en segundo plano que carga histórico o concilia posiciones. El trabajo tarda un poco más y se completa entero.

rlbReject lanza EsgcHTTPRateLimit de inmediato y no envía nada. Es lo que quieres cuando una petición tardía es peor que ninguna petición. Una orden que llega tres segundos después de que decidieras enviarla puede ser una orden que ya no quieres, y lanzarla a un mercado en movimiento es peor que fallar de forma ruidosa:

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;

Una configuración habitual son los dos, con dos componentes: rlbWait en el componente que hace la carga masiva y rlbReject en el componente que coloca las órdenes, cada uno con su propio presupuesto.

Este no es el limitador del lado del servidor

Conviene ser explícito, porque los nombres se parecen. sgcWebSockets 2026.5 incorporó TsgcWSRateLimiter, que es un limitador del lado del servidor: protege tu servidor de tus clientes, limitando lo que una conexión entrante puede enviarte. El de este artículo apunta en la dirección contraria. Es un limitador del lado del cliente que te protege a ti de los límites de otro, limitando lo que tu aplicación envía a un exchange. Son independientes, y una aplicación que es a la vez servidor y consumidora de un exchange usará encantada los dos.

No solo criptomonedas

RateLimit vive en el cliente HTTP de API base, así que lo heredan todos los clientes REST ya preparados de la librería, no solo los de exchanges. Los clientes de IA tienen límites de peticiones exactamente del mismo tipo, así que OpenAI, Anthropic y Gemini lo reciben, y también Stripe y el resto de integraciones de API. La propiedad está en el mismo sitio con los mismos cuatro ajustes:

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;

Si tu cuenta está en un nivel con un techo bajo de peticiones por minuto, esta es la forma más barata de evitar que un trabajo por lotes en paralelo lo sobrepase.

Disponibilidad

La resuscripción automática y el limitador de peticiones en el cliente están disponibles en sgcWebSockets 2026.7 para Delphi 7 a 13 y C++Builder, en Win32/Win64, Linux64, macOS, Android e iOS. Los dos están desactivados por defecto, así que la actualización es directa.

Los clientes con una suscripción activa pueden descargar la nueva versión desde el área de clientes. Los usuarios de la versión de prueba pueden obtener el instalador actualizado en esegece.com/products/websockets/download.

¿Preguntas, comentarios o ayuda para integrar esto en tu aplicación de trading? Ponte en contacto, recibirás respuesta de las personas que escribieron el código.