docs(snapshot): sync workspace documentation
This commit is contained in:
184
dlob-basics.md
Normal file
184
dlob-basics.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# DLOB + L1…L10 — podstawy (co jest czym i gdzie to liczymy)
|
||||
|
||||
Ten dokument wyjaśnia pojęcia:
|
||||
- **DLOB** (Drift Limit Order Book),
|
||||
- **L1 / L2 / L3** oraz potoczne **L1…L10**,
|
||||
- na jakich warstwach w naszym stacku powstają dane i metryki,
|
||||
- gdzie “pracuje AI” (modele/strategie) vs gdzie jest execution (order placement).
|
||||
|
||||
## Co to jest DLOB
|
||||
|
||||
**DLOB** = *Decentralized Limit Order Book* w Drift.
|
||||
|
||||
W praktyce: to jest **księga zleceń** dla rynku (np. `SOL-PERP`):
|
||||
- **bids** = zlecenia kupna (po stronie bid),
|
||||
- **asks** = zlecenia sprzedaży (po stronie ask).
|
||||
|
||||
Księga ma wiele “poziomów” cenowych; przy każdej cenie stoi pewna ilość (size).
|
||||
|
||||
## L1 / L2 / L3 (format i sens)
|
||||
|
||||
### L1 (Top of Book)
|
||||
L1 to skrót od “top of book”:
|
||||
- **best bid** = najwyższa cena kupna (pierwszy poziom po stronie bid),
|
||||
- **best ask** = najniższa cena sprzedaży (pierwszy poziom po stronie ask).
|
||||
|
||||
Z L1 najczęściej liczysz:
|
||||
- **spread** = `best_ask - best_bid`,
|
||||
- **mid** = `(best_bid + best_ask) / 2`.
|
||||
|
||||
### L2 (zagregowane poziomy)
|
||||
L2 to lista poziomów (levels) po obu stronach:
|
||||
- `bids: [{ price, size }, ...]` (zwykle posortowane malejąco po `price`)
|
||||
- `asks: [{ price, size }, ...]` (zwykle posortowane rosnąco po `price`)
|
||||
|
||||
To jest najpopularniejszy “orderbook UI”: słupki/heat per poziom ceny.
|
||||
|
||||
### L3 (pojedyncze zlecenia)
|
||||
L3 to “niezagregowane” dane: pojedyncze zlecenia (większy wolumen danych).
|
||||
U nas pod UI i metryki zazwyczaj wystarcza L2.
|
||||
|
||||
## L1…L10 (co to znaczy w praktyce)
|
||||
|
||||
**L1…L10** to potoczne określenie:
|
||||
> “pierwsze 10 poziomów z L2 najbliżej top of book”.
|
||||
|
||||
To nie jest osobny format; to po prostu wycinek L2.
|
||||
|
||||
W naszym stacku “ile leveli bierzemy” kontroluje:
|
||||
- `DLOB_DEPTH` (np. 10 → “L1…L10”).
|
||||
|
||||
## Jak to działa w naszym stacku (warstwy)
|
||||
|
||||
Poniżej aktualny łańcuch od źródła do metryk w live runtime:
|
||||
|
||||
### Warstwa A: On-chain → DLOB w pamięci (VPS/k3s)
|
||||
Komponenty: `dlob-publisher-hot` i `dlob-publisher-all`.
|
||||
|
||||
- Łączą się do Solany przez prywatny RPC/WS/gRPC.
|
||||
- Budują DLOB w pamięci.
|
||||
- Publikują snapshoty do Redis:
|
||||
- `dlob-hot:*`
|
||||
- `dlob-all:*`
|
||||
|
||||
To jest najbliżej źródła i najbardziej “real-time”.
|
||||
|
||||
### Warstwa B: Redis → PostgreSQL (VPS/k3s)
|
||||
Komponenty:
|
||||
|
||||
- `dlob-hot-redis-to-postgres-raw-writer`
|
||||
- `dlob-hot-postgres-to-postgres-derived-writer`
|
||||
- `dlob-all-redis-to-postgres-derived-writer`
|
||||
|
||||
Ten etap:
|
||||
|
||||
- utrwala raw `hot` w PostgreSQL,
|
||||
- buduje derived layer `hot` i `all`,
|
||||
- zapisuje znormalizowane poziomy orderbooka oraz metryki top-of-book do tabel `dlob_*_derived_*`.
|
||||
|
||||
### Warstwa C: Hasura + aplikacja
|
||||
|
||||
- `Hasura` wystawia derived tables jako GraphQL + subscriptions.
|
||||
- UI i narzędzia aplikacyjne czytają z `dlob_hot_derived_latest` oraz `dlob_all_derived_latest`.
|
||||
- Metryki depth/slippage nie są już liczone przez osobne workery k3s; bieżąca ścieżka aplikacji wylicza je z danych L2/derived.
|
||||
|
||||
## Gdzie “pracuje AI” (TFT itp.)
|
||||
|
||||
AI/strategia powinna pracować na warstwie “features”, a nie na surowych subskrypcjach Solany:
|
||||
|
||||
Najczęstszy zestaw wejść dla modelu:
|
||||
- candles/ticki (np. `drift_ticks` + `get_drift_candles(...)`),
|
||||
- bieżące statsy z DLOB:
|
||||
- `dlob_stats_latest` (mid/spread/depth/imbalance),
|
||||
- `dlob_depth_bps_latest` (depth w bandach),
|
||||
- `dlob_slippage_latest` (slippage vs size),
|
||||
- opcjonalnie pełny snapshot L2 (z `dlob_l2_latest`), jeśli model potrzebuje “kształtu” książki.
|
||||
|
||||
Kluczowa zasada bezpieczeństwa:
|
||||
- **Model (np. na Vast)** może sugerować “desired state” (wejść/wyjść/parametry),
|
||||
- **Executor na VPS** zawsze odpowiada za:
|
||||
- risk checks,
|
||||
- składanie/cancel/close,
|
||||
- klucze prywatne i podpisywanie transakcji,
|
||||
- kill switch.
|
||||
|
||||
## Szybki słownik (1-liner)
|
||||
|
||||
- **bid**: kupno, zielona strona książki
|
||||
- **ask**: sprzedaż, czerwona strona książki
|
||||
- **best bid / best ask (L1)**: top-of-book
|
||||
- **spread**: koszt “wejścia/wyjścia natychmiast” (ask-bid)
|
||||
- **mid**: punkt odniesienia między bid/ask
|
||||
- **L2**: lista poziomów `{price,size}`
|
||||
- **L1…L10**: top 10 poziomów z L2 (u nas kontrolowane przez `DLOB_DEPTH`)
|
||||
|
||||
## Jak liczymy “liquidity” i “kasa” (USD) w metrykach
|
||||
|
||||
W UI/DB słowo “liquidity” zwykle oznacza **depth**: “ile wolumenu stoi w orderbooku blisko ceny”.
|
||||
U nas trzymamy to rozdzielnie dla bid/ask oraz w dwóch wariantach:
|
||||
|
||||
### A) Top‑N leveli (np. L1…L10) — `dlob_*_derived_latest`
|
||||
Zapisywane w writerach warstwy pochodnej na podstawie live snapshotów orderbooka:
|
||||
|
||||
- Bierzemy znormalizowane top level’e z `bids_norm` i `asks_norm`.
|
||||
- Każdy level ma:
|
||||
- `price`
|
||||
- `size_base`
|
||||
- “kasa” (notional) na tym levelu: `size_usd = size_base * price`
|
||||
- Sumujemy po levelach:
|
||||
- `depth_bid_base = Σ size_base` (po stronie bid),
|
||||
- `depth_bid_usd = Σ (size_base * price)` (po stronie bid),
|
||||
- analogicznie `depth_ask_base`, `depth_ask_usd` (po stronie ask).
|
||||
|
||||
To odpowiada intuicji “ile jest płynności na L1…LN”.
|
||||
|
||||
### B) Okno cenowe w bps od mid
|
||||
W aktualnej ścieżce aplikacji to liczenie jest robione z danych L2/derived, a nie przez osobny backend worker:
|
||||
|
||||
- Dla pasma `band_bps` wyznaczamy:
|
||||
- `minBidPrice = mid * (1 - band_bps/10_000)`
|
||||
- `maxAskPrice = mid * (1 + band_bps/10_000)`
|
||||
- Sumujemy wszystkie levele, które mieszczą się w tym oknie:
|
||||
- bids: `price >= minBidPrice`
|
||||
- asks: `price <= maxAskPrice`
|
||||
- Liczymy sumy:
|
||||
- `bid_base`, `bid_usd`, `ask_base`, `ask_usd` tak jak wyżej (`usd = base * price`).
|
||||
|
||||
To odpowiada intuicji “ile płynności jest *blisko* ceny w ±X bps”.
|
||||
|
||||
### Ważne doprecyzowanie
|
||||
|
||||
Te liczby to **notional z orderbooka** (ile “stoi” na poziomach cenowych).
|
||||
Nie są to “pieniądze w kontrakcie”, tylko przybliżenie kosztu/pojemności wykonania przy danej cenie i bez przesunięcia rynku.
|
||||
|
||||
## Spec: Orderbook UI (L1…L10 + “liquidity bars”)
|
||||
|
||||
Wizualizacja orderbooka (jak na screenach) jest oparta o L2 i pokazuje tylko top‑N leveli:
|
||||
- `N` = liczba leveli wyświetlanych na stronę (np. 10 → “L1…L10”).
|
||||
|
||||
### Kolumny / wartości
|
||||
|
||||
Na każdym levelu liczymy:
|
||||
- `size_usd = size_base * price`
|
||||
|
||||
W UI pokazujemy:
|
||||
- `Size (USD)` = `size_usd` dla danego poziomu,
|
||||
- `Total (USD)` = suma skumulowana od best‑price “w głąb” (cumulative):
|
||||
- bids: kumulacja od best bid w dół,
|
||||
- asks: kumulacja od best ask w górę (w UI zwykle best ask jest bliżej środka).
|
||||
|
||||
### “Liquidity bars” (znormalizowane słupki tła)
|
||||
|
||||
Żeby “na oko” widzieć gdzie stoi płynność:
|
||||
|
||||
1) **Level bar (per‑poziom)** — normalizacja do największego `size_usd` w widocznych levelach danej strony:
|
||||
- `level_scale = size_usd / max(size_usd w widoku)`
|
||||
2) **Total bar (cumulative)** — normalizacja do największego `total_usd` w widocznych levelach danej strony:
|
||||
- `total_scale = total_usd / max(total_usd w widoku)`
|
||||
|
||||
Żeby duże “ściany” nie zabijały kontrastu, warto użyć krzywej:
|
||||
- `scale_curved = sqrt(clamp01(scale))`
|
||||
|
||||
Interpretacja:
|
||||
- **level bar** = “ile stoi na tym poziomie”,
|
||||
- **total bar** = “ile stoi łącznie do tego poziomu”.
|
||||
Reference in New Issue
Block a user