# V11b Polymarket Bot — Setup & Infrastructure

## Contexto del problema

El servidor VPS está en **Francia (OVH, IP 51.210.246.110)**. Polymarket bloquea el acceso al
CLOB REST API desde Francia (devuelve HTTP 403 "Trading restricted").

**Lo que SÍ funciona desde el VPS directo:**
- Binance WebSocket (`wss://stream.binance.com`) — sin bloqueo
- Polymarket CLOB WebSocket (`wss://ws-subscriptions-clob.polymarket.com`) — sin bloqueo
- Polymarket Gamma API, Data API (lectura) — sin bloqueo

**Lo que NO funciona desde el VPS directo:**
- Polymarket CLOB REST API (`https://clob.polymarket.com`) — bloqueado (403)
- Colocación de órdenes — bloqueado (403)

**Solución adoptada:** SSH reverse tunnel desde el laptop del usuario en España.
España no está bloqueada (devuelve 401 en lugar de 403 — autenticación, no geo-bloqueo).

---

## Arquitectura del proxy

```
[VPS Francia]
  └─ Bot (python3 -m v11b.main)
       ├─ HTTPS_PROXY=socks5h://127.0.0.1:40001  →  REST API Polymarket (órdenes)
       └─ no_proxy (directo)  →  Binance WS + CLOB WS (no bloqueados)

[Puerto 40001 en VPS]  ←  SSH reverse tunnel  ←  [Laptop España]
                                                      └─ pproxy SOCKS5 en puerto 1080
                                                           └─ Sale por IP española
```

---

## Setup del tunnel (CADA VEZ que se reinicia el laptop)

El tunnel NO es persistente — se cae si el laptop se reinicia o la sesión SSH se corta.
Hay que ejecutar esto en el laptop cada vez:

### Terminal 1 (laptop)
```bash
python3 -m pproxy -l socks5://127.0.0.1:1080
```
Levanta un SOCKS5 server local en el puerto 1080.

### Terminal 2 (laptop)
```bash
ssh -R 40001:127.0.0.1:1080 ubuntu@51.210.246.110 -N -o ServerAliveInterval=30
```
Crea el reverse tunnel: el puerto 40001 del VPS apunta al SOCKS5 del laptop.
No pide contraseña (la clave pública `joan@server` ya está en `~/.ssh/authorized_keys` del VPS).

### Verificar que el tunnel funciona (desde el VPS)
```bash
curl -s --socks5 127.0.0.1:40001 https://ipv4.icanhazip.com
# Debe devolver una IP española (ej: 79.150.74.38)
```

---

## Setup permanente del VPS (ya hecho, no repetir)

### 1. Dependencias Python

```bash
pip install pproxy --break-system-packages         # SOCKS5 server (en el laptop)
pip install socksio --break-system-packages        # httpx necesita esto para SOCKS5
pip install PySocks --break-system-packages        # requests necesita esto para SOCKS5
pip install python-socks --break-system-packages   # websocket-client necesita esto para SOCKS5
```

### 2. /etc/hosts (evitar que Python use IPv6 y salte el proxy)

```
# /etc/hosts — fuerza IPv4 para Polymarket (bypass IPv6 que no va por el proxy)
104.18.34.205 clob.polymarket.com
104.18.34.205 gamma-api.polymarket.com
104.18.34.205 data-api.polymarket.com
104.18.34.205 ws-subscriptions-clob.polymarket.com
```

### 3. SSH config del VPS — habilitar reverse tunnels

Añadido en `/etc/ssh/sshd_config.d/50-cloud-init.conf`:
```
GatewayPorts clientspecified
AllowTcpForwarding yes
```
Recarga: `sudo systemctl reload sshd`

### 4. SSH authorized_keys del VPS

La clave pública del laptop (`joan@server`) está en `/home/ubuntu/.ssh/authorized_keys`.
Esto permite conectar sin contraseña y sin que se corte la sesión.

---

## Multi-wallet (Opción A — thresholds escalonados)

El sistema soporta hasta 4 wallets simultáneos. Cada wallet opera con un threshold
más alto que el anterior, de modo que compiten menos entre sí por el mismo mercado.

### Thresholds por wallet

| Wallet | BTC | ETH | SOL | `--thresh-mult` |
|--------|-----|-----|-----|-----------------|
| w1 | 0.053% | 0.066% | 0.075% | 1.0 (base) |
| w2 | 0.066% | 0.083% | 0.094% | 1.25 |
| w3 | 0.080% | 0.099% | 0.113% | 1.50 |

