diff --git a/doc/dlob-services.md b/doc/dlob-services.md new file mode 100644 index 0000000..bff964d --- /dev/null +++ b/doc/dlob-services.md @@ -0,0 +1,153 @@ +# Serwisy DLOB na VPS (k3s / `trade-staging`) + +Ten dokument opisuje rolę serwisów “DLOB” uruchomionych w namespace `trade-staging` oraz ich przepływ danych. + +## Czy `dlob-worker` pracuje na VPS? + +Tak — wszystkie serwisy wymienione niżej działają **na VPS** jako Deploymenty w klastrze k3s, w namespace `trade-staging`. + +## Czy na VPS jest GraphQL/WS dla stats i orderbook? + +Tak — **GraphQL wystawia Hasura** (na VPS w k3s), a nie `dlob-server`. + +- Dane L2 i liczone statsy są zapisane do Postgresa jako tabele `dlob_*_latest` i są dostępne przez Hasurę jako GraphQL (query + subscriptions). +- Z zewnątrz korzystamy przez frontend (proxy) pod: + - HTTP: `https://trade.rv32i.pl/graphql` + - WS: `wss://trade.rv32i.pl/graphql` (subskrypcje, protokół `graphql-ws`) + +`dlob-server` wystawia **REST** (np. `/l2`, `/l3`) w klastrze; to jest źródło danych dla workerów albo do debugowania. + +## TL;DR: kto co robi + +### `dlob-worker` +- **Rola:** kolektor L2 + wyliczenie “basic stats”. +- **Wejście:** HTTP L2 z `DLOB_HTTP_URL` (u nas obecnie `https://dlob.drift.trade`, ale można przełączyć na `http://dlob-server:6969`). +- **Wyjście:** upsert do Hasury (Postgres) tabel: + - `dlob_l2_latest` (raw snapshot L2, JSON leveli) + - `dlob_stats_latest` (pochodne: best bid/ask, mid, spread, depth, imbalance, itp.) +- **Częstotliwość:** `DLOB_POLL_MS` (u nas 500 ms). + +### `dlob-slippage-worker` +- **Rola:** symulacja slippage vs rozmiar zlecenia na podstawie L2. +- **Wejście:** czyta z Hasury `dlob_l2_latest` (dla listy rynków). +- **Wyjście:** upsert do Hasury tabeli `dlob_slippage_latest` (m.in. `impact_bps`, `vwap_price`, `worst_price`, `fill_pct`). +- **Częstotliwość:** `DLOB_POLL_MS` (u nas 1000 ms); rozmiary w `DLOB_SLIPPAGE_SIZES_USD`. + +### `dlob-depth-worker` +- **Rola:** metryki “głębokości” w pasmach ±bps wokół mid. +- **Wejście:** czyta z Hasury `dlob_l2_latest`. +- **Wyjście:** upsert do Hasury tabeli `dlob_depth_bps_latest` (per `(market_name, band_bps)`). +- **Częstotliwość:** `DLOB_POLL_MS` (u nas 1000 ms); pasma w `DLOB_DEPTH_BPS_BANDS`. + +### `dlob-publisher` +- **Rola:** utrzymuje “żywy” DLOB na podstawie subskrypcji on-chain i publikuje snapshoty do Redis. +- **Wejście:** Solana RPC/WS (`ENDPOINT`, `WS_ENDPOINT` z secreta `trade-dlob-rpc`), Drift SDK; konfiguracja rynków np. `PERP_MARKETS_TO_LOAD`. +- **Wyjście:** zapis/publish do `dlob-redis` (cache / pubsub / streamy), z którego korzysta serwer HTTP (i ewentualnie WS manager). + +### `dlob-server` +- **Rola:** HTTP API do danych DLOB (np. `/l2`, `/l3`) serwowane z cache Redis. +- **Wejście:** `dlob-redis` + slot subscriber (do oceny “świeżości” danych). +- **Wyjście:** endpoint HTTP w klastrze (Service `dlob-server:6969`), który może być źródłem dla `dlob-worker` (gdy `DLOB_HTTP_URL=http://dlob-server:6969`). + +### `dlob-redis` +- **Rola:** Redis (u nas single-node “cluster mode”) jako **cache i kanał komunikacji** między `dlob-publisher` a `dlob-server`. +- **Uwagi:** to “klej” między komponentami publish/serve; bez niego publisher i server nie współpracują. + +## Jak to się spina (przepływ danych) + +1) `dlob-publisher` (on-chain) → publikuje snapshoty do `dlob-redis`. +2) `dlob-server` → serwuje `/l2` i `/l3` z `dlob-redis` (HTTP w klastrze). +3) `dlob-worker` → pobiera L2 (obecnie z `https://dlob.drift.trade`; opcjonalnie z `dlob-server`) i zapisuje “latest” do Hasury/DB. +4) `dlob-slippage-worker` + `dlob-depth-worker` → liczą agregaty z `dlob_l2_latest` i zapisują do Hasury/DB (pod UI). + +## Co to jest L1 / L2 / L3 (orderbook) + +- `L1` (top-of-book): tylko najlepszy bid i najlepszy ask (czasem też spread). +- `L2` (Level 2): **zagregowane poziomy cenowe** po stronie bid/ask — lista leveli `{ price, size }`, gdzie `size` to suma wolumenu na danej cenie (to jest typowy “orderbook UI” i baza pod spread/depth/imbalance). +- `L3` (Level 3): **niezagregowane, pojedyncze zlecenia** (każde osobno, zwykle z dodatkowymi polami/identyfikatorami). Większy wolumen danych; przydatne do “pro” analiz i debugowania mikrostruktury. + +W tym stacku: +- `dlob-server` udostępnia REST endpointy `/l2` i `/l3`. +- Hasura/DB trzyma “latest” snapshot L2 w `dlob_l2_latest` oraz metryki w `dlob_stats_latest` / `dlob_depth_bps_latest` / `dlob_slippage_latest`. + +## Słownik pojęć (bid/ask/spread i metryki) + +### Podstawy orderbooka + +- **Bid**: zlecenia kupna (chęć kupna). W orderbooku “bid side”. +- **Ask**: zlecenia sprzedaży (chęć sprzedaży). W orderbooku “ask side”. +- **Best bid / best ask**: najlepsza (najwyższa) cena kupna i najlepsza (najniższa) cena sprzedaży na topie księgi (L1). +- **Spread**: różnica pomiędzy `best_ask` a `best_bid`. Im mniejszy spread, tym “taniej” wejść/wyjść (mniej kosztów natychmiastowej realizacji). +- **Mid price**: cena “po środku”: `(best_bid + best_ask) / 2`. Używana jako punkt odniesienia do bps i slippage. +- **Level**: pojedynczy poziom cenowy w L2 (np. `price=100.00`, `size=12.3`). +- **Size**: ilość/płynność na poziomie (zwykle w jednostkach “base asset”). +- **Base / Quote**: + - `base` = instrument bazowy (np. SOL), + - `quote` = waluta wyceny (często USD). + +## Kolory w UI (visualizer) + +- `bid` / “buy side” = zielony (`.pos`, `#22c55e`) +- `ask` / “sell side” = czerwony (`.neg`, `#ef4444`) +- “flat” / brak zmiany = niebieski (`#60a5fa`) — używany m.in. w “brick stack” pod świecami + +### Jednostki i skróty + +- **bps (basis points)**: 1 bps = 0.01% = `0.0001`. Np. 25 bps = 0.25%. +- **USD**: u nas wiele wartości jest przeliczanych do USD (np. `size_base * price`). + +### Metryki “stats” (np. `dlob_stats_latest`) + +- `spread_abs` (USD): `best_ask - best_bid`. +- `spread_bps` (bps): `(spread_abs / mid_price) * 10_000`. +- `depth_levels`: ile leveli (top‑N) z każdej strony braliśmy do liczenia “depth”. +- `depth_bid_base` / `depth_ask_base`: suma `size` po top‑N levelach bid/ask (w base). +- `depth_bid_usd` / `depth_ask_usd`: suma `size_base * price` po top‑N levelach (w USD). +- `imbalance` ([-1..1]): miara asymetrii płynności: + - `(depth_bid_usd - depth_ask_usd) / (depth_bid_usd + depth_ask_usd)` + - >0 = relatywnie więcej płynności po bid, <0 = po ask. +- `oracle_price`: cena z oracla (np. Pyth) jako punkt odniesienia. +- `mark_price`: “mark” z rynku/perp (cena referencyjna dla rozliczeń); różni się od oracle/top-of-book. + +### Metryki “depth bands” (np. `dlob_depth_bps_latest`) + +- `band_bps`: szerokość pasma wokół `mid_price` (np. 5/10/20/50/100/200 bps). +- `bid_usd` / `ask_usd`: płynność po danej stronie, ale **tylko z poziomów mieszczących się w oknie ±`band_bps`** wokół mid. +- `imbalance`: jak wyżej, ale liczony per band. + +### Metryki “slippage” (np. `dlob_slippage_latest`) + +To jest symulacja “gdybym teraz zrobił market order o rozmiarze X” na podstawie L2. + +- `size_usd`: docelowy rozmiar zlecenia w USD. +- `vwap_price`: średnia cena realizacji (Volume Weighted Average Price) dla symulowanego fill. +- `impact_bps`: koszt/odchylenie względem `mid_price` wyrażone w bps (zwykle na bazie `vwap` vs `mid`). +- `worst_price`: najgorsza cena dotknięta podczas “zjadania” kolejnych leveli. +- `filled_usd` / `filled_base`: ile realnie udało się wypełnić (może być < docelowego, jeśli brakuje płynności). +- `fill_pct`: procent wypełnienia (100% = pełny fill). +- `levels_consumed`: ile leveli zostało “zjedzonych” podczas fill. + +### Metadane czasu (“świeżość”) + +- `ts`: timestamp źródła (czas snapshotu). +- `slot`: slot Solany, z którego pochodzi snapshot (monotoniczny “numer czasu” chaina). +- `updated_at`: kiedy nasz worker zapisał/odświeżył rekord w DB (do oceny, czy dane są świeże). + +## Szybka diagnostyka na VPS + +```bash +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n trade-staging get deploy | grep -E 'dlob-(worker|slippage-worker|depth-worker|publisher|server|redis)' +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n trade-staging logs deploy/dlob-worker --tail=80 +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n trade-staging logs deploy/dlob-publisher --tail=80 +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n trade-staging logs deploy/dlob-server --tail=80 +``` + +## Ważna uwaga (źródło L2 w `dlob-worker`) + +Jeśli chcesz, żeby `dlob-worker` polegał na **naszym** stacku (własny RPC + `dlob-publisher` + `dlob-server`), ustaw: + +- `DLOB_HTTP_URL=http://dlob-server:6969` + +Aktualnie w `trade-staging` jest ustawione: + +- `DLOB_HTTP_URL=https://dlob.drift.trade`