跳转至

Dashboards

Strategy dashboards are Streamlit pages loaded by the hosted platform's dashboard image and by almanak dashboard locally. Both call your render_custom_dashboard() with the same arguments.

Anatomy of a dashboard

If a built-in template renderer fits your strategy, call it. The renderer owns the title, the strategy header (Deployment ID / pool / chain markdown), and the three audit sections (PnL, cost stack, trade tape). Do not wrap it with your own st.title(...) or audit-section helpers — that double-renders the title and the audit panels.

from almanak.framework.dashboard.templates import get_bollinger_config, render_ta_dashboard

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state):
    config = get_bollinger_config(period=20, std_dev=1.0)
    render_ta_dashboard(deployment_id, strategy_config, session_state, config)

Need to add summary cards or extra metrics? Call the renderer first and append your own widgets after — see strategies/accounting/lp/dashboard/ui.py and strategies/accounting/looping/dashboard/ui.py for committed reference implementations of that pattern (renderer + st.divider() + bespoke st.metric(...) cards below).

Need a custom title or to replace the audit sections entirely? Hand-roll the dashboard instead — see the next snippet. What you must NOT do is wrap render_*_dashboard() with extra st.title(...) / render_pnl_section(...) calls; the template already emits those, so you'll double-render.

If no template fits, hand-roll Streamlit and wire the audit primitives yourself (this is what almanak strat new scaffolds for blank / multi-step templates; LP / lending / TA / perp templates scaffold the template-renderer path above):

import streamlit as st
from almanak.framework.dashboard import (
    render_pnl_section, render_cost_stack_section, render_trade_tape_section,
)

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state):
    st.title("My Custom Strategy")
    render_pnl_section(deployment_id)
    # your indicator / position / performance UI
    render_cost_stack_section(deployment_id)
    render_trade_tape_section(deployment_id)

Audit primitives

almanak.framework.dashboard

Almanak Strategy Framework v2.0 - Dashboard

Public exports for dashboard data access, rendering, and PM integration. External consumers (PM dashboard, custom UIs) should import from here.

The streamlit-using render_*_section helpers are resolved lazily via :pep:562 __getattr__ so that gateway-side consumers — which import almanak.framework.dashboard.quant_aggregations to build PnL / cost-stack RPC responses — do not transitively pay the cost of loading streamlit at package init. The gateway image strips streamlit (see deploy/docker/strip-list-gateway.txt); an eager re-export here would ModuleNotFoundError on every dashboard RPC in production (VIB-4048). Regression guard: tests/gateway/test_imports_lean.py.

For strategy authors writing a dashboard/ui.py for their strategy, the recommended convention is to frame render_custom_dashboard() with three section helpers (VIB-3969) so accounting is visually QA'able locally and on the hosted platform from the same single-source code path:

  • render_pnl_section(deployment_id) — top, the 5-second eyeball
  • render_cost_stack_section(deployment_id) — bottom, life-to-date costs
  • render_trade_tape_section(deployment_id) — bottom, TX-level audit

Usage::

from almanak.framework.dashboard import (
    DashboardDataClient,
    Strategy,
    render_cost_stack_section,
    render_pnl_section,
    render_strategy_detail,
    render_strategy_timeline,
    render_trade_tape_section,
    strategy_from_pm_dict,
)

render_pnl_section

render_pnl_section(deployment_id: str) -> None

Render the 5-second-eyeball PnL section (VIB-3969).

Money Trail row: Deployed / NAV / Lifetime PnL / Net APR. The standard top-of-dashboard card so an operator answers "am I making or losing money?" before scrolling. Backed by the gateway's GetPnLSummary RPC; on RPC failure the section degrades to an info banner rather than crashing the page.

Conventionally placed immediately below the strategy title.

Parameters:

Name Type Description Default
deployment_id str

