#![allow(clippy::unwrap_used, clippy::expect_used)]
use chrono::{Datelike, Duration, NaiveTime, Utc, Weekday};
use futures::StreamExt;
use rustrade_data::exchange::lse::vault::LseVaultClient;
use std::collections::HashMap;
use tracing::info;
#[tokio::main]
async fn main() {
init_logging();
let client = LseVaultClient::from_env()
.expect("set LSE_API_KEY - get a free key at https://londonstrategicedge.com/data");
let mut day = Utc::now().date_naive() - Duration::days(1);
while matches!(day.weekday(), Weekday::Sat | Weekday::Sun) {
day -= Duration::days(1);
}
let start = day
.and_time(NaiveTime::from_hms_opt(15, 0, 0).unwrap())
.and_utc();
let end = start + Duration::minutes(5);
let prints = client.fetch_option_flow(Some("SPY"), start, end);
futures::pin_mut!(prints);
let mut per_contract: HashMap<String, usize> = HashMap::new();
let mut total = 0usize;
while let Some(print) = prints.next().await {
let print = print.expect("option print");
total += 1;
*per_contract
.entry(print.contract.ticker.to_string())
.or_default() += 1;
if total <= 3 {
info!(
id = print.id,
time = %print.time,
ticker = %print.contract.ticker,
kind = ?print.contract.kind,
strike = %print.contract.strike,
expiry = %print.contract.expiry,
price = %print.price,
contracts = print.volume,
delta = ?print.greeks.delta,
iv = ?print.greeks.implied_volatility,
underlying = ?print.greeks.underlying_price,
"SPY option print"
);
}
}
info!(
total,
contracts = per_contract.len(),
"SPY print tape complete"
);
let Some((ticker, count)) = per_contract.into_iter().max_by_key(|(_, count)| *count) else {
info!("no prints in the window - a US market holiday?");
return;
};
info!(%ticker, count, "busiest contract");
let candles = client
.collect_option_candles(&ticker, start, end)
.await
.expect("option candles");
for candle in &candles {
info!(
close_time = %candle.candle.close_time,
close = %candle.candle.close,
contracts = ?candle.candle.volume,
prints = ?candle.candle.trade_count,
delta_avg = ?candle.greeks.delta,
"option candle"
);
}
}
fn init_logging() {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::filter::EnvFilter::builder()
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
.from_env_lossy(),
)
.with_ansi(cfg!(debug_assertions))
.json()
.init()
}