docs(snapshot): sync workspace documentation
This commit is contained in:
240
observer-sol-v1.md
Normal file
240
observer-sol-v1.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# SOL-PERP Observer V1
|
||||
|
||||
Ten dokument definiuje pierwszy działający observer bota dla `SOL-PERP`.
|
||||
|
||||
Celem nie jest jeszcze trading, tylko:
|
||||
- stabilny loop `1s`
|
||||
- powtarzalny snapshot feature'ów
|
||||
- decyzja `long|flat|short`
|
||||
- heartbeat i audyt w `bot_state` / `bot_events`
|
||||
|
||||
## Zakres
|
||||
|
||||
- rynek: `SOL-PERP`
|
||||
- tryb: `observe`
|
||||
- źródło danych v1: `Hasura`
|
||||
- bez kluczy prywatnych
|
||||
- bez składania transakcji
|
||||
|
||||
## Architektura
|
||||
|
||||
- `bot_config` pozostaje desired state i źródłem parametrów
|
||||
- `bot-observer` czyta `bot_config`, pobiera snapshot rynku, liczy feature'y i zapisuje wynik
|
||||
- `bot_state` przechowuje heartbeat, ostatni błąd i ostatni wynik loopa
|
||||
- `bot_events` przechowuje append-only audyt decyzji i błędów
|
||||
|
||||
## Źródła danych
|
||||
|
||||
Observer czyta z Hasury:
|
||||
- `get_drift_candles(...)`
|
||||
- `dlob_hot_derived_latest` dla hot marketów z fallbackiem do `dlob_all_derived_latest`
|
||||
|
||||
Depth bands i slippage nie są już czytane z osobnych legacy tabel.
|
||||
Observer liczy je lokalnie z `bids_norm` / `asks_norm` nowego derived read-model.
|
||||
|
||||
Wersja v1 zakłada małe query tylko dla jednego rynku.
|
||||
|
||||
## Parametry w `bot_config.params`
|
||||
|
||||
Minimalny kontrakt:
|
||||
|
||||
```json
|
||||
{
|
||||
"strategy": {
|
||||
"type": "predictive_observer_v1"
|
||||
},
|
||||
"loop": {
|
||||
"decision_interval_ms": 1000,
|
||||
"candle_bucket_seconds": 1,
|
||||
"candles_limit": 64
|
||||
},
|
||||
"features": {
|
||||
"mom_fast_s": 3,
|
||||
"mom_mid_s": 10,
|
||||
"mom_slow_s": 30,
|
||||
"vol_window_s": 30,
|
||||
"depth_band_bps": 10,
|
||||
"slippage_size_usd": 500
|
||||
},
|
||||
"gates": {
|
||||
"freshness_max_ms": 800,
|
||||
"spread_max_bps": 8,
|
||||
"slippage_max_bps": 12,
|
||||
"depth_band_min_usd": 3000
|
||||
},
|
||||
"sizing": {
|
||||
"target_notional_usd": 500
|
||||
},
|
||||
"decision": {
|
||||
"threshold": 1.2,
|
||||
"horizon_s": 60
|
||||
},
|
||||
"scoring": {
|
||||
"weights": {
|
||||
"mom_fast": 0.9,
|
||||
"mom_mid": 0.35,
|
||||
"mom_slow_reversal": 0.55,
|
||||
"imbalance": 5.0,
|
||||
"mark_vs_oracle": 0.08,
|
||||
"spread": 0.15,
|
||||
"slippage": 0.12
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Feature Snapshot
|
||||
|
||||
Na każdy tick observer liczy:
|
||||
- `mark_price`
|
||||
- `oracle_price`
|
||||
- `mid_price`
|
||||
- `spread_bps`
|
||||
- `stats_imbalance`
|
||||
- `depth_bid_usd`
|
||||
- `depth_ask_usd`
|
||||
- `depth_imbalance`
|
||||
- `buy_slippage_bps`
|
||||
- `sell_slippage_bps`
|
||||
- `mark_vs_oracle_bps`
|
||||
- `mom_3s`
|
||||
- `mom_10s`
|
||||
- `mom_30s`
|
||||
- `vol_30s`
|
||||
- `data_age_ms`
|
||||
|
||||
## Gates
|
||||
|
||||
Jeśli którykolwiek gate nie przechodzi, observer nie produkuje sygnału kierunkowego i zapisuje event `skip`.
|
||||
|
||||
Wersja v1:
|
||||
- `data_age_ms <= freshness_max_ms`
|
||||
- `spread_bps <= spread_max_bps`
|
||||
- `max(buy_slippage_bps, sell_slippage_bps) <= slippage_max_bps`
|
||||
- `min(depth_bid_usd, depth_ask_usd) >= depth_band_min_usd`
|
||||
|
||||
## Model decyzji
|
||||
|
||||
V1 nie używa ML. To baseline scoring do zebrania danych i benchmarku.
|
||||
|
||||
Long side:
|
||||
|
||||
```text
|
||||
long_score =
|
||||
mom_fast * w_mom_fast
|
||||
+ mom_mid * w_mom_mid
|
||||
- mom_slow * w_mom_slow_reversal
|
||||
+ depth_imbalance * w_imbalance
|
||||
- mark_vs_oracle_bps * w_mark_vs_oracle
|
||||
- spread_bps * w_spread
|
||||
- buy_slippage_bps * w_slippage
|
||||
```
|
||||
|
||||
Short side jest lustrzanym odbiciem long side.
|
||||
|
||||
Decyzja:
|
||||
- jeśli gates fail -> `flat`
|
||||
- jeśli `max(abs(long_score), abs(short_score)) < threshold` -> `flat`
|
||||
- w przeciwnym razie `long` albo `short`
|
||||
|
||||
## Event `decision`
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "observer-sol-v1",
|
||||
"bot": {
|
||||
"id": "uuid",
|
||||
"name": "sol-observer",
|
||||
"mode": "observe",
|
||||
"market_name": "SOL-PERP",
|
||||
"kill_switch": false
|
||||
},
|
||||
"runtime": {
|
||||
"service": "bot-observer",
|
||||
"observe_only": true,
|
||||
"loop_ms": 1000,
|
||||
"query_latency_ms": 82,
|
||||
"loop_latency_ms": 96
|
||||
},
|
||||
"snapshot": {
|
||||
"data_age_ms": 214,
|
||||
"stats_updated_at": "2026-03-23T20:12:31.112Z",
|
||||
"depth_updated_at": "2026-03-23T20:12:31.112Z",
|
||||
"buy_slippage_updated_at": "2026-03-23T20:12:31.112Z",
|
||||
"sell_slippage_updated_at": "2026-03-23T20:12:31.112Z"
|
||||
},
|
||||
"features": {
|
||||
"mom_3s": 3.8,
|
||||
"mom_10s": 6.1,
|
||||
"mom_30s": -12.5,
|
||||
"vol_30s": 5.9,
|
||||
"spread_bps": 2.1,
|
||||
"depth_imbalance": 0.18,
|
||||
"buy_slippage_bps": 4.2,
|
||||
"sell_slippage_bps": 4.0,
|
||||
"mark_vs_oracle_bps": -1.3
|
||||
},
|
||||
"gates": {
|
||||
"fresh": true,
|
||||
"spread_ok": true,
|
||||
"slippage_ok": true,
|
||||
"depth_ok": true
|
||||
},
|
||||
"decision": {
|
||||
"side": "long",
|
||||
"confidence": 0.72,
|
||||
"long_score": 1.91,
|
||||
"short_score": -2.34,
|
||||
"target_notional_usd": 500,
|
||||
"horizon_s": 60
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Event `skip`
|
||||
|
||||
Observer zapisuje `skip`, gdy:
|
||||
- dane są stale
|
||||
- brakuje wymaganych metryk
|
||||
- gates nie przechodzą
|
||||
- bot jest w trybie innym niż aktywny observe loop
|
||||
|
||||
Payload `skip` ma ten sam nagłówek co `decision`, ale z polem:
|
||||
|
||||
```json
|
||||
{
|
||||
"skip_reason": "gate_failed:freshness"
|
||||
}
|
||||
```
|
||||
|
||||
## `bot_state.state`
|
||||
|
||||
V1 zapisuje w `bot_state.state` znormalizowany stan loopa:
|
||||
- `service`
|
||||
- `version`
|
||||
- `observe_only`
|
||||
- `market_name`
|
||||
- `mode`
|
||||
- `status`
|
||||
- `last_decision`
|
||||
- `last_features`
|
||||
- `last_gates`
|
||||
- `last_snapshot`
|
||||
- `counters`
|
||||
|
||||
## Zmienne środowiskowe
|
||||
|
||||
Najważniejsze:
|
||||
- `BOT_ID` albo `BOT_NAME`
|
||||
- `HASURA_GRAPHQL_URL`
|
||||
- `HASURA_ADMIN_SECRET`
|
||||
- `DLOB_SOURCE` opcjonalnie, jeśli chcesz zawęzić derived read-model do konkretnego `source`
|
||||
- `CANDLES_SOURCE` opcjonalnie, jeśli chcesz zawęzić candles do konkretnego źródła ticków
|
||||
- `OBSERVER_PORT` opcjonalnie, domyślnie `8791`
|
||||
|
||||
## Cel wersji v1
|
||||
|
||||
V1 ma odpowiedzieć na trzy pytania:
|
||||
- czy Hasura daje stabilny loop `1s` dla jednego rynku
|
||||
- czy feature snapshot jest wystarczająco świeży
|
||||
- czy baseline scoring daje sensowny materiał do dalszego strojenia i późniejszego ML
|
||||
Reference in New Issue
Block a user