This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
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.
Metadata
Release files for ccxt-resilience 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ccxt_resilience-0.1.0.tar.gz | 11.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ccxt_resilience-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 22.3 kB
Release files / ccxt_resilience-0.1.0.tar.gz
| Download URL | ccxt_resilience-0.1.0.tar.gz |
|---|---|
| Size | 11.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b307386a8927598af6a038269c4ddfbfae1b6ec596859ee684c458ce84c850f9
|
|
BLAKE2b-256 checksum How to use checksums |
a2eebefb3078adfce410cdb86579ce61a85174277dea6c6970c50ff5a27fe02b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.
Transparency logRelease files / ccxt_resilience-0.1.0-py3-none-any.whl
| Download URL | ccxt_resilience-0.1.0-py3-none-any.whl |
|---|---|
| Size | 10.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e7e3e2168d9defd4f9d35978bd88fe882d7870fcaf9f8ebde38f8ee0f537dc9b
|
|
BLAKE2b-256 checksum How to use checksums |
52fa3cc74da9ee99fa358ac8d7067d3a27efd082fe413706747d9aba3c269ff6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.
Transparency log