### Estructura de ficheros

```
v11b/wallets/
├── w1.env          ← wallet activo (credenciales actuales)
├── w2.env          ← nuevo wallet (rellenar y activar)
├── w3.env          ← nuevo wallet (rellenar y activar)
├── template.env    ← plantilla vacía
└── derive_creds.py ← script para derivar API keys desde PK+PROXY
```

### Añadir un wallet nuevo (w2 o w3)

**Paso 1 — Crear el fichero de credenciales:**
```bash
cp /var/www/html/v11b/wallets/template.env /var/www/html/v11b/wallets/w2.env
# Editar w2.env: añadir PK y POLY_PROXY del nuevo wallet
```

**Paso 2 — Derivar las API credentials** (tunnel SSH activo obligatorio):
```bash
cd /var/www/html
python3 v11b/wallets/derive_creds.py --pk 0x<PK_nuevo> --proxy 0x<PROXY_nuevo>
# Copia el output (KEY, SECRET, PASSPHRASE) a w2.env
```

**Paso 3 — Crear logs y activar servicios:**
```bash
mkdir -p /var/www/html/v11b/logs/w2_{btc,eth,sol}_momentum_5m_live
sudo systemctl enable --now v11b-w2-btc v11b-w2-eth v11b-w2-sol
```

**Verificar que w2 arrancó:**
```bash
sudo systemctl status v11b-w2-btc
tail -f /var/www/html/v11b/logs/w2_btc_momentum_5m_live/run.log
```

### Qué necesita cada wallet

- **PK** — clave privada del EOA (signing address)
- **POLY_PROXY** — dirección del proxy wallet que guarda el pUSD
- **API credentials** — se derivan automáticamente con `derive_creds.py`
- **pUSD** — fondos depositados en el proxy wallet en Polygon

---

## Servicios systemd

Los bots corren como servicios systemd. Se inician automáticamente al arrancar el VPS.
**Importante:** el tunnel SSH del proxy hay que levantarlo manualmente desde el laptop.
Sin él, los bots arrancan pero no pueden colocar órdenes (403).

### Servicios disponibles

| Servicio | Wallet | Asset | Thresh-mult |
|----------|--------|-------|-------------|
| `v11b-btc` | w1 | BTC | 1.0 |
| `v11b-eth` | w1 | ETH | 1.0 |
| `v11b-sol` | w1 | SOL | 1.0 |
| `v11b-w2-btc` | w2 | BTC | 1.25 |
| `v11b-w2-eth` | w2 | ETH | 1.25 |
| `v11b-w2-sol` | w2 | SOL | 1.25 |
| `v11b-w3-btc` | w3 | BTC | 1.50 |
| `v11b-w3-eth` | w3 | ETH | 1.50 |
| `v11b-w3-sol` | w3 | SOL | 1.50 |

Los servicios w2 y w3 están creados en `/etc/systemd/system/` pero **no activados** hasta
que se rellene el `.env` correspondiente.

### Ejemplo de servicio (v11b-w2-btc.service)

```ini
[Unit]
Description=Polymarket V11b Bot — BTC 5min (w2)
After=network-online.target wg-quick@wg1.service
Wants=network-online.target wg-quick@wg1.service

[Service]
Environment=PYTHONUNBUFFERED=1
Environment=HTTPS_PROXY=socks5h://127.0.0.1:40001
Environment=HTTP_PROXY=socks5h://127.0.0.1:40001
Environment=no_proxy=stream.binance.com,data-stream.binance.com,api.binance.com,ws-subscriptions-clob.polymarket.com
User=ubuntu
WorkingDirectory=/var/www/html
ExecStart=/bin/bash /var/www/html/v11b/v11b_run.sh btc 5 --live --wallet wallets/w2.env --thresh-mult 1.25
Restart=always
RestartSec=10
StandardOutput=append:/var/www/html/v11b/logs/w2_btc_momentum_5m_live/run.log
StandardError=append:/var/www/html/v11b/logs/w2_btc_momentum_5m_live/run.log

[Install]
WantedBy=multi-user.target
```

### Comandos útiles

```bash
# Estado de todos los bots activos
sudo systemctl status v11b-btc v11b-eth v11b-sol

# Reiniciar w1
sudo systemctl restart v11b-btc v11b-eth v11b-sol

# Reiniciar w2 (cuando esté activo)
sudo systemctl restart v11b-w2-btc v11b-w2-eth v11b-w2-sol

# Logs w1
tail -f /var/www/html/v11b/logs/btc_momentum_5m_live/run.log
tail -f /var/www/html/v11b/logs/eth_momentum_5m_live/run.log
tail -f /var/www/html/v11b/logs/sol_momentum_5m_live/run.log

# Logs w2
tail -f /var/www/html/v11b/logs/w2_btc_momentum_5m_live/run.log

# Estado actual (JSON)
cat /var/www/html/v11b/logs/btc_momentum_5m_live/state.json
```

