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:
- Falsos positivos del WAF. Muchos exchanges ponen Cloudflare delante de su
REST y, a ratos, challenguean con
403a peticiones perfectamente válidas de tu propia cuenta. - 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
403de 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b307386a8927598af6a038269c4ddfbfae1b6ec596859ee684c458ce84c850f9
|
|
| MD5 |
26ea778736875aa725bacfb7693c8926
|
|
| BLAKE2b-256 |
a2eebefb3078adfce410cdb86579ce61a85174277dea6c6970c50ff5a27fe02b
|
Provenance
The following attestation bundles were made for ccxt_resilience-0.1.0.tar.gz:
Publisher:
publish.yml on isazajuancarlos/ccxt-resilience
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ccxt_resilience-0.1.0.tar.gz -
Subject digest:
b307386a8927598af6a038269c4ddfbfae1b6ec596859ee684c458ce84c850f9 - Sigstore transparency entry: 2191913747
- Sigstore integration time:
-
Permalink:
isazajuancarlos/ccxt-resilience@7c4c9461a2bcd6ae08a9fa546ccf04a9e4d93290 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/isazajuancarlos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7c4c9461a2bcd6ae08a9fa546ccf04a9e4d93290 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7e3e2168d9defd4f9d35978bd88fe882d7870fcaf9f8ebde38f8ee0f537dc9b
|
|
| MD5 |
5cc8513f64cfcf20b8eaeb1c299f1e1b
|
|
| BLAKE2b-256 |
52fa3cc74da9ee99fa358ac8d7067d3a27efd082fe413706747d9aba3c269ff6
|
Provenance
The following attestation bundles were made for ccxt_resilience-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on isazajuancarlos/ccxt-resilience
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ccxt_resilience-0.1.0-py3-none-any.whl -
Subject digest:
e7e3e2168d9defd4f9d35978bd88fe882d7870fcaf9f8ebde38f8ee0f537dc9b - Sigstore transparency entry: 2191913753
- Sigstore integration time:
-
Permalink:
isazajuancarlos/ccxt-resilience@7c4c9461a2bcd6ae08a9fa546ccf04a9e4d93290 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/isazajuancarlos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7c4c9461a2bcd6ae08a9fa546ccf04a9e4d93290 -
Trigger Event:
push
-
Statement type: