idx-cli/src/api/msn/mod.rs
Ciphercat 6d6d51a04f refactor(msn): remove HistoryProvider — Finance/Charts 404s on all IDX stocks
MSN Finance/Charts does not serve OHLCV data for XIDX stocks (returns 404).
Following the FP principle of not exposing capabilities a provider cannot fulfil:

- Remove impl HistoryProvider for MsnProvider entirely
- Remove fetch_charts from MsnClient
- Remove parse_chart_history, resample_history, trim_history_to_period from map.rs
- Remove MsnChart, ChartSeries, RawChart from raw_types.rs
- Remove parse_history_from_str, parse_close_only_history from parse.rs
- Decouple HistoryProvider from MarketDataProvider trait bound
- Add history_provider() factory: returns None for MSN, Some(Yahoo) for Yahoo
- CLI gates History/Technical on history_provider(), fails fast for MSN
- MSN mock returns Err(Unsupported); tests verify the behaviour explicitly
2026-03-06 20:55:35 +00:00

102 lines
2.9 KiB
Rust

mod client;
mod map;
mod parse;
mod raw_types;
mod symbols;
use crate::api::types::{
CompanyProfile, EarningsReport, FinancialStatements, Fundamentals, InsightData, NewsItem,
Quote, SentimentData,
};
use crate::api::{
EarningsProvider, FinancialsProvider, FundamentalsProvider, InsightsProvider, NewsProvider,
ProfileProvider, QuoteProvider, SentimentProvider,
};
use crate::error::IdxError;
use client::MsnClient;
use map::{
parse_earnings, parse_financial_statements, parse_fundamentals, parse_insights, parse_news,
parse_profile, parse_quote, parse_screener_results, parse_sentiment,
};
pub(crate) use parse::{parse_fundamentals_from_str, parse_quote_from_str};
pub struct MsnProvider {
client: MsnClient,
}
impl MsnProvider {
pub fn new(_verbose: bool) -> Self {
Self {
client: MsnClient::new(),
}
}
pub fn screener(
&self,
filter: &str,
region: &str,
limit: usize,
) -> Result<Vec<Quote>, IdxError> {
let raw = self.client.fetch_screener(filter, region, limit)?;
parse_screener_results(&raw)
}
}
impl QuoteProvider for MsnProvider {
fn quote(&self, symbol: &str) -> Result<Quote, IdxError> {
let quotes = self.client.fetch_quotes(symbol)?;
parse_quote(symbol, &quotes)
}
}
impl FundamentalsProvider for MsnProvider {
fn fundamentals(&self, symbol: &str) -> Result<Fundamentals, IdxError> {
let ratios = self.client.fetch_key_ratios(symbol)?;
let quote = self.client.fetch_quotes(symbol)?;
parse_fundamentals(&ratios, quote.first())
}
}
impl ProfileProvider for MsnProvider {
fn profile(&self, symbol: &str) -> Result<CompanyProfile, IdxError> {
let raw = self.client.fetch_equities(symbol)?;
parse_profile(symbol, &raw)
}
}
impl EarningsProvider for MsnProvider {
fn earnings(&self, symbol: &str) -> Result<EarningsReport, IdxError> {
let raw = self.client.fetch_earnings(symbol)?;
parse_earnings(symbol, &raw)
}
}
impl FinancialsProvider for MsnProvider {
fn financials(&self, symbol: &str) -> Result<FinancialStatements, IdxError> {
let raw = self.client.fetch_financial_statements(symbol)?;
parse_financial_statements(symbol, &raw)
}
}
impl SentimentProvider for MsnProvider {
fn sentiment(&self, symbol: &str) -> Result<SentimentData, IdxError> {
let raw = self.client.fetch_sentiment(symbol)?;
parse_sentiment(symbol, &raw)
}
}
impl InsightsProvider for MsnProvider {
fn insights(&self, symbol: &str) -> Result<InsightData, IdxError> {
let raw = self.client.fetch_insights(symbol)?;
parse_insights(symbol, &raw)
}
}
impl NewsProvider for MsnProvider {
fn news(&self, symbol: &str, limit: usize) -> Result<Vec<NewsItem>, IdxError> {
let raw = self.client.fetch_news(symbol, limit)?;
parse_news(&raw)
}
}