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",
"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())
raise
def run_cnn_training():
"""Train CNN models only with comprehensive pipeline"""
def run_cnn_training(config: Config, symbol: str):
"""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:
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(f" Best validation accuracy: {results['best_val_accuracy']:.4f}")
logger.info(f" Best validation loss: {results['best_val_loss']:.4f}")
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
try:
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}")
logger.info(f"📊 View training progress: tensorboard --logdir=runs")
logger.info("Evaluating CNN on test data...")
# Evaluate on test data
try:
logger.info("Evaluating CNN on test data...")
test_symbols = ['ETH/USDT'] # Use subset for testing
eval_results = trainer.evaluate_model(test_symbols)
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}")
# Quick evaluation on same symbols
test_results = trainer.evaluate(symbols[:1]) # Use first symbol for quick test
logger.info("CNN Evaluation Results:")
logger.info(f" Test accuracy: {test_results['test_accuracy']:.4f}")
logger.info(f" Test loss: {test_results['test_loss']:.4f}")
logger.info(f" Average confidence: {test_results['avg_confidence']:.4f}")
logger.info("CNN training completed successfully!")
except Exception as e:
logger.error(f"Error in CNN training: {e}")
import traceback
logger.error(traceback.format_exc())
logger.error(f"CNN training failed: {e}")
raise
finally:
trainer.close_tensorboard()
def run_rl_training():
"""Train RL agents only with comprehensive pipeline"""
@ -404,7 +382,7 @@ async def main():
if args.mode == 'test':
run_data_test()
elif args.mode == 'cnn':
run_cnn_training()
run_cnn_training(get_config(), args.symbol)
elif args.mode == 'rl':
run_rl_training()
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
### CNN Training
### CNN Training with TensorBoard
```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
# Monitor training in real-time
tensorboard --logdir=runs
# Or use the convenience script
python run_tensorboard.py
# Quick test with real data
python test_cnn_only.py
```
### RL Training
### RL Training with TensorBoard
```bash
# Train RL agent with real data
python main_clean.py --mode rl --symbol ETH/USDT
# Real-time RL training
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
- **Memory Usage**: <2GB per model

View File

@ -1,69 +1,74 @@
import os
import sys
import subprocess
import webbrowser
import time
import argparse
#!/usr/bin/env python3
"""
TensorBoard Launch Script
def run_tensorboard():
"""Run TensorBoard server and open browser"""
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()
Starts TensorBoard server for monitoring training progress.
"""
import subprocess
import sys
import os
import time
import webbrowser
from pathlib import Path
def main():
"""Launch TensorBoard"""
# Create log directory if it doesn't exist
os.makedirs(args.logdir, exist_ok=True)
# Check if runs directory exists
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
print("\n" + "="*60)
print("📊 TRADING BOT - TENSORBOARD MONITORING 📊")
print("="*60)
print(f"Starting TensorBoard server on port {args.port}")
print(f"Log directory: {args.logdir}")
print("Press Ctrl+C to stop the server")
print("="*60 + "\n")
# Check if there are any log directories
log_dirs = list(runs_dir.glob("*"))
if not log_dirs:
print("❌ No training logs found in 'runs' directory.")
print(" Start training first to generate TensorBoard logs.")
return
# Start TensorBoard server
cmd = ["tensorboard", "--logdir", args.logdir, "--port", str(args.port)]
print("🚀 Starting TensorBoard...")
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:
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
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True
)
cmd = [sys.executable, "-m", "tensorboard.main", "--logdir", str(runs_dir), "--port", str(port)]
# Wait for TensorBoard to start
time.sleep(3)
print("\n" + "="*50)
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
if not args.no_browser:
url = f"http://localhost:{args.port}"
print(f"Opening browser to {url}")
webbrowser.open(url)
# Run TensorBoard
subprocess.run(cmd)
# 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:
print("\nStopping TensorBoard server...")
process.terminate()
return 0
print("\n🛑 TensorBoard stopped")
except FileNotFoundError:
print("❌ TensorBoard not found. Install with: pip install tensorboard")
except Exception as e:
print(f"Error running TensorBoard: {str(e)}")
return 1
print(f"Error starting TensorBoard: {e}")
if __name__ == "__main__":
exit_code = run_tensorboard()
sys.exit(exit_code)
main()

View File

@ -1,54 +1,65 @@
#!/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
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from core.config import setup_logging
import logging
from core.config import setup_logging, get_config
from core.data_provider import DataProvider
from training.cnn_trainer import CNNTrainer
def main():
"""Test CNN training with real market data"""
setup_logging()
print("Setting up CNN training test...")
print("📊 Monitor training: tensorboard --logdir=runs")
# Setup
data_provider = DataProvider(['ETH/USDT'], ['1m', '5m', '1h'])
trainer = CNNTrainer(data_provider)
# Configure test parameters
config = get_config()
# Configure for quick test
trainer.num_samples = 500 # Very small dataset
trainer.num_epochs = 2 # Just 2 epochs
trainer.batch_size = 16
trainer.timeframes = ['1m', '5m', '1h'] # Skip 1s for now
trainer.n_timeframes = 3
# Test configuration
symbols = ['ETH/USDT']
timeframes = ['1m', '5m', '1h']
num_samples = 500
epochs = 2
batch_size = 16
print(f"Configuration:")
print(f" Samples: {trainer.num_samples}")
print(f" Epochs: {trainer.num_epochs}")
print(f" Batch size: {trainer.batch_size}")
print(f" Timeframes: {trainer.timeframes}")
# Override config for quick test
config._config['timeframes'] = timeframes # Direct config access
trainer = CNNTrainer(config)
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:
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" Best accuracy: {results['best_val_accuracy']:.4f}")
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:
print(f"\n❌ Training failed: {e}")
print(f"❌ Training failed: {e}")
import traceback
traceback.print_exc()
return 1
return 0
finally:
trainer.close_tensorboard()
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:
- Automated data generation and preprocessing
- Training with validation and early stopping
- Memory-efficient batch processing
- Model evaluation and metrics
This module handles training of the CNN model using ONLY real market data.
All training metrics are logged to TensorBoard for real-time monitoring.
"""
import torch
import torch.nn as nn
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 pandas as pd
import logging
from typing import Dict, List, Tuple, Optional
import time
from pathlib import Path
import time
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.model_selection import train_test_split
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__))))
import json
from core.config import get_config
from core.data_provider import DataProvider
@ -33,13 +25,12 @@ from models.cnn.scalping_cnn import MultiTimeframeCNN, ScalpingDataGenerator
logger = logging.getLogger(__name__)
class TradingDataset(Dataset):
"""PyTorch dataset for trading data"""
class CNNDataset(Dataset):
"""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.labels = torch.FloatTensor(labels)
self.metadata = metadata or {}
self.labels = torch.LongTensor(np.argmax(labels, axis=1)) # Convert one-hot to class indices
def __len__(self):
return len(self.features)
@ -48,431 +39,437 @@ class TradingDataset(Dataset):
return self.features[idx], self.labels[idx]
class CNNTrainer:
"""
CNN Training Pipeline for Scalping
"""
"""CNN Trainer using ONLY real market data with TensorBoard monitoring"""
def __init__(self, data_provider: DataProvider, config: Optional[Dict] = None):
self.data_provider = data_provider
def __init__(self, config: Optional[Dict] = None):
"""Initialize CNN trainer"""
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')
# Initialize data generator
self.data_generator = ScalpingDataGenerator(data_provider, self.window_size)
# Training parameters
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.train_losses = []
self.val_losses = []
self.train_accuracies = []
self.val_accuracies = []
# TensorBoard setup
self.setup_tensorboard()
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]:
"""Prepare training and validation data"""
logger.info("Preparing training data...")
def setup_tensorboard(self):
"""Setup TensorBoard logging"""
# Create tensorboard logs directory
log_dir = Path("runs") / f"cnn_training_{int(time.time())}"
log_dir.mkdir(parents=True, exist_ok=True)
all_features = []
all_labels = []
all_metadata = {'symbols': []}
self.writer = SummaryWriter(log_dir=str(log_dir))
self.tensorboard_dir = log_dir
# Generate data for each symbol
for symbol in symbols:
logger.info(f"Generating data for {symbol}...")
features, labels, metadata = self.data_generator.generate_training_cases(
symbol, self.timeframes, self.num_samples // len(symbols)
)
if features is not None and labels is not None:
all_features.append(features)
all_labels.append(labels)
all_metadata['symbols'].extend([symbol] * len(features))
logger.info(f"Generated {len(features)} samples for {symbol}")
# 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
logger.info(f"TensorBoard logging to: {log_dir}")
logger.info(f"Run: tensorboard --logdir=runs")
def log_model_architecture(self):
"""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}")
# Log model parameters count
total_params = sum(p.numel() for p in self.model.parameters())
trainable_params = sum(p.numel() for p in self.model.parameters() if p.requires_grad)
self.writer.add_scalar('Model/TotalParameters', total_params, 0)
self.writer.add_scalar('Model/TrainableParameters', trainable_params, 0)
def create_model(self) -> MultiTimeframeCNN:
"""Create and initialize the CNN model"""
"""Create CNN model"""
model = MultiTimeframeCNN(
n_timeframes=self.n_timeframes,
window_size=self.window_size,
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
total_params = sum(p.numel() for p in model.parameters())
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"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
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,
optimizer: optim.Optimizer, criterion: nn.Module) -> Tuple[float, float]:
"""Train for one epoch"""
optimizer: torch.optim.Optimizer, criterion: nn.Module, epoch: int) -> Tuple[float, float]:
"""Train for one epoch with TensorBoard logging"""
model.train()
total_loss = 0.0
correct_predictions = 0
total_predictions = 0
correct = 0
total = 0
for batch_idx, (features, labels) in enumerate(train_loader):
features = features.to(self.device)
labels = labels.to(self.device)
features, labels = features.to(self.device), labels.to(self.device)
# Zero gradients
optimizer.zero_grad()
# Forward pass
predictions = model(features)
# Calculate loss (multi-task loss)
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
loss = criterion(predictions['action'], labels)
loss.backward()
optimizer.step()
# Track metrics
total_loss += total_loss_batch.item()
total_loss += loss.item()
_, predicted = torch.max(predictions['action'].data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# Calculate accuracy
pred_classes = torch.argmax(predictions['action'], dim=1)
true_classes = torch.argmax(labels, dim=1)
correct_predictions += (pred_classes == true_classes).sum().item()
total_predictions += labels.size(0)
# Log batch metrics
step = epoch * len(train_loader) + batch_idx
self.writer.add_scalar('Training/BatchLoss', loss.item(), step)
# Log progress
if batch_idx % 100 == 0:
logger.debug(f"Batch {batch_idx}/{len(train_loader)}, Loss: {total_loss_batch.item():.4f}")
if batch_idx % 50 == 0: # Log every 50 batches
batch_acc = 100. * (predicted == labels).sum().item() / labels.size(0)
self.writer.add_scalar('Training/BatchAccuracy', batch_acc, step)
# Log confidence scores
avg_confidence = predictions['confidence'].mean().item()
self.writer.add_scalar('Training/BatchConfidence', avg_confidence, step)
avg_loss = total_loss / len(train_loader)
accuracy = correct_predictions / total_predictions
epoch_loss = total_loss / len(train_loader)
epoch_accuracy = correct / total
return avg_loss, accuracy
return epoch_loss, epoch_accuracy
def validate_epoch(self, model: nn.Module, val_loader: DataLoader,
criterion: nn.Module) -> Tuple[float, float, Dict]:
"""Validate for one epoch"""
criterion: nn.Module, epoch: int) -> Tuple[float, float, Dict]:
"""Validate for one epoch with TensorBoard logging"""
model.eval()
total_loss = 0.0
correct_predictions = 0
total_predictions = 0
correct = 0
total = 0
all_predictions = []
all_labels = []
all_confidences = []
with torch.no_grad():
for features, labels in val_loader:
features = features.to(self.device)
labels = labels.to(self.device)
features, labels = features.to(self.device), labels.to(self.device)
# Forward pass
predictions = model(features)
# Calculate loss
loss = criterion(predictions['action'], labels)
total_loss += loss.item()
_, predicted = torch.max(predictions['action'].data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
# Track predictions
pred_classes = torch.argmax(predictions['action'], dim=1)
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_predictions.extend(predicted.cpu().numpy())
all_labels.extend(labels.cpu().numpy())
all_confidences.extend(predictions['confidence'].cpu().numpy())
avg_loss = total_loss / len(val_loader)
accuracy = correct_predictions / total_predictions
epoch_loss = total_loss / len(val_loader)
epoch_accuracy = correct / total
# Additional metrics
metrics = {
'predictions': np.array(all_predictions),
'labels': np.array(all_labels),
'confidences': np.array(all_confidences),
'accuracy_by_class': {},
'avg_confidence': np.mean(all_confidences)
}
# Calculate detailed metrics
metrics = self.calculate_detailed_metrics(all_predictions, all_labels, all_confidences)
# Calculate per-class accuracy
for class_idx in range(self.n_classes):
class_mask = metrics['labels'] == class_idx
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
# Log validation metrics to TensorBoard
self.writer.add_scalar('Validation/Loss', epoch_loss, epoch)
self.writer.add_scalar('Validation/Accuracy', epoch_accuracy, epoch)
self.writer.add_scalar('Validation/AvgConfidence', metrics['avg_confidence'], epoch)
return avg_loss, accuracy, metrics
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 train(self, symbols: List[str], save_path: Optional[str] = None) -> Dict:
"""Train the CNN model"""
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)
}
def train(self, symbols: List[str], save_path: str = 'models/cnn/scalping_cnn_trained.pt',
num_samples: int = 10000) -> Dict:
"""Train CNN model with TensorBoard monitoring"""
logger.info("Starting CNN training...")
logger.info("Using ONLY real market data from exchange APIs")
# Prepare data first to get actual feature count
train_loader, val_loader, dataset_info = self.prepare_data(symbols)
# Prepare data
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.log_model_architecture()
# Setup training
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(self.model.parameters(), lr=self.learning_rate)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
optimizer, mode='min', factor=0.5, patience=5, verbose=True
)
scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=5, verbose=True)
# Training state
# Training loop
best_val_loss = float('inf')
best_val_accuracy = 0.0
patience_counter = 0
start_time = time.time()
# Training loop
for epoch in range(self.num_epochs):
epoch_start_time = time.time()
for epoch in range(self.epochs):
epoch_start = time.time()
# Train
train_loss, train_accuracy = self.train_epoch(
self.model, train_loader, optimizer, criterion
)
train_loss, train_accuracy = self.train_epoch(self.model, train_loader, optimizer, criterion, epoch)
# Validate
val_loss, val_accuracy, val_metrics = self.validate_epoch(
self.model, val_loader, criterion
)
val_loss, val_accuracy, val_metrics = self.validate_epoch(self.model, val_loader, criterion, epoch)
# Update learning rate
scheduler.step(val_loss)
current_lr = optimizer.param_groups[0]['lr']
# Track metrics
self.train_losses.append(train_loss)
self.val_losses.append(val_loss)
self.train_accuracies.append(train_accuracy)
self.val_accuracies.append(val_accuracy)
# Log epoch metrics
self.writer.add_scalar('Training/EpochLoss', train_loss, epoch)
self.writer.add_scalar('Training/EpochAccuracy', train_accuracy, epoch)
self.writer.add_scalar('Training/LearningRate', current_lr, epoch)
# 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:
best_val_loss = val_loss
best_val_accuracy = val_accuracy
patience_counter = 0
# Save best model
if save_path:
best_path = save_path.replace('.pt', '_best.pt')
self.model.save(best_path)
logger.info(f"New best model saved: {best_path}")
best_path = save_path.replace('.pt', '_best.pt')
self.model.save(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:
patience_counter += 1
# Log progress
epoch_time = time.time() - epoch_start_time
logger.info(
f"Epoch {epoch+1}/{self.num_epochs} - "
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"
)
logger.info(f"Epoch {epoch+1}/{self.epochs} - "
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:
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}")
# Early stopping
if patience_counter >= self.patience:
if patience_counter >= self.early_stopping_patience:
logger.info(f"Early stopping triggered after {epoch+1} epochs")
break
# Training complete
# Training completed
total_time = time.time() - start_time
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 accuracy: {best_val_accuracy:.4f}")
# Save final model
if save_path:
self.model.save(save_path)
logger.info(f"Final model saved: {save_path}")
# Log final metrics
self.writer.add_scalar('Final/TotalTrainingTime', total_time, 0)
self.writer.add_scalar('Final/TotalEpochs', epoch + 1, 0)
# Prepare training results
results = {
# Save final model
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_accuracy': best_val_accuracy,
'total_epochs': epoch + 1,
'total_time': total_time,
'train_losses': self.train_losses,
'val_losses': self.val_losses,
'train_accuracies': self.train_accuracies,
'val_accuracies': self.val_accuracies,
'dataset_info': dataset_info,
'final_metrics': val_metrics
'training_time': total_time,
'tensorboard_dir': str(self.tensorboard_dir)
}
return results
def evaluate_model(self, test_symbols: List[str]) -> Dict:
def evaluate(self, symbols: List[str], num_samples: int = 5000) -> Dict:
"""Evaluate trained model on test data"""
if self.model is None:
raise ValueError("Model not trained yet")
logger.info("Evaluating model...")
# Generate test data
test_features = []
test_labels = []
# Generate test data from real market data
features, labels, metadata = self.prepare_data(symbols, num_samples)
for symbol in test_symbols:
features, labels, _ = self.data_generator.generate_training_cases(
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)
# Create test dataset and loader
test_dataset = CNNDataset(features, labels)
test_loader = DataLoader(test_dataset, batch_size=self.batch_size, shuffle=False)
# Evaluate
criterion = nn.CrossEntropyLoss()
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']
classification_rep = classification_report(
test_metrics['labels'],
test_metrics['predictions'],
target_names=class_names,
output_dict=True
)
all_predictions = []
all_labels = []
# Confusion matrix
conf_matrix = confusion_matrix(
test_metrics['labels'],
test_metrics['predictions']
with torch.no_grad():
for features_batch, labels_batch in test_loader:
features_batch = features_batch.to(self.device)
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 = {
'test_loss': test_loss,
'test_accuracy': test_accuracy,
'classification_report': classification_rep,
'confusion_matrix': conf_matrix,
'class_accuracies': test_metrics['accuracy_by_class'],
'avg_confidence': test_metrics['avg_confidence']
'class_accuracies': test_metrics['class_accuracies'],
'avg_confidence': test_metrics['avg_confidence'],
'confusion_matrix': test_metrics['confusion_matrix']
}
logger.info(f"Test accuracy: {test_accuracy:.4f}")
@ -480,40 +477,15 @@ class CNNTrainer:
return evaluation_results
def plot_training_history(self, save_path: Optional[str] = None):
"""Plot training history"""
if not self.train_losses:
logger.warning("No training history to plot")
return
fig, ((ax1, ax2)) = plt.subplots(1, 2, figsize=(12, 4))
# Loss plot
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()
def close_tensorboard(self):
"""Close TensorBoard writer"""
if hasattr(self, 'writer'):
self.writer.close()
logger.info("TensorBoard writer closed")
def __del__(self):
"""Cleanup"""
self.close_tensorboard()
# Export
__all__ = ['CNNTrainer', 'TradingDataset']
__all__ = ['CNNTrainer', 'CNNDataset']

View File

@ -18,6 +18,7 @@ from pathlib import Path
import matplotlib.pyplot as plt
from collections import deque
import random
from torch.utils.tensorboard import SummaryWriter
# Add project imports
import sys
@ -75,8 +76,23 @@ class RLTrainer:
self.win_rates = []
self.avg_rewards = []
# TensorBoard setup
self.setup_tensorboard()
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]:
"""Setup trading environment and RL agent"""
logger.info("Setting up environment and agent...")
@ -443,6 +459,29 @@ class RLTrainer:
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:
"""
Hybrid training pipeline combining CNN and RL