Files
foxhunt/services/backtesting_service/src/repositories.rs
jgrusewski afd85b2f8f chore: clean up examples, update ML binaries and risk tests
- Delete 14 unused example files (-3,543 lines): config, adaptive-strategy,
  data, storage, trading_engine, api_gateway, backtesting, trading_service, chaos
- Update ML training/eval binaries: improved CLI args, completion tracking,
  CUDA test cleanup, hyperopt enhancements
- Fix KAN network and TFT module adjustments
- Update risk test assertions for consistency
- Fix backtesting repositories and promotion manager
- Update .serena project config and Cargo dependencies

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 01:33:18 +01:00

243 lines
7.8 KiB
Rust

//! Repository traits for clean database abstraction in backtesting service
use anyhow::Result;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use crate::foxhunt::tli::BacktestStatus;
use crate::performance::PerformanceMetrics;
use crate::storage::BacktestSummary;
use crate::strategy_engine::BacktestTrade;
/// Repository trait for market data operations
///
/// This trait abstracts market data retrieval for backtesting,
/// eliminating direct database coupling from business logic.
#[async_trait]
pub trait MarketDataRepository: Send + Sync {
/// Load historical market data for backtesting
///
/// # Arguments
/// * `symbols` - List of symbols to load data for
///
/// * `start_time` - Start timestamp in nanoseconds
/// * `end_time` - End timestamp in nanoseconds
///
/// # Returns
///
/// Vector of market data events sorted by timestamp
async fn load_historical_data(
&self,
symbols: &[String],
start_time: i64,
end_time: i64,
) -> Result<Vec<crate::strategy_engine::MarketData>>;
}
/// Repository trait for trading and backtest result operations
///
/// This trait handles persistence and retrieval of backtest results,
/// trading history, and performance metrics.
#[async_trait]
pub trait TradingRepository: Send + Sync {
/// Save backtest results to storage
async fn save_backtest_results(
&self,
backtest_id: &str,
trades: &[BacktestTrade],
metrics: &PerformanceMetrics,
) -> Result<()>;
/// Load backtest results from storage
async fn load_backtest_results(
&self,
backtest_id: &str,
) -> Result<(Vec<BacktestTrade>, PerformanceMetrics)>;
/// List historical backtests
async fn list_backtests(
&self,
limit: u32,
offset: u32,
strategy_name: Option<String>,
status_filter: Option<BacktestStatus>,
) -> Result<Vec<BacktestSummary>>;
}
/// Repository trait for news and sentiment data
///
/// This trait provides access to news events and sentiment data
/// that can influence trading strategies.
#[async_trait]
pub trait NewsRepository: Send + Sync {
/// Load news events for given symbols and time range
async fn load_news_events(
&self,
symbols: &[String],
start_time: DateTime<Utc>,
end_time: DateTime<Utc>,
) -> Result<Vec<crate::strategy_engine::NewsEvent>>;
}
/// Combined repository trait for dependency injection
///
/// This trait combines all repository interfaces to simplify
/// dependency injection in the service layer.
#[async_trait]
pub trait BacktestingRepositories: Send + Sync {
/// Get market data repository
fn market_data(&self) -> &dyn MarketDataRepository;
/// Get trading repository
fn trading(&self) -> &dyn TradingRepository;
/// Get news repository
fn news(&self) -> &dyn NewsRepository;
}
/// Default implementation that provides all repositories
pub struct DefaultRepositories {
/// Market data repository for historical data
pub market_data: Box<dyn MarketDataRepository>,
/// Trading repository for order and execution data
pub trading: Box<dyn TradingRepository>,
/// News repository for market news events
pub news: Box<dyn NewsRepository>,
}
#[async_trait]
impl BacktestingRepositories for DefaultRepositories {
fn market_data(&self) -> &dyn MarketDataRepository {
self.market_data.as_ref()
}
fn trading(&self) -> &dyn TradingRepository {
self.trading.as_ref()
}
fn news(&self) -> &dyn NewsRepository {
self.news.as_ref()
}
}
#[cfg(any(test, feature = "test-utils"))]
impl DefaultRepositories {
/// Create a mock instance for testing
///
/// This method is only available in test builds and creates
/// in-memory mock repositories for unit testing.
pub fn mock() -> Self {
use std::sync::Arc;
use tokio::sync::RwLock;
use std::collections::HashMap;
// Mock market data repository
struct MockMarketData {
data: Arc<RwLock<Vec<crate::strategy_engine::MarketData>>>,
}
#[async_trait]
impl MarketDataRepository for MockMarketData {
async fn load_historical_data(
&self,
_symbols: &[String],
_start_time: i64,
_end_time: i64,
) -> Result<Vec<crate::strategy_engine::MarketData>> {
Ok(self.data.read().await.clone())
}
}
// Mock trading repository
struct MockTrading {
trades: Arc<RwLock<HashMap<String, Vec<BacktestTrade>>>>,
metrics: Arc<RwLock<HashMap<String, PerformanceMetrics>>>,
backtests: Arc<RwLock<Vec<BacktestSummary>>>,
}
#[async_trait]
impl TradingRepository for MockTrading {
async fn save_backtest_results(
&self,
backtest_id: &str,
trades: &[BacktestTrade],
metrics: &PerformanceMetrics,
) -> Result<()> {
self.trades.write().await.insert(backtest_id.to_string(), trades.to_vec());
self.metrics.write().await.insert(backtest_id.to_string(), metrics.clone());
Ok(())
}
async fn load_backtest_results(
&self,
backtest_id: &str,
) -> Result<(Vec<BacktestTrade>, PerformanceMetrics)> {
let trades = self.trades.read().await
.get(backtest_id)
.cloned()
.unwrap_or_default();
let metrics = self.metrics.read().await
.get(backtest_id)
.cloned()
.unwrap_or_default();
Ok((trades, metrics))
}
async fn list_backtests(
&self,
limit: u32,
offset: u32,
strategy_name: Option<String>,
status_filter: Option<BacktestStatus>,
) -> Result<Vec<BacktestSummary>> {
let backtests = self.backtests.read().await;
let filtered: Vec<BacktestSummary> = backtests
.iter()
.filter(|bt| {
let name_match = strategy_name.as_ref()
.map(|n| bt.strategy_name == *n)
.unwrap_or(true);
let status_match = status_filter.map(|s| bt.status == s).unwrap_or(true);
name_match && status_match
})
.skip(offset as usize)
.take(limit as usize)
.cloned()
.collect();
Ok(filtered)
}
}
// Mock news repository
struct MockNews {
events: Arc<RwLock<Vec<crate::strategy_engine::NewsEvent>>>,
}
#[async_trait]
impl NewsRepository for MockNews {
async fn load_news_events(
&self,
_symbols: &[String],
_start_time: DateTime<Utc>,
_end_time: DateTime<Utc>,
) -> Result<Vec<crate::strategy_engine::NewsEvent>> {
Ok(self.events.read().await.clone())
}
}
Self {
market_data: Box::new(MockMarketData {
data: Arc::new(RwLock::new(Vec::new())),
}),
trading: Box::new(MockTrading {
trades: Arc::new(RwLock::new(HashMap::new())),
metrics: Arc::new(RwLock::new(HashMap::new())),
backtests: Arc::new(RwLock::new(Vec::new())),
}),
news: Box::new(MockNews {
events: Arc::new(RwLock::new(Vec::new())),
}),
}
}
}