- 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>
243 lines
7.8 KiB
Rust
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())),
|
|
}),
|
|
}
|
|
}
|
|
}
|