misc
This commit is contained in:
43
.vscode/launch.json
vendored
43
.vscode/launch.json
vendored
@ -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
332
TENSORBOARD_MONITORING.md
Normal 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
1
TRAINING_STATUS.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -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"""
|
||||||
try:
|
|
||||||
logger.info("Starting CNN Training Mode...")
|
logger.info("Starting CNN Training Mode...")
|
||||||
|
|
||||||
# Initialize components
|
# Initialize data provider and trainer
|
||||||
data_provider = DataProvider(
|
data_provider = DataProvider(config)
|
||||||
symbols=['ETH/USDT', 'BTC/USDT'],
|
trainer = CNNTrainer(config)
|
||||||
timeframes=['1s', '1m', '5m', '1h', '4h']
|
|
||||||
)
|
|
||||||
|
|
||||||
# Import and create CNN trainer
|
# Use configured symbols or provided symbol
|
||||||
from training.cnn_trainer import CNNTrainer
|
symbols = config.symbols if symbol == "ETH/USDT" else [symbol] + config.symbols
|
||||||
trainer = CNNTrainer(data_provider)
|
save_path = f"models/cnn/scalping_cnn_trained.pt"
|
||||||
|
|
||||||
# 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"Training CNN for symbols: {symbols}")
|
||||||
logger.info(f"Will save to: {save_path}")
|
logger.info(f"Will save to: {save_path}")
|
||||||
|
logger.info(f"🔗 Monitor training: tensorboard --logdir=runs")
|
||||||
|
|
||||||
results = trainer.train(symbols, save_path)
|
try:
|
||||||
|
# Train model with TensorBoard logging
|
||||||
|
results = trainer.train(symbols, save_path=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:
|
|
||||||
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
|
|
||||||
try:
|
|
||||||
logger.info("Evaluating CNN on test data...")
|
logger.info("Evaluating CNN on test data...")
|
||||||
test_symbols = ['ETH/USDT'] # Use subset for testing
|
|
||||||
eval_results = trainer.evaluate_model(test_symbols)
|
|
||||||
|
|
||||||
|
# Quick evaluation on same symbols
|
||||||
|
test_results = trainer.evaluate(symbols[:1]) # Use first symbol for quick test
|
||||||
logger.info("CNN Evaluation Results:")
|
logger.info("CNN Evaluation Results:")
|
||||||
logger.info(f" Test accuracy: {eval_results['test_accuracy']:.4f}")
|
logger.info(f" Test accuracy: {test_results['test_accuracy']:.4f}")
|
||||||
logger.info(f" Test loss: {eval_results['test_loss']:.4f}")
|
logger.info(f" Test loss: {test_results['test_loss']:.4f}")
|
||||||
logger.info(f" Average confidence: {eval_results['avg_confidence']:.4f}")
|
logger.info(f" Average confidence: {test_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
83
monitor_training.py
Normal 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}")
|
35
readme.md
35
readme.md
@ -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
|
||||||
|
@ -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)
|
|
@ -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()
|
420
train_realtime_with_tensorboard.py
Normal file
420
train_realtime_with_tensorboard.py
Normal 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())
|
@ -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
|
|
||||||
logger.info(
|
|
||||||
f"Epoch {epoch+1}/{self.num_epochs} - "
|
|
||||||
f"Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.4f} - "
|
f"Train Loss: {train_loss:.4f}, Train Acc: {train_accuracy:.4f} - "
|
||||||
f"Val Loss: {val_loss:.4f}, Val Acc: {val_accuracy:.4f} - "
|
f"Val Loss: {val_loss:.4f}, Val Acc: {val_accuracy:.4f} - "
|
||||||
f"Time: {epoch_time:.2f}s"
|
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}")
|
||||||
|
|
||||||
|
# Log final metrics
|
||||||
|
self.writer.add_scalar('Final/TotalTrainingTime', total_time, 0)
|
||||||
|
self.writer.add_scalar('Final/TotalEpochs', epoch + 1, 0)
|
||||||
|
|
||||||
# Save final model
|
# Save final model
|
||||||
if save_path:
|
|
||||||
self.model.save(save_path)
|
self.model.save(save_path)
|
||||||
logger.info(f"Final model saved: {save_path}")
|
logger.info(f"Final model saved: {save_path}")
|
||||||
|
|
||||||
# Prepare training results
|
# Log training summary
|
||||||
results = {
|
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']
|
@ -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
|
||||||
|
Reference in New Issue
Block a user