---

## Routing de red — qué va por el proxy y qué no

| Tráfico | Proxy | Motivo |
|---|---|---|
| `https://clob.polymarket.com` (REST, órdenes) | SÍ — proxy España | Bloqueado desde Francia |
| `https://gamma-api.polymarket.com` | SÍ — proxy España | Por precaución |
| `wss://stream.binance.com` (precio spot) | NO — directo | No bloqueado, proxy rompe WS |
| `wss://ws-subscriptions-clob.polymarket.com` | NO — directo | No bloqueado, proxy rompe WS |

**Regla:** Solo las llamadas REST a Polymarket necesitan el proxy.
Los WebSockets (Binance y CLOB) van directo — no están bloqueados desde Francia.

---

## Señales de que todo funciona correctamente

En el log del bot debes ver:
```
[SIGNAL] YES | move=+0.15% | price=$73,934 vs strike=$73,817 | ask=0.65
[TAKE SENT] MOM YES ...   ← orden colocada OK
```

Si ves esto, el tunnel está activo:
```
[TAKE ERR] MOM YES: PolyApiException[status_code=403 ...]   ← tunnel caído o no iniciado
```

Los ticks normales se ven así (con aY/aN = datos CLOB):
```
[18:03:53] t- 67s | $74,024 | move=-0.0000% | SCANNING | aY=0.77 aN=0.24
```
Si los ticks NO tienen `aY=` y `aN=`, el CLOB WebSocket no está conectado (esperar unos segundos,
se reconecta solo).

---

## Lógica de entrada del bot

El bot entra en una posición cuando:
1. `move_pct > threshold` (0.053% para BTC, 0.066% ETH, 0.075% SOL)
2. El ask del lado a comprar está en rango razonable (no ya priceado al 90%+)
3. Estamos en fase `SCANNING` (no en `WARMUP` ni `CUTOFF`)
4. No hay cooldown activo

Fases de la ventana:
- `WARMUP`: primeros ~30s, espera que el precio se estabilice
- `SCANNING`: ventana de entrada activa (~240s)
- `CUTOFF`: últimos ~60s, ya no entra nuevas posiciones

---

## Wallet y balance

- **Proxy wallet**: `0x81f5b39F51C8ad5119E7e8070FC044F63285154F`
- **Balance**: leído on-chain desde Polygon RPC (`balanceOf` del contrato pUSD)
- **Dashboard**: http://51.210.246.110/v11b/index.html (o `/v11bkalshi/`)

---

## Troubleshooting

### Bot muestra 403 en cada orden
→ El tunnel no está activo. Levantar pproxy + SSH en el laptop.

### Bot atascado en "esperando primer tick de Binance"
→ El Binance WebSocket está fallando. Posiblemente `python-socks` no instalado,
o el `HTTPS_PROXY` está rompiendo el WS de Binance. Verificar:
```bash
pip install python-socks --break-system-packages
# y asegurar que no_proxy incluye stream.binance.com en el servicio systemd
```

### Ticks sin aY/aN (CLOB no conecta)
→ El WebSocket de Polymarket está fallando. Verificar que `ws-subscriptions-clob.polymarket.com`
está en `no_proxy` en el servicio systemd. El WS de Polymarket va DIRECTO (no por proxy).

### ImportError socksio / PySocks
→ El httpx/requests no puede usar el proxy SOCKS5. Instalar:
```bash
pip install socksio PySocks --break-system-packages
```

### VPS reiniciado — ¿qué hay que hacer?
1. Levantar el tunnel desde el laptop (Terminal 1 + Terminal 2 arriba)
2. Los bots arrancan solos vía systemd
3. Verificar con `curl -s --socks5 127.0.0.1:40001 https://ipv4.icanhazip.com` que el tunnel responde
4. Opcionalmente reiniciar los bots: `sudo systemctl restart v11b-btc v11b-eth v11b-sol`

### Un wallet nuevo no arranca / ImportError
→ Verificar que el `.env` tiene todas las claves (PK, PROXY, API_KEY, API_SECRET, API_PASSPHRASE).
→ Ejecutar `derive_creds.py` de nuevo con el tunnel activo si las creds son incorrectas.