The deployment id (passed straight through from render_custom_dashboard's first positional argument).

required

render_cost_stack_section

render_cost_stack_section(
    deployment_id: str, *, heading: str = "### Cost Stack"
) -> None

Render the life-to-date Cost Stack section (VIB-3969).

Gas / Fees / Slippage / Earn — generic across primitives (every primitive emits these into transaction_ledger + accounting_events). Backed by the gateway's GetCostStack RPC; on RPC failure the section degrades to an info banner.

Conventionally placed at the start of an "Audit" section, just above the trade tape.

Parameters:

Name Type Description Default
deployment_id str

The deployment id.

required
heading str

Override the section heading. Pass an empty string to suppress the heading entirely (useful when composing inside a larger Audit panel that already has its own heading).

'### Cost Stack'

render_trade_tape_section

render_trade_tape_section(
    deployment_id: str, *, limit: int = 50
) -> None

Render the standard trade-tape section.

Conventionally placed at the bottom of every render_custom_dashboard() so accounting can be visually QA'd locally and on the hosted platform from the same code path. The underlying render_trade_tape reads through the gateway's DashboardService.GetTradeTape, which abstracts SQLite (local) and Postgres (hosted) — the section travels everywhere the gateway does.

Parameters:

Name Type Description Default
deployment_id str

The deployment id (passed straight through from render_custom_dashboard's first positional argument).

required
limit int

Most recent intents to fetch. Defaults to 50.

50

Template renderers

Pre-built sections for common strategy types. Each renderer is paired with factory configs that adapt the rendering to a specific protocol or indicator. Use these to fill the middle of the dashboard instead of hand-rolling indicator/position/performance UI.

Technical analysis (RSI, MACD, Bollinger, …)

almanak.framework.dashboard.templates.ta_dashboard

Technical Analysis (TA) Dashboard Template.

Reusable template for creating dashboards for indicator-based strategies. Supports any TA indicator with configurable signal logic and visualization.

Scope (single-position): the template drives one position on one base_token/quote_token pair. The 3 accounting sections (PnL, Cost Stack, Trade Tape) are baked in so every TA dashboard ships with full accounting by default.

  • Single indicator — pass one TADashboardConfig.
  • Multiple indicators (multi-signal, VIB-4897) — compose with :func:multi_ta_config. The template stacks one panel per indicator under a shared price chart (all on one time axis). Useful for confluence strategies (e.g. RSI + MACD + Bollinger).

For genuinely multi-position layouts the template is still the wrong tool — hand-roll from the section helpers (render_pnl_section, render_cost_stack_section, render_trade_tape_section) plus the primitive plot helpers in almanak.framework.dashboard.plots. See the dashboard blueprints.

Usage (single indicator): from almanak.framework.dashboard.templates import TADashboardConfig, render_ta_dashboard

config = TADashboardConfig(
    indicator_name="RSI", indicator_period=14,
    upper_threshold=70, lower_threshold=30, signal_type="reversion",
)

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state):
    session_state = prepare_ta_session_state(api_client, session_state, config)
    render_ta_dashboard(deployment_id, strategy_config, session_state, config)

Usage (multi-signal): from almanak.framework.dashboard.templates import ( get_rsi_config, get_macd_config, get_bollinger_config, multi_ta_config, prepare_ta_session_state, render_ta_dashboard, )

config = multi_ta_config(get_rsi_config(), get_macd_config(), get_bollinger_config())

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state):
    session_state = prepare_ta_session_state(api_client, session_state, config)
    render_ta_dashboard(deployment_id, strategy_config, session_state, config)

TADashboardConfig dataclass

TADashboardConfig(
    indicator_name: str,
    indicator_period: int = 14,
    secondary_periods: list[int] = list(),
    upper_threshold: float | None = None,
    lower_threshold: float | None = None,
    signal_type: Literal[
        "reversion", "momentum"
    ] = "reversion",
    value_format: str = "{:.1f}",
    value_suffix: str = "",
    custom_signal_fn: Callable[[dict[str, Any]], str]
    | None = None,
    chain: str = "Arbitrum",
    protocol: str = "Uniswap V3",
    base_token: str = "WETH",
    quote_token: str = "USDC",
    timeframe: str = "1h",
    extra_indicators: list[TADashboardConfig] = list(),
)

Configuration for a TA dashboard.

Attributes:

Name Type Description
indicator_name str

Name of the indicator (e.g., "RSI", "MACD", "CCI")

indicator_period int

Primary period for the indicator

secondary_periods list[int]

Additional periods (e.g., signal line for MACD)

upper_threshold float | None

Upper threshold for signals (overbought/bullish)

lower_threshold float | None

Lower threshold for signals (oversold/bearish)

signal_type Literal['reversion', 'momentum']

Type of signal logic - "reversion" or "momentum"

value_format str

Format string for displaying indicator value (e.g., "{:.1f}", "{:+.2f}")

value_suffix str

Suffix for indicator value (e.g., "%", " bps")

custom_signal_fn Callable[[dict[str, Any]], str] | None

Optional custom function for signal determination

chain str

Default chain name

protocol str

Default protocol name

base_token str

Default base token

quote_token str

Default quote token

timeframe str

OHLCV candle interval the dashboard fetches and computes the indicator series from — one of 1m/5m/15m/1h/4h/1d. Defaults to "1h" for back-compat. Must match the strategy's own data_granularity: otherwise the dashboard RSI/MACD/etc. line is a different series from the one the strategy decides on, so buy/sell markers won't align with the indicator band (VIB-4969). For the multi-signal layout the primary config's timeframe is authoritative (one shared OHLCV fetch); extras' timeframes are ignored, mirroring how their pair/chain are ignored.

