| Crates.io | paft |
| lib.rs | paft |
| version | 0.7.1 |
| created_at | 2025-09-15 22:56:26.588584+00 |
| updated_at | 2025-10-31 17:56:19.074966+00 |
| description | Facade crate for paft: unified public API over the paft ecosystem. |
| homepage | https://github.com/paft-rs/paft |
| repository | https://github.com/paft-rs/paft |
| max_upload_size | |
| id | 1840669 |
| size | 164,824 |
Provider Agnostic Financial Types for Rust
Standardized Rust types for financial data that work with any provider—Yahoo Finance, Bloomberg, Alpha Vantage, and more.
🌟 Ecosystem Overview: For the bigger picture, vision, and contributor guidance, see the workspace README.
[dependencies]
# Basic installation with default feature set (domain + market + fundamentals)
paft = "0.7.1"
# Or, add optional analysis helpers (Polars DataFrame support)
paft = { version = "0.7.1", features = ["dataframe"] }
# Or, opt into aggregates snapshot models as well
paft = { version = "0.7.1", features = ["aggregates"] }
# Or, enable the full bundle of features
paft = { version = "0.7.1", features = ["full"] }
# Or, customize your installation
paft = { version = "0.7.1", default-features = false, features = ["fundamentals", "dataframe"] }
# Switch the money backend to BigDecimal (default is rust_decimal)
paft = { version = "0.7.1", features = ["bigdecimal"] }
All features are optional—disable the defaults (default-features = false) and opt back into what you need.
domain (default): exposes instrument, exchange, period, and other domain models.market (default, enables domain): markets and history types such as Quote, Candle, and HistoryRequest.fundamentals (default, enables domain): fundamentals, ESG, and ownership data structures.aggregates: exposes aggregated snapshot models like FastInfo and Info.bigdecimal: swaps the money backend to BigDecimal when you require arbitrary precision.dataframe: forwards DataFrame support from paft-utils, providing ToDataFrame/ToDataFrameVec.full: convenience bundle for domain, market, fundamentals, aggregates, and dataframe.panicking-money-ops: re-enables Money arithmetic operators that panic on mismatched currencies (see below).money-formatting: forwards to paft-money/money-formatting for locale-aware formatting and parsing APIs.tracing: enables lightweight instrumentation via the tracing crate; zero‑cost when disabled; adds spans/events in constructors and validators across the workspace.Instrument::figi and Instrument::isin are now typed as Option<Figi> / Option<Isin>. Use Figi::new("...") and Isin::new("...") to construct validated identifiers, and call figi_str() / isin_str() when you need a borrowed &str.CompanyProfile::isin and FundProfile::isin now store Option<Isin>; update struct literals to pass Isin::new(..)? and adjust deserialization expectations accordingly.Isin::new and Figi::new now always enforce checksum validation. If you previously relied on lenient mode, strip placeholders or keep them in Symbol fields instead.#[serde(transparent)], so existing JSON payloads continue to operate with plain strings while now enforcing checksum validation at the boundary.Instrument with hierarchical identifiers, AssetKindQuote, Candle, HistoryResponse, MarketStateOptionContract, OptionChainNewsArticle, SearchResultToDataFrame traituse paft::prelude::*;
use rust_decimal::Decimal;
// Create instruments with different levels of identification
let apple = Instrument::try_new(
"AAPL",
AssetKind::Equity,
Some("BBG000B9XRY4"), // FIGI (best)
Some("US0378331005"), // ISIN
Some(Exchange::NASDAQ),
)
.expect("valid instrument");
let bitcoin = Instrument::from_symbol("BTC-USD", AssetKind::Crypto)
.expect("valid crypto symbol");
// Create market data
let quote = Quote {
symbol: Symbol::new("AAPL").unwrap(),
shortname: Some("Apple Inc.".to_string()),
price: Some(Money::from_canonical_str("190.12", Currency::Iso(IsoCurrency::USD)).unwrap()),
previous_close: Some(Money::from_canonical_str("189.96", Currency::Iso(IsoCurrency::USD)).unwrap()),
exchange: Some(Exchange::NASDAQ),
market_state: Some(MarketState::Regular),
};
// Automatic prioritization: FIGI > ISIN > Symbol@Exchange > Symbol
println!("{}", apple.unique_key()); // "BBG000B9XRY4" (uses FIGI)
println!("{}", bitcoin.unique_key()); // "BTC-USD" (uses symbol)
// Check identification levels
if apple.is_globally_identified() {
println!("Has FIGI or ISIN - works across all providers");
}
// Access specific identifiers
if let Some(figi) = apple.figi() {
println!("FIGI: {}", figi);
}
use paft::prelude::*;
// Request 6 months of daily data (validated in constructor)
let request = HistoryRequest::try_from_range(Range::M6, Interval::D1).unwrap();
Enable DataFrame support for analysis:
[dependencies]
paft = { version = "0.7.1", features = ["dataframe"] }
use paft::prelude::*;
let quotes = vec![quote1, quote2, quote3];
let df = quotes.to_dataframe()?;
println!("Average price: {:.2}", df.column("price")?.mean()?);
Enable the money-formatting feature to opt into locale-aware Display and strict parsing:
[dependencies]
paft = { version = "0.7.1", features = ["money-formatting"] }
use paft::money::{Currency, IsoCurrency, Money, Locale};
let m = Money::from_canonical_str("1234.56", Currency::Iso(IsoCurrency::USD))?;
let us = m.format_with_locale(Locale::EnUs)?;
let de = m.format_with_locale(Locale::EnEu)?;
assert_eq!(us, "$1,234.56");
assert_eq!(de, "$1.234,56");
// Strict parsing
let parsed = Money::from_str_locale("$1,234.56", Currency::Iso(IsoCurrency::USD), Locale::EnUs)?;
By default, Money arithmetic operators (+, -, /, *) that would
panic on invalid input are disabled. Use the safe methods instead:
let sum = a.try_add(&b)?;
let diff = a.try_sub(&b)?;
let half = a.try_div(Decimal::from(2))?;
If you explicitly want the ergonomic panicking operators, enable the
panicking-money-ops feature via the paft facade (it forwards to paft-money):
[dependencies]
paft = { version = "0.7.1", features = ["panicking-money-ops"] }
Note: This feature is opt-in and enables the +, -, and / operators to panic
on currency mismatch or division by zero. Prefer try_* methods in most apps.
For ergonomics in math-heavy code, you may enable this only when you control
the data end to end (e.g., internal pipelines with strict invariants) and are
absolutely sure all arithmetic uses matching currencies. For external or
untrusted data, keep this feature disabled and use the try_* APIs.
paft uses extensible enums with Other(Canonical) variants to gracefully handle unknown provider values:
use paft::prelude::*;
// Handle unknown currencies from providers
match currency {
Currency::Iso(IsoCurrency::USD) => "US Dollar",
Currency::Iso(IsoCurrency::EUR) => "Euro",
Currency::Other(code) => match code.as_ref() {
"BTC" => "Bitcoin",
_ => "Unknown currency",
},
}
// Same pattern for exchanges, asset types, etc.
let exchange: Exchange = "BATS".parse().unwrap(); // Unknown exchange handled via Other
This pattern ensures your code never breaks when providers return new or unexpected values.
Enums ship with three complementary string representations:
code() returns the canonical token used in APIs and serialization.to_string() mirrors code() so logging and dataframes stay consistent.Currency::full_name(), AssetKind::full_name(), and MarketState::full_name() provide sentence-case labels for UI surfaces.Keep the rule of thumb: wire = code = Display; human prose = explicit helper.
MIT License. See LICENSE for details.