added corporate quarterly announcments for the last 4 years
This commit is contained in:
@@ -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)?;
|
||||
|
||||
Reference in New Issue
Block a user