extra_indicators list[TADashboardConfig]

Additional indicator configs to render as stacked panels (multi-signal layout, VIB-4897). Empty by default — the single-indicator path is unchanged. Compose via :func:multi_ta_config. Each extra contributes one more panel beneath the price chart; the extras' pair/chain/timeframe are ignored (the primary config drives the shared OHLCV fetch).

multi_ta_config

multi_ta_config(
    primary: TADashboardConfig, *extras: TADashboardConfig
) -> TADashboardConfig

Compose a multi-indicator (multi-signal) TA dashboard config.

The first config is the primary — it drives the dashboard title, the configured pair/chain, the shared OHLCV fetch, and the signal-status section. Each additional config renders as one more stacked indicator panel beneath the price chart. Indicator params (periods / thresholds) on the extras are honoured; their base_token / quote_token / chain are not — the primary's pair is authoritative so every panel shares one time axis.

Example::

config = multi_ta_config(
    get_rsi_config(period=14),
    get_macd_config(),
    get_bollinger_config(period=20, std_dev=2.0),
)
session_state = prepare_ta_session_state(api_client, session_state, config)
render_ta_dashboard(deployment_id, strategy_config, session_state, config)

Returns a new config (does not mutate primary).

prepare_ta_session_state

prepare_ta_session_state(
    api_client: Any,
    session_state: dict[str, Any] | None = None,
    config: TADashboardConfig | None = None,
) -> dict[str, Any]

Enrich session state for render_ta_dashboard (chart subplot).

Mirrors :func:prepare_lp_session_state: fetches OHLCV via the api_client, computes the indicator series client-side, reads the trade tape for buy/sell markers, and loads wallet balances for the Current Position section — strategy authors don't write any of that plumbing. Without this helper the chart section silently degrades to Price history data not available (nothing populates price_history / rsi_history / buy_signals / sell_signals) and the Current Position section reads 0.0000 / $0.00 / $0.00 (nothing populates base_balance / quote_balance / base_price).

Parameters:

Name Type Description Default
api_client Any

DashboardAPIClient (or a duck-typed mock).

required
session_state dict[str, Any] | None

Optional pre-existing state. Caller-supplied keys are preserved — never overwritten — so custom dashboards that already populate price_history keep working.

None
config TADashboardConfig | None

TADashboardConfig describing the indicator, pair, and chain. Required to know which token to fetch OHLCV for.

None

Returns:

Type Description
dict[str, Any]

The enriched session_state dict. Always returns; degrades to the

dict[str, Any]

unenriched state on any API failure rather than raising.

render_ta_dashboard

render_ta_dashboard(
    deployment_id: str,
    strategy_config: dict[str, Any],
    session_state: dict[str, Any],
    config: TADashboardConfig,
) -> None

Render a technical analysis dashboard using the provided configuration.

Single-position template. Renders one indicator panel by default; pass a :func:multi_ta_config (config.extra_indicators set) to stack one panel per indicator under a shared price chart (multi-signal, VIB-4897). Bakes in the 3 accounting sections (PnL → chart content → Cost Stack → Trade Tape). For multi-position layouts, compose a custom dashboard from the section helpers directly rather than parameterizing this template.

Parameters:

Name Type Description Default
deployment_id str

The deployment identifier

required
strategy_config dict[str, Any]

Strategy configuration dictionary

required
session_state dict[str, Any]

Current session state with indicator values

required
config TADashboardConfig

TADashboardConfig for this dashboard

required

get_rsi_config

get_rsi_config(
    period: int = 14,
    overbought: float = 70,
    oversold: float = 30,
    timeframe: str = "1h",
) -> TADashboardConfig

Get pre-configured RSI dashboard config.

timeframe must match the strategy's data_granularity so the dashboard RSI is computed from the same candles the strategy decides on (VIB-4969). Defaults to "1h" for back-compat.

get_macd_config

get_macd_config(
    fast: int = 12,
    slow: int = 26,
    signal: int = 9,
    timeframe: str = "1h",
) -> TADashboardConfig

Get pre-configured MACD dashboard config.

timeframe must match the strategy's data_granularity (VIB-4969).

get_cci_config

get_cci_config(
    period: int = 20,
    overbought: float = 100,
    oversold: float = -100,
    timeframe: str = "1h",
) -> TADashboardConfig

Get pre-configured CCI dashboard config.

timeframe must match the strategy's data_granularity (VIB-4969).

