Time-Weighted Balances & Engine Flow
Overview
Time-weighted balances (TWB) represent the average value of a position over a target period by combining:
📊 Core Components
- 🔄 Balance windows — Every time the balance changes, a new window is emitted
- 📈 TWAP (Time-Weighted Average Price) — Price is averaged separately per window duration
- 💰 Balance × TWAP — Each window holds a distinct balance multiplied by its TWAP
Engine Flow
Flow Diagram
Adapter -> emit(...) -> Engine.ingest(...) -> Redis state
-> periodic flush to windows (TWB)
-> price backfill per window boundary
-> enrichment (runner info, base fields, prices, dedupe)
-> sinks (stdout, csv, ...)
Key Stages
📥 Ingest
The engine normalizes Subsquid logs and transactions into a common context with ts
, height
, txHash
, and logIndex
.
🪟 Windows
Each balance change emits a new window.
Windows are closed either by a balance delta or by a periodic flush.
A window is [startTs, endTs]
with a fixed balance.
💰 Pricing
Each window is priced independently using TWAP over its duration:
Feed Handler | Purpose |
---|---|
coingecko | Market prices |
pegged | Stablecoin pegs |
univ2nav | Uniswap V2 liquidity |
ichinav | Ichi liquidity |
univ3lp | Uniswap V3 positions |
🎨 Enrichment
Adds runner metadata, dedupes actions by id
, filters invalid items, and prepares rows for export.
TWB Calculation
Time-weighted balances are calculated by:
Correct Example (with 2 windows)
// User holds 100 USDC for 1 hour, then 200 USDC for 2 hours
// Price of USDC = $1.00 throughout (TWAP = 1 for both windows)
// Window 1: [0h-1h] => balance = 100, TWAP = 1 → 100 * 1 = 100
// Window 2: [1h-3h] => balance = 200, TWAP = 1 → 200 * 1 = 200