Time-Weighted Balances & Engine Flow – Absinthe Docs
Skip to content

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 HandlerPurpose
coingeckoMarket prices
peggedStablecoin pegs
univ2navUniswap V2 liquidity
ichinavIchi liquidity
univ3lpUniswap 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