get_stochastic_config

get_stochastic_config(
    fast_k: int = 14,
    slow_k: int = 3,
    slow_d: int = 3,
    overbought: float = 80,
    oversold: float = 20,
    timeframe: str = "1h",
) -> TADashboardConfig

Get pre-configured Stochastic dashboard config.

timeframe must match the strategy's data_granularity (VIB-4969).

get_atr_config

get_atr_config(
    period: int = 14, timeframe: str = "1h"
) -> TADashboardConfig

Get pre-configured ATR dashboard config.

timeframe must match the strategy's data_granularity (VIB-4969).

get_adx_config

get_adx_config(
    period: int = 14,
    trend_threshold: float = 25,
    timeframe: str = "1h",
) -> TADashboardConfig

Get pre-configured ADX dashboard config.

timeframe must match the strategy's data_granularity (VIB-4969).

get_bollinger_config

get_bollinger_config(
    period: int = 20,
    std_dev: float = 2.0,
    timeframe: str = "1h",
) -> TADashboardConfig

Get pre-configured Bollinger Bands dashboard config.

timeframe must match the strategy's data_granularity (VIB-4969).

Liquidity provision

almanak.framework.dashboard.templates.lp_dashboard

Liquidity Provider (LP) Dashboard Template.

Reusable template for creating dashboards for LP strategies on concentrated liquidity protocols like Uniswap V3, PancakeSwap V3, TraderJoe V2, and Aerodrome.

Scope (single-signal / single-position): the template renders one active LP position on one token0/token1 pair. LPSessionState is intentionally scalar (position_id, range_lower, range_upper); strategies that hold multiple LP NFTs simultaneously are not modelled here even though the gateway data model (PositionSummary.lp_positions) is multi-aware. The 3 accounting sections (PnL, Cost Stack, Trade Tape) are baked in so every LP dashboard ships with full accounting. For multi- position or multi-signal layouts, compose a custom dashboard from the section helpers (render_pnl_section, render_cost_stack_section, render_trade_tape_section) plus primitive plot helpers from almanak.framework.dashboard.plots directly. See the dashboard blueprints for the recommended composition.

Usage

from almanak.framework.dashboard.templates import ( LPDashboardConfig, render_lp_dashboard, prepare_lp_session_state, get_uniswap_v3_config, )

config = get_uniswap_v3_config(token0="WETH", token1="USDC")

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state): session_state = prepare_lp_session_state(api_client, config=config) # Pass api_client so the template renders the gateway-backed # Positions registry + Position Lifecycle sections (PR #2373). render_lp_dashboard(deployment_id, strategy_config, session_state, config, api_client=api_client)

LP_CRITICAL_KEYS module-attribute

LP_CRITICAL_KEYS: list[str] = [
    "position_id",
    "range_lower",
    "range_upper",
    "total_value_usd",
    "is_active",
    "current_price",
    "in_range",
    "token0_amount",
    "token1_amount",
]

Keys that prepare_lp_session_state must produce and the template reads.

LP_LIVE_STATE_KEYS module-attribute

LP_LIVE_STATE_KEYS: frozenset[str] = frozenset(
    LP_CRITICAL_KEYS
) | {
    "current_position_id",
    "lower_tick",
    "upper_tick",
    "current_tick",
}

LP-critical state owned by the live gateway/market reads.

These keys reflect on-chain / market truth at render time. A caller-supplied session_state must not seed them ahead of the live reads — otherwise a stale, preserved dashboard state masks fresh state after the strategy has rebalanced on-chain (VIB-5025). The live read always wins; a caller value is used only as a last-resort fallback when the live path produced nothing (Empty != Zero), or when a caller explicitly pins the key via preserve_keys.

Any other key a caller passes (custom chart data such as position_history / price_history, fixture/display extras) is not live-owned and passes through untouched.

LPDashboardConfig dataclass

LPDashboardConfig(
    protocol: str = "uniswap_v3",
    token0: str = "WETH",
    token1: str = "USDC",
    fee_tier: str = "0.30%",
    chain: str = DEFAULT_CHAIN,
    show_liquidity_distribution: bool = True,
    show_position_history: bool = True,
    show_impermanent_loss: bool = True,
    show_fee_accumulation: bool = True,
    invert_prices: bool = False,
    position_bounds_ratio: float | None = 0.8,
    pool_address: str | None = None,
    token0_address: str | None = None,
    token1_address: str | None = None,
    timeframe: str = "1h",
)

Configuration for an LP dashboard.

Attributes:

Name Type Description
protocol str

Protocol name (e.g., "uniswap_v3", "aerodrome", "traderjoe_v2")

