Aller au contenu
login
arrow_backRetour aux issues
Wayfare-labs/wayfare #36

Metric: bid/ask spread on the direct order book

ecoDébutant help wanted area:pricing difficulty:medium

descriptionDescription

Written to the standard set by #33 — read that issue first for the expected level of detail and the acceptance criteria every check shares. ## What Measure the bid/ask spread on the direct order book for a corridor, where one exists. ## Why it matters The spread is the cheapest possible signal of whether a market is real. The USDC/NGNC book measured **128.8% of mid** on 2026-08-04 — a number that says "no two-sided participation" far more directly than a loss percentage does. ## Which layer **Layer 2 — deterministic calculation** over layer 1 facts. It may not be more certain than the order book it is computed from. ## This is a metric, not a check Read the "Checks and metrics are separate shapes" section of [docs/checks.md](https://github.com/Wayfare-labs/wayfare/blob/main/docs/checks.md) before starting. This produces a **quantity**, so it returns `MetricResult` with `Value` and `Unit`, not `CheckResult` with `Passed`. Do not add a threshold turning it into a pass/fail — deciding what spread is unacceptable is a maintainer-owned judgement, and no such threshold exists yet. ## Exactly where the code goes - **New file:** `checks/metric_spread.go` - Tests appended to `checks/checks_test.go` - `dex.BookHealth` in `dex/health.go` **already computes `SpreadPct`** — reuse it rather than reimplementing. This issue is largely about exposing it as a metric through the contract ## Where the data comes from `dex.Client.OrderBook` (`dex/health.go`), which wraps Horizon's `/order_book`. ## What "unmeasurable" means here - No order book for the pair, or one side empty → `Determined: false`, **never `Value: 0`**. A spread of nothing and a spread that could not be read are different facts, and zero is a plausible-looking number for the second - Dust-only book → undetermined, with the reason naming it. `dex/health.go` already filters dust and explains why ## Acceptance criteria - [ ] Returns `MetricResult`, not `CheckResult` - [ ] `Unit` is `UnitPercent` - [ ] `decimal.Decimal` throughout; **no float64** anywhere in the calculation - [ ] Returns UNABLE-TO-DETERMINE (not zero) when the book is empty or one-sided - [ ] Records evidence: the market queried and the levels observed - [ ] Reuses `dex.BookHealth` rather than recomputing the spread - [ ] Table tests from `dex/testdata/orderbook-xlm-ngnc.json` — a real captured book already in the repo - [ ] Negative test: an empty or one-sided book - [ ] No new third-party dependencies - [ ] gofmt, vet, test -race, golangci-lint clean - [ ] Does not change the headline integrity state or verdict thresholds - [ ] **Adds no threshold** turning the metric into a verdict ## Out of scope Nothing in `dex/` may change — `BookHealth` is maintainer-owned pricing code and this issue only consumes it. Nothing in `route/`, `sep38/`, `runstore/runstore.go`. ## How to verify locally ```bash make offline-test go test ./checks/ -run TestSpread -v ```
codeOuvre sur GitHub