added corporate quarterly announcments for the last 4 years

This commit is contained in:
2025-11-23 16:02:23 +01:00
parent cd3f47d91f
commit 462f7ca672
12 changed files with 1457 additions and 104 deletions

View File

@@ -1,11 +1,11 @@
// src/corporate/storage.rs
use super::types::{CompanyEvent, CompanyPrice};
use std::collections::{HashMap, HashSet};
use super::types::{CompanyEvent, CompanyPrice, CompanyEventChange};
use super::helpers::*;
use tokio::fs;
use chrono::{Local, NaiveDate};
use chrono::{Local, NaiveDate, Datelike};
use std::collections::HashMap;
/// Load all events from disk into a HashMap<ticker|date, event>
async fn load_all_events_map() -> anyhow::Result<HashMap<String, CompanyEvent>> {
pub async fn load_existing_events() -> anyhow::Result<HashMap<String, CompanyEvent>> {
let mut map = HashMap::new();
let dir = std::path::Path::new("corporate_events");
if !dir.exists() {
@@ -16,11 +16,12 @@ async fn load_all_events_map() -> anyhow::Result<HashMap<String, CompanyEvent>>
while let Some(entry) = entries.next_entry().await? {
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("json") {
let content = fs::read_to_string(&path).await?;
if let Ok(events) = serde_json::from_str::<Vec<CompanyEvent>>(&content) {
let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
if name.starts_with("events_") && name.len() == 17 { // events_yyyy-mm.json
let content = fs::read_to_string(&path).await?;
let events: Vec<CompanyEvent> = serde_json::from_str(&content)?;
for event in events {
let key = format!("{}|{}", event.ticker, event.date);
map.insert(key, event);
map.insert(event_key(&event), event);
}
}
}
@@ -28,34 +29,68 @@ async fn load_all_events_map() -> anyhow::Result<HashMap<String, CompanyEvent>>
Ok(map)
}
/// Merge new events with existing ones and save back to disk
pub async fn merge_and_save_events(ticker: &str, new_events: Vec<CompanyEvent>) -> anyhow::Result<()> {
let mut existing = load_all_events_map().await?;
// Insert or update
for event in new_events {
let key = format!("{}|{}", event.ticker, event.date);
existing.insert(key, event);
}
// Convert back to Vec and save (simple single file for now)
let all_events: Vec<CompanyEvent> = existing.into_values().collect();
pub async fn save_optimized_events(events: HashMap<String, CompanyEvent>) -> anyhow::Result<()> {
let dir = std::path::Path::new("corporate_events");
fs::create_dir_all(dir).await?;
let path = dir.join("all_events.json");
let json = serde_json::to_string_pretty(&all_events)?;
fs::write(&path, json).await?;
// Delete old files
let mut entries = fs::read_dir(dir).await?;
while let Some(entry) = entries.next_entry().await? {
let path = entry.path();
let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
if name.starts_with("events_") && path.extension().map(|e| e == "json").unwrap_or(false) {
fs::remove_file(&path).await?;
}
}
let mut sorted: Vec<_> = events.into_values().collect();
sorted.sort_by_key(|e| (e.ticker.clone(), e.date.clone()));
let mut by_month: HashMap<String, Vec<CompanyEvent>> = HashMap::new();
for e in sorted {
if let Ok(d) = NaiveDate::parse_from_str(&e.date, "%Y-%m-%d") {
let key = format!("{}-{:02}", d.year(), d.month());
by_month.entry(key).or_default().push(e);
}
}
for (month, list) in by_month {
let path = dir.join(format!("events_{}.json", month));
fs::write(&path, serde_json::to_string_pretty(&list)?).await?;
}
Ok(())
}
/// Save price history for a single ticker (overwrite old file)
pub async fn save_prices_for_ticker(ticker: &str, prices: Vec<CompanyPrice>) -> anyhow::Result<()> {
pub async fn save_changes(changes: &[CompanyEventChange]) -> anyhow::Result<()> {
if changes.is_empty() { return Ok(()); }
let dir = std::path::Path::new("corporate_event_changes");
fs::create_dir_all(dir).await?;
let mut by_month: HashMap<String, Vec<CompanyEventChange>> = HashMap::new();
for c in changes {
if let Ok(d) = NaiveDate::parse_from_str(&c.date, "%Y-%m-%d") {
let key = format!("{}-{:02}", d.year(), d.month());
by_month.entry(key).or_default().push(c.clone());
}
}
for (month, list) in by_month {
let path = dir.join(format!("changes_{}.json", month));
let mut all = if path.exists() {
let s = fs::read_to_string(&path).await?;
serde_json::from_str(&s).unwrap_or_default()
} else { vec![] };
all.extend(list);
fs::write(&path, serde_json::to_string_pretty(&all)?).await?;
}
Ok(())
}
pub async fn save_prices_for_ticker(ticker: &str, mut prices: Vec<CompanyPrice>) -> anyhow::Result<()> {
let dir = std::path::Path::new("corporate_prices");
fs::create_dir_all(dir).await?;
let path = dir.join(format!("{}.json", ticker));
// Optional: sort by date
let mut prices = prices;
prices.sort_by_key(|p| p.date.clone());
let json = serde_json::to_string_pretty(&prices)?;