token0 str

First token symbol

token1 str

Second token symbol

fee_tier str

Fee tier display string (e.g., "0.30%")

chain str

Chain name

show_liquidity_distribution bool

Whether to show liquidity distribution chart

show_position_history bool

Whether to show position history chart

show_impermanent_loss bool

Whether to show IL tracking

show_fee_accumulation bool

Whether to show fee accumulation chart

invert_prices bool

Whether to invert price display

position_bounds_ratio float | None

Ratio for position bounds lines (None to disable)

timeframe str

OHLCV candle interval for the price-history chart — one of 1m/5m/15m/1h/4h/1d. Defaults to "1h" for back-compat. Set it to the strategy's data_granularity so the price chart matches the cadence the strategy actually trades on (VIB-4969); the recent-window candle count scales per timeframe.

LPSessionState

Bases: TypedDict

Keys expected by render_lp_dashboard() in session_state.

Use prepare_lp_session_state(api_client, config=config) to populate this automatically from the gateway.

Keys from strategy state (read directly, no mapping): position_id: Active LP position identifier. range_lower: Lower price bound of the LP position. range_upper: Upper price bound of the LP position. total_value_usd: Total position value in USD.

Keys derived/loaded by prepare_lp_session_state(): is_active: Whether a position is currently active. current_price: Current market price of token0 in USD. in_range: Whether current_price is within [range_lower, range_upper]. token0_amount: Amount of token0 in the position. token1_amount: Amount of token1 in the position.

Optional keys (strategy may or may not provide): total_fees_usd, impermanent_loss_pct, net_pnl_usd: Performance metrics. tick_data, lower_tick, upper_tick, current_tick: Liquidity distribution. position_history, price_history, fee_history, il_history: Chart data.

prepare_lp_session_state

prepare_lp_session_state(
    api_client: Any,
    session_state: dict[str, Any] | None = None,
    config: LPDashboardConfig | None = None,
    preserve_keys: Collection[str] | None = None,
) -> dict[str, Any]

Load strategy data from the gateway and enrich for the LP dashboard.

The dashboard is a live view: the gateway/market reads are the source of truth (blueprint 22/23; VIB-2838 "dashboard as a validation client"). The result is therefore built from the live api_client.get_state() read first, then enriched with derived fields (is_active, in_range) and live market data (current_price, token amounts).

A caller-supplied session_state contributes custom / non-live keys only (custom chart data such as position_history / price_history, fixture/display extras). The LP-critical live-state keys (:data:LP_LIVE_STATE_KEYS) are owned by the live reads and are never seeded from the caller ahead of them — this prevents a stale, preserved dashboard state from masking fresh on-chain state after a rebalance (VIB-5025). A caller value for a live key is used only as a last-resort fallback when the live path produced nothing (Empty != Zero), or when the caller explicitly pins the key via preserve_keys.

Parameters:

Name Type Description Default
api_client Any

DashboardAPIClient instance.

required
session_state dict[str, Any] | None

Optional pre-existing state. Non-live keys pass through and are preserved; live-state keys are refreshed from the gateway. Pass None (or an empty dict) for a pure fresh fetch.

None
config LPDashboardConfig | None

LPDashboardConfig -- needed to know which token to price. If None, current_price will not be fetched.

None
preserve_keys Collection[str] | None

Optional explicit opt-out. Keys listed here keep the caller-provided value over the live read (e.g. a replay / snapshot dashboard that intentionally renders a historical state rather than live state). The safe default (None) refreshes every live key.

None

Returns:

Type Description
dict[str, Any]

Enriched dict containing all :data:LP_CRITICAL_KEYS.

render_lp_dashboard

render_lp_dashboard(
    deployment_id: str,
    strategy_config: dict[str, Any],
    session_state: dict[str, Any],
    config: LPDashboardConfig,
    api_client: Any | None = None,
) -> None

Render an LP strategy dashboard using the provided configuration.

Single-signal / single-position template — renders one active LP position on one configured pair. Bakes in the 3 accounting sections (PnL → primitive content → Cost Stack → Trade Tape). For multi- position or multi-signal layouts, compose a custom dashboard from the section helpers directly rather than parameterizing this template.

Parameters:

Name Type Description Default
deployment_id str

The deployment identifier

required
strategy_config dict[str, Any]

Strategy configuration dictionary

required
session_state dict[str, Any]

Current session state with position data. Use :func:prepare_lp_session_state to populate this from the gateway before calling this function.

required
config LPDashboardConfig

LPDashboardConfig for this dashboard

required
api_client Any | None

