atelier_data 0.0.15

Data Artifacts and I/O for the atelier-rs engine
use std::path::Path;

use super::MarketSnapshotConfig;

// ─────────────────────────────────────────────────────────────────────────────
// Banner
// ─────────────────────────────────────────────────────────────────────────────

/// Print a standardized startup banner for a [`MarketSnapshotConfig`] run.
pub fn print_banner(title: &str, cfg: &MarketSnapshotConfig) {
    let period_ns = cfg.period_ns();
    let flush_ns = cfg.flush_interval_ns();
    let flush_secs = flush_ns as f64 / 1e9;
    println!();
    println!(" ══════════════════════════════════════════════════════════");
    println!("  {}", title);
    println!(" ══════════════════════════════════════════════════════════");
    println!("  Symbol:    {}", cfg.symbol.name);
    println!("  Exchange:  {}", cfg.exchange.name);
    println!("  Mode:      {}", cfg.clock_mode_label());
    println!(
        "  Grid:      {} ns ({:.1} ms)",
        period_ns,
        period_ns as f64 / 1_000_000.0,
    );
    println!(
        "  Flush:     every {} snapshots ({:.0}s)",
        cfg.pipeline.flush_threshold,
        flush_secs,
    );
    println!("  Output:    {}", cfg.output_dir().display());
    println!("  Stop:      Ctrl-C (continuous)");
    println!(" ══════════════════════════════════════════════════════════");
    println!();
}

// ─────────────────────────────────────────────────────────────────────────────
// Snapshot summary printer
// ─────────────────────────────────────────────────────────────────────────────

/// Print a one-line summary of a `MarketSnapshot`.
pub fn _print_snapshot_line(
    idx: usize,
    ts_ns: u64,
    ob_info: Option<(f64, f64, usize, usize)>, // (best_bid, best_ask, bid_depth, ask_depth)
    n_trades: usize,
    n_liqs: usize,
    n_fr: usize,
    n_oi: usize,
) {
    let ob_desc = ob_info
        .map(|(bid, ask, bd, ad)| {
            format!("mid={:.2} bids={} asks={}", (bid + ask) / 2.0, bd, ad)
        })
        .unwrap_or_else(|| "OB=∅".to_string());

    println!(
        "  [{:>3}] ts_ns={:<20} | {} | tr={} lq={} fr={} oi={}",
        idx, ts_ns, ob_desc, n_trades, n_liqs, n_fr, n_oi,
    );
}

// ─────────────────────────────────────────────────────────────────────────────
// FlushResult printer
// ─────────────────────────────────────────────────────────────────────────────

/// Print the results of a `flush_to_parquet` call.
pub fn print_flush_result(result: &crate::FlushResult) {
    println!();
    println!(" ── Parquet Flush ──────────────────────────────────────────");
    println!("  Snapshots flushed: {}", result.snapshot_count);

    if let Some(p) = &result.orderbook_path {
        println!("  Orderbooks:    {}", p.display());
    }
    if let Some(p) = &result.trades_path {
        println!("  Trades:        {}", p.display());
    }
    if let Some(p) = &result.liquidations_path {
        println!("  Liquidations:  {}", p.display());
    }
    if let Some(p) = &result.funding_path {
        println!("  Funding rates: {}", p.display());
    }
    if let Some(p) = &result.open_interest_path {
        println!("  Open interest: {}", p.display());
    }
    println!(" ──────────────────────────────────────────────────────────");
}

// ─────────────────────────────────────────────────────────────────────────────
// Aggregate summary printer
// ─────────────────────────────────────────────────────────────────────────────

/// Print a compact table header for MarketAggregate rows.
pub fn print_aggregate_header() {
    println!(
        "  {:>5} {:>14} {:>10} {:>10} {:>8} {:>10} {:>6} {:>12} {:>4}",
        "idx",
        "ts_ns",
        "mid_price",
        "spread",
        "imb",
        "trade_vol",
        "tr_n",
        "liq_not",
        "lq_n",
    );
    println!("  {}", "".repeat(90));
}

/// Print a single MarketAggregate row.
pub fn print_aggregate_row(idx: usize, agg: &crate::MarketAggregate) {
    println!(
        "  {:>5} {:>14} {:>10.2} {:>10.4} {:>8.4} {:>10.6} {:>6} {:>12.2} {:>4}",
        idx,
        agg.ts_ns,
        agg.ob_mid_price,
        agg.ob_spread,
        agg.ob_imbalance,
        agg.trade_volume,
        agg.trade_count,
        agg.liq_notional,
        agg.liq_count,
    );
}

/// Print a load-mode banner.
pub fn print_load_banner(title: &str, path: &Path) {
    println!();
    println!(" ══════════════════════════════════════════════════════════");
    println!("  {}", title);
    println!(" ══════════════════════════════════════════════════════════");
    println!("  File: {}", path.display());
    println!(" ══════════════════════════════════════════════════════════");
    println!();
}