This commit is contained in:
Dobromir Popov
2025-05-24 09:58:36 +03:00
parent ef71160282
commit 0fe8286787
11 changed files with 1396 additions and 483 deletions

43
.vscode/launch.json vendored
View File

@ -204,6 +204,49 @@
], ],
"console": "integratedTerminal", "console": "integratedTerminal",
"justMyCode": true "justMyCode": true
},
{
"name": "Realtime RL Training + TensorBoard + Web UI",
"type": "python",
"request": "launch",
"program": "train_realtime_with_tensorboard.py",
"args": [
"--episodes",
"50",
"--symbol",
"ETH/USDT",
"--balance",
"1000.0",
"--web-port",
"8051"
],
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONUNBUFFERED": "1",
"ENABLE_REAL_DATA_ONLY": "1"
},
"preLaunchTask": "Kill Stale Processes"
},
{
"name": "Quick CNN Test (Real Data + TensorBoard)",
"type": "python",
"request": "launch",
"program": "test_cnn_only.py",
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONUNBUFFERED": "1"
},
"preLaunchTask": "Kill Stale Processes"
},
{
"name": "TensorBoard Monitor (All Runs)",
"type": "python",
"request": "launch",
"program": "run_tensorboard.py",
"console": "integratedTerminal",
"justMyCode": true
} }
] ]
} }

332
TENSORBOARD_MONITORING.md Normal file
View File

@ -0,0 +1,332 @@
# TensorBoard Monitoring Guide
## Overview
The trading system now uses **TensorBoard** for real-time training monitoring instead of static charts. This provides dynamic, interactive visualizations that update during training.
## 🚨 CRITICAL: Real Market Data Only
All TensorBoard metrics are derived from **REAL market data training**. No synthetic or generated data is used.
## Quick Start
### 1. Start Training with TensorBoard
```bash
# CNN Training with TensorBoard
python main_clean.py --mode cnn --symbol ETH/USDT
# RL Training with TensorBoard
python train_rl_with_realtime.py --episodes 10
# Quick CNN Test
python test_cnn_only.py
```
### 2. Launch TensorBoard
```bash
# Option 1: Direct command
tensorboard --logdir=runs
# Option 2: Convenience script
python run_tensorboard.py
```
### 3. Access TensorBoard
Open your browser to: **http://localhost:6006**
## Available Metrics
### CNN Training Metrics
#### **Training Progress**
- `Training/EpochLoss` - Training loss per epoch
- `Training/EpochAccuracy` - Training accuracy per epoch
- `Training/BatchLoss` - Batch-level loss
- `Training/BatchAccuracy` - Batch-level accuracy
- `Training/BatchConfidence` - Model confidence scores
- `Training/LearningRate` - Learning rate schedule
- `Training/EpochTime` - Time per epoch
#### **Validation Metrics**
- `Validation/Loss` - Validation loss
- `Validation/Accuracy` - Validation accuracy
- `Validation/AvgConfidence` - Average confidence on validation set
- `Validation/Class_0_Accuracy` - BUY class accuracy
- `Validation/Class_1_Accuracy` - SELL class accuracy
- `Validation/Class_2_Accuracy` - HOLD class accuracy
#### **Best Model Tracking**
- `Best/ValidationLoss` - Best validation loss achieved
- `Best/ValidationAccuracy` - Best validation accuracy achieved
#### **Data Statistics**
- `Data/TotalSamples` - Number of training samples from real data
- `Data/Features` - Number of features (detected from real data)
- `Data/Timeframes` - Number of timeframes used
- `Data/WindowSize` - Window size for temporal patterns
- `Data/Class_X_Count` - Sample count per class
- `Data/Feature_X_Mean/Std` - Feature statistics
#### **Model Architecture**
- `Model/TotalParameters` - Total model parameters
- `Model/TrainableParameters` - Trainable parameters
#### **Training Configuration**
- `Config/LearningRate` - Learning rate used
- `Config/BatchSize` - Batch size
- `Config/MaxEpochs` - Maximum epochs
### RL Training Metrics
#### **Episode Performance**
- `Episode/TotalReward` - Total reward per episode
- `Episode/FinalBalance` - Final balance after episode
- `Episode/TotalReturn` - Return percentage
- `Episode/Steps` - Steps taken in episode
#### **Trading Performance**
- `Trading/TotalTrades` - Number of trades executed
- `Trading/WinRate` - Percentage of profitable trades
- `Trading/ProfitFactor` - Gross profit / gross loss ratio
- `Trading/MaxDrawdown` - Maximum drawdown percentage
#### **Agent Learning**
- `Agent/Epsilon` - Exploration rate (epsilon)
- `Agent/LearningRate` - Agent learning rate
- `Agent/MemorySize` - Experience replay buffer size
- `Agent/Loss` - Training loss from experience replay
#### **Moving Averages**
- `Moving_Average/Reward_50ep` - 50-episode average reward
- `Moving_Average/Return_50ep` - 50-episode average return
#### **Best Performance**
- `Best/Return` - Best return percentage achieved
## Directory Structure
```
runs/
├── cnn_training_1748043814/ # CNN training session
│ ├── events.out.tfevents.* # TensorBoard event files
│ └── ...
├── rl_training_1748043920/ # RL training session
│ ├── events.out.tfevents.*
│ └── ...
└── ... # Other training sessions
```
## TensorBoard Features
### **Scalars Tab**
- Real-time line charts of all metrics
- Smoothing controls for noisy metrics
- Multiple run comparisons
- Download data as CSV
### **Images Tab**
- Model architecture visualizations
- Training progression images
### **Graphs Tab**
- Computational graph of models
- Network architecture visualization
### **Histograms Tab**
- Weight and gradient distributions
- Activation patterns over time
### **Projector Tab**
- High-dimensional data visualization
- Feature embeddings
## Usage Examples
### 1. Monitor CNN Training
```bash
# Start CNN training (generates TensorBoard logs)
python main_clean.py --mode cnn --symbol ETH/USDT
# In another terminal, start TensorBoard
tensorboard --logdir=runs
# Open browser to http://localhost:6006
# Navigate to Scalars tab to see:
# - Training/EpochLoss declining over time
# - Validation/Accuracy improving
# - Training/LearningRate schedule
```
### 2. Compare Multiple Training Runs
```bash
# Run multiple training sessions
python test_cnn_only.py # Creates cnn_training_X
python test_cnn_only.py # Creates cnn_training_Y
# TensorBoard automatically shows both runs
# Compare performance across runs in the same charts
```
### 3. Monitor RL Agent Training
```bash
# Start RL training with TensorBoard logging
python main_clean.py --mode rl --symbol ETH/USDT
# View in TensorBoard:
# - Episode/TotalReward trending up
# - Trading/WinRate improving
# - Agent/Epsilon decreasing (less exploration)
```
## Real-Time Monitoring
### Key Indicators to Watch
#### **CNN Training Health**
-`Training/EpochLoss` should decrease over time
-`Validation/Accuracy` should increase
- ⚠️ Watch for overfitting (val loss increases while train loss decreases)
-`Training/LearningRate` should follow schedule
#### **RL Training Health**
-`Episode/TotalReward` trending upward
-`Trading/WinRate` above 50%
-`Moving_Average/Return_50ep` positive and stable
- ⚠️ `Agent/Epsilon` should decay over time
### Warning Signs
- **Loss not decreasing**: Check learning rate, data quality
- **Accuracy plateauing**: May need more data or different architecture
- **RL rewards oscillating**: Unstable learning, adjust hyperparameters
- **Win rate dropping**: Strategy not working, need different approach
## Configuration
### Custom TensorBoard Setup
```python
from torch.utils.tensorboard import SummaryWriter
# Custom log directory
writer = SummaryWriter(log_dir='runs/my_experiment')
# Log custom metrics
writer.add_scalar('Custom/Metric', value, step)
writer.add_histogram('Custom/Weights', weights, step)
```
### Advanced Features
```bash
# Start TensorBoard with custom port
tensorboard --logdir=runs --port=6007
# Enable debugging
tensorboard --logdir=runs --debugger_port=6064
# Profile performance
tensorboard --logdir=runs --load_fast=false
```
## Integration with Training
### CNN Trainer Integration
- Automatically logs all training metrics
- Model architecture visualization
- Real data statistics tracking
- Best model checkpointing based on TensorBoard metrics
### RL Trainer Integration
- Episode-by-episode performance tracking
- Trading strategy effectiveness monitoring
- Agent learning progress visualization
- Hyperparameter optimization guidance
## Benefits Over Static Charts
### ✅ **Real-Time Updates**
- See training progress as it happens
- No need to wait for training completion
- Immediate feedback on hyperparameter changes
### ✅ **Interactive Exploration**
- Zoom, pan, and explore metrics
- Smooth noisy data with built-in controls
- Compare multiple training runs side-by-side
### ✅ **Rich Visualizations**
- Scalars, histograms, images, and graphs
- Model architecture visualization
- High-dimensional data projections
### ✅ **Data Export**
- Download metrics as CSV
- Programmatic access to training data
- Integration with external analysis tools
## Troubleshooting
### TensorBoard Not Starting
```bash
# Check if TensorBoard is installed
pip install tensorboard
# Verify runs directory exists
dir runs # Windows
ls runs # Linux/Mac
# Kill existing TensorBoard processes
taskkill /F /IM tensorboard.exe # Windows
pkill -f tensorboard # Linux/Mac
```
### No Data Showing
- Ensure training is generating logs in `runs/` directory
- Check browser console for errors
- Try refreshing the page
- Verify correct port (default 6006)
### Performance Issues
- Use `--load_fast=true` for faster loading
- Clear old log directories
- Reduce logging frequency in training code
## Best Practices
### 🎯 **Regular Monitoring**
- Check TensorBoard every 10-20 epochs during CNN training
- Monitor RL agents every 50-100 episodes
- Look for concerning trends early
### 📊 **Metric Organization**
- Use clear naming conventions (Training/, Validation/, etc.)
- Group related metrics together
- Log at appropriate frequencies (not every step)
### 💾 **Data Management**
- Archive old training runs periodically
- Keep successful run logs for reference
- Document experiment parameters in run names
### 🔍 **Hyperparameter Tuning**
- Compare multiple runs with different hyperparameters
- Use TensorBoard data to guide optimization
- Track which settings produce best results
---
## Summary
TensorBoard integration provides **real-time, interactive monitoring** of training progress using **only real market data**. This replaces static plots with dynamic visualizations that help optimize model performance and catch issues early.
**Key Commands:**
```bash
# Train with TensorBoard logging
python main_clean.py --mode cnn --symbol ETH/USDT
# Start TensorBoard
python run_tensorboard.py
# Access dashboard
http://localhost:6006
```
All metrics are derived from **real cryptocurrency market data** to ensure authentic trading model development.