Optional DashboardAPIClient (the same one passed into render_custom_dashboard). When supplied, the template renders the gateway-backed Positions registry and Position Lifecycle sections so AlmanakCode-generated LP dashboards inherit the same tables the local detail page shows (PR 2 / Problem A2). When None (legacy callers), those sections are skipped silently — backward-compatible with every existing render_lp_dashboard(...) call site.

None

get_uniswap_v3_config

get_uniswap_v3_config(
    token0: str = "WETH",
    token1: str = "USDC",
    fee_tier: str = "0.30%",
    chain: str = "arbitrum",
    timeframe: str = "1h",
) -> LPDashboardConfig

Get pre-configured Uniswap V3 LP dashboard config.

timeframe sets the price-chart candle interval (VIB-4969); defaults to "1h".

get_aerodrome_config

get_aerodrome_config(
    token0: str = "WETH",
    token1: str = "USDC",
    pool_type: str = "volatile",
    chain: str = "base",
    timeframe: str = "1h",
) -> LPDashboardConfig

Get pre-configured Aerodrome LP dashboard config.

timeframe sets the price-chart candle interval (VIB-4969); defaults to "1h".

get_traderjoe_v2_config

get_traderjoe_v2_config(
    token0: str = "WAVAX",
    token1: str = "USDC",
    bin_step: str = "20",
    chain: str = "avalanche",
    timeframe: str = "1h",
) -> LPDashboardConfig

Get pre-configured TraderJoe V2 LP dashboard config.

timeframe sets the price-chart candle interval (VIB-4969); defaults to "1h".

get_pancakeswap_v3_config

get_pancakeswap_v3_config(
    token0: str = "WBNB",
    token1: str = "USDT",
    fee_tier: str = "0.25%",
    chain: str = "bsc",
    timeframe: str = "1h",
) -> LPDashboardConfig

Get pre-configured PancakeSwap V3 LP dashboard config.

timeframe sets the price-chart candle interval (VIB-4969); defaults to "1h".

Lending

almanak.framework.dashboard.templates.lending_dashboard

Lending Protocol Dashboard Template.

Reusable template for creating dashboards for lending strategies on protocols like Aave V3, Morpho Blue, Compound V3, and Spark.

Scope (single-signal / single-position): the template renders one collateral / borrow pair with one scalar health factor and LTV — the shape of a single supply-borrow loop. Multi-collateral is partially supported through collateral_assets (a dict feeding the breakdown plot), but the headline metrics remain singular. The 3 accounting sections (PnL, Cost Stack, Trade Tape) are baked in so every lending dashboard ships with full accounting. For multi-signal layouts (e.g. "supply on Aave + supply on Morpho" as separate motivations), do not parameterize this template — write a custom dashboard composed from the section helpers (render_pnl_section, render_cost_stack_section, render_trade_tape_section) plus primitive plot helpers from almanak.framework.dashboard.plots directly. See the dashboard blueprints for the recommended composition.

Usage

from almanak.framework.dashboard.templates import LendingDashboardConfig, render_lending_dashboard

config = LendingDashboardConfig( protocol="aave_v3", collateral_token="WETH", borrow_token="USDC", )

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state): render_lending_dashboard(deployment_id, strategy_config, session_state, config)

LendingDashboardConfig dataclass

LendingDashboardConfig(
    protocol: str = "aave_v3",
    collateral_token: str = "WETH",
    borrow_token: str = "USDC",
    chain: str = DEFAULT_CHAIN,
    liquidation_threshold: float = 1.0,
    safe_threshold: float = 1.5,
    max_ltv: float = 0.8,
    liquidation_ltv: float = 0.85,
    show_health_factor: bool = True,
    show_ltv: bool = True,
    show_collateral_breakdown: bool = True,
    show_rate_comparison: bool = False,
)

Configuration for a lending dashboard.

Attributes:

Name Type Description
protocol str

Protocol name (e.g., "aave_v3", "morpho_blue", "compound_v3")

collateral_token str

Primary collateral token symbol

borrow_token str

Primary borrow token symbol

chain str

Chain name

liquidation_threshold float

Health factor threshold for liquidation (default 1.0)

safe_threshold float

Health factor threshold considered safe (default 1.5)

max_ltv float

Maximum LTV ratio (default 0.8)

liquidation_ltv float

LTV at which liquidation occurs (default 0.85)

show_health_factor bool

Whether to show health factor gauge

show_ltv bool

Whether to show LTV ratio visualization

show_collateral_breakdown bool

Whether to show collateral breakdown

show_rate_comparison bool

Whether to show rate comparison (for multi-protocol)

prepare_lending_session_state

