|
| 1 | +//! Historical Data API example |
| 2 | +//! |
| 3 | +//! Demonstrates the Historical Data API for fetching archived market data, |
| 4 | +//! including cutoff timestamps, historical markets, candlesticks, fills, and orders. |
| 5 | +//! |
| 6 | +//! Run with: cargo run --example historical |
| 7 | +
|
| 8 | +use kalshi_trade_rs::{ |
| 9 | + CandlestickPeriod, GetHistoricalCandlesticksParams, GetHistoricalFillsParams, |
| 10 | + GetHistoricalMarketsParams, GetHistoricalOrdersParams, KalshiClient, KalshiConfig, |
| 11 | +}; |
| 12 | + |
| 13 | +#[tokio::main] |
| 14 | +async fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 15 | + dotenvy::dotenv().ok(); |
| 16 | + |
| 17 | + let config = KalshiConfig::from_env()?; |
| 18 | + println!("Connected to {:?} environment\n", config.environment); |
| 19 | + |
| 20 | + let client = KalshiClient::new(config)?; |
| 21 | + |
| 22 | + // 1. Get Historical Cutoff Timestamps |
| 23 | + println!("=== Historical Cutoff ==="); |
| 24 | + let cutoff = client.get_historical_cutoff().await?; |
| 25 | + println!("Markets archived through: {}", cutoff.market_settled_ts); |
| 26 | + println!("Trades archived through: {}", cutoff.trades_created_ts); |
| 27 | + println!("Orders archived through: {}", cutoff.orders_updated_ts); |
| 28 | + println!(); |
| 29 | + |
| 30 | + // 2. Get Historical Markets (default params) |
| 31 | + println!("=== Historical Markets (first 5) ==="); |
| 32 | + let params = GetHistoricalMarketsParams::new().limit(5); |
| 33 | + let markets = client.get_historical_markets_with_params(params).await?; |
| 34 | + println!("Returned {} historical markets", markets.markets.len()); |
| 35 | + |
| 36 | + for market in &markets.markets { |
| 37 | + println!( |
| 38 | + " {} | {:?} | result: {:?} | vol: {}", |
| 39 | + market.ticker, |
| 40 | + market.status, |
| 41 | + market.result, |
| 42 | + market.volume.unwrap_or(0) |
| 43 | + ); |
| 44 | + } |
| 45 | + |
| 46 | + if let Some(cursor) = &markets.cursor { |
| 47 | + println!(" Next cursor: {}...", &cursor[..cursor.len().min(20)]); |
| 48 | + } |
| 49 | + println!(); |
| 50 | + |
| 51 | + // 3. Get a specific historical market and its candlesticks |
| 52 | + if let Some(market) = markets.markets.first() { |
| 53 | + let ticker = &market.ticker; |
| 54 | + |
| 55 | + println!("=== Historical Market Detail: {} ===", ticker); |
| 56 | + let detail = client.get_historical_market(ticker).await?; |
| 57 | + let m = &detail.market; |
| 58 | + |
| 59 | + println!(" Title: {}", m.title.as_deref().unwrap_or("(none)")); |
| 60 | + println!(" Event: {}", m.event_ticker); |
| 61 | + println!(" Type: {:?}", m.market_type); |
| 62 | + println!(" Status: {:?}", m.status); |
| 63 | + if let Some(sv) = &m.settlement_value_dollars { |
| 64 | + println!(" Settlement value: ${}", sv); |
| 65 | + } |
| 66 | + println!(); |
| 67 | + |
| 68 | + // 4. Get Historical Candlesticks |
| 69 | + // Use a broad time range to catch data for archived markets |
| 70 | + println!("=== Historical Candlesticks: {} ===", ticker); |
| 71 | + let now = std::time::SystemTime::now() |
| 72 | + .duration_since(std::time::UNIX_EPOCH)? |
| 73 | + .as_secs() as i64; |
| 74 | + let one_year_ago = now - 365 * 86400; |
| 75 | + |
| 76 | + let params = |
| 77 | + GetHistoricalCandlesticksParams::new(one_year_ago, now, CandlestickPeriod::OneDay); |
| 78 | + match client.get_historical_candlesticks(ticker, params).await { |
| 79 | + Ok(candles) => { |
| 80 | + println!(" {} candlesticks returned", candles.candlesticks.len()); |
| 81 | + for candle in candles.candlesticks.iter().take(3) { |
| 82 | + let close = candle |
| 83 | + .price |
| 84 | + .as_ref() |
| 85 | + .and_then(|p| p.close.as_deref()) |
| 86 | + .unwrap_or("N/A"); |
| 87 | + println!( |
| 88 | + " ts={} close=${} vol={}", |
| 89 | + candle.end_period_ts, close, candle.volume |
| 90 | + ); |
| 91 | + } |
| 92 | + if candles.candlesticks.len() > 3 { |
| 93 | + println!(" ... and {} more", candles.candlesticks.len() - 3); |
| 94 | + } |
| 95 | + } |
| 96 | + Err(e) => println!(" Could not fetch candlesticks: {}", e), |
| 97 | + } |
| 98 | + println!(); |
| 99 | + } |
| 100 | + |
| 101 | + // 5. Get Historical Fills (requires auth) |
| 102 | + println!("=== Historical Fills (first 5) ==="); |
| 103 | + let params = GetHistoricalFillsParams::new().limit(5); |
| 104 | + let fills = client.get_historical_fills_with_params(params).await?; |
| 105 | + println!("Returned {} historical fills", fills.fills.len()); |
| 106 | + |
| 107 | + for fill in &fills.fills { |
| 108 | + println!( |
| 109 | + " {} {} {} {} @ {} ({})", |
| 110 | + fill.ticker, |
| 111 | + fill.action, |
| 112 | + fill.count_fp, |
| 113 | + fill.side, |
| 114 | + fill.yes_price_fixed, |
| 115 | + if fill.is_taker { "taker" } else { "maker" }, |
| 116 | + ); |
| 117 | + } |
| 118 | + |
| 119 | + if fills.fills.is_empty() { |
| 120 | + println!(" (No historical fills found)"); |
| 121 | + } |
| 122 | + println!(); |
| 123 | + |
| 124 | + // 6. Get Historical Orders (requires auth) |
| 125 | + println!("=== Historical Orders (first 5) ==="); |
| 126 | + let params = GetHistoricalOrdersParams::new().limit(5); |
| 127 | + let orders = client.get_historical_orders_with_params(params).await?; |
| 128 | + println!("Returned {} historical orders", orders.orders.len()); |
| 129 | + |
| 130 | + for order in &orders.orders { |
| 131 | + println!( |
| 132 | + " {} {} {} {} | {:?} | filled: {}/{}", |
| 133 | + order.ticker, |
| 134 | + order.action, |
| 135 | + order.initial_count, |
| 136 | + order.side, |
| 137 | + order.status, |
| 138 | + order.fill_count, |
| 139 | + order.initial_count, |
| 140 | + ); |
| 141 | + } |
| 142 | + |
| 143 | + if orders.orders.is_empty() { |
| 144 | + println!(" (No historical orders found)"); |
| 145 | + } |
| 146 | + |
| 147 | + println!("\n=== Done ==="); |
| 148 | + Ok(()) |
| 149 | +} |
0 commit comments