binflow 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
binflow-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 nand0san
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
binflow-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,555 @@
1
+ Metadata-Version: 2.4
2
+ Name: binflow
3
+ Version: 0.1.0
4
+ Summary: Persistent WebSocket engine for Binance market data (Spot, USD-M, COIN-M)
5
+ Author: nand0san
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/nand0san/binflow
8
+ Project-URL: Repository, https://github.com/nand0san/binflow
9
+ Project-URL: Issues, https://github.com/nand0san/binflow/issues
10
+ Keywords: binance,websocket,market-data,trading,cryptocurrency,streaming
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Financial and Insurance Industry
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Office/Business :: Financial :: Investment
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: websockets>=13.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=8.0; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # binflow
31
+
32
+ Motor de WebSockets persistente para consumo de datos de mercado en tiempo real desde Binance.
33
+
34
+ Soporta **Spot**, **USD-M Futures** y **COIN-M Futures**. Componente de infraestructura reutilizable que mantiene un cache de mercado vivo en memoria, con reconexion automatica, observabilidad integrada y API sincrona simple.
35
+
36
+ ## Caracteristicas
37
+
38
+ - **Multi-mercado** -- Spot, USD-M Futures y COIN-M Futures con un solo parametro
39
+ - **Streaming en tiempo real** de trades y order book desde Binance
40
+ - **Streams combinados** -- multiplexa cientos de simbolos en pocas conexiones WebSocket
41
+ - **Order books profundos** -- hasta 200 niveles por lado via diff depth stream
42
+ - **Cache en memoria** thread-safe con acceso O(1)
43
+ - **Reconexion automatica** con backoff exponencial y jitter
44
+ - **API sincrona** -- se usa desde codigo Python normal, sin `async`/`await`
45
+ - **Observabilidad** -- estado de streams, metricas, deteccion de degradacion
46
+ - **Logging persistente** -- rotacion por tamano, archivo de errores separado, limites de disco
47
+ - **Shutdown limpio** -- sin tareas pendientes ni warnings
48
+ - **Context manager** -- soporte `with` para manejo automatico del ciclo de vida
49
+ - **Probado bajo carga** -- 728 simbolos simultaneos, 60s, cero gaps en trade IDs
50
+
51
+ ## Instalacion
52
+
53
+ ```bash
54
+ pip install -e .
55
+ ```
56
+
57
+ O con dependencias de desarrollo:
58
+
59
+ ```bash
60
+ pip install -e ".[dev]"
61
+ ```
62
+
63
+ ### Requisitos
64
+
65
+ - Python >= 3.11
66
+ - `websockets >= 13.0`
67
+
68
+ ## Inicio rapido
69
+
70
+ ```python
71
+ import time
72
+ from market_streaming import MarketStreamManager, StreamConfig
73
+
74
+ config = StreamConfig(
75
+ max_recent_trades=500,
76
+ default_order_book_depth=10,
77
+ )
78
+
79
+ with MarketStreamManager(config) as manager:
80
+ manager.add_trade_stream("BTCUSDT")
81
+ manager.add_order_book_stream("BTCUSDT", depth=10)
82
+
83
+ time.sleep(5) # esperar a que lleguen datos
84
+
85
+ # Ultimo trade
86
+ trade = manager.get_last_trade("BTCUSDT")
87
+ if trade:
88
+ print(f"{trade.price} x {trade.quantity}")
89
+
90
+ # Order book
91
+ book = manager.get_order_book("BTCUSDT")
92
+ if book:
93
+ print(f"Mejor bid: {book.bids[0].price}")
94
+ print(f"Mejor ask: {book.asks[0].price}")
95
+
96
+ # Salud del sistema
97
+ print(manager.is_healthy())
98
+ ```
99
+
100
+ ### Streams masivos (cientos de simbolos)
101
+
102
+ Para suscribirse a muchos simbolos a la vez, usar `add_trade_streams()` o `add_order_book_streams()`. Estos metodos multiplexan automaticamente los simbolos en conexiones combinadas (hasta 200 por WebSocket), evitando el rate limit de conexiones de Binance:
103
+
104
+ ```python
105
+ symbols = ["BTCUSDT", "ETHUSDT", "SOLUSDT", ...] # cientos de simbolos
106
+
107
+ with MarketStreamManager(config) as manager:
108
+ # Registra todos los simbolos en pocas conexiones combinadas
109
+ manager.add_trade_streams(symbols)
110
+
111
+ time.sleep(10)
112
+
113
+ for symbol in symbols:
114
+ trade = manager.get_last_trade(symbol)
115
+ if trade:
116
+ print(f"{symbol}: {trade.price}")
117
+ ```
118
+
119
+ ### Order books profundos
120
+
121
+ Para acumular mas de 20 niveles, configurar `default_order_book_depth` > 20. El sistema usara automaticamente el diff depth stream de Binance:
122
+
123
+ ```python
124
+ config = StreamConfig(default_order_book_depth=200)
125
+
126
+ with MarketStreamManager(config) as manager:
127
+ manager.add_order_book_streams(["BTCUSDT", "ETHUSDT"], depth=200)
128
+ time.sleep(60) # acumular niveles
129
+
130
+ book = manager.get_order_book("BTCUSDT")
131
+ print(f"Niveles bid: {len(book.bids)}, ask: {len(book.asks)}")
132
+ ```
133
+
134
+ > **Nota**: profundidades de 5, 10 y 20 usan el Partial Book Depth Stream (snapshots completos). Cualquier otro valor usa el Diff Depth Stream (actualizaciones incrementales), que acumula niveles con el tiempo.
135
+
136
+ ### Futuros USD-M
137
+
138
+ ```python
139
+ from market_streaming import MarketStreamManager, StreamConfig, Market
140
+
141
+ config = StreamConfig(market=Market.FUTURES_USD)
142
+
143
+ with MarketStreamManager(config) as manager:
144
+ manager.add_trade_stream("BTCUSDT")
145
+ manager.add_order_book_stream("BTCUSDT")
146
+ # ...
147
+ ```
148
+
149
+ ### Futuros COIN-M
150
+
151
+ ```python
152
+ from market_streaming import StreamConfig, Market
153
+
154
+ config = StreamConfig(market=Market.FUTURES_COIN)
155
+ # Los pares de COIN-M usan formato distinto (ej: BTCUSD_PERP)
156
+ ```
157
+
158
+ ## API publica
159
+
160
+ ### MarketStreamManager
161
+
162
+ Fachada principal del sistema. Gestiona streams, expone datos del cache y metricas.
163
+
164
+ #### Ciclo de vida
165
+
166
+ | Metodo | Descripcion |
167
+ |--------|-------------|
168
+ | `start()` | Arranca el motor en un thread dedicado |
169
+ | `stop()` | Detiene todos los streams y libera recursos |
170
+
171
+ Soporta context manager (`with MarketStreamManager(config) as mgr:`).
172
+
173
+ #### Registro de streams individuales
174
+
175
+ | Metodo | Descripcion |
176
+ |--------|-------------|
177
+ | `add_trade_stream(symbol)` | Suscribe al stream de trades de un simbolo |
178
+ | `add_order_book_stream(symbol, depth=20)` | Suscribe al stream de profundidad de un simbolo |
179
+ | `remove_stream(stream_id)` | Detiene y elimina un stream |
180
+
181
+ Cada metodo devuelve un `stream_id` (ej: `trade_BTCUSDT`, `depth_BTCUSDT`).
182
+
183
+ #### Registro de streams masivos (combinados)
184
+
185
+ | Metodo | Descripcion |
186
+ |--------|-------------|
187
+ | `add_trade_streams(symbols, batch_size=200)` | Registra trades para multiples simbolos en conexiones combinadas |
188
+ | `add_order_book_streams(symbols, depth=None, batch_size=200)` | Registra order books para multiples simbolos en conexiones combinadas |
189
+
190
+ Estos metodos crean `CombinedStreamWorker`s que multiplexan hasta `batch_size` simbolos por conexion WebSocket usando el endpoint `/stream?streams=...` de Binance. Devuelven una lista de worker IDs.
191
+
192
+ #### Consulta de datos
193
+
194
+ | Metodo | Retorno |
195
+ |--------|---------|
196
+ | `get_last_trade(symbol)` | `Trade` o `None` |
197
+ | `get_recent_trades(symbol, limit=100)` | `list[Trade]` |
198
+ | `get_order_book(symbol)` | `OrderBookSnapshot` o `None` |
199
+
200
+ Los simbolos son case-insensitive: `"btcusdt"` y `"BTCUSDT"` son equivalentes.
201
+
202
+ #### Observabilidad
203
+
204
+ | Metodo | Descripcion |
205
+ |--------|-------------|
206
+ | `get_stream_status(stream_id)` | Estado de un stream individual |
207
+ | `get_all_streams_status()` | Estado de todos los streams |
208
+ | `get_health()` | Diagnostico de salud global (`SystemHealth`) |
209
+ | `get_stats()` | Estadisticas resumidas (dict) |
210
+ | `is_healthy()` | `True` si todos los streams estan sanos |
211
+ | `print_summary()` | Imprime resumen por logging |
212
+
213
+ ### Modelos de datos
214
+
215
+ #### Trade
216
+
217
+ ```python
218
+ @dataclass(frozen=True)
219
+ class Trade:
220
+ symbol: str # par de trading (ej: "BTCUSDT")
221
+ trade_id: int # ID unico del trade en Binance
222
+ price: float # precio de ejecucion
223
+ quantity: float # cantidad ejecutada
224
+ quote_quantity: float # cantidad en moneda cotizada
225
+ buyer_maker: bool # True si el comprador es el maker (trade = venta)
226
+ timestamp_ms: int # timestamp del trade en milisegundos
227
+ price_str: str # precio como cadena original (precision completa)
228
+ quantity_str: str # cantidad como cadena original
229
+ quote_quantity_str: str
230
+ is_best_match: bool # solo Spot
231
+ event_time_ms: int # timestamp del evento WebSocket
232
+ ```
233
+
234
+ Incluye `to_rest_format()` que devuelve un dict compatible con GET /api/v3/trades.
235
+
236
+ #### OrderBookSnapshot
237
+
238
+ ```python
239
+ @dataclass
240
+ class OrderBookSnapshot:
241
+ symbol: str
242
+ bids: list[OrderBookLevel] # ordenados precio descendente (mejor bid primero)
243
+ asks: list[OrderBookLevel] # ordenados precio ascendente (mejor ask primero)
244
+ last_update_id: int # ID de la ultima actualizacion aplicada
245
+ timestamp: float # time.time() de la ultima actualizacion
246
+ event_time_ms: int
247
+ transaction_time_ms: int
248
+ ```
249
+
250
+ #### OrderBookLevel
251
+
252
+ ```python
253
+ @dataclass(frozen=True)
254
+ class OrderBookLevel:
255
+ price: float
256
+ quantity: float
257
+ price_str: str # cadena original de Binance
258
+ quantity_str: str
259
+ ```
260
+
261
+ Incluye `to_rest_format()` que devuelve `[price_str, quantity_str]` compatible con la REST API.
262
+
263
+ #### StreamState
264
+
265
+ Estados posibles de un stream:
266
+
267
+ | Estado | Significado |
268
+ |--------|-------------|
269
+ | `starting` | Iniciando conexion |
270
+ | `running` | Conectado y recibiendo datos |
271
+ | `reconnecting` | Reconectando tras un error |
272
+ | `stale` | Conectado pero sin datos recientes |
273
+ | `stopped` | Detenido de forma limpia |
274
+ | `failed` | Error fatal, no reconectable |
275
+
276
+ #### SystemHealth
277
+
278
+ ```python
279
+ @dataclass
280
+ class SystemHealth:
281
+ is_healthy: bool # True si todos los streams estan sanos
282
+ total_streams: int
283
+ running_streams: int
284
+ stale_streams: int
285
+ reconnecting_streams: int
286
+ stopped_streams: int
287
+ uptime_s: float # segundos desde el arranque
288
+ total_messages: int # total de mensajes procesados
289
+ stream_details: dict[str, StreamStatus]
290
+ ```
291
+
292
+ ## Configuracion
293
+
294
+ Toda la configuracion se centraliza en `StreamConfig`:
295
+
296
+ ```python
297
+ from market_streaming import StreamConfig, Market
298
+
299
+ config = StreamConfig(
300
+ # Mercado (default: Spot)
301
+ market=Market.SPOT, # SPOT | FUTURES_USD | FUTURES_COIN
302
+ # base_url="wss://...", # si se pasa, tiene prioridad sobre market
303
+
304
+ # Conexion
305
+ ping_interval_s=20.0,
306
+ ping_timeout_s=10.0,
307
+
308
+ # Cache
309
+ max_recent_trades=1000,
310
+ default_order_book_depth=20, # >20 usa diff depth stream
311
+
312
+ # Reconexion
313
+ reconnect_base_delay_s=1.0,
314
+ reconnect_max_delay_s=60.0,
315
+ reconnect_jitter_factor=0.2,
316
+ max_reconnect_attempts=0, # 0 = sin limite
317
+
318
+ # Health
319
+ stale_threshold_s=30.0,
320
+
321
+ # Logging
322
+ log_level=logging.INFO,
323
+ log_dir="logs",
324
+ log_max_bytes=10 * 1024 * 1024, # 10 MB por archivo
325
+ log_backup_count=5, # max 5 archivos rotados
326
+ )
327
+ ```
328
+
329
+ ### Mercados soportados
330
+
331
+ | Market | URL WebSocket | Ejemplo de par |
332
+ |--------|---------------|----------------|
333
+ | `Market.SPOT` | `wss://stream.binance.com:9443/ws` | `BTCUSDT` |
334
+ | `Market.FUTURES_USD` | `wss://fstream.binance.com/ws` | `BTCUSDT` |
335
+ | `Market.FUTURES_COIN` | `wss://dstream.binance.com/ws` | `BTCUSD_PERP` |
336
+
337
+ Todos los campos tienen valores por defecto razonables. `StreamConfig()` sin argumentos conecta a Spot.
338
+
339
+ ## Logging
340
+
341
+ El sistema genera dos archivos de log con rotacion automatica:
342
+
343
+ | Archivo | Nivel | Uso |
344
+ |---------|-------|-----|
345
+ | `binflow.log` | DEBUG+ | Analisis completo, debug, tracing |
346
+ | `binflow.error.log` | WARNING+ | Deteccion rapida de fallos e interrupciones |
347
+
348
+ ### Rotacion y limites de disco
349
+
350
+ - Cada archivo rota al alcanzar `log_max_bytes` (default: 10 MB)
351
+ - Se mantienen como maximo `log_backup_count` archivos rotados (default: 5)
352
+ - Espacio maximo en disco: ~120 MB (2 archivos x 6 versiones x 10 MB)
353
+ - Los archivos rotados se nombran `binflow.log.1`, `binflow.log.2`, etc.
354
+
355
+ ### Formato de archivo
356
+
357
+ ```
358
+ 2026-03-06 20:15:32 | INFO | market_streaming.worker:_connect_and_consume:178 | Stream trade_BTCUSDT: conexion establecida
359
+ 2026-03-06 20:15:33 | WARNING | market_streaming.worker:_run:123 | Error en stream depth_BTCUSDT (intento 1): [Errno 111] Connection refused
360
+ ```
361
+
362
+ ### Configuracion de logging
363
+
364
+ ```python
365
+ import logging
366
+ from market_streaming import StreamConfig
367
+
368
+ # Produccion: solo errores en consola, todo en disco
369
+ config = StreamConfig(
370
+ log_level=logging.ERROR,
371
+ log_dir="logs",
372
+ log_max_bytes=10 * 1024 * 1024,
373
+ log_backup_count=5,
374
+ )
375
+
376
+ # Desarrollo: verbose en consola, sin disco
377
+ config = StreamConfig(
378
+ log_level=logging.DEBUG,
379
+ log_dir="", # desactiva archivos en disco
380
+ )
381
+
382
+ # Directorio personalizado
383
+ config = StreamConfig(log_dir="/var/log/binflow")
384
+ ```
385
+
386
+ ## Arquitectura
387
+
388
+ ```
389
+ MarketStreamManager API publica sincrona (fachada)
390
+ |
391
+ +-- threading.Thread Thread dedicado con event loop asyncio
392
+ | |
393
+ | +-- WebSocketStreamWorker (trade_BTCUSDT) 1 simbolo / conexion
394
+ | +-- WebSocketStreamWorker (depth_BTCUSDT) 1 simbolo / conexion
395
+ | +-- CombinedStreamWorker (combined_trades_0) hasta 200 simbolos / conexion
396
+ | +-- CombinedStreamWorker (combined_depth_0) hasta 200 simbolos / conexion
397
+ | +-- ...
398
+ |
399
+ +-- MarketDataCache Cache en memoria (threading.Lock)
400
+ |
401
+ +-- HealthMonitor Evaluacion de salud
402
+ |
403
+ +-- Logging RotatingFileHandler (general + errores)
404
+ ```
405
+
406
+ ### Workers
407
+
408
+ | Worker | Uso | Conexiones |
409
+ |--------|-----|-----------|
410
+ | `WebSocketStreamWorker` | 1 simbolo por conexion (`add_trade_stream`, `add_order_book_stream`) | 1 WS por stream |
411
+ | `CombinedStreamWorker` | Hasta 200 simbolos por conexion (`add_trade_streams`, `add_order_book_streams`) | 1 WS por batch |
412
+
413
+ Los workers combinados usan el endpoint `/stream?streams=sym1@trade/sym2@trade/...` de Binance y desenvuelven el formato `{stream, data}` de los mensajes.
414
+
415
+ ### Modelo de concurrencia
416
+
417
+ El sistema usa un **thread dedicado con event loop asyncio**:
418
+
419
+ - **API publica sincrona**: el codigo cliente llama `manager.start()`, `manager.get_last_trade()`, etc. sin `await`. Esto permite usar el motor desde cualquier contexto Python.
420
+ - **Event loop interno**: un thread daemon ejecuta el loop asyncio donde corren todos los workers WebSocket de forma concurrente.
421
+ - **Cache thread-safe**: `threading.Lock` protege las escrituras (desde el thread asyncio) y las lecturas (desde el thread principal). El contention es despreciable porque las operaciones son O(1).
422
+
423
+ ### Reconexion
424
+
425
+ Cada worker gestiona su propia reconexion:
426
+
427
+ 1. Error de conexion o desconexion detectada
428
+ 2. Backoff exponencial: `min(base * 2^n, max_delay)`
429
+ 3. Jitter aleatorio de +-20% sobre el delay calculado
430
+ 4. Contador de reconexiones incrementado
431
+ 5. Si se supera `max_reconnect_attempts` (y no es 0), el stream pasa a `failed`
432
+ 6. Errores fatales (ej: stream invalido) no reconectan
433
+
434
+ ### Depth streams
435
+
436
+ | Profundidad | Stream | Tipo de mensaje |
437
+ |-------------|--------|-----------------|
438
+ | 5, 10, 20 | `symbol@depth{N}` (Partial Book Depth) | Snapshots completos cada ~1s |
439
+ | Cualquier otro valor | `symbol@depth` (Diff Depth) | Actualizaciones incrementales |
440
+
441
+ El diff depth stream acumula niveles con el tiempo. Para un order book completo desde el primer momento, usar profundidades de 5, 10 o 20.
442
+
443
+ ### Cache en memoria
444
+
445
+ | Dato | Estructura | Acceso |
446
+ |------|-----------|--------|
447
+ | Ultimo trade por simbolo | `dict[symbol, Trade]` | O(1) |
448
+ | Trades recientes por simbolo | `dict[symbol, deque(maxlen=N)]` | O(1) amortizado |
449
+ | Order book por simbolo | `dict[symbol, OrderBookSnapshot]` | O(1) |
450
+
451
+ El order book soporta tanto snapshots completos como actualizaciones incrementales con eliminacion de niveles con cantidad cero.
452
+
453
+ ## Estructura del proyecto
454
+
455
+ ```
456
+ market_streaming/
457
+ __init__.py Re-exports de la API publica
458
+ config.py StreamConfig, Market, MARKET_URLS
459
+ models.py Trade, OrderBookSnapshot, StreamStatus, SystemHealth
460
+ exceptions.py Excepciones del dominio
461
+ cache.py MarketDataCache
462
+ worker.py WebSocketStreamWorker, CombinedStreamWorker
463
+ health.py HealthMonitor
464
+ manager.py MarketStreamManager
465
+ logging_config.py Setup de logging con rotacion
466
+ tests/
467
+ test_cache.py 18 tests - trades, order book, continuidad
468
+ test_models.py 16 tests - inmutabilidad, defaults, config, mercados
469
+ test_health.py 8 tests - deteccion stale, salud global
470
+ test_worker.py 12 tests - URLs por mercado, parsing mensajes, backoff
471
+ test_manager.py 13 tests - lifecycle, streams, observabilidad
472
+ test_logging.py 13 tests - handlers, rotacion, archivos, teardown
473
+ test_load.py 8 tests - carga: 728 symbols trades, 60s
474
+ test_load_orderbook.py 13 tests - carga: 728 symbols order books profundos
475
+ examples/
476
+ inspect_trade.py Estructura del Trade: campos, tipos, precision, formato REST
477
+ inspect_order_book.py OrderBookSnapshot: estructura, niveles, formato REST
478
+ inspect_config.py StreamConfig: campos, Market enum, URLs (sin conexion)
479
+ inspect_health.py SystemHealth, StreamStatus, StreamState
480
+ live_trades.py Feed de trades en tiempo real
481
+ live_order_book.py Order book visual con barras de volumen y spread
482
+ multi_market.py Tabla comparativa multi-simbolo en tiempo real
483
+ notebooks/
484
+ streaming_demo.ipynb Demo completa: stream, inspeccion, acumulacion, verificacion
485
+ ```
486
+
487
+ ## Ejemplos
488
+
489
+ Todos los ejemplos se ejecutan con `python examples/<nombre>.py`.
490
+
491
+ ### Inspeccion de datos (sin conexion)
492
+
493
+ ```bash
494
+ python examples/inspect_trade.py # estructura Trade
495
+ python examples/inspect_order_book.py # estructura OrderBookSnapshot
496
+ python examples/inspect_config.py # StreamConfig, Market, URLs
497
+ python examples/inspect_health.py # SystemHealth, StreamStatus
498
+ ```
499
+
500
+ ### Streams en vivo
501
+
502
+ ```bash
503
+ python examples/live_trades.py # feed de trades BTCUSDT en tiempo real
504
+ python examples/live_order_book.py # order book visual con spread
505
+ python examples/multi_market.py # tabla comparativa multi-simbolo
506
+ ```
507
+
508
+ ### Notebook
509
+
510
+ ```bash
511
+ jupyter notebook notebooks/streaming_demo.ipynb
512
+ ```
513
+
514
+ Demo interactiva: arranque, inspeccion, acumulacion de 2 minutos con verificacion de continuidad, estadisticas y shutdown limpio.
515
+
516
+ ## Tests
517
+
518
+ ```bash
519
+ # Ejecutar todos los tests unitarios (83 tests, <1s)
520
+ pytest tests/ --ignore=tests/test_load.py --ignore=tests/test_load_orderbook.py -v
521
+
522
+ # Tests de carga contra Binance real (~70s cada uno)
523
+ pytest tests/test_load.py -v -s # 728 symbols, trades, 60s
524
+ pytest tests/test_load_orderbook.py -v -s # 728 symbols, depth 200, 60s
525
+
526
+ # Todos los tests (102 tests)
527
+ pytest tests/ -v -s
528
+
529
+ # Un test especifico
530
+ pytest tests/test_cache.py::TestTradeCache::test_trade_ids_continuous -v
531
+ ```
532
+
533
+ ### Pruebas de carga
534
+
535
+ Los tests de carga (`test_load.py`, `test_load_orderbook.py`) conectan a Binance real y verifican:
536
+
537
+ - **Continuidad**: trade IDs consecutivos sin huecos
538
+ - **Unicidad**: cero duplicados
539
+ - **Orden**: IDs estrictamente crecientes
540
+ - **Timestamps**: no decrecientes
541
+ - **Profundidad**: order books de hasta 200 niveles por lado
542
+ - **Integridad estructural**: bids descendentes, asks ascendentes, spread positivo
543
+ - **Precision**: cadenas originales de Binance preservadas
544
+ - **Estabilidad**: todos los workers running, cero reconexiones
545
+
546
+ ## Limitaciones
547
+
548
+ - No implementa el flujo completo de sincronizacion del order book de Binance (REST snapshot + WebSocket diff). Para profundidades > 20, el diff depth stream acumula niveles incrementalmente sin snapshot REST inicial.
549
+ - No persiste datos en disco. Si el proceso muere, se pierde el cache.
550
+ - Las metricas son in-process. No hay exportacion a Prometheus, StatsD u otros sistemas externos.
551
+ - No implementa autenticacion para streams privados (user data streams).
552
+
553
+ ## Licencia
554
+
555
+ MIT