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
This commit is contained in:
Ciphercat 2026-03-06 20:55:35 +00:00
commit 6d6d51a04f
8 changed files with 71 additions and 504 deletions

View file

@ -14,7 +14,7 @@ use crate::api::types::{
};
use crate::api::{
EarningsProvider, FinancialsProvider, InsightsProvider, MarketDataProvider, NewsProvider,
ProfileProvider, SentimentProvider,
ProfileProvider, SentimentProvider, history_provider,
};
use crate::cache::Cache;
use crate::config::IdxConfig;
@ -208,6 +208,13 @@ pub fn handle(
period,
interval,
} => {
let hist_provider = history_provider(config.provider, false).ok_or_else(|| {
IdxError::Unsupported(
"MSN does not provide price history for IDX stocks. \
Use --provider yahoo for historical data."
.into(),
)
})?;
let history_bucket = cache_bucket(config, "history");
let resolved = crate::api::resolve_symbol(symbol, &config.exchange);
let key = format!("{}-{}", period.as_str(), interval.as_str());
@ -231,7 +238,7 @@ pub fn handle(
return render_history(&resolved, &stale, &config.output);
}
match provider.history(&resolved, period, interval) {
match hist_provider.history(&resolved, period, interval) {
Ok(history) => {
if !no_cache {
cache.put(
@ -258,6 +265,13 @@ pub fn handle(
}
}
StocksSubcommand::Technical { symbol } => {
let hist_provider = history_provider(config.provider, false).ok_or_else(|| {
IdxError::Unsupported(
"MSN does not provide price history for IDX stocks. \
Use --provider yahoo for technical analysis."
.into(),
)
})?;
let technical_bucket = cache_bucket(config, "technical");
let resolved = crate::api::resolve_symbol(symbol, &config.exchange);
if !no_cache
@ -272,7 +286,7 @@ pub fn handle(
return render_technical(&stale, &config.output, config.no_color);
}
match provider.history(&resolved, &Period::OneYear, &Interval::Day) {
match hist_provider.history(&resolved, &Period::OneYear, &Interval::Day) {
Ok(history) => {
let report = build_technical_report(&resolved, &history)?;
if !no_cache {