prepare_lending_session_state(
    api_client: Any,
    *,
    session_state: dict[str, Any],
    config: LendingDashboardConfig,
    strategy_config: dict[str, Any] | None = None,
) -> dict[str, Any]

Hydrate generic lending dashboard fields from strategy state.

Hosted/custom dashboards receive raw strategy persistence, which often stores domain names such as supplied_token_amount and borrowed_token_amount. The lending template renders generic fields (collateral_amount, borrowed_amount, ltv, health_factor). This adapter keeps strategy dashboards thin while making the SDK template useful for Aave-style supply/borrow loops.

render_lending_dashboard

render_lending_dashboard(
    deployment_id: str,
    strategy_config: dict[str, Any],
    session_state: dict[str, Any],
    config: LendingDashboardConfig,
) -> None

Render a lending strategy dashboard using the provided configuration.

Single-signal / single-position template — one collateral/borrow pair with scalar health factor and LTV. Bakes in the 3 accounting sections (PnL → primitive content → Cost Stack → Trade Tape). For multi- position or multi-signal layouts, compose a custom dashboard from the section helpers directly rather than parameterizing this template.

Parameters:

Name Type Description Default
deployment_id str

The deployment identifier

required
strategy_config dict[str, Any]

Strategy configuration dictionary

required
session_state dict[str, Any]

Current session state with position data

required
config LendingDashboardConfig

LendingDashboardConfig for this dashboard

required

get_aave_v3_config

get_aave_v3_config(
    collateral_token: str = "WETH",
    borrow_token: str = "USDC",
    chain: str = DEFAULT_CHAIN,
) -> LendingDashboardConfig

Get pre-configured Aave V3 lending dashboard config.

get_morpho_blue_config

get_morpho_blue_config(
    collateral_token: str = "wstETH",
    borrow_token: str = "USDC",
    chain: str = "ethereum",
) -> LendingDashboardConfig

Get pre-configured Morpho Blue lending dashboard config.

get_compound_v3_config

get_compound_v3_config(
    collateral_token: str = "WETH",
    borrow_token: str = "USDC",
    chain: str = "ethereum",
) -> LendingDashboardConfig

Get pre-configured Compound V3 lending dashboard config.

get_spark_config

get_spark_config(
    collateral_token: str = "WETH",
    borrow_token: str = "DAI",
    chain: str = "ethereum",
) -> LendingDashboardConfig

Get pre-configured Spark lending dashboard config.

Perpetuals

almanak.framework.dashboard.templates.perp_dashboard

Perpetual Futures Dashboard Template.

Reusable template for creating dashboards for perpetual trading strategies on protocols like GMX V2 and Hyperliquid.

Scope (single-signal / single-position): the template renders one perp position on one market. has_position is a boolean and entry_price / is_long / liquidation_price are scalars; an account holding multiple perps simultaneously is not modelled here. The 3 accounting sections (PnL, Cost Stack, Trade Tape) are baked in so every perp dashboard ships with full accounting. For multi-position or multi-signal layouts (e.g. a basket of perp legs hedging spot exposure), do not parameterize this template — write a custom dashboard composed from the section helpers (render_pnl_section, render_cost_stack_section, render_trade_tape_section) plus primitive plot helpers from almanak.framework.dashboard.plots directly. See the dashboard blueprints for the recommended composition.

Usage

from almanak.framework.dashboard.templates import PerpDashboardConfig, render_perp_dashboard

config = PerpDashboardConfig( protocol="gmx_v2", market="ETH/USD", collateral_token="WETH", )

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state): render_perp_dashboard(deployment_id, strategy_config, session_state, config)

PerpDashboardConfig dataclass

PerpDashboardConfig(
    protocol: str = "gmx_v2",
    market: str = "ETH/USD",
    collateral_token: str = "WETH",
    chain: str = DEFAULT_CHAIN,
    max_leverage: float = 50.0,
    safe_leverage: float = 10.0,
    show_position_dashboard: bool = True,
    show_funding_history: bool = True,
    show_leverage_gauge: bool = True,
    show_liquidation_levels: bool = True,
)

Configuration for a perpetual futures dashboard.

Attributes:

Name Type Description
protocol str

Protocol name (e.g., "gmx_v2", "hyperliquid")

market str

Market identifier (e.g., "ETH/USD", "BTC/USD")

collateral_token str

Collateral token symbol

chain str

Chain name

max_leverage float

Maximum allowed leverage

safe_leverage float

Recommended safe leverage

show_position_dashboard bool

Whether to show the main position dashboard

show_funding_history bool

Whether to show funding rate history

show_leverage_gauge bool

Whether to show leverage gauge

show_liquidation_levels bool

Whether to show liquidation levels

render_perp_dashboard