1
TRAINING_STATUS.md Normal file
View File

@ -0,0 +1 @@

View File

@ -82,72 +82,50 @@ def run_data_test():
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
raise raise
def run_cnn_training(): def run_cnn_training(config: Config, symbol: str):
"""Train CNN models only with comprehensive pipeline""" """Run CNN training mode with TensorBoard monitoring"""
logger.info("Starting CNN Training Mode...")
# Initialize data provider and trainer
data_provider = DataProvider(config)
trainer = CNNTrainer(config)
# Use configured symbols or provided symbol
symbols = config.symbols if symbol == "ETH/USDT" else [symbol] + config.symbols
save_path = f"models/cnn/scalping_cnn_trained.pt"
logger.info(f"Training CNN for symbols: {symbols}")
logger.info(f"Will save to: {save_path}")
logger.info(f"🔗 Monitor training: tensorboard --logdir=runs")
try: try:
logger.info("Starting CNN Training Mode...") # Train model with TensorBoard logging
results = trainer.train(symbols, save_path=save_path)
# Initialize components
data_provider = DataProvider(
symbols=['ETH/USDT', 'BTC/USDT'],
timeframes=['1s', '1m', '5m', '1h', '4h']
)
# Import and create CNN trainer
from training.cnn_trainer import CNNTrainer
trainer = CNNTrainer(data_provider)
# Configure training
trainer.num_samples = 20000 # Training samples
trainer.batch_size = 64
trainer.num_epochs = 100
trainer.patience = 15
# Train the model
symbols = ['ETH/USDT', 'BTC/USDT']
save_path = 'models/cnn/scalping_cnn_trained.pt'
logger.info(f"Training CNN for symbols: {symbols}")
logger.info(f"Will save to: {save_path}")
results = trainer.train(symbols, save_path)
# Log results
logger.info("CNN Training Results:") logger.info("CNN Training Results:")
logger.info(f" Best validation accuracy: {results['best_val_accuracy']:.4f}") logger.info(f" Best validation accuracy: {results['best_val_accuracy']:.4f}")
logger.info(f" Best validation loss: {results['best_val_loss']:.4f}") logger.info(f" Best validation loss: {results['best_val_loss']:.4f}")
logger.info(f" Total epochs: {results['total_epochs']}") logger.info(f" Total epochs: {results['total_epochs']}")
logger.info(f" Training time: {results['total_time']:.2f} seconds") logger.info(f" Training time: {results['training_time']:.2f} seconds")
logger.info(f" TensorBoard logs: {results['tensorboard_dir']}")
# Plot training history logger.info(f"📊 View training progress: tensorboard --logdir=runs")
try: logger.info("Evaluating CNN on test data...")
plot_path = 'models/cnn/training_history.png'
trainer.plot_training_history(plot_path)
logger.info(f"Training plots saved to: {plot_path}")
except Exception as e:
logger.warning(f"Could not save training plots: {e}")
# Evaluate on test data # Quick evaluation on same symbols
try: test_results = trainer.evaluate(symbols[:1]) # Use first symbol for quick test
logger.info("Evaluating CNN on test data...") logger.info("CNN Evaluation Results:")
test_symbols = ['ETH/USDT'] # Use subset for testing logger.info(f" Test accuracy: {test_results['test_accuracy']:.4f}")
eval_results = trainer.evaluate_model(test_symbols) logger.info(f" Test loss: {test_results['test_loss']:.4f}")
logger.info(f" Average confidence: {test_results['avg_confidence']:.4f}")
logger.info("CNN Evaluation Results:")
logger.info(f" Test accuracy: {eval_results['test_accuracy']:.4f}")
logger.info(f" Test loss: {eval_results['test_loss']:.4f}")
logger.info(f" Average confidence: {eval_results['avg_confidence']:.4f}")
except Exception as e:
logger.warning(f"Could not run evaluation: {e}")
logger.info("CNN training completed successfully!") logger.info("CNN training completed successfully!")
except Exception as e: except Exception as e:
logger.error(f"Error in CNN training: {e}") logger.error(f"CNN training failed: {e}")
import traceback
logger.error(traceback.format_exc())
raise raise
finally:
trainer.close_tensorboard()
def run_rl_training(): def run_rl_training():
"""Train RL agents only with comprehensive pipeline""" """Train RL agents only with comprehensive pipeline"""
@ -404,7 +382,7 @@ async def main():
if args.mode == 'test': if args.mode == 'test':
run_data_test() run_data_test()
elif args.mode == 'cnn': elif args.mode == 'cnn':
run_cnn_training() run_cnn_training(get_config(), args.symbol)
elif args.mode == 'rl': elif args.mode == 'rl':
run_rl_training() run_rl_training()
elif args.mode == 'train': elif args.mode == 'train':

