paft-domain 0.8.0

Domain modeling primitives (instrument, exchange, period, market state) for the paft ecosystem.
Documentation

paft-domain

Domain modeling primitives for the paft ecosystem: instruments, exchanges, periods, and market state.

Crates.io Docs.rs

  • Strongly-typed identifiers for securities (Symbol, Figi, Isin) with enforced validation
  • Instrument with hierarchical identifiers for securities (FIGI → ISIN → Symbol@Exchange → Symbol)
  • Canonical, serde-stable extensible enums (Exchange, AssetKind, MarketState)
  • Period parsing for quarters, years, and dates with a canonical wire format

Install

Prefer the facade crate for most applications:

[dependencies]
paft = "0.8.0"

Advanced (direct dependency, minimal):

[dependencies]
paft-domain = { version = "0.8.0", default-features = false }

Enable DataFrame helpers as needed:

[dependencies]
paft-domain = { version = "0.8.0", default-features = false, features = ["dataframe"] }

Features

  • tracing: enable lightweight instrumentation on constructors and validators
  • dataframe: enable DataFrame traits for Polars integration

Quickstart

The quickstart below uses the direct paft-domain dependency shown above. If you depend on the facade crate instead, import these types from paft::domain or paft::prelude.

use paft_domain::{AssetKind, Exchange, Figi, Instrument, Isin, MarketState, Period, Symbol};

// Minimal: instrument from symbol + exchange
let aapl = Instrument::from_symbol_and_exchange("AAPL", Exchange::NASDAQ, AssetKind::Equity)
    .unwrap();

// Globally-identified: build the flat struct directly to attach FIGI/ISIN
// (preferred over symbol when available).
let aapl_pro = Instrument {
    symbol: Symbol::new("AAPL").unwrap(),
    exchange: Some(Exchange::NASDAQ),
    figi: Some(Figi::new("BBG000B9XRY4").unwrap()),
    isin: Some(Isin::new("US0378331005").unwrap()),
    kind: AssetKind::Equity,
};
assert_eq!(aapl_pro.unique_key(), "BBG000B9XRY4");

// Period parsing with canonical output (wire = Display)
let q4 = "2023-Q4".parse::<Period>().unwrap();
assert_eq!(q4.to_string(), "2023Q4");

// Unknown provider states round-trip through Other(Canonical).
let delayed = "DELAYED".parse::<MarketState>().unwrap();
assert_eq!(delayed.to_string(), "DELAYED");

Prediction markets

Prediction-market identity is intentionally outside paft-domain; use the separate paft-prediction crate:

[dependencies]
paft-domain = "0.8.0"
paft-prediction = "0.8.0"
use paft_prediction::PredictionInstrument;

// Create an instrument for a prediction market outcome
let pm = PredictionInstrument::new(
    "0x5eed579ff6763914d78a966c83473ba2485ac8910d0a0914eef6d9fcb33085de",
    "73470541315377973562501025254719659796416871135081220986683321361000395461644",
).unwrap();

// Unique key for prediction markets is event_id/outcome_id
let expected = concat!(
    "0x5eed579ff6763914d78a966c83473ba2485ac8910d0a0914eef6d9fcb33085de",
    "/",
    "73470541315377973562501025254719659796416871135081220986683321361000395461644",
);
assert_eq!(
    pm.unique_key(),
    expected,
);

Links