init: estudio_mercados analysis from fn_registry

This commit is contained in:
2026-04-06 00:57:05 +02:00
commit 65460ca942
48 changed files with 1888583 additions and 0 deletions
@@ -0,0 +1,77 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "8b2334dd",
"metadata": {},
"source": [
"# 01 — Descarga Masiva de Datos Historicos (Binance)\n",
"\n",
"Dos metodos para obtener datos historicos:\n",
"\n",
"1. **REST API** (`/api/v3/klines`) — Paginado, max 1000 velas por request. Ideal para 7 dias.\n",
"2. **Data Vision** (`data.binance.vision`) — CSVs comprimidos diarios/mensuales. Ideal para meses/anos.\n",
"\n",
"**Rate limits REST:** 6000 weight/min, klines cuesta 2 weight.\n",
"\n",
"| Endpoint | Max/req | Weight | Uso |\n",
"|---|---|---|---|\n",
"| `/api/v3/klines` | 1000 velas | 2 | Candlesticks OHLCV |\n",
"| `/api/v3/aggTrades` | 1000 trades | 2 | Trades agregados (max 1h window) |\n",
"| `/api/v3/historicalTrades` | 1000 trades | 25 | Trades individuales (requiere API key) |\n",
"| `data.binance.vision` | Sin limite | 0 | CSVs bulk diarios/mensuales |"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3fe45a0a",
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"import time\n",
"import datetime\n",
"import io\n",
"import zipfile\n",
"import pandas as pd\n",
"\n",
"BASE = \"https://api.binance.com\"\n",
"DATA_VISION = \"https://data.binance.vision\""
]
},
{
"cell_type": "markdown",
"id": "721f68a0",
"metadata": {},
"source": [
"## Metodo 1: REST API — Klines con paginacion automatica\n",
"\n",
"`GET /api/v3/klines` devuelve max 1000 velas. Paginamos con `startTime`/`endTime`.\n",
"\n",
"Para 7 dias de velas 1m: ceil(7*24*60/1000) = **11 requests** (22 weight total, trivial)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -0,0 +1,113 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "45f026b5",
"metadata": {},
"source": [
"# 02 — Streaming de Datos en Tiempo Real (Binance WebSocket)\n",
"\n",
"Binance ofrece WebSocket streams push-based para datos de mercado en tiempo real.\n",
"\n",
"**Base URLs:**\n",
"- Produccion: `wss://stream.binance.com:9443/ws/<stream>`\n",
"- Testnet: `wss://testnet.binance.vision/ws/<stream>`\n",
"- Multi-stream: `wss://stream.binance.com:9443/stream?streams=<s1>/<s2>`\n",
"\n",
"**Streams principales:**\n",
"| Stream | Nombre | Frecuencia |\n",
"|---|---|---|\n",
"| Trades individuales | `<symbol>@trade` | Cada trade |\n",
"| Klines en vivo | `<symbol>@kline_<interval>` | Cada cambio en vela |\n",
"| Mini ticker 24h | `<symbol>@miniTicker` | ~1s |\n",
"| Book ticker (best bid/ask) | `<symbol>@bookTicker` | Cada cambio |\n",
"| Todos los tickers | `!miniTicker@arr` | ~1s |\n",
"\n",
"**Reglas de conexion:**\n",
"- Ping cada 3 min desde Binance, pong requerido\n",
"- Desconexion automatica a las 24h — reconectar periodicamente\n",
"- Se puede suscribir/desuscribir dinamicamente via JSON"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6bb48c2e",
"metadata": {},
"outputs": [],
"source": [
"import asyncio\n",
"import json\n",
"import websockets\n",
"import pandas as pd\n",
"from datetime import datetime, timezone\n",
"from collections import deque\n",
"\n",
"WS_BASE = \"wss://stream.binance.com:9443/ws\""
]
},
{
"cell_type": "markdown",
"id": "2b2d9b2d",
"metadata": {},
"source": [
"## Stream de Trades individuales\n",
"\n",
"`<symbol>@trade` — recibe cada trade ejecutado en tiempo real.\n",
"\n",
"Campos clave:\n",
"- `p` = precio, `q` = cantidad\n",
"- `m` = true si el buyer es maker (es decir, fue un sell market order que impacto un bid)\n",
"- `t` = trade ID, `T` = timestamp"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aaed9f77",
"metadata": {},
"outputs": [],
"source": [
"async def stream_trades(symbol: str, max_trades: int = 100) -> list[dict]:\n",
" \"\"\"Captura N trades en tiempo real y retorna como lista.\"\"\"\n",
" url = f\"{WS_BASE}/{symbol.lower()}@trade\"\n",
" trades = []\n",
"\n",
" async with websockets.connect(url) as ws:\n",
" while len(trades) < max_trades:\n",
" msg = json.loads(await ws.recv())\n",
" trades.append({\n",
" \"trade_id\": msg[\"t\"],\n",
" \"time\": datetime.fromtimestamp(msg[\"T\"] / 1000, tz=timezone.utc),\n",
" \"price\": float(msg[\"p\"]),\n",
" \"qty\": float(msg[\"q\"]),\n",
" \"is_buyer_maker\": msg[\"m\"],\n",
" \"side\": \"SELL\" if msg[\"m\"] else \"BUY\",\n",
" })\n",
"\n",
" return trades"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -0,0 +1,119 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "c723d607",
"metadata": {},
"source": [
"# 03 — Libro de Ordenes en Tiempo Real (Binance)\n",
"\n",
"Dos enfoques para mantener un order book local:\n",
"\n",
"### Enfoque A: Partial Book Depth (simple)\n",
"Stream `<symbol>@depth<levels>@100ms` con levels = 5, 10, 20.\n",
"Envia snapshot completo del top N en cada update. Sin logica de sync.\n",
"\n",
"### Enfoque B: Diff Depth + REST Snapshot (completo)\n",
"1. Abrir stream `<symbol>@depth@100ms` (diffs incrementales)\n",
"2. Buffear eventos iniciales\n",
"3. Pedir snapshot REST: `GET /api/v3/depth?symbol=X&limit=1000`\n",
"4. Descartar eventos con `u <= lastUpdateId` del snapshot\n",
"5. Primer evento procesado debe tener `U <= lastUpdateId+1` AND `u >= lastUpdateId+1`\n",
"6. Aplicar: qty > 0 = update nivel, qty = 0 = eliminar nivel\n",
"7. Validar continuidad: cada evento `U` == anterior `u + 1`, si no, re-sync\n",
"\n",
"### Campos del depth update\n",
"```json\n",
"{\n",
" \"U\": 157, \"u\": 160,\n",
" \"b\": [[\"price\", \"qty\"], ...], \n",
" \"a\": [[\"price\", \"qty\"], ...] \n",
"}\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23b19294",
"metadata": {},
"outputs": [],
"source": [
"import asyncio\n",
"import json\n",
"import requests\n",
"import websockets\n",
"from decimal import Decimal\n",
"from collections import deque\n",
"import pandas as pd\n",
"\n",
"BASE = \"https://api.binance.com\"\n",
"WS_BASE = \"wss://stream.binance.com:9443/ws\""
]
},
{
"cell_type": "markdown",
"id": "cff459c9",
"metadata": {},
"source": [
"## Enfoque A: Partial Book Depth (simple, sin sync)\n",
"\n",
"Stream `<symbol>@depth<levels>@100ms` — recibe snapshot completo del top N cada 100ms.\n",
"\n",
"Ideal para monitoreo rapido sin necesidad de mantener estado."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bf70712b",
"metadata": {},
"outputs": [],
"source": [
"async def stream_top_book(symbol: str, levels: int = 10, snapshots: int = 50) -> list[dict]:\n",
" \"\"\"Captura N snapshots del top del order book.\"\"\"\n",
" url = f\"{WS_BASE}/{symbol.lower()}@depth{levels}@100ms\"\n",
" results = []\n",
"\n",
" async with websockets.connect(url) as ws:\n",
" while len(results) < snapshots:\n",
" data = json.loads(await ws.recv())\n",
" best_bid = (float(data[\"bids\"][0][0]), float(data[\"bids\"][0][1]))\n",
" best_ask = (float(data[\"asks\"][0][0]), float(data[\"asks\"][0][1]))\n",
" spread = best_ask[0] - best_bid[0]\n",
" mid = (best_bid[0] + best_ask[0]) / 2\n",
" results.append({\n",
" \"time\": pd.Timestamp.now(tz=\"UTC\"),\n",
" \"best_bid\": best_bid[0], \"bid_qty\": best_bid[1],\n",
" \"best_ask\": best_ask[0], \"ask_qty\": best_ask[1],\n",
" \"spread\": spread, \"spread_bps\": (spread / mid) * 10000,\n",
" \"bids\": [(float(p), float(q)) for p, q in data[\"bids\"]],\n",
" \"asks\": [(float(p), float(q)) for p, q in data[\"asks\"]],\n",
" })\n",
"\n",
" return results"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
@@ -0,0 +1,137 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "c4c1bfe6",
"metadata": {},
"source": [
"# 04 — Trading Programatico (Binance API)\n",
"\n",
"Operaciones de trading via REST API con autenticacion HMAC-SHA256.\n",
"\n",
"**Autenticacion:** Cada request firmado necesita:\n",
"1. Header `X-MBX-APIKEY` con tu API key\n",
"2. Parametro `timestamp` (unix ms, dentro de 5000ms del server)\n",
"3. Parametro `signature` = HMAC-SHA256(query_string, secret_key)\n",
"\n",
"**Endpoints de trading (Spot):**\n",
"| Accion | Metodo | Endpoint | Weight |\n",
"|---|---|---|---|\n",
"| Crear orden | POST | `/api/v3/order` | 1 |\n",
"| Test orden | POST | `/api/v3/order/test` | 1 |\n",
"| Cancelar orden | DELETE | `/api/v3/order` | 1 |\n",
"| Cancelar todas | DELETE | `/api/v3/openOrders` | 1 |\n",
"| Ver orden | GET | `/api/v3/order` | 4 |\n",
"| Ordenes abiertas | GET | `/api/v3/openOrders` | 6 |\n",
"| Cuenta/balances | GET | `/api/v3/account` | 20 |\n",
"| Mis trades | GET | `/api/v3/myTrades` | 20 |\n",
"\n",
"**Tipos de orden:** MARKET, LIMIT (GTC/IOC/FOK), STOP_LOSS_LIMIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER\n",
"\n",
"**TESTNET:** `https://testnet.binance.vision` — mismo API, balances gratis, keys via GitHub login"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "599a54e7",
"metadata": {},
"outputs": [],
"source": [
"import hashlib\n",
"import hmac\n",
"import time\n",
"import math\n",
"import requests\n",
"import pandas as pd\n",
"\n",
"# --- CONFIGURACION ---\n",
"# Para testnet (seguro para pruebas):\n",
"BASE = \"https://testnet.binance.vision\"\n",
"# Para produccion (dinero real):\n",
"# BASE = \"https://api.binance.com\"\n",
"\n",
"# Crea tus keys en https://testnet.binance.vision (login con GitHub)\n",
"API_KEY = \"\" # <-- tu API key aqui\n",
"API_SECRET = \"\" # <-- tu secret aqui"
]
},
{
"cell_type": "markdown",
"id": "acc0b354",
"metadata": {},
"source": [
"## Firma HMAC-SHA256\n",
"\n",
"Toda request autenticada requiere `timestamp` + `signature`. La firma es HMAC del query string completo."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3fa09567",
"metadata": {},
"outputs": [],
"source": [
"def signed_request(method: str, endpoint: str, params: dict | None = None) -> dict:\n",
" \"\"\"Request firmado a Binance API (funciona con testnet y produccion).\"\"\"\n",
" if params is None:\n",
" params = {}\n",
"\n",
" params[\"timestamp\"] = int(time.time() * 1000)\n",
" params[\"recvWindow\"] = 5000\n",
"\n",
" query_string = \"&\".join(f\"{k}={v}\" for k, v in params.items())\n",
" signature = hmac.new(\n",
" API_SECRET.encode(), query_string.encode(), hashlib.sha256\n",
" ).hexdigest()\n",
" params[\"signature\"] = signature\n",
"\n",
" headers = {\"X-MBX-APIKEY\": API_KEY}\n",
"\n",
" if method == \"GET\":\n",
" resp = requests.get(f\"{BASE}{endpoint}\", params=params, headers=headers)\n",
" elif method == \"POST\":\n",
" resp = requests.post(f\"{BASE}{endpoint}\", params=params, headers=headers)\n",
" elif method == \"DELETE\":\n",
" resp = requests.delete(f\"{BASE}{endpoint}\", params=params, headers=headers)\n",
" else:\n",
" raise ValueError(f\"Metodo no soportado: {method}\")\n",
"\n",
" resp.raise_for_status()\n",
" return resp.json()"
]
},
{
"cell_type": "markdown",
"id": "725c3d14",
"metadata": {},
"source": [
"## Consultar informacion del simbolo (filtros de ordenes)\n",
"\n",
"Antes de operar, hay que conocer los filtros: `LOT_SIZE` (min/max qty, step), `PRICE_FILTER` (tick size), `NOTIONAL` (min valor en quote)."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 5
}