83
monitor_training.py Normal file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""
Training Monitor Script
Quick script to check the status of realtime training and show key metrics.
"""
import os
import time
from pathlib import Path
from datetime import datetime
import glob
def check_training_status():
"""Check status of training processes and logs"""
print("=" * 60)
print("REALTIME RL TRAINING STATUS CHECK")
print("=" * 60)
# Check TensorBoard logs
runs_dir = Path("runs")
if runs_dir.exists():
log_dirs = list(runs_dir.glob("rl_training_*"))
recent_logs = sorted(log_dirs, key=lambda x: x.name)[-3:] # Last 3 sessions
print("\n📊 RECENT TENSORBOARD LOGS:")
for log_dir in recent_logs:
# Get creation time
stat = log_dir.stat()
created = datetime.fromtimestamp(stat.st_ctime)
# Check for event files
event_files = list(log_dir.glob("*.tfevents.*"))
print(f" 📁 {log_dir.name}")
print(f" Created: {created.strftime('%Y-%m-%d %H:%M:%S')}")
print(f" Event files: {len(event_files)}")
if event_files:
latest_event = max(event_files, key=lambda x: x.stat().st_mtime)
modified = datetime.fromtimestamp(latest_event.stat().st_mtime)
print(f" Last update: {modified.strftime('%Y-%m-%d %H:%M:%S')}")
print()
# Check running processes
print("🔍 PROCESS STATUS:")
try:
import subprocess
result = subprocess.run(['tasklist'], capture_output=True, text=True, shell=True)
python_processes = [line for line in result.stdout.split('\n') if 'python.exe' in line]
print(f" Python processes running: {len(python_processes)}")
for i, proc in enumerate(python_processes[:5]): # Show first 5
print(f" {i+1}. {proc.strip()}")
except Exception as e:
print(f" Error checking processes: {e}")
# Check web services
print("\n🌐 WEB SERVICES:")
print(" TensorBoard: http://localhost:6006")
print(" Web Dashboard: http://localhost:8051")
# Check model saves
models_dir = Path("models/rl")
if models_dir.exists():
model_files = list(models_dir.glob("realtime_agent_*.pt"))
print(f"\n💾 SAVED MODELS: {len(model_files)}")
for model_file in sorted(model_files, key=lambda x: x.stat().st_mtime)[-3:]:
modified = datetime.fromtimestamp(model_file.stat().st_mtime)
print(f" 📄 {model_file.name} - {modified.strftime('%Y-%m-%d %H:%M:%S')}")
print("\n" + "=" * 60)
print("✅ MONITORING URLs:")
print("📊 TensorBoard: http://localhost:6006")
print("🌐 Dashboard: http://localhost:8051")
print("=" * 60)
if __name__ == "__main__":
try:
check_training_status()
except KeyboardInterrupt:
print("\nMonitoring stopped.")
except Exception as e:
print(f"Error: {e}")

View File

@ -80,24 +80,53 @@ gogo2/
## Training Modes ## Training Modes
### CNN Training ### CNN Training with TensorBoard
```bash ```bash
# Train on real ETH/USDT data # Train on real ETH/USDT data with TensorBoard monitoring
python main_clean.py --mode cnn --symbol ETH/USDT python main_clean.py --mode cnn --symbol ETH/USDT
# Monitor training in real-time
tensorboard --logdir=runs
# Or use the convenience script
python run_tensorboard.py
# Quick test with real data # Quick test with real data
python test_cnn_only.py python test_cnn_only.py
``` ```
### RL Training ### RL Training with TensorBoard
```bash ```bash
# Train RL agent with real data # Train RL agent with real data
python main_clean.py --mode rl --symbol ETH/USDT python main_clean.py --mode rl --symbol ETH/USDT
# Real-time RL training # Real-time RL training
python train_rl_with_realtime.py --episodes 10 python train_rl_with_realtime.py --episodes 10
# Monitor RL training metrics
tensorboard --logdir=runs
``` ```
## TensorBoard Monitoring
All training sessions are logged to TensorBoard for real-time monitoring:
```bash
# Start TensorBoard server
tensorboard --logdir=runs
# Or use the convenience script
python run_tensorboard.py
```
**Metrics Available:**
- **CNN Training**: Loss, accuracy, confidence scores, feature statistics
- **RL Training**: Rewards, returns, win rates, epsilon values, trading metrics
- **Model Architecture**: Parameter counts, memory usage
- **Real-time Updates**: Batch-level and epoch-level metrics
Access TensorBoard at: http://localhost:6006
## Performance ## Performance
- **Memory Usage**: <2GB per model - **Memory Usage**: <2GB per model

View File

@ -1,69 +1,74 @@
import os #!/usr/bin/env python3
import sys """
TensorBoard Launch Script
Starts TensorBoard server for monitoring training progress.
"""
import subprocess import subprocess
import webbrowser import sys
import os
import time import time
import argparse import webbrowser
from pathlib import Path
def run_tensorboard(): def main():
"""Run TensorBoard server and open browser""" """Launch TensorBoard"""
parser = argparse.ArgumentParser(description='TensorBoard Launcher')
parser.add_argument('--port', type=int, default=6006, help='Port for TensorBoard server')
parser.add_argument('--logdir', type=str, default='runs', help='Log directory for TensorBoard')
parser.add_argument('--no-browser', action='store_true', help='Do not open browser automatically')
args = parser.parse_args()
# Create log directory if it doesn't exist # Check if runs directory exists
os.makedirs(args.logdir, exist_ok=True) runs_dir = Path("runs")
if not runs_dir.exists():
print("❌ No 'runs' directory found.")
print(" Start training first to generate TensorBoard logs.")
return
# Print banner # Check if there are any log directories
print("\n" + "="*60) log_dirs = list(runs_dir.glob("*"))
print("📊 TRADING BOT - TENSORBOARD MONITORING 📊") if not log_dirs:
print("="*60) print("❌ No training logs found in 'runs' directory.")
print(f"Starting TensorBoard server on port {args.port}") print(" Start training first to generate TensorBoard logs.")
print(f"Log directory: {args.logdir}") return
print("Press Ctrl+C to stop the server")
print("="*60 + "\n")
# Start TensorBoard server print("🚀 Starting TensorBoard...")
cmd = ["tensorboard", "--logdir", args.logdir, "--port", str(args.port)] print(f"📁 Log directory: {runs_dir.absolute()}")
print(f"📊 Found {len(log_dirs)} training sessions")
# List available sessions
print("\nAvailable training sessions:")
for i, log_dir in enumerate(sorted(log_dirs), 1):
print(f" {i}. {log_dir.name}")
# Start TensorBoard
try: try:
port = 6006
print(f"\n🌐 Starting TensorBoard on port {port}...")
print(f"🔗 Access at: http://localhost:{port}")
# Try to open browser automatically
try:
webbrowser.open(f"http://localhost:{port}")
print("🌍 Browser opened automatically")
except:
pass
# Start TensorBoard process # Start TensorBoard process
process = subprocess.Popen( cmd = [sys.executable, "-m", "tensorboard.main", "--logdir", str(runs_dir), "--port", str(port)]
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True
)
# Wait for TensorBoard to start print("\n" + "="*50)
time.sleep(3) print("🔥 TensorBoard is running!")
print(f"📈 View training metrics at: http://localhost:{port}")
print("⏹️ Press Ctrl+C to stop TensorBoard")
print("="*50 + "\n")
# Open browser # Run TensorBoard
if not args.no_browser: subprocess.run(cmd)
url = f"http://localhost:{args.port}"
print(f"Opening browser to {url}")
webbrowser.open(url)
# Print TensorBoard output
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
print(output.strip())
return process.poll()
except KeyboardInterrupt: except KeyboardInterrupt:
print("\nStopping TensorBoard server...") print("\n🛑 TensorBoard stopped")
process.terminate() except FileNotFoundError:
return 0 print("❌ TensorBoard not found. Install with: pip install tensorboard")
except Exception as e: except Exception as e:
print(f"Error running TensorBoard: {str(e)}") print(f"Error starting TensorBoard: {e}")
return 1
if __name__ == "__main__": if __name__ == "__main__":
exit_code = run_tensorboard() main()
sys.exit(exit_code)

View File

@ -1,54 +1,65 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Quick CNN training test Quick CNN Training Test - Real Market Data Only
This script tests CNN training with a small dataset for quick validation.
All training metrics are logged to TensorBoard for real-time monitoring.
""" """
import sys import logging
from pathlib import Path from core.config import setup_logging, get_config
sys.path.insert(0, str(Path(__file__).parent))
from core.config import setup_logging
from core.data_provider import DataProvider from core.data_provider import DataProvider
from training.cnn_trainer import CNNTrainer from training.cnn_trainer import CNNTrainer
def main(): def main():
"""Test CNN training with real market data"""
setup_logging() setup_logging()
print("Setting up CNN training test...") print("Setting up CNN training test...")
print("📊 Monitor training: tensorboard --logdir=runs")
# Setup # Configure test parameters
data_provider = DataProvider(['ETH/USDT'], ['1m', '5m', '1h']) config = get_config()
trainer = CNNTrainer(data_provider)
# Configure for quick test # Test configuration
trainer.num_samples = 500 # Very small dataset symbols = ['ETH/USDT']
trainer.num_epochs = 2 # Just 2 epochs timeframes = ['1m', '5m', '1h']
trainer.batch_size = 16 num_samples = 500
trainer.timeframes = ['1m', '5m', '1h'] # Skip 1s for now epochs = 2
trainer.n_timeframes = 3 batch_size = 16
print(f"Configuration:") # Override config for quick test
print(f" Samples: {trainer.num_samples}") config._config['timeframes'] = timeframes # Direct config access
print(f" Epochs: {trainer.num_epochs}")
print(f" Batch size: {trainer.batch_size}") trainer = CNNTrainer(config)
print(f" Timeframes: {trainer.timeframes}") trainer.batch_size = batch_size
trainer.epochs = epochs
print("Configuration:")
print(f" Symbols: {symbols}")
print(f" Timeframes: {timeframes}")
print(f" Samples: {num_samples}")
print(f" Epochs: {epochs}")
print(f" Batch size: {batch_size}")
print(" Data source: REAL market data from exchange APIs")
# Train
try: try:
results = trainer.train(['ETH/USDT'], save_path='test_models/quick_cnn.pt') # Train model with TensorBoard logging
results = trainer.train(symbols, save_path='test_models/quick_cnn.pt', num_samples=num_samples)
print(f"\n✅ CNN Training completed!") print(f"\n✅ CNN Training completed!")
print(f" Best accuracy: {results['best_val_accuracy']:.4f}") print(f" Best accuracy: {results['best_val_accuracy']:.4f}")
print(f" Total epochs: {results['total_epochs']}") print(f" Total epochs: {results['total_epochs']}")
print(f" Training time: {results['total_time']:.2f}s") print(f" Training time: {results['training_time']:.2f}s")
print(f" TensorBoard logs: {results['tensorboard_dir']}")
print(f"\n📊 View training progress: tensorboard --logdir=runs")
except Exception as e: except Exception as e:
print(f"\n❌ Training failed: {e}") print(f"❌ Training failed: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return 1 finally:
trainer.close_tensorboard()
return 0
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) main()

View File

@ -0,0 +1,420 @@
#!/usr/bin/env python3
"""
Realtime RL Training with TensorBoard and Web UI Monitoring
This script runs RL training with:
- TensorBoard monitoring for training metrics
- Web UI for real-time trading visualization
- Real market data integration
- PnL tracking and performance analysis
"""
import asyncio
import threading
import time
import logging
import argparse
from datetime import datetime
import os
import sys
from pathlib import Path
# Add project path
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))
from core.config import setup_logging, get_config
from core.data_provider import DataProvider
from training.rl_trainer import RLTrainer
from torch.utils.tensorboard import SummaryWriter
logger = logging.getLogger(__name__)
class RealtimeRLTrainer:
"""Realtime RL Trainer with TensorBoard and Web UI"""
def __init__(self, symbol="ETH/USDT", initial_balance=1000.0):
self.symbol = symbol
self.initial_balance = initial_balance
# Initialize data provider
self.data_provider = DataProvider(
symbols=[symbol],
timeframes=['1s', '1m', '5m', '15m', '1h']
)
# Initialize RL trainer with TensorBoard
self.rl_trainer = RLTrainer(self.data_provider)
# Training state
self.current_episode = 0
self.session_trades = []
self.session_balance = initial_balance
self.session_pnl = 0.0
self.training_active = False
# Web dashboard
self.dashboard = None
self.dashboard_thread = None
logger.info(f"RealtimeRLTrainer initialized for {symbol}")
logger.info(f"TensorBoard logs: {self.rl_trainer.tensorboard_dir}")
def setup_web_dashboard(self, port=8051):
"""Setup web dashboard for monitoring"""
try:
import dash
from dash import dcc, html, Input, Output
import plotly.graph_objects as go
import plotly.express as px
# Create Dash app
app = dash.Dash(__name__)
# Layout
app.layout = html.Div([
html.H1(f"RL Training Monitor - {self.symbol}",
style={'textAlign': 'center', 'color': '#2c3e50'}),
# Refresh interval
dcc.Interval(
id='interval-component',
interval=2000, # Update every 2 seconds
n_intervals=0
),
# Status row
html.Div([
html.Div([
html.H3("Training Status", style={'color': '#34495e'}),
html.P(id='training-status', style={'fontSize': 18})
], className='three columns'),
html.Div([
html.H3("Current Episode", style={'color': '#34495e'}),
html.P(id='current-episode', style={'fontSize': 18})
], className='three columns'),
html.Div([
html.H3("Session Balance", style={'color': '#27ae60'}),
html.P(id='session-balance', style={'fontSize': 18})
], className='three columns'),
html.Div([
html.H3("Session PnL", style={'color': '#e74c3c'}),
html.P(id='session-pnl', style={'fontSize': 18})
], className='three columns'),
], className='row', style={'margin': '20px'}),
# Charts row
html.Div([
html.Div([
dcc.Graph(id='rewards-chart')
], className='six columns'),
html.Div([
dcc.Graph(id='balance-chart')
], className='six columns'),
], className='row'),
html.Div([
html.Div([
dcc.Graph(id='trades-chart')
], className='six columns'),
html.Div([
dcc.Graph(id='win-rate-chart')
], className='six columns'),
], className='row'),
# TensorBoard link
html.Div([
html.H3("TensorBoard Monitoring"),
html.A("Open TensorBoard",
href="http://localhost:6006",
target="_blank",
style={'fontSize': 16, 'color': '#3498db'})
], style={'textAlign': 'center', 'margin': '20px'})
])
# Callbacks
@app.callback(
[Output('training-status', 'children'),
Output('current-episode', 'children'),
Output('session-balance', 'children'),
Output('session-pnl', 'children'),
Output('rewards-chart', 'figure'),
Output('balance-chart', 'figure'),
Output('trades-chart', 'figure'),
Output('win-rate-chart', 'figure')],
[Input('interval-component', 'n_intervals')]
)
def update_dashboard(n):
# Status updates
status = "TRAINING" if self.training_active else "IDLE"
episode = f"{self.current_episode}"
balance = f"${self.session_balance:.2f}"
pnl = f"${self.session_pnl:.2f}"
# Create charts
rewards_fig = self._create_rewards_chart()
balance_fig = self._create_balance_chart()
trades_fig = self._create_trades_chart()
win_rate_fig = self._create_win_rate_chart()
return status, episode, balance, pnl, rewards_fig, balance_fig, trades_fig, win_rate_fig
self.dashboard = app
logger.info(f"Web dashboard created for port {port}")
except Exception as e:
logger.error(f"Error setting up web dashboard: {e}")
self.dashboard = None
def _create_rewards_chart(self):
"""Create rewards chart"""
import plotly.graph_objects as go
if not self.rl_trainer.episode_rewards:
fig = go.Figure()
fig.add_annotation(text="No data yet", x=0.5, y=0.5, xref="paper", yref="paper")
else:
fig = go.Figure()
fig.add_trace(go.Scatter(
y=self.rl_trainer.episode_rewards,
mode='lines',
name='Episode Rewards',
line=dict(color='#3498db')
))
# Add moving average if enough data
if len(self.rl_trainer.avg_rewards) > 0:
fig.add_trace(go.Scatter(
y=self.rl_trainer.avg_rewards,
mode='lines',
name='Moving Average',
line=dict(color='#e74c3c', width=2)
))
fig.update_layout(title="Episode Rewards", xaxis_title="Episode", yaxis_title="Reward")
return fig
def _create_balance_chart(self):
"""Create balance chart"""
import plotly.graph_objects as go
if not self.rl_trainer.episode_balances:
fig = go.Figure()
fig.add_annotation(text="No data yet", x=0.5, y=0.5, xref="paper", yref="paper")
else:
fig = go.Figure()
fig.add_trace(go.Scatter(
y=self.rl_trainer.episode_balances,
mode='lines',
name='Balance',
line=dict(color='#27ae60')
))
# Add initial balance line
fig.add_hline(y=self.initial_balance, line_dash="dash",
annotation_text="Initial Balance")
fig.update_layout(title="Portfolio Balance", xaxis_title="Episode", yaxis_title="Balance ($)")
return fig
def _create_trades_chart(self):
"""Create trades per episode chart"""
import plotly.graph_objects as go
if not self.rl_trainer.episode_trades:
fig = go.Figure()
fig.add_annotation(text="No data yet", x=0.5, y=0.5, xref="paper", yref="paper")
else:
fig = go.Figure()
fig.add_trace(go.Bar(
y=self.rl_trainer.episode_trades,
name='Trades per Episode',
marker_color='#f39c12'
))
fig.update_layout(title="Trades per Episode", xaxis_title="Episode", yaxis_title="Number of Trades")
return fig
def _create_win_rate_chart(self):
"""Create win rate chart"""
import plotly.graph_objects as go
if not self.rl_trainer.win_rates:
fig = go.Figure()
fig.add_annotation(text="No data yet", x=0.5, y=0.5, xref="paper", yref="paper")
else:
fig = go.Figure()
fig.add_trace(go.Scatter(
y=self.rl_trainer.win_rates,
mode='lines+markers',
name='Win Rate',
line=dict(color='#9b59b6')
))
# Add 50% line
fig.add_hline(y=0.5, line_dash="dash",
annotation_text="Break Even")
fig.update_layout(title="Win Rate", xaxis_title="Evaluation", yaxis_title="Win Rate")
return fig
def start_web_dashboard(self, port=8051):
"""Start web dashboard in background thread"""
if self.dashboard is None:
self.setup_web_dashboard(port)
if self.dashboard is not None:
def run_dashboard():
try:
# Use run instead of run_server for newer Dash versions
self.dashboard.run(port=port, debug=False, use_reloader=False)
except Exception as e:
logger.error(f"Error running dashboard: {e}")
self.dashboard_thread = threading.Thread(target=run_dashboard, daemon=True)
self.dashboard_thread.start()
logger.info(f"Web dashboard started on http://localhost:{port}")
else:
logger.warning("Dashboard not available")
async def train_realtime(self, episodes=100, evaluation_interval=10):
"""Run realtime training with monitoring"""
logger.info(f"Starting realtime RL training for {episodes} episodes")
logger.info(f"TensorBoard: http://localhost:6006")
logger.info(f"Web UI: http://localhost:8051")
self.training_active = True
# Setup environment and agent
environment, agent = self.rl_trainer.setup_environment_and_agent()
# Training loop
for episode in range(episodes):
self.current_episode = episode
# Run episode
episode_start = time.time()
results = self.rl_trainer.run_episode(episode, training=True)
episode_time = time.time() - episode_start
# Update session tracking
self.session_balance = results.get('balance', self.initial_balance)
self.session_pnl = self.session_balance - self.initial_balance
# Log episode metrics to TensorBoard
self.rl_trainer.log_episode_metrics(episode, {
'total_reward': results['reward'],
'final_balance': results['balance'],
'total_return': results['pnl_percentage'],
'steps': results['steps'],
'total_trades': results['trades'],
'win_rate': 1.0 if results['pnl'] > 0 else 0.0,
'epsilon': agent.epsilon,
'memory_size': len(agent.memory) if hasattr(agent, 'memory') else 0
})
# Log progress
if episode % 10 == 0:
logger.info(
f"Episode {episode}/{episodes} - "
f"Reward: {results['reward']:.4f}, "
f"Balance: ${results['balance']:.2f}, "
f"PnL: {results['pnl_percentage']:.2f}%, "
f"Trades: {results['trades']}, "
f"Time: {episode_time:.2f}s"
)
# Evaluation
if episode % evaluation_interval == 0 and episode > 0:
eval_results = self.rl_trainer.evaluate_agent(num_episodes=3)
logger.info(
f"Evaluation - Avg Reward: {eval_results['avg_reward']:.4f}, "
f"Win Rate: {eval_results['win_rate']:.2%}"
)
# Small delay to allow UI updates
await asyncio.sleep(0.1)
self.training_active = False
logger.info("Training completed!")
# Save final model
save_path = f"models/rl/realtime_agent_{int(time.time())}.pt"
agent.save(save_path)
logger.info(f"Model saved: {save_path}")
return {
'episodes': episodes,
'final_balance': self.session_balance,
'final_pnl': self.session_pnl,
'model_path': save_path
}
async def main():
"""Main function"""
parser = argparse.ArgumentParser(description='Realtime RL Training with Monitoring')
parser.add_argument('--symbol', type=str, default='ETH/USDT', help='Trading symbol')
parser.add_argument('--episodes', type=int, default=50, help='Number of episodes')
parser.add_argument('--balance', type=float, default=1000.0, help='Initial balance')
parser.add_argument('--web-port', type=int, default=8051, help='Web dashboard port')
args = parser.parse_args()
# Setup logging
setup_logging()
logger.info("=" * 60)
logger.info("REALTIME RL TRAINING WITH MONITORING")
logger.info(f"Symbol: {args.symbol}")
logger.info(f"Episodes: {args.episodes}")
logger.info(f"Initial Balance: ${args.balance:.2f}")
logger.info("=" * 60)
try:
# Create trainer
trainer = RealtimeRLTrainer(
symbol=args.symbol,
initial_balance=args.balance
)
# Start web dashboard
trainer.start_web_dashboard(port=args.web_port)
# Wait for dashboard to start
await asyncio.sleep(2)
logger.info("MONITORING READY!")
logger.info(f"TensorBoard: http://localhost:6006")
logger.info(f"Web Dashboard: http://localhost:{args.web_port}")
logger.info("=" * 60)
# Run training
results = await trainer.train_realtime(
episodes=args.episodes,
evaluation_interval=10
)
logger.info("Training Results:")
logger.info(f" Final Balance: ${results['final_balance']:.2f}")
logger.info(f" Final PnL: ${results['final_pnl']:.2f}")
logger.info(f" Model Saved: {results['model_path']}")
# Keep running for monitoring
logger.info("Training complete. Press Ctrl+C to exit monitoring.")
while True:
await asyncio.sleep(1)
except KeyboardInterrupt:
logger.info("Training stopped by user")
except Exception as e:
logger.error(f"Error in training: {e}")
import traceback
logger.error(traceback.format_exc())
if __name__ == "__main__":
asyncio.run(main())

View File

@ -1,31 +1,23 @@
""" """
CNN Training Pipeline - Scalping Pattern Recognition CNN Training Pipeline
Comprehensive training pipeline for multi-timeframe CNN models: This module handles training of the CNN model using ONLY real market data.
- Automated data generation and preprocessing All training metrics are logged to TensorBoard for real-time monitoring.
- Training with validation and early stopping
- Memory-efficient batch processing
- Model evaluation and metrics
""" """
import torch import torch
import torch.nn as nn import torch.nn as nn
import torch.optim as optim import torch.optim as optim
from torch.utils.data import DataLoader, Dataset from torch.utils.data import Dataset, DataLoader, random_split
from torch.utils.tensorboard import SummaryWriter
import numpy as np import numpy as np
import pandas as pd import pandas as pd
import logging import logging
from typing import Dict, List, Tuple, Optional from typing import Dict, List, Tuple, Optional
import time
from pathlib import Path from pathlib import Path
import time
from sklearn.metrics import classification_report, confusion_matrix from sklearn.metrics import classification_report, confusion_matrix
from sklearn.model_selection import train_test_split import json
import matplotlib.pyplot as plt
# Add project imports
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from core.config import get_config from core.config import get_config
from core.data_provider import DataProvider from core.data_provider import DataProvider
@ -33,13 +25,12 @@ from models.cnn.scalping_cnn import MultiTimeframeCNN, ScalpingDataGenerator
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class TradingDataset(Dataset): class CNNDataset(Dataset):
"""PyTorch dataset for trading data""" """Dataset for CNN training with real market data"""
def __init__(self, features: np.ndarray, labels: np.ndarray, metadata: Optional[Dict] = None): def __init__(self, features: np.ndarray, labels: np.ndarray):
self.features = torch.FloatTensor(features) self.features = torch.FloatTensor(features)
self.labels = torch.FloatTensor(labels) self.labels = torch.LongTensor(np.argmax(labels, axis=1)) # Convert one-hot to class indices
self.metadata = metadata or {}
def __len__(self): def __len__(self):
return len(self.features) return len(self.features)
@ -48,431 +39,437 @@ class TradingDataset(Dataset):
return self.features[idx], self.labels[idx] return self.features[idx], self.labels[idx]
class CNNTrainer: class CNNTrainer:
""" """CNN Trainer using ONLY real market data with TensorBoard monitoring"""
CNN Training Pipeline for Scalping
"""
def __init__(self, data_provider: DataProvider, config: Optional[Dict] = None): def __init__(self, config: Optional[Dict] = None):
self.data_provider = data_provider """Initialize CNN trainer"""
self.config = config or get_config() self.config = config or get_config()
# Training parameters
self.learning_rate = 1e-4
self.batch_size = 64
self.num_epochs = 100
self.patience = 15
self.validation_split = 0.2
# Data parameters
self.timeframes = ['1s', '1m', '5m', '1h']
self.window_size = 20
self.num_samples = 20000
# Model parameters
self.n_timeframes = len(self.timeframes)
self.n_features = 26 # Number of technical indicators
self.n_classes = 3 # BUY, SELL, HOLD
# Device
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# Initialize data generator # Training parameters
self.data_generator = ScalpingDataGenerator(data_provider, self.window_size) self.learning_rate = self.config.training.get('learning_rate', 0.001)
self.batch_size = self.config.training.get('batch_size', 32)
self.epochs = self.config.training.get('epochs', 100)
self.validation_split = self.config.training.get('validation_split', 0.2)
self.early_stopping_patience = self.config.training.get('early_stopping_patience', 10)
# Training state # Model parameters - will be updated based on real data
self.n_timeframes = len(self.config.timeframes)
self.window_size = self.config.cnn.get('window_size', 20)
self.n_features = self.config.cnn.get('features', 26) # Will be dynamically updated
self.n_classes = 3 # BUY, SELL, HOLD
# Initialize components
self.data_provider = DataProvider(self.config)
self.data_generator = ScalpingDataGenerator(self.data_provider, self.window_size)
self.model = None self.model = None
self.train_losses = []
self.val_losses = [] # TensorBoard setup
self.train_accuracies = [] self.setup_tensorboard()
self.val_accuracies = []
logger.info(f"CNNTrainer initialized with {self.n_timeframes} timeframes, {self.n_features} features") logger.info(f"CNNTrainer initialized with {self.n_timeframes} timeframes, {self.n_features} features")
logger.info("Will use ONLY real market data for training")
def prepare_data(self, symbols: List[str]) -> Tuple[DataLoader, DataLoader, Dict]: def setup_tensorboard(self):
"""Prepare training and validation data""" """Setup TensorBoard logging"""
logger.info("Preparing training data...") # Create tensorboard logs directory
log_dir = Path("runs") / f"cnn_training_{int(time.time())}"
log_dir.mkdir(parents=True, exist_ok=True)
all_features = [] self.writer = SummaryWriter(log_dir=str(log_dir))
all_labels = [] self.tensorboard_dir = log_dir
all_metadata = {'symbols': []}
# Generate data for each symbol logger.info(f"TensorBoard logging to: {log_dir}")
for symbol in symbols: logger.info(f"Run: tensorboard --logdir=runs")
logger.info(f"Generating data for {symbol}...")
features, labels, metadata = self.data_generator.generate_training_cases( def log_model_architecture(self):
symbol, self.timeframes, self.num_samples // len(symbols) """Log model architecture to TensorBoard"""
) if self.model is not None:
# Log model graph (requires a dummy input)
dummy_input = torch.randn(1, self.n_timeframes, self.window_size, self.n_features).to(self.device)
try:
self.writer.add_graph(self.model, dummy_input)
logger.info("Model architecture logged to TensorBoard")
except Exception as e:
logger.warning(f"Could not log model graph: {e}")
if features is not None and labels is not None: # Log model parameters count
all_features.append(features) total_params = sum(p.numel() for p in self.model.parameters())
all_labels.append(labels) trainable_params = sum(p.numel() for p in self.model.parameters() if p.requires_grad)
all_metadata['symbols'].extend([symbol] * len(features))
logger.info(f"Generated {len(features)} samples for {symbol}") self.writer.add_scalar('Model/TotalParameters', total_params, 0)
self.writer.add_scalar('Model/TrainableParameters', trainable_params, 0)
# Update feature count based on actual data
if len(all_features) == 1:
actual_features = features.shape[-1]
if actual_features != self.n_features:
logger.info(f"Updating feature count from {self.n_features} to {actual_features}")
self.n_features = actual_features
else:
logger.warning(f"No data generated for {symbol}")
if not all_features:
raise ValueError("No training data generated")
# Combine all data
combined_features = np.concatenate(all_features, axis=0)
combined_labels = np.concatenate(all_labels, axis=0)
logger.info(f"Total dataset: {len(combined_features)} samples")
logger.info(f"Features shape: {combined_features.shape}")
logger.info(f"Labels shape: {combined_labels.shape}")
# Split into train/validation
X_train, X_val, y_train, y_val = train_test_split(
combined_features, combined_labels,
test_size=self.validation_split,
stratify=np.argmax(combined_labels, axis=1),
random_state=42
)
# Create datasets
train_dataset = TradingDataset(X_train, y_train)
val_dataset = TradingDataset(X_val, y_val)
# Create data loaders
train_loader = DataLoader(
train_dataset,
batch_size=self.batch_size,
shuffle=True,
num_workers=0, # Set to 0 to avoid multiprocessing issues
pin_memory=True if torch.cuda.is_available() else False
)
val_loader = DataLoader(
val_dataset,
batch_size=self.batch_size,
shuffle=False,
num_workers=0,
pin_memory=True if torch.cuda.is_available() else False
)
# Prepare metadata for return
dataset_info = {
'train_size': len(train_dataset),
'val_size': len(val_dataset),
'feature_shape': combined_features.shape[1:],
'label_distribution': {
'train': np.bincount(np.argmax(y_train, axis=1)),
'val': np.bincount(np.argmax(y_val, axis=1))
}
}
logger.info(f"Train samples: {dataset_info['train_size']}")
logger.info(f"Validation samples: {dataset_info['val_size']}")
logger.info(f"Train label distribution: {dataset_info['label_distribution']['train']}")
logger.info(f"Val label distribution: {dataset_info['label_distribution']['val']}")
return train_loader, val_loader, dataset_info
def create_model(self) -> MultiTimeframeCNN: def create_model(self) -> MultiTimeframeCNN:
"""Create and initialize the CNN model""" """Create CNN model"""
model = MultiTimeframeCNN( model = MultiTimeframeCNN(
n_timeframes=self.n_timeframes, n_timeframes=self.n_timeframes,
window_size=self.window_size, window_size=self.window_size,
n_features=self.n_features, n_features=self.n_features,
n_classes=self.n_classes n_classes=self.n_classes,
dropout_rate=self.config.cnn.get('dropout', 0.2)
) )
model.to(self.device) model = model.to(self.device)
# Log model info # Log model info
total_params = sum(p.numel() for p in model.parameters()) total_params = sum(p.numel() for p in model.parameters())
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad) trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
memory_usage = model.get_memory_usage()
logger.info(f"Model created with {total_params:,} total parameters") logger.info(f"Model created with {total_params:,} total parameters")
logger.info(f"Trainable parameters: {trainable_params:,}") logger.info(f"Trainable parameters: {trainable_params:,}")
logger.info(f"Estimated memory usage: {model.get_memory_usage()}MB") logger.info(f"Estimated memory usage: {memory_usage}MB")
return model return model
def prepare_data(self, symbols: List[str], num_samples: int = 10000) -> Tuple[np.ndarray, np.ndarray, Dict]:
"""Prepare training data from REAL market data"""
logger.info("Preparing training data...")
logger.info("Data source: REAL market data from exchange APIs")
all_features = []
all_labels = []
all_metadata = []
for symbol in symbols:
logger.info(f"Generating data for {symbol}...")
features, labels, metadata = self.data_generator.generate_training_cases(
symbol=symbol,
timeframes=self.config.timeframes,
num_samples=num_samples
)
if features is not None:
all_features.append(features)
all_labels.append(labels)
all_metadata.append(metadata)
logger.info(f"Generated {len(features)} samples for {symbol}")
# Update feature count if needed
actual_features = features.shape[-1]
if actual_features != self.n_features:
logger.info(f"Updating feature count from {self.n_features} to {actual_features}")
self.n_features = actual_features
if not all_features:
raise ValueError("No training data generated from real market data")
# Combine all data
features = np.concatenate(all_features, axis=0)
labels = np.concatenate(all_labels, axis=0)
# Log data statistics to TensorBoard
self.log_data_statistics(features, labels)
return features, labels, all_metadata
def log_data_statistics(self, features: np.ndarray, labels: np.ndarray):
"""Log data statistics to TensorBoard"""
# Dataset size
self.writer.add_scalar('Data/TotalSamples', len(features), 0)
self.writer.add_scalar('Data/Features', features.shape[-1], 0)
self.writer.add_scalar('Data/Timeframes', features.shape[1], 0)
self.writer.add_scalar('Data/WindowSize', features.shape[2], 0)
# Class distribution
class_counts = np.bincount(np.argmax(labels, axis=1))
for i, count in enumerate(class_counts):
self.writer.add_scalar(f'Data/Class_{i}_Count', count, 0)
# Feature statistics
feature_means = features.mean(axis=(0, 1, 2))
feature_stds = features.std(axis=(0, 1, 2))
for i in range(min(10, len(feature_means))): # Log first 10 features
self.writer.add_scalar(f'Data/Feature_{i}_Mean', feature_means[i], 0)
self.writer.add_scalar(f'Data/Feature_{i}_Std', feature_stds[i], 0)
def train_epoch(self, model: nn.Module, train_loader: DataLoader, def train_epoch(self, model: nn.Module, train_loader: DataLoader,
optimizer: optim.Optimizer, criterion: nn.Module) -> Tuple[float, float]: optimizer: torch.optim.Optimizer, criterion: nn.Module, epoch: int) -> Tuple[float, float]:
"""Train for one epoch""" """Train for one epoch with TensorBoard logging"""
model.train() model.train()
total_loss = 0.0 total_loss = 0.0
correct_predictions = 0 correct = 0
total_predictions = 0 total = 0
for batch_idx, (features, labels) in enumerate(train_loader): for batch_idx, (features, labels) in enumerate(train_loader):
features = features.to(self.device) features, labels = features.to(self.device), labels.to(self.device)
labels = labels.to(self.device)
# Zero gradients
optimizer.zero_grad() optimizer.zero_grad()
# Forward pass
predictions = model(features) predictions = model(features)
loss = criterion(predictions['action'], labels)
# Calculate loss (multi-task loss) loss.backward()
action_loss = criterion(predictions['action'], labels)
# Additional losses for auxiliary tasks
confidence_loss = torch.mean(torch.abs(predictions['confidence'] - 0.5)) # Encourage diversity
# Total loss
total_loss_batch = action_loss + 0.1 * confidence_loss
# Backward pass
total_loss_batch.backward()
# Gradient clipping
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
# Update weights
optimizer.step() optimizer.step()
# Track metrics total_loss += loss.item()
total_loss += total_loss_batch.item() _, predicted = torch.max(predictions['action'].data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# Calculate accuracy # Log batch metrics
pred_classes = torch.argmax(predictions['action'], dim=1) step = epoch * len(train_loader) + batch_idx
true_classes = torch.argmax(labels, dim=1) self.writer.add_scalar('Training/BatchLoss', loss.item(), step)
correct_predictions += (pred_classes == true_classes).sum().item()
total_predictions += labels.size(0)
# Log progress if batch_idx % 50 == 0: # Log every 50 batches
if batch_idx % 100 == 0: batch_acc = 100. * (predicted == labels).sum().item() / labels.size(0)
logger.debug(f"Batch {batch_idx}/{len(train_loader)}, Loss: {total_loss_batch.item():.4f}") self.writer.add_scalar('Training/BatchAccuracy', batch_acc, step)
avg_loss = total_loss / len(train_loader) # Log confidence scores
accuracy = correct_predictions / total_predictions avg_confidence = predictions['confidence'].mean().item()
self.writer.add_scalar('Training/BatchConfidence', avg_confidence, step)
return avg_loss, accuracy epoch_loss = total_loss / len(train_loader)
epoch_accuracy = correct / total
return epoch_loss, epoch_accuracy
def validate_epoch(self, model: nn.Module, val_loader: DataLoader, def validate_epoch(self, model: nn.Module, val_loader: DataLoader,
criterion: nn.Module) -> Tuple[float, float, Dict]: criterion: nn.Module, epoch: int) -> Tuple[float, float, Dict]:
"""Validate for one epoch""" """Validate for one epoch with TensorBoard logging"""
model.eval() model.eval()
total_loss = 0.0 total_loss = 0.0
correct_predictions = 0 correct = 0
total_predictions = 0 total = 0
all_predictions = [] all_predictions = []
all_labels = [] all_labels = []
all_confidences = [] all_confidences = []
with torch.no_grad(): with torch.no_grad():
for features, labels in val_loader: for features, labels in val_loader:
features = features.to(self.device) features, labels = features.to(self.device), labels.to(self.device)
labels = labels.to(self.device)
# Forward pass
predictions = model(features) predictions = model(features)
# Calculate loss
loss = criterion(predictions['action'], labels) loss = criterion(predictions['action'], labels)
total_loss += loss.item() total_loss += loss.item()
_, predicted = torch.max(predictions['action'].data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# Track predictions all_predictions.extend(predicted.cpu().numpy())
pred_classes = torch.argmax(predictions['action'], dim=1) all_labels.extend(labels.cpu().numpy())
true_classes = torch.argmax(labels, dim=1)
correct_predictions += (pred_classes == true_classes).sum().item()
total_predictions += labels.size(0)
# Store for detailed analysis
all_predictions.extend(pred_classes.cpu().numpy())
all_labels.extend(true_classes.cpu().numpy())
all_confidences.extend(predictions['confidence'].cpu().numpy()) all_confidences.extend(predictions['confidence'].cpu().numpy())
avg_loss = total_loss / len(val_loader) epoch_loss = total_loss / len(val_loader)
accuracy = correct_predictions / total_predictions epoch_accuracy = correct / total
# Additional metrics # Calculate detailed metrics
metrics = { metrics = self.calculate_detailed_metrics(all_predictions, all_labels, all_confidences)
'predictions': np.array(all_predictions),
'labels': np.array(all_labels), # Log validation metrics to TensorBoard
'confidences': np.array(all_confidences), self.writer.add_scalar('Validation/Loss', epoch_loss, epoch)
'accuracy_by_class': {}, self.writer.add_scalar('Validation/Accuracy', epoch_accuracy, epoch)
'avg_confidence': np.mean(all_confidences) self.writer.add_scalar('Validation/AvgConfidence', metrics['avg_confidence'], epoch)
for class_idx, acc in metrics['class_accuracies'].items():
self.writer.add_scalar(f'Validation/Class_{class_idx}_Accuracy', acc, epoch)
return epoch_loss, epoch_accuracy, metrics
def calculate_detailed_metrics(self, predictions: List, labels: List, confidences: List) -> Dict:
"""Calculate detailed training metrics"""
predictions = np.array(predictions)
labels = np.array(labels)
confidences = np.array(confidences)
# Class-wise accuracies
class_accuracies = {}
for class_idx in range(self.n_classes):
class_mask = labels == class_idx
if class_mask.sum() > 0:
class_acc = (predictions[class_mask] == labels[class_mask]).mean()
class_accuracies[class_idx] = class_acc
return {
'class_accuracies': class_accuracies,
'avg_confidence': confidences.mean(),
'confusion_matrix': confusion_matrix(labels, predictions)
} }
# Calculate per-class accuracy def train(self, symbols: List[str], save_path: str = 'models/cnn/scalping_cnn_trained.pt',
for class_idx in range(self.n_classes): num_samples: int = 10000) -> Dict:
class_mask = metrics['labels'] == class_idx """Train CNN model with TensorBoard monitoring"""
if np.sum(class_mask) > 0:
class_accuracy = np.mean(metrics['predictions'][class_mask] == metrics['labels'][class_mask])
metrics['accuracy_by_class'][class_idx] = class_accuracy
return avg_loss, accuracy, metrics
def train(self, symbols: List[str], save_path: Optional[str] = None) -> Dict:
"""Train the CNN model"""
logger.info("Starting CNN training...") logger.info("Starting CNN training...")
logger.info("Using ONLY real market data from exchange APIs")
# Prepare data first to get actual feature count # Prepare data
train_loader, val_loader, dataset_info = self.prepare_data(symbols) features, labels, metadata = self.prepare_data(symbols, num_samples)
# Create model with correct feature count # Log training configuration
self.writer.add_text('Config/Symbols', str(symbols), 0)
self.writer.add_text('Config/Timeframes', str(self.config.timeframes), 0)
self.writer.add_scalar('Config/LearningRate', self.learning_rate, 0)
self.writer.add_scalar('Config/BatchSize', self.batch_size, 0)
self.writer.add_scalar('Config/MaxEpochs', self.epochs, 0)
# Create datasets
dataset = CNNDataset(features, labels)
# Split data
val_size = int(len(dataset) * self.validation_split)
train_size = len(dataset) - val_size
train_dataset, val_dataset = random_split(dataset, [train_size, val_size])
# Create data loaders
train_loader = DataLoader(train_dataset, batch_size=self.batch_size, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=self.batch_size, shuffle=False)
logger.info(f"Total dataset: {len(dataset)} samples")
logger.info(f"Features shape: {features.shape}")
logger.info(f"Labels shape: {labels.shape}")
logger.info(f"Train samples: {train_size}")
logger.info(f"Validation samples: {val_size}")
# Log class distributions
train_labels = [dataset[i][1].item() for i in train_dataset.indices]
val_labels = [dataset[i][1].item() for i in val_dataset.indices]
logger.info(f"Train label distribution: {np.bincount(train_labels)}")
logger.info(f"Val label distribution: {np.bincount(val_labels)}")
# Create model
self.model = self.create_model() self.model = self.create_model()
self.log_model_architecture()
# Setup training # Setup training
criterion = nn.CrossEntropyLoss() criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(self.model.parameters(), lr=self.learning_rate) optimizer = optim.Adam(self.model.parameters(), lr=self.learning_rate)
scheduler = optim.lr_scheduler.ReduceLROnPlateau( scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=5, verbose=True)
optimizer, mode='min', factor=0.5, patience=5, verbose=True
)
# Training state # Training loop
best_val_loss = float('inf') best_val_loss = float('inf')
best_val_accuracy = 0.0 best_val_accuracy = 0.0
patience_counter = 0 patience_counter = 0
start_time = time.time() start_time = time.time()
# Training loop for epoch in range(self.epochs):
for epoch in range(self.num_epochs): epoch_start = time.time()
epoch_start_time = time.time()
# Train # Train
train_loss, train_accuracy = self.train_epoch( train_loss, train_accuracy = self.train_epoch(self.model, train_loader, optimizer, criterion, epoch)
self.model, train_loader, optimizer, criterion
)
# Validate # Validate
val_loss, val_accuracy, val_metrics = self.validate_epoch( val_loss, val_accuracy, val_metrics = self.validate_epoch(self.model, val_loader, criterion, epoch)
self.model, val_loader, criterion
)
# Update learning rate # Update learning rate
scheduler.step(val_loss) scheduler.step(val_loss)
current_lr = optimizer.param_groups[0]['lr']
# Track metrics # Log epoch metrics
self.train_losses.append(train_loss) self.writer.add_scalar('Training/EpochLoss', train_loss, epoch)
self.val_losses.append(val_loss) self.writer.add_scalar('Training/EpochAccuracy', train_accuracy, epoch)
self.train_accuracies.append(train_accuracy) self.writer.add_scalar('Training/LearningRate', current_lr, epoch)
self.val_accuracies.append(val_accuracy)
# Check for improvement epoch_time = time.time() - epoch_start
self.writer.add_scalar('Training/EpochTime', epoch_time, epoch)
# Save best model
if val_loss < best_val_loss: if val_loss < best_val_loss:
best_val_loss = val_loss best_val_loss = val_loss
best_val_accuracy = val_accuracy best_val_accuracy = val_accuracy
patience_counter = 0 patience_counter = 0
# Save best model # Save best model
if save_path: best_path = save_path.replace('.pt', '_best.pt')
best_path = save_path.replace('.pt', '_best.pt') self.model.save(best_path)
self.model.save(best_path) logger.info(f"New best model saved: {best_path}")
logger.info(f"New best model saved: {best_path}")
# Log best metrics
self.writer.add_scalar('Best/ValidationLoss', best_val_loss, epoch)
self.writer.add_scalar('Best/ValidationAccuracy', best_val_accuracy, epoch)
else: else:
patience_counter += 1 patience_counter += 1
# Log progress logger.info(f"Epoch {epoch+1}/{self.epochs} - "
epoch_time = time.time() - epoch_start_time f"Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.4f} - "
logger.info( f"Val Loss: {val_loss:.4f}, Val Acc: {val_accuracy:.4f} - "
f"Epoch {epoch+1}/{self.num_epochs} - " f"Time: {epoch_time:.2f}s")
f"Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.4f} - "
f"Val Loss: {val_loss:.4f}, Val Acc: {val_accuracy:.4f} - "
f"Time: {epoch_time:.2f}s"
)
# Detailed validation metrics every 10 epochs # Log detailed metrics every 10 epochs
if (epoch + 1) % 10 == 0: if (epoch + 1) % 10 == 0:
logger.info(f"Class accuracies: {val_metrics['accuracy_by_class']}") logger.info(f"Class accuracies: {val_metrics['class_accuracies']}")
logger.info(f"Average confidence: {val_metrics['avg_confidence']:.4f}") logger.info(f"Average confidence: {val_metrics['avg_confidence']:.4f}")
# Early stopping # Early stopping
if patience_counter >= self.patience: if patience_counter >= self.early_stopping_patience:
logger.info(f"Early stopping triggered after {epoch+1} epochs") logger.info(f"Early stopping triggered after {epoch+1} epochs")
break break
# Training complete # Training completed
total_time = time.time() - start_time total_time = time.time() - start_time
logger.info(f"Training completed in {total_time:.2f} seconds") logger.info(f"Training completed in {total_time:.2f} seconds")
logger.info(f"Best validation loss: {best_val_loss:.4f}") logger.info(f"Best validation loss: {best_val_loss:.4f}")
logger.info(f"Best validation accuracy: {best_val_accuracy:.4f}") logger.info(f"Best validation accuracy: {best_val_accuracy:.4f}")
# Save final model # Log final metrics
if save_path: self.writer.add_scalar('Final/TotalTrainingTime', total_time, 0)
self.model.save(save_path) self.writer.add_scalar('Final/TotalEpochs', epoch + 1, 0)
logger.info(f"Final model saved: {save_path}")
# Prepare training results # Save final model
results = { self.model.save(save_path)
logger.info(f"Final model saved: {save_path}")
# Log training summary
self.writer.add_text('Training/Summary',
f"Completed training with {len(features)} real market samples. "
f"Best validation accuracy: {best_val_accuracy:.4f}", 0)
return {
'best_val_loss': best_val_loss, 'best_val_loss': best_val_loss,
'best_val_accuracy': best_val_accuracy, 'best_val_accuracy': best_val_accuracy,
'total_epochs': epoch + 1, 'total_epochs': epoch + 1,
'total_time': total_time, 'training_time': total_time,
'train_losses': self.train_losses, 'tensorboard_dir': str(self.tensorboard_dir)
'val_losses': self.val_losses,
'train_accuracies': self.train_accuracies,
'val_accuracies': self.val_accuracies,
'dataset_info': dataset_info,
'final_metrics': val_metrics
} }
return results def evaluate(self, symbols: List[str], num_samples: int = 5000) -> Dict:
def evaluate_model(self, test_symbols: List[str]) -> Dict:
"""Evaluate trained model on test data""" """Evaluate trained model on test data"""
if self.model is None: if self.model is None:
raise ValueError("Model not trained yet") raise ValueError("Model not trained yet")
logger.info("Evaluating model...") logger.info("Evaluating model...")
# Generate test data # Generate test data from real market data
test_features = [] features, labels, metadata = self.prepare_data(symbols, num_samples)
test_labels = []
for symbol in test_symbols: # Create test dataset and loader
features, labels, _ = self.data_generator.generate_training_cases( test_dataset = CNNDataset(features, labels)
symbol, self.timeframes, 5000
)
if features is not None:
test_features.append(features)
test_labels.append(labels)
if not test_features:
raise ValueError("No test data generated")
test_features = np.concatenate(test_features, axis=0)
test_labels = np.concatenate(test_labels, axis=0)
# Create test loader
test_dataset = TradingDataset(test_features, test_labels)
test_loader = DataLoader(test_dataset, batch_size=self.batch_size, shuffle=False) test_loader = DataLoader(test_dataset, batch_size=self.batch_size, shuffle=False)
# Evaluate # Evaluate
criterion = nn.CrossEntropyLoss() criterion = nn.CrossEntropyLoss()
test_loss, test_accuracy, test_metrics = self.validate_epoch( test_loss, test_accuracy, test_metrics = self.validate_epoch(
self.model, test_loader, criterion self.model, test_loader, criterion, epoch=0
) )
# Generate classification report # Generate detailed classification report
from sklearn.metrics import classification_report
class_names = ['BUY', 'SELL', 'HOLD'] class_names = ['BUY', 'SELL', 'HOLD']
classification_rep = classification_report( all_predictions = []
test_metrics['labels'], all_labels = []
test_metrics['predictions'],
target_names=class_names,
output_dict=True
)
# Confusion matrix with torch.no_grad():
conf_matrix = confusion_matrix( for features_batch, labels_batch in test_loader:
test_metrics['labels'], features_batch = features_batch.to(self.device)
test_metrics['predictions'] predictions = self.model(features_batch)
_, predicted = torch.max(predictions['action'].data, 1)
all_predictions.extend(predicted.cpu().numpy())
all_labels.extend(labels_batch.numpy())
classification_rep = classification_report(
all_labels, all_predictions, target_names=class_names, output_dict=True
) )
evaluation_results = { evaluation_results = {
'test_loss': test_loss, 'test_loss': test_loss,
'test_accuracy': test_accuracy, 'test_accuracy': test_accuracy,
'classification_report': classification_rep, 'classification_report': classification_rep,
'confusion_matrix': conf_matrix, 'class_accuracies': test_metrics['class_accuracies'],
'class_accuracies': test_metrics['accuracy_by_class'], 'avg_confidence': test_metrics['avg_confidence'],
'avg_confidence': test_metrics['avg_confidence'] 'confusion_matrix': test_metrics['confusion_matrix']
} }
logger.info(f"Test accuracy: {test_accuracy:.4f}") logger.info(f"Test accuracy: {test_accuracy:.4f}")
@ -480,40 +477,15 @@ class CNNTrainer:
return evaluation_results return evaluation_results
def plot_training_history(self, save_path: Optional[str] = None): def close_tensorboard(self):
"""Plot training history""" """Close TensorBoard writer"""
if not self.train_losses: if hasattr(self, 'writer'):
logger.warning("No training history to plot") self.writer.close()
return logger.info("TensorBoard writer closed")
fig, ((ax1, ax2)) = plt.subplots(1, 2, figsize=(12, 4)) def __del__(self):
"""Cleanup"""
# Loss plot self.close_tensorboard()
epochs = range(1, len(self.train_losses) + 1)
ax1.plot(epochs, self.train_losses, 'b-', label='Training Loss')
ax1.plot(epochs, self.val_losses, 'r-', label='Validation Loss')
ax1.set_title('Training and Validation Loss')
ax1.set_xlabel('Epoch')
ax1.set_ylabel('Loss')
ax1.legend()
ax1.grid(True)
# Accuracy plot
ax2.plot(epochs, self.train_accuracies, 'b-', label='Training Accuracy')
ax2.plot(epochs, self.val_accuracies, 'r-', label='Validation Accuracy')
ax2.set_title('Training and Validation Accuracy')
ax2.set_xlabel('Epoch')
ax2.set_ylabel('Accuracy')
ax2.legend()
ax2.grid(True)
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
logger.info(f"Training history plot saved: {save_path}")
plt.show()
# Export # Export
__all__ = ['CNNTrainer', 'TradingDataset'] __all__ = ['CNNTrainer', 'CNNDataset']

View File

@ -18,6 +18,7 @@ from pathlib import Path
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from collections import deque from collections import deque
import random import random
from torch.utils.tensorboard import SummaryWriter
# Add project imports # Add project imports
import sys import sys
@ -75,8 +76,23 @@ class RLTrainer:
self.win_rates = [] self.win_rates = []
self.avg_rewards = [] self.avg_rewards = []
# TensorBoard setup
self.setup_tensorboard()
logger.info(f"RLTrainer initialized for symbols: {self.symbols}") logger.info(f"RLTrainer initialized for symbols: {self.symbols}")
def setup_tensorboard(self):
"""Setup TensorBoard logging"""
# Create tensorboard logs directory
log_dir = Path("runs") / f"rl_training_{int(time.time())}"
log_dir.mkdir(parents=True, exist_ok=True)
self.writer = SummaryWriter(log_dir=str(log_dir))
self.tensorboard_dir = log_dir
logger.info(f"TensorBoard logging to: {log_dir}")
logger.info(f"Run: tensorboard --logdir=runs")
def setup_environment_and_agent(self) -> Tuple[ScalpingEnvironment, ScalpingRLAgent]: def setup_environment_and_agent(self) -> Tuple[ScalpingEnvironment, ScalpingRLAgent]:
"""Setup trading environment and RL agent""" """Setup trading environment and RL agent"""
logger.info("Setting up environment and agent...") logger.info("Setting up environment and agent...")
@ -443,6 +459,29 @@ class RLTrainer:
plt.show() plt.show()
def log_episode_metrics(self, episode: int, metrics: Dict):
"""Log episode metrics to TensorBoard"""
# Main performance metrics
self.writer.add_scalar('Episode/TotalReward', metrics['total_reward'], episode)
self.writer.add_scalar('Episode/FinalBalance', metrics['final_balance'], episode)
self.writer.add_scalar('Episode/TotalReturn', metrics['total_return'], episode)
self.writer.add_scalar('Episode/Steps', metrics['steps'], episode)
# Trading metrics
self.writer.add_scalar('Trading/TotalTrades', metrics['total_trades'], episode)
self.writer.add_scalar('Trading/WinRate', metrics['win_rate'], episode)
self.writer.add_scalar('Trading/ProfitFactor', metrics.get('profit_factor', 0), episode)
self.writer.add_scalar('Trading/MaxDrawdown', metrics.get('max_drawdown', 0), episode)
# Agent metrics
self.writer.add_scalar('Agent/Epsilon', metrics['epsilon'], episode)
self.writer.add_scalar('Agent/LearningRate', metrics.get('learning_rate', self.learning_rate), episode)
self.writer.add_scalar('Agent/MemorySize', metrics.get('memory_size', 0), episode)
# Loss metrics (if available)
if 'loss' in metrics:
self.writer.add_scalar('Agent/Loss', metrics['loss'], episode)
class HybridTrainer: class HybridTrainer:
""" """
Hybrid training pipeline combining CNN and RL Hybrid training pipeline combining CNN and RL