// src/corporate/fx.rs use std::collections::HashMap; use reqwest; use serde_json::Value; use tokio::fs; use std::path::Path; static FX_CACHE_PATH: &str = "fx_rates.json"; pub async fn get_usd_rate(currency: &str) -> anyhow::Result { if currency == "USD" { return Ok(1.0); } let mut cache: HashMap = if Path::new(FX_CACHE_PATH).exists() { let content = fs::read_to_string(FX_CACHE_PATH).await?; serde_json::from_str(&content).unwrap_or_default() } else { HashMap::new() }; let today = chrono::Local::now().format("%Y-%m-%d").to_string(); if let Some((rate, date)) = cache.get(currency) { if date == &today { return Ok(*rate); } } let symbol = format!("{}USD=X", currency); let url = format!("https://query1.finance.yahoo.com/v8/finance/chart/{}?range=1d&interval=1d", symbol); let json: Value = reqwest::Client::new() .get(&url) .header("User-Agent", "Mozilla/5.0") .send() .await? .json() .await?; let close = json["chart"]["result"][0]["meta"]["regularMarketPrice"] .as_f64() .or_else(|| json["chart"]["result"][0]["indicators"]["quote"][0]["close"][0].as_f64()) .unwrap_or(1.0); let rate = if currency == "JPY" || currency == "KRW" { close } else { 1.0 / close }; // inverse pairs cache.insert(currency.to_string(), (rate, today.clone())); let _ = fs::write(FX_CACHE_PATH, serde_json::to_string_pretty(&cache)?).await; Ok(rate) }