finzdata 0.2.0

Official Rust client for FinzData point-in-time market data: US stocks since 2000 (delisted included), every futures contract since 2007, point-in-time GEX, FX, indexes, crypto, COT, SEC fundamentals and vintage macro
Documentation
//! Live API checks: FINZDATA_API_KEY=... cargo test --test live -- --ignored
use finzdata::{blocking, Client, Row};

#[tokio::test]
#[ignore]
async fn live_async() {
    let fz = Client::new().expect("client");
    let me = fz.me().await.expect("me");
    assert!(me.tier.is_some());
    let bars = fz.prices("AAPL", Some("2026-09-01"), Some("2026-09-05"), None).await.expect("prices");
    assert!(!bars.is_empty() && bars.data[0].close.is_some());
    let mins = fz.minutes("AAPL", Some("2026-09-02"), Some("2026-09-02"), Some("5min"), None).await.expect("minutes");
    assert!(mins.len() > 50);
    let cot = fz.cot(Some("legacy_fo"), Some("088691"), None, Some("2026-08-01"), None).await.expect("cot");
    assert!(!cot.is_empty());
    let cpi = fz.macro_obs("CPIAUCSL", Some("2026-01-01"), None, None, None).await.expect("macro");
    assert!(!cpi.is_empty());
    let f = fz.fundamentals(Some("AAPL"), None, Some("Revenues"), None).await.expect("fundamentals");
    assert!(!f.is_empty());
    let ds = fz.datasets().await.expect("datasets");
    assert!(ds.len() > 10);
    let gex = fz.gex("SPY", Some("2025-01-02"), Some("2025-01-10")).await.expect("gex");
    println!("gex rows {} note {:?}", gex.len(), gex.history_note);
    let raw = fz.get::<Row>("/v1/gex/tickers", &[]).await.expect("generic get");
    println!("gex tickers {}", raw.len());
    match fz.gex_strikes("SPY", "2025-01-02").await {
        Err(finzdata::Error::Api { status, detail }) => println!("strikes gated as expected: {status} {detail}"),
        Ok(r) => println!("strikes rows {}", r.len()),
        Err(e) => panic!("unexpected {e}"),
    }
}

#[test]
#[ignore]
fn live_blocking() {
    let fz = blocking::Client::new().expect("client");
    let b = fz.prices("MSFT", Some("2026-09-01"), Some("2026-09-05"), None).expect("prices");
    assert!(!b.is_empty());
}

#[tokio::test]
#[ignore]
async fn bad_key_is_api_error() {
    let fz = Client::builder().api_key("nope").build().expect("client");
    match fz.prices("AAPL", None, None, None).await {
        Err(finzdata::Error::Api { status, .. }) => assert!(status == 401 || status == 403),
        other => panic!("expected Api error, got {other:?}"),
    }
}