use super::{DataFrame, DataQuery, Timeframe};
use std::sync::Arc;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum DataError {
#[error("Symbol not found: {0}")]
SymbolNotFound(String),
#[error("No data available for timeframe: {0}")]
TimeframeNotAvailable(String),
#[error("No data in requested range")]
NoDataInRange,
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Provider error: {0}")]
Provider(String),
#[error("Configuration error: {0}")]
Config(String),
}
pub trait DataProvider: Send + Sync {
fn load(&self, query: &DataQuery) -> Result<DataFrame, DataError>;
fn has_data(&self, symbol: &str, timeframe: &Timeframe) -> bool;
fn symbols(&self) -> Vec<String>;
fn timeframes(&self, symbol: &str) -> Vec<Timeframe> {
let _ = symbol;
Vec::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct NullProvider;
impl DataProvider for NullProvider {
fn load(&self, query: &DataQuery) -> Result<DataFrame, DataError> {
Err(DataError::SymbolNotFound(query.id.clone()))
}
fn has_data(&self, _symbol: &str, _timeframe: &Timeframe) -> bool {
false
}
fn symbols(&self) -> Vec<String> {
Vec::new()
}
}
pub type SharedDataProvider = Arc<dyn DataProvider>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_null_provider() {
let provider = NullProvider;
let query = DataQuery::new("TEST", Timeframe::d1());
assert!(!provider.has_data("TEST", &Timeframe::d1()));
assert!(provider.symbols().is_empty());
assert!(provider.load(&query).is_err());
}
}