render_perp_dashboard(
    deployment_id: str,
    strategy_config: dict[str, Any],
    session_state: dict[str, Any],
    config: PerpDashboardConfig,
) -> None

Render a perpetual futures strategy dashboard using the provided configuration.

Single-signal / single-position template — one perp position on one market. Bakes in the 3 accounting sections (PnL → primitive content → Cost Stack → Trade Tape). For multi-position or multi-signal layouts, compose a custom dashboard from the section helpers directly rather than parameterizing this template.

Parameters:

Name Type Description Default
deployment_id str

The deployment identifier

required
strategy_config dict[str, Any]

Strategy configuration dictionary

required
session_state dict[str, Any]

Current session state with position data

required
config PerpDashboardConfig

PerpDashboardConfig for this dashboard

required

get_gmx_v2_config

get_gmx_v2_config(
    market: str = "ETH/USD",
    collateral_token: str = "WETH",
    chain: str = DEFAULT_CHAIN,
) -> PerpDashboardConfig

Get pre-configured GMX V2 perpetuals dashboard config.

get_hyperliquid_config

get_hyperliquid_config(
    market: str = "ETH",
    collateral_token: str = "USDC",
    chain: str = "hyperliquid",
) -> PerpDashboardConfig

Get pre-configured Hyperliquid perpetuals dashboard config.

Prediction markets

almanak.framework.dashboard.templates.prediction_dashboard

Prediction Market Dashboard Template.

Reusable template for creating dashboards for prediction market strategies on platforms like Polymarket.

Scope (single-signal / single-position): the template renders one active market with one YES/NO position. market_id / yes_shares / no_shares / cost_basis are scalars; an account holding positions across multiple markets simultaneously is not modelled in the headline panels (the optional tracked_markets plot is informational only). The 3 accounting sections (PnL, Cost Stack, Trade Tape) are baked in so every prediction dashboard ships with full accounting. For multi-market or multi-signal layouts (e.g. an arbitrage basket spanning N markets), do not parameterize this template — write a custom dashboard composed from the section helpers (render_pnl_section, render_cost_stack_section, render_trade_tape_section) plus primitive plot helpers from almanak.framework.dashboard.plots directly. See the dashboard blueprints for the recommended composition.

Usage

from almanak.framework.dashboard.templates import PredictionDashboardConfig, render_prediction_dashboard

protocol defaults to the connector default ("polymarket"); pass

protocol="" to override for another prediction venue.

config = PredictionDashboardConfig()

def render_custom_dashboard(deployment_id, strategy_config, api_client, session_state): render_prediction_dashboard(deployment_id, strategy_config, session_state, config)

PredictionDashboardConfig dataclass

PredictionDashboardConfig(
    protocol: str = (
        lambda: _default_prediction_protocol()
        or "polymarket"
    )(),
    chain: str = "polygon",
    show_position_overview: bool = True,
    show_probability_chart: bool = True,
    show_market_outcomes: bool = True,
    show_arbitrage_analysis: bool = True,
    show_pnl_breakdown: bool = True,
)

Configuration for a prediction market dashboard.

Attributes:

Name Type Description
protocol str

Protocol name (e.g., "polymarket")

chain str

Chain name

show_position_overview bool

Whether to show position overview

show_probability_chart bool

Whether to show probability over time

show_market_outcomes bool

Whether to show market outcomes comparison

show_arbitrage_analysis bool

Whether to show arbitrage opportunity analysis

show_pnl_breakdown bool

Whether to show PnL breakdown

render_prediction_dashboard

render_prediction_dashboard(
    deployment_id: str,
    strategy_config: dict[str, Any],
    session_state: dict[str, Any],
    config: PredictionDashboardConfig,
) -> None

Render a prediction market strategy dashboard using the provided configuration.

Single-signal / single-position template — one active market with one YES/NO position. Bakes in the 3 accounting sections (PnL → primitive content → Cost Stack → Trade Tape). For multi-position or multi-signal layouts, compose a custom dashboard from the section helpers directly rather than parameterizing this template.

Parameters:

Name Type Description Default
deployment_id str

The deployment identifier

required
strategy_config dict[str, Any]

Strategy configuration dictionary

required
session_state dict[str, Any]

Current session state with position data

required
config PredictionDashboardConfig

PredictionDashboardConfig for this dashboard

required

get_polymarket_config

get_polymarket_config() -> PredictionDashboardConfig

Get pre-configured Polymarket dashboard config.

get_polymarket_arbitrage_config

get_polymarket_arbitrage_config() -> (
    PredictionDashboardConfig
)

Get pre-configured Polymarket arbitrage dashboard config.