跳转至

VIB-4062 Migration Guide — Unified MarketSnapshot

Audience: external strategy authors, internal contributors, anyone whose code imported MarketSnapshot before 2026-05-06.

TL;DR: from almanak import MarketSnapshot continues to work. Legacy deep imports under almanak.framework.strategies and almanak.framework.data break; deep imports under almanak.framework.market are the supported replacement.

What happened

Two MarketSnapshot classes existed in this repo from 2026-01-26 through 2026-05-06. They silently diverged — methods added to one didn't reach the other. Production saw 'MarketSnapshot' object has no attribute … errors. VIB-4062 unifies them into a single canonical class at almanak.framework.market.snapshot.MarketSnapshot.

What works unchanged

from almanak import MarketSnapshot           # KEEP
from almanak import MultiChainMarketSnapshot # KEEP — TypeAlias to MarketSnapshot

What breaks

Old import New import
from almanak.framework.strategies import MarketSnapshot from almanak import MarketSnapshot
from almanak.framework.strategies.intent_strategy import MarketSnapshot from almanak.framework.market import MarketSnapshot
from almanak.framework.strategies.intent_strategy import MultiChainMarketSnapshot from almanak.framework.market import MultiChainMarketSnapshot
from almanak.framework.strategies.multichain import MultiChainMarketSnapshot from almanak.framework.market import MultiChainMarketSnapshot
from almanak.framework.data.market_snapshot import MarketSnapshot from almanak.framework.market import MarketSnapshot
from almanak.framework.strategies.intent_strategy import (TokenBalance, RSIData, …) from almanak.framework.market import (TokenBalance, RSIData, …)
from almanak.framework.data.market_snapshot import (PriceUnavailableError, …) from almanak.framework.market import (PriceUnavailableError, …)

What changes for unit-test code

The legacy set_* injectors (market.set_price, market.set_balance, …) are preserved but you should prefer the new seed_* API:

# Old — still works, prefer the new form below
market.set_price("ETH", Decimal("3000"))
market.set_balance("USDC", TokenBalance(...))

# New canonical (PRD §4.6)
market.seed_price("ETH", Decimal("3000"))
market.seed_balance("USDC", TokenBalance(...))

# Or, build a fully-seeded snapshot from scratch:
from almanak.framework.market import MarketSnapshotBuilder
market = MarketSnapshotBuilder.seeded(
    chain="arbitrum",
    wallet_address="0x...",
    prices={"ETH": Decimal("3000")},
    balances={"USDC": TokenBalance(...)},
)

Multi-chain behavior change

Multi-chain snapshots no longer accept chain=None:

market = MarketSnapshot(chains=["arbitrum", "ethereum"])
market.price("ETH")                    # raises AmbiguousChainError
market.price("ETH", chain="arbitrum")  # OK
market.price("ETH", chain="polygon")   # raises ChainNotConfiguredError

Single-chain snapshots default chain=None to the only configured chain (no behavior change for the common case).

What is runtime_surface?

Every snapshot now records the builder factory that produced it:

market.runtime_surface in {
    "local_sdk", "hosted", "pnl_backtest", "paper_fork",
    "http_backtest", "unit_test",
}

Strategy code rarely needs to inspect this — it's used by the runner and by accounting for telemetry.

What is fork_rpc_url?

It is no longer part of the public strategy contract. The property still exists on MarketSnapshot, but production strategy code should not depend on it: paper trading uses an internal fork-aware service adapter, and the same decide() is supposed to run identically in paper and live. Reading market.fork_rpc_url from a strategy is a code smell — the framework now hides paper-vs-live behind the service layer.

What if I had a method that the canonical class doesn't have?

VIB-4062 ports the strategy-layer rich-typed methods. If you depended on a data-layer-only method (liquidity_depth, pool_price accessors, prediction_*, vol, risk, …) and your imports were rewritten by the codemod, you now get AttributeError. Either:

  1. Use the public namespaced analytics — market.risk.*, market.pools.*, market.prediction.*, market.volatility.* (post-VIB-4062 surface).
  2. File a Linear ticket if the method you need isn't surfaced yet.

I see # VIB-4062-MIGRATE in my code

That comment is a marker the codemod left behind for an import shape it couldn't auto-rewrite. Resolve it by hand and remove the comment. Commit 8 of the migration runs a CI check that fails if any markers survive.

Reporting issues

  • GitHub issues at the SDK repo with the vib-4062 label.
  • Internal: post in #sdk-eng Slack channel.