**Wave D Phase 6 - Technical Debt Cleanup (Agent C6)** ## Changes - Identified deprecated code patterns across codebase - Analyzed mock repository usage (strategically retained per AGENT_M13) - Documented deprecation cleanup strategy - Prepared deprecation removal todos ## Analysis Results - Mock structs: RETAINED (strategic testing infrastructure) - Never-read fields: 2 instances in backtesting_service - Dead code warnings: 35 total across workspace - databento_old references: None found in active code ## Status - ✅ Deprecation analysis complete - ⏳ Cleanup execution pending user confirmation - 📊 Test impact assessment ready 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
14 KiB
Mock Repository Reference Guide
Purpose: Quick reference for understanding backtesting service mock repositories
Audience: Developers working on backtesting service
Last Updated: 2025-10-18
At a Glance
┌────────────────────────────────────────────────────────────┐
│ Backtesting Service - Repository Layer │
├─────────────────────────┬──────────────────────────────────┤
│ PRODUCTION CODE │ TEST CODE │
│ │ │
│ main.rs (line 133) │ strategy_engine_tests.rs │
│ ↓ │ ↓ │
│ create_repositories() │ MockBacktestingRepositories │
│ ↓ │ ├─ MockMarketDataRepository │
│ ┌─ Databento API │ ├─ MockTradingRepository │
│ └─ DBN Files │ └─ MockNewsRepository │
│ ┌─ PostgreSQL │ │
│ └─ Benzinga API │ +19 other test files │
└────────────────────────────────────────────────────────────┘
Mock Hierarchy
Level 1: Repository Trait Definitions
File: src/repositories.rs (lines 1-187)
#[async_trait]
pub trait MarketDataRepository: Send + Sync {
async fn load_historical_data(...) -> Result<Vec<MarketData>>;
async fn check_data_availability(...) -> Result<HashMap<String, bool>>;
}
#[async_trait]
pub trait TradingRepository: Send + Sync {
async fn save_backtest_results(...) -> Result<()>;
async fn load_backtest_results(...) -> Result<(Vec<BacktestTrade>, PerformanceMetrics)>;
// ... 5 more methods
}
#[async_trait]
pub trait NewsRepository: Send + Sync {
async fn load_news_events(...) -> Result<Vec<NewsEvent>>;
async fn get_sentiment_data(...) -> Result<HashMap<String, f64>>;
}
Level 2: Production Mock Stubs
File: src/repositories.rs (lines 188-302)
These are used only in production code when DefaultRepositories::mock() is called (rare):
pub struct MockMarketDataRepository;
#[async_trait]
impl MarketDataRepository for MockMarketDataRepository {
async fn load_historical_data(...) -> Result<Vec<MarketData>> {
Ok(vec![]) // Empty - no data loading
}
// ...
}
Usage in production code: 2 places (wave_comparison.rs for metric validation)
Level 3: Test Helper Mocks
File: tests/mock_repositories.rs (lines 1-441)
These are more sophisticated mocks used in actual tests:
pub struct MockMarketDataRepository {
pub data: Arc<RwLock<Vec<MarketData>>>, // Can hold test data
}
impl MockMarketDataRepository {
pub fn new() -> Self { /* ... */ }
pub fn with_data(data: Vec<MarketData>) -> Self { /* ... */ }
}
#[async_trait]
impl MarketDataRepository for MockMarketDataRepository {
async fn load_historical_data(
&self,
symbols: &[String],
start_time: i64,
end_time: i64,
) -> Result<Vec<MarketData>> {
// Actually filters and returns test data!
let data = self.data.read().await;
let filtered: Vec<MarketData> = data
.iter()
.filter(|d| {
symbols.contains(&d.symbol)
&& d.timestamp.timestamp_nanos_opt().unwrap_or(0) >= start_time
&& d.timestamp.timestamp_nanos_opt().unwrap_or(0) <= end_time
})
.cloned()
.collect();
Ok(filtered)
}
}
Usage: All unit/integration tests
Level 4: Real Implementations
File: src/repository_impl.rs (lines 1-365)
pub struct DataProviderMarketDataRepository {
databento_provider: Arc<DatabentoHistoricalProvider>,
}
#[async_trait]
impl MarketDataRepository for DataProviderMarketDataRepository {
async fn load_historical_data(...) -> Result<Vec<MarketData>> {
// Actually loads from Databento API
let market_events = self.databento_provider.fetch(...).await?;
// Convert and return real data
Ok(all_market_data)
}
}
Also in this file:
StorageManagerTradingRepository- Uses PostgreSQLBenzingaNewsRepository- Uses Benzinga APIcreate_repositories()- Factory function
Usage: Production code (main.rs), ML backtesting (ml_strategy_engine.rs)
When to Use Which Mock
Use Production Mock Stubs (src/repositories.rs)
Scenario: Only when testing metric calculations that don't depend on data loading
// Example: wave_comparison.rs
let backtest = WaveComparisonBacktest::new(
Arc::new(DefaultRepositories::mock()), // Empty mocks OK here
100000.0,
);
let improvements = backtest.calculate_improvements(...);
// Only calculates percentages, doesn't load data
Characteristics:
- No data loading needed
- Only calculation logic
- Can use empty implementations
Use Test Helper Mocks (tests/mock_repositories.rs)
Scenario: Testing strategy logic, portfolio management, order execution
// Example: strategy_engine_tests.rs
let market_data = generate_sample_market_data(
"AAPL",
100,
100.0,
0.05,
);
let market_data_repo = Box::new(
MockMarketDataRepository::with_data(market_data)
);
let engine = StrategyEngine::new(&config, repositories).await?;
let trades = engine.execute_backtest(&context).await?;
// Assert specific behavior based on deterministic data
assert_eq!(trades.len(), expected_count);
Characteristics:
- Hold test data
- Stateful (can track trades, metrics)
- Deterministic data patterns
- Fast execution (no I/O)
Use Real Implementations (src/repository_impl.rs)
Scenario: Production, integration tests with real data
// Example: main.rs
let repositories = Arc::new(
create_repositories(storage_manager)
.await?
);
// Uses Databento API or DBN files (based on USE_DBN_DATA env var)
Or in integration tests:
// Example: dbn_integration_tests.rs
let repo = DbnMarketDataRepository::new(file_mapping).await?;
let data = repo.load_historical_data(&symbols, start_time, end_time).await?;
// Assert real market patterns
Key Functions
Test Data Generators
File: tests/mock_repositories.rs
/// Generate deterministic sample market data
pub fn generate_sample_market_data(
symbol: &str,
num_points: usize,
start_price: f64,
volatility: f64,
) -> Vec<MarketData> {
// Creates sine-wave price pattern
// Ensures price oscillates through levels multiple times
}
/// Generate sample news events
pub fn generate_sample_news_events(
symbols: &[String],
num_events: usize,
) -> Vec<NewsEvent> {
// Creates random news with sentiment scores
}
/// Create DBN-based repository for real data
pub async fn create_dbn_repository() -> Result<Box<dyn MarketDataRepository>> {
use backtesting_service::dbn_repository::DbnMarketDataRepository;
let mut file_mapping = HashMap::new();
file_mapping.insert("ES.FUT".to_string(), get_dbn_test_file_path());
let repo = DbnMarketDataRepository::new(file_mapping).await?;
Ok(Box::new(repo))
}
Repository Factory
File: src/repository_impl.rs
pub async fn create_repositories(
storage_manager: Arc<StorageManager>,
) -> Result<DefaultRepositories> {
// Environment-controlled selection:
// USE_DBN_DATA=true → DbnMarketDataRepository (test_data/)
// USE_DBN_DATA=false → DataProviderMarketDataRepository (Databento API)
let market_data: Box<dyn MarketDataRepository> = if use_dbn_data {
// Load from local DBN files
let file_mapping = HashMap::new();
file_mapping.insert("ES.FUT".to_string(), "test_data/real/databento/ES.FUT_ohlcv-1m_2024-01-02.dbn");
Box::new(DbnMarketDataRepository::new(file_mapping).await?)
} else {
// Use Databento API
Box::new(DataProviderMarketDataRepository::new().await?)
};
let trading = Box::new(StorageManagerTradingRepository::new(storage_manager));
let news = Box::new(BenzingaNewsRepository::new().await?);
Ok(DefaultRepositories { market_data, trading, news })
}
Usage Statistics
Mock Occurrences
| Mock Type | Count | Primary Files |
|---|---|---|
MockMarketDataRepository |
59 | strategy_engine_tests.rs (15+), others (44+) |
MockTradingRepository |
61 | strategy_engine_tests.rs (15+), others (46+) |
MockNewsRepository |
54 | strategy_engine_tests.rs (10+), others (44+) |
| Total | 174 | 8 test files |
Real Repository Occurrences
| Type | Count | Primary Usage |
|---|---|---|
DbnMarketDataRepository |
24+ | dbn_repository.rs tests, create_repositories() |
DataProviderMarketDataRepository |
12+ | repository_impl.rs, tests |
StorageManagerTradingRepository |
12+ | repository_impl.rs, main.rs, ml_strategy_engine.rs |
BenzingaNewsRepository |
12+ | repository_impl.rs, create_repositories() |
| Total | 67 | Production code, integration tests |
Testing Strategy
Fast Path (< 1 second)
Unit Tests → Mock Repositories → In-memory operations → Fast ✓
Typical test:
#[tokio::test]
async fn test_portfolio_initialization() -> Result<()> {
let market_data_repo = Box::new(MockMarketDataRepository::new());
let engine = StrategyEngine::new(&config, repositories).await?;
let trades = engine.execute_backtest(&context).await?;
assert_eq!(trades.len(), 0);
}
Real Data Path (1-10 seconds)
Integration Tests → DbnMarketDataRepository → File I/O → Real data ✓
Typical test:
#[tokio::test]
async fn test_dbn_data_loading() -> Result<()> {
let repo = DbnMarketDataRepository::new(file_mapping).await?;
let data = repo.load_historical_data(&symbols, start_time, end_time).await?;
assert!(data.len() > 0);
}
Environment Variables
For Testing
# Use local DBN files instead of API
export USE_DBN_DATA=true
# Specify DBN file paths (comma-separated symbol:path pairs)
export DBN_SYMBOL_MAPPINGS="ES.FUT:test_data/real/databento/ES.FUT_ohlcv-1m_2024-01-02.dbn,NQ.FUT:test_data/real/databento/NQ.FUT_ohlcv-1m_2024-01-02.dbn"
# Optional: Symbol mapping for test compatibility
export DBN_SYMBOL_MAP="BTC/USD:ES.FUT,ETH/USD:NQ.FUT"
For Production
# Use Databento API (default)
export USE_DBN_DATA=false # or unset
# Databento credentials
export DATABENTO_API_KEY=your_key_here
# Database
export DATABASE_URL=postgresql://user:pass@localhost/foxhunt
# Other services
export BENZINGA_API_KEY=your_key_here
Common Patterns
Pattern 1: Quick Unit Test with Mocks
#[tokio::test]
async fn test_strategy_logic() -> Result<()> {
// 1. Create test data
let market_data = generate_sample_market_data("AAPL", 100, 100.0, 0.05);
// 2. Create mock repositories
let market_data_repo = Box::new(
MockMarketDataRepository::with_data(market_data)
);
let trading_repo = Box::new(MockTradingRepository::new());
let news_repo = Box::new(MockNewsRepository::new());
// 3. Combine into repositories
let repositories = Arc::new(MockBacktestingRepositories::new(
market_data_repo,
trading_repo,
news_repo,
));
// 4. Test business logic
let engine = StrategyEngine::new(&config, repositories).await?;
let trades = engine.execute_backtest(&context).await?;
// 5. Assert results
assert!(trades.len() > 0);
Ok(())
}
Pattern 2: Integration Test with Real Data
#[tokio::test]
async fn test_with_real_dbn_data() -> Result<()> {
// 1. Load real data
let mut file_mapping = HashMap::new();
file_mapping.insert("ES.FUT".to_string(), "test_data/real/databento/ES.FUT_ohlcv-1m_2024-01-02.dbn".to_string());
let repo = DbnMarketDataRepository::new(file_mapping).await?;
// 2. Use real repository directly
let data = repo.load_historical_data(&["ES.FUT".to_string()], start_time, end_time).await?;
// 3. Assert real market patterns
assert!(data.len() > 0);
// Validate prices, timestamps, etc.
Ok(())
}
Pattern 3: Production Code (No Mocks)
// In main.rs
let repositories = Arc::new(
create_repositories(storage_manager)
.await?
);
let service = BacktestingServiceImpl::new(repositories, Some(Arc::clone(&model_cache)))
.await?;
// repositories uses real implementations, never mocks
Troubleshooting
"Mock returned empty data"
Issue: Test expecting data but mock returns empty Vec
Solution: Use MockMarketDataRepository::with_data() instead of new()
// Wrong
let repo = Box::new(MockMarketDataRepository::new());
// Correct
let data = generate_sample_market_data("AAPL", 100, 100.0, 0.05);
let repo = Box::new(MockMarketDataRepository::with_data(data));
"Tests running slow"
Issue: Using real repositories (DBN files) in unit tests Solution: Use mocks for fast tests, real data only for integration tests
"Production using mocks"
Issue: main.rs calling DefaultRepositories::mock()
Solution: Should never happen. Always call create_repositories() instead
Best Practices
- Use mocks for unit tests - They're fast, deterministic, and isolated
- Use real data for integration tests - Validate actual patterns and edge cases
- Never use mocks in production code - Only in tests and optional validation (wave_comparison.rs)
- Use environment variables for control - USE_DBN_DATA, DBN_SYMBOL_MAPPINGS
- Generate realistic test data - Use
generate_sample_market_data()for deterministic patterns - Keep mock implementations simple - Easy to reason about in tests
Related Documentation:
- AGENT_M1_MOCK_USAGE_ANALYSIS.md - Detailed analysis report
- AGENT_M1_QUICK_SUMMARY.md - 60-second summary
- services/backtesting_service/src/repositories.rs - Trait definitions
- services/backtesting_service/tests/mock_repositories.rs - Mock implementations