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:
- Use the public namespaced analytics —
market.risk.*,market.pools.*,market.prediction.*,market.volatility.*(post-VIB-4062 surface). - 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-4062label. - Internal: post in
#sdk-engSlack channel.