218 lines
7.8 KiB
Markdown
218 lines
7.8 KiB
Markdown
# 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.
|