# ADR-002: Separation of Visualization from Strategy ## Status Accepted ## Context The original system embedded visualization functionality within the `DefaultStrategy` class, creating tight coupling between trading analysis logic and chart rendering. This design had several issues: 1. **Mixed Responsibilities**: Strategy classes handled both trading logic and GUI operations 2. **Testing Complexity**: Strategy tests required mocking GUI components 3. **Deployment Flexibility**: Strategies couldn't run in headless environments 4. **Timing Control**: Visualization timing was tied to strategy execution rather than application flow The user specifically requested to display visualizations after processing each database file, requiring better control over visualization timing. ## Decision We will separate visualization from strategy components with the following architecture: 1. **Remove Visualization from Strategy**: Strategy classes focus solely on trading analysis 2. **Main Application Control**: `main.py` orchestrates visualization timing and updates 3. **Independent Configuration**: Strategy and Visualizer get database paths independently 4. **Clean Interfaces**: No direct dependencies between strategy and visualization components ## Consequences ### Positive - **Single Responsibility**: Strategy focuses on trading logic, Visualizer on charts - **Better Testability**: Strategy tests run without GUI dependencies - **Flexible Deployment**: Strategies can run in headless/server environments - **Timing Control**: Visualization updates precisely when needed (after each DB) - **Maintainability**: Changes to visualization don't affect strategy logic - **Performance**: No GUI overhead during strategy analysis ### Negative - **Increased Complexity**: Main application handles more orchestration logic - **Coordination Required**: Must ensure strategy and visualizer get same database path - **Breaking Change**: Existing strategy initialization code needs updates ## Alternatives Considered ### Option 1: Keep Visualization in Strategy **Rejected**: Violates single responsibility principle. Makes testing difficult and deployment inflexible. ### Option 2: Observer Pattern **Rejected**: Adds unnecessary complexity for this use case. Direct control in main.py is simpler and more explicit. ### Option 3: Visualization Service **Rejected**: Over-engineering for current requirements. May be considered for future multi-strategy scenarios. ## Implementation Details ### Before (Coupled Design) ```python class DefaultStrategy: def __init__(self, instrument: str, enable_visualization: bool = True): self.visualizer = Visualizer(...) if enable_visualization else None def on_booktick(self, book: Book): # Trading analysis # ... # Visualization update if self.visualizer: self.visualizer.update_from_book(book) ``` ### After (Separated Design) ```python # Strategy focuses on analysis only class DefaultStrategy: def __init__(self, instrument: str): # No visualization dependencies def on_booktick(self, book: Book): # Pure trading analysis # No visualization code # Main application orchestrates both def main(): strategy = DefaultStrategy(instrument) visualizer = Visualizer(...) for db_path in db_paths: strategy.set_db_path(db_path) visualizer.set_db_path(db_path) # Process data storage.build_booktick_from_db(db_path, db_date) # Analysis strategy.on_booktick(storage.book) # Visualization (controlled timing) visualizer.update_from_book(storage.book) # Final display visualizer.show() ``` ### Interface Changes #### Strategy Interface (Simplified) ```python class DefaultStrategy: def __init__(self, instrument: str) # Removed visualization param def set_db_path(self, db_path: Path) -> None # No visualizer.set_db_path() def on_booktick(self, book: Book) -> None # No visualization calls ``` #### Main Application (Enhanced) ```python def main(): # Separate initialization strategy = DefaultStrategy(instrument) visualizer = Visualizer(window_seconds=60, max_bars=500) # Independent configuration for db_path in db_paths: strategy.set_db_path(db_path) visualizer.set_db_path(db_path) # Controlled execution strategy.on_booktick(storage.book) # Analysis visualizer.update_from_book(storage.book) # Visualization ``` ## Migration Strategy ### Code Changes Required 1. **Strategy Classes**: Remove visualization initialization and calls 2. **Main Application**: Add visualizer creation and orchestration 3. **Tests**: Update strategy tests to remove visualization mocking 4. **Configuration**: Remove visualization parameters from strategy constructors ### Backward Compatibility - **API Breaking**: Strategy constructor signature changes - **Functionality Preserved**: All visualization features remain available - **Test Updates**: Strategy tests become simpler (no GUI mocking needed) ### Migration Steps 1. Update `DefaultStrategy` to remove visualization dependencies 2. Modify `main.py` to create and manage `Visualizer` instance 3. Update all strategy constructor calls to remove `enable_visualization` 4. Update tests to reflect new interfaces 5. Verify visualization timing meets requirements ## Benefits Achieved ### Clean Architecture - **Strategy**: Pure trading analysis logic - **Visualizer**: Pure chart rendering logic - **Main**: Application flow and component coordination ### Improved Testing ```python # Before: Complex mocking required def test_strategy(): with patch('visualizer.Visualizer') as mock_viz: strategy = DefaultStrategy("BTC", enable_visualization=True) # Complex mock setup... # After: Simple, direct testing def test_strategy(): strategy = DefaultStrategy("BTC") # Direct testing of analysis logic ``` ### Flexible Deployment ```python # Headless server deployment strategy = DefaultStrategy("BTC") # No GUI dependencies, can run anywhere # Development with visualization strategy = DefaultStrategy("BTC") visualizer = Visualizer(...) # Full GUI functionality when needed ``` ### Precise Timing Control ```python # Visualization updates exactly when requested for db_file in database_files: process_database(db_file) # Data processing strategy.analyze(book) # Trading analysis visualizer.update_from_book(book) # Chart update after each DB ``` ## Monitoring and Validation ### Success Criteria - **Test Simplification**: Strategy tests run without GUI mocking - **Timing Accuracy**: Visualization updates after each database as requested - **Performance**: No GUI overhead during pure analysis operations - **Maintainability**: Visualization changes don't affect strategy code ### Validation Methods - Run strategy tests in headless environment - Verify visualization timing matches requirements - Performance comparison of analysis-only vs. GUI operations - Code complexity metrics for strategy vs. visualization modules ## Future Considerations ### Potential Enhancements - **Multiple Visualizers**: Support different chart types or windows - **Visualization Plugins**: Pluggable chart renderers for different outputs - **Remote Visualization**: Web-based charts for server deployments - **Batch Visualization**: Process multiple databases before chart updates ### Extensibility - **Strategy Plugins**: Easy to add strategies without visualization concerns - **Visualization Backends**: Swap chart libraries without affecting strategies - **Analysis Pipeline**: Clear separation enables complex analysis workflows --- This separation provides a clean, maintainable architecture that supports the requested visualization timing while improving code quality and testability.