Skip to main content

Endurece un cliente ccxt legítimo contra falsos positivos de WAF (Cloudflare) y errores transitorios: retry selectivo con backoff + jitter y hardening de cabeceras.

Project description

ccxt-resilience

Endurece un cliente ccxt legítimo contra dos molestias reales de operar contra un exchange:

  1. Falsos positivos del WAF. Muchos exchanges ponen Cloudflare delante de su REST y, a ratos, challenguean con 403 a peticiones perfectamente válidas de tu propia cuenta.
  2. Errores transitorios de red (429, timeouts, ExchangeNotAvailable) que se curan solos si esperas un momento y reintentas.

Son dos herramientas pequeñas y sin estado, que puedes usar por separado.

Alcance y ética. Esto endurece tu cuenta contra la API oficial del exchange: mitiga falsos positivos del WAF sobre un cliente legítimo. No evade control de acceso ni resuelve challenges — si el WAF insiste, el error se re-lanza. Nació de un bot de trading propio sobre OKX tras varias rachas de 403 de Cloudflare, y se extrajo como librería. La técnica es genérica a cualquier exchange ccxt detrás de un WAF; el ajuste fino está probado contra OKX.

Instalación

pip install ccxt-resilience          # ccxt es opcional
pip install "ccxt-resilience[ccxt]"  # trae ccxt para clasificar por tipo de excepción

ccxt es una dependencia blanda: sin él la librería funciona clasificando los errores por el mensaje; con él, además reconoce los tipos de excepción de ccxt (DDoSProtection, RequestTimeout, …).

Uso

1. harden — que el WAF challengue menos

import ccxt
from ccxt_resilience import harden

exchange = harden(ccxt.okx({
    "apiKey": ...,
    "secret": ...,
    "password": ...,
}))

harden ajusta un User-Agent de navegador, la cabecera Accept-Language y un timeout mínimo holgado sobre un cliente ya construido. Devuelve el mismo objeto (encadenable) y nunca rompe la construcción del exchange.

2. with_retry — reintentar solo lo que se debe

from ccxt_resilience import with_retry

# Reintenta ante 403/Cloudflare/DDoS/timeout con backoff exponencial + jitter.
balance = with_retry(exchange.fetch_balance)

# Con argumentos y parámetros propios:
ohlcv = with_retry(exchange.fetch_ohlcv, "BTC/USDT", timeframe="1m",
                   attempts=4, base=1.0, max_s=8.0)

Lo importante es lo que no reintenta: un error de autenticación, de fondos o de lógica se re-lanza en el acto. Reintentar un fallo real solo gasta tiempo y enmascara el problema. Y si se agotan los intentos, se re-lanza la última excepción, para que tu try/except de fail-safe siga gobernando.

Backoff: la espera del intento i es min(max_s, base * 2**i) + rand()*base.

También como decorador:

from ccxt_resilience import retry

@retry(attempts=4)
def fetch_balance():
    return exchange.fetch_balance()

Otras APIs (no solo exchanges)

with_retry acepta tu propio predicado de reintento:

with_retry(mi_llamada, is_retryable=lambda e: "boom" in str(e))

Configuración

Los defaults (attempts=3, base=1.0 s, max_s=6.0 s) se pasan por argumento en cada llamada; no hay estado global. El User-Agent, Accept-Language y el timeout mínimo de harden también son argumentos.

Por qué reintentar de forma selectiva

Un retry que reintenta cualquier excepción es una trampa: convierte un error de credenciales en una espera de 30 segundos que termina igual de mal, y esconde bugs de lógica detrás de reintentos. Aquí la clasificación (is_transient_error) es explícita, inspeccionable y sustituible.

Tests

pip install "ccxt-resilience[test]"
pytest

17 tests, sin red y sin dormir de verdad (_sleep/_rand inyectados): el backoff es determinista. Portados del bot que originó la librería —donde probaron la matemática exacta del backoff en producción— y ampliados.

Licencia

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ccxt_resilience-0.1.0.tar.gz (11.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ccxt_resilience-0.1.0-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file ccxt_resilience-0.1.0.tar.gz.

File metadata

  • Download URL: ccxt_resilience-0.1.0.tar.gz
  • Upload date:
  • Size: 11.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ccxt_resilience-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b307386a8927598af6a038269c4ddfbfae1b6ec596859ee684c458ce84c850f9
MD5 26ea778736875aa725bacfb7693c8926
BLAKE2b-256 a2eebefb3078adfce410cdb86579ce61a85174277dea6c6970c50ff5a27fe02b

See more details on using hashes here.

Provenance

The following attestation bundles were made for ccxt_resilience-0.1.0.tar.gz:

Publisher: publish.yml on isazajuancarlos/ccxt-resilience

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ccxt_resilience-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: ccxt_resilience-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for ccxt_resilience-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e7e3e2168d9defd4f9d35978bd88fe882d7870fcaf9f8ebde38f8ee0f537dc9b
MD5 5cc8513f64cfcf20b8eaeb1c299f1e1b
BLAKE2b-256 52fa3cc74da9ee99fa358ac8d7067d3a27efd082fe413706747d9aba3c269ff6

See more details on using hashes here.

Provenance

The following attestation bundles were made for ccxt_resilience-0.1.0-py3-none-any.whl:

Publisher: publish.yml on isazajuancarlos/ccxt-resilience

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page