Files
trade-doc/dlob-basics.md

6.9 KiB
Raw Permalink Blame History

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) TopN leveli (np. L1…L10) — dlob_*_derived_latest

Zapisywane w writerach warstwy pochodnej na podstawie live snapshotów orderbooka:

  • Bierzemy znormalizowane top levele 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 topN 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 bestprice “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 (perpoziom) — 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”.