Applied Market-Data Workflows

Two compact, applied market-data workflows using an offline deterministic provider:

  1. Single-ticker options workflow — quotes, listed option chains, BSM pricing, and Greeks for one ticker.

  2. Multi-ticker universe workflow — aligned prices/returns and a maximum-Sharpe portfolio across a small universe.

Both reuse the same deterministic provider pattern from notebook 06 — Market Data (Offline).

Setup

import abaquant
print(f"AbaQuant version: {abaquant.__version__}")
AbaQuant version: 1.0.0rc1
import pandas as pd

from abaquant.marketdata import get_ticker, get_tickers
from abaquant.visualization import VisualizationError


class DeterministicMarketDataProvider:
    """Offline provider reused across both workflows below."""

    name = "deterministic-example"

    def fast_info(self, symbol):
        return {"lastPrice": 105.0}

    def info(self, symbol):
        return {"currency": "USD", "marketCap": 600.0, "symbol": symbol}

    def history(self, symbol, **kwargs):
        import numpy as np
        dates = pd.date_range("2025-01-02", periods=24, freq="B")
        return pd.DataFrame({"Close": 100.0 + np.linspace(0, 8, len(dates))}, index=dates)

    def history_many(self, symbols, **kwargs):
        import numpy as np
        dates = pd.date_range("2025-01-02", periods=24, freq="B")
        data = {s: 100.0 + i * 5 + np.linspace(0, 8, len(dates)) for i, s in enumerate(symbols)}
        return pd.DataFrame(data, index=dates)

    def option_expirations(self, symbol):
        return ["2027-01-15"]

    def option_chain(self, symbol, expiry):
        strikes = [80.0, 90.0, 100.0, 110.0, 120.0]
        calls = pd.DataFrame({
            "contractSymbol": [f"{symbol}C{int(k)}" for k in strikes], "strike": strikes,
            "lastPrice": [22.0, 14.5, 8.0, 4.5, 2.4], "bid": [21.5, 14.0, 7.6, 4.1, 2.0],
            "ask": [22.5, 15.0, 8.4, 4.9, 2.8],
            "impliedVolatility": [0.31, 0.27, 0.23, 0.25, 0.29],
            "openInterest": [120, 240, 520, 310, 180], "volume": [12, 28, 65, 34, 16],
        })
        puts = pd.DataFrame({
            "contractSymbol": [f"{symbol}P{int(k)}" for k in strikes], "strike": strikes,
            "lastPrice": [2.2, 4.1, 7.8, 13.9, 21.0], "bid": [1.9, 3.8, 7.4, 13.4, 20.4],
            "ask": [2.5, 4.4, 8.2, 14.4, 21.6],
            "impliedVolatility": [0.35, 0.30, 0.24, 0.26, 0.32],
            "openInterest": [210, 330, 610, 270, 155], "volume": [18, 36, 70, 29, 14],
        })
        return calls, puts

    def income_statement(self, symbol, *, period="annual"):
        return pd.DataFrame({"2025-12-31": {"Total Revenue": 450.0}})

    def balance_sheet(self, symbol, *, period="annual"):
        return pd.DataFrame({"2025-12-31": {"Total Debt": 120.0}})

    def cash_flow_statement(self, symbol, *, period="annual"):
        return pd.DataFrame({"2025-12-31": {"Operating Cash Flow": 70.0}})

1. Single-ticker options workflow

Spot quote, listed expirations, one option chain, listed implied volatility, a BSM call price, and delta.

provider = DeterministicMarketDataProvider()
ticker = get_ticker("DEMO", provider=provider, financial_cache="memory")

option_workflow = {
    "spot": ticker.spot(),
    "expirations": ticker.options.expirations(),
    "chain_rows": len(ticker.options.chain(expiry="2027-01-15")),
    "listed_iv": ticker.options.listed_implied_volatility(strike=100.0, expiry="2027-01-15"),
    "bsm_call": ticker.options.bsm(
        strike=100.0, maturity=0.5, risk_free_rate=0.04, volatility=0.20
    ),
    "delta": ticker.options.greeks(
        strike=100.0, maturity=0.5, risk_free_rate=0.04, volatility=0.20
    )["delta"],
}
for key, value in option_workflow.items():
    print(f"{key:14s}: {value}")
spot          : 105.0
expirations   : ['2027-01-15']
chain_rows    : 10
listed_iv     : 0.23
bsm_call      : 9.87487438732785
delta         : 0.711280896917368
try:
    ticker.visualize(period="1mo")
except VisualizationError as exc:
    print(f"Visualization skipped (optional dependency missing): {exc}")
../../_images/f31e40afafccff591d049f5ebc3dbafa31a0973ab58f09fcb6a5b259589db598.png

2. Multi-ticker universe workflow

Aligned price/return panels, per-asset statistics, and a maximum-Sharpe portfolio across a three-asset universe.

universe = get_tickers(["ALPHA", "BETA", "GAMMA"], provider=provider)
portfolio = universe.portfolio.max_sharpe(period="1mo", risk_free_rate=0.02)

universe_workflow = {
    "symbols": universe.symbols,
    "price_shape": universe.history.prices(period="1mo").shape,
    "return_shape": universe.history.returns(period="1mo").shape,
    "statistics_rows": len(universe.statistics.summary(period="1mo")),
    "max_sharpe_alpha_weight": float(next(iter(portfolio.weights.values()))),
    "max_sharpe_ratio": portfolio.sharpe_ratio,
}
for key, value in universe_workflow.items():
    print(f"{key:24s}: {value}")
symbols                 : ('ALPHA', 'BETA', 'GAMMA')
price_shape             : (24, 3)
return_shape            : (23, 3)
statistics_rows         : 3
max_sharpe_alpha_weight : 0.0
max_sharpe_ratio        : 745.6999002212838
try:
    universe.visualize(period="1mo")
except VisualizationError as exc:
    print(f"Visualization skipped (optional dependency missing): {exc}")
../../_images/1744989966747151eb700eba574dbc05c08a34bf5d893850a3c671ee55f766a2.png

Takeaway

These are the two smallest useful entry points into abaquant.marketdata: one ticker for single-name option analytics, one universe for cross-asset portfolio construction. Both are lazy — no data is retrieved until you call a method like .spot() or .history.prices().