This commit is contained in:
zhutoutoutousan
2026-01-05 05:37:33 +01:00
parent 7d41b04aef
commit 5b44e14211
79 changed files with 19884 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# Models and Data
models/
*.onnx
*.h5
*.pb
*.pkl
*.csv
*.npy
# TensorFlow
*.ckpt
checkpoints/
logs/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Jupyter
.ipynb_checkpoints/
*.ipynb
+406
View File
@@ -0,0 +1,406 @@
//+------------------------------------------------------------------+
//| ONNX_EA.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "Expert Advisor using ONNX model for price prediction"
#property description "Based on: https://www.mql5.com/en/docs/onnx/onnx_prepare"
#include <Trade\Trade.mqh>
//--- Input parameters
input group "ONNX Model Settings"
input string InpModelPath = "models\\XAUUSD_H1_model.onnx"; // ONNX Model Path
input int InpLookback = 60; // Lookback Period (bars)
input bool InpUsePrediction = true; // Use Model Prediction
input group "Trading Settings"
input double InpLotSize = 0.01; // Lot Size
input int InpMagicNumber = 123456; // Magic Number
input int InpSlippage = 3; // Slippage (points)
input int InpStopLoss = 50; // Stop Loss (pips)
input int InpTakeProfit = 100; // Take Profit (pips)
input group "Prediction Settings"
input double InpPredictionThreshold = 0.0001; // Min Prediction Change (0.01%)
input bool InpUseConfidence = true; // Use Confidence Filter
input double InpMinConfidence = 0.6; // Minimum Confidence
//--- Global variables
CTrade trade;
long onnx_handle = INVALID_HANDLE;
datetime last_bar_time = 0;
double last_prediction = 0.0;
double last_confidence = 0.0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Set trade parameters
trade.SetExpertMagicNumber(InpMagicNumber);
trade.SetDeviationInPoints(InpSlippage);
trade.SetTypeFilling(ORDER_FILLING_FOK);
// Load ONNX model
string model_path = InpModelPath;
// Convert relative path to full path
if(StringFind(model_path, "\\") == 0 || StringFind(model_path, "/") == 0)
{
// Already absolute path
}
else
{
// Relative path - prepend terminal data folder
model_path = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\" + model_path;
}
// Replace forward slashes with backslashes for Windows
StringReplace(model_path, "/", "\\");
Print("Loading ONNX model from: ", model_path);
onnx_handle = OnnxCreate(model_path, ONNX_DEFAULT);
if(onnx_handle == INVALID_HANDLE)
{
Print("ERROR: Failed to load ONNX model. Error: ", GetLastError());
Print("Make sure the model file exists at: ", model_path);
return(INIT_FAILED);
}
// Get model info
int input_count = OnnxGetInputCount(onnx_handle);
int output_count = OnnxGetOutputCount(onnx_handle);
Print("ONNX Model loaded successfully");
Print(" Inputs: ", input_count);
Print(" Outputs: ", output_count);
if(input_count > 0)
{
string input_name = OnnxGetInputName(onnx_handle, 0);
Print(" Input name: ", input_name);
}
if(output_count > 0)
{
string output_name = OnnxGetOutputName(onnx_handle, 0);
Print(" Output name: ", output_name);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Release ONNX model
if(onnx_handle != INVALID_HANDLE)
{
OnnxRelease(onnx_handle);
Print("ONNX model released");
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Check if new bar
datetime current_bar_time = iTime(_Symbol, PERIOD_CURRENT, 0);
if(current_bar_time == last_bar_time)
{
return; // Still the same bar
}
last_bar_time = current_bar_time;
// Check if we should use prediction
if(!InpUsePrediction)
{
return;
}
// Prepare input data
float input_data[];
if(!PrepareInputData(input_data))
{
Print("ERROR: Failed to prepare input data");
return;
}
// Run ONNX model
float output_data[];
if(!RunONNXModel(input_data, output_data))
{
Print("ERROR: Failed to run ONNX model");
return;
}
// Get prediction
if(ArraySize(output_data) == 0)
{
Print("ERROR: Empty output from ONNX model");
return;
}
double predicted_price = output_data[0];
double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
// Calculate prediction change
double price_change = predicted_price - current_price;
double price_change_pct = (price_change / current_price) * 100.0;
// Calculate confidence (simple heuristic based on prediction magnitude)
double confidence = MathAbs(price_change_pct) / 1.0; // Normalize
if(confidence > 1.0) confidence = 1.0;
last_prediction = predicted_price;
last_confidence = confidence;
// Log prediction
Print("Prediction: Current=", current_price,
" Predicted=", predicted_price,
" Change=", price_change_pct, "%",
" Confidence=", confidence);
// Check if we should trade
if(!InpUseConfidence || confidence >= InpMinConfidence)
{
// Check if prediction is significant
if(MathAbs(price_change_pct) >= InpPredictionThreshold)
{
// Check existing position
if(PositionSelect(_Symbol))
{
// Manage existing position
ManagePosition(predicted_price, price_change_pct);
}
else
{
// Open new position based on prediction
if(price_change_pct > InpPredictionThreshold)
{
OpenBuyPosition();
}
else if(price_change_pct < -InpPredictionThreshold)
{
OpenSellPosition();
}
}
}
}
}
//+------------------------------------------------------------------+
//| Prepare input data for ONNX model |
//+------------------------------------------------------------------+
bool PrepareInputData(float &input_array[])
{
// We need to prepare data similar to training
// This is a simplified version - you may need to adjust based on your model
int lookback = InpLookback;
int features = 12; // Adjust based on your model (OHLC + volume + indicators)
ArrayResize(input_array, lookback * features);
ArrayInitialize(input_array, 0.0);
// Get historical data
double open[], high[], low[], close[], volume[];
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
ArraySetAsSeries(volume, true);
if(CopyOpen(_Symbol, PERIOD_CURRENT, 0, lookback + 50, open) < lookback)
return false;
if(CopyHigh(_Symbol, PERIOD_CURRENT, 0, lookback + 50, high) < lookback)
return false;
if(CopyLow(_Symbol, PERIOD_CURRENT, 0, lookback + 50, low) < lookback)
return false;
if(CopyClose(_Symbol, PERIOD_CURRENT, 0, lookback + 50, close) < lookback)
return false;
if(CopyTickVolume(_Symbol, PERIOD_CURRENT, 0, lookback + 50, volume) < lookback)
return false;
// Calculate indicators (simplified - you may need to match training exactly)
double rsi[], ema20[], ema50[], atr[];
ArraySetAsSeries(rsi, true);
ArraySetAsSeries(ema20, true);
ArraySetAsSeries(ema50, true);
ArraySetAsSeries(atr, true);
// Calculate RSI
int rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
if(rsi_handle == INVALID_HANDLE) return false;
if(CopyBuffer(rsi_handle, 0, 0, lookback + 50, rsi) < lookback)
{
IndicatorRelease(rsi_handle);
return false;
}
IndicatorRelease(rsi_handle);
// Calculate EMAs
int ema20_handle = iMA(_Symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
int ema50_handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
if(ema20_handle == INVALID_HANDLE || ema50_handle == INVALID_HANDLE) return false;
if(CopyBuffer(ema20_handle, 0, 0, lookback + 50, ema20) < lookback ||
CopyBuffer(ema50_handle, 0, 0, lookback + 50, ema50) < lookback)
{
IndicatorRelease(ema20_handle);
IndicatorRelease(ema50_handle);
return false;
}
IndicatorRelease(ema20_handle);
IndicatorRelease(ema50_handle);
// Calculate ATR
int atr_handle = iATR(_Symbol, PERIOD_CURRENT, 14);
if(atr_handle == INVALID_HANDLE) return false;
if(CopyBuffer(atr_handle, 0, 0, lookback + 50, atr) < lookback)
{
IndicatorRelease(atr_handle);
return false;
}
IndicatorRelease(atr_handle);
// Normalize and prepare data (simplified normalization)
// IMPORTANT: This uses simplified normalization. For best results, you should:
// 1. Save the scaler during training (train_onnx_model.py does this automatically)
// 2. Implement the same normalization logic in MQL5, OR
// 3. Pre-normalize data in Python and pass to MQL5 via files/global variables
// The current implementation may not match training exactly, which can affect accuracy
int idx = 0;
for(int i = 0; i < lookback; i++)
{
// Normalize features (simplified - use proper scaler in production)
input_array[idx++] = (float)((open[i] - close[lookback-1]) / close[lookback-1]);
input_array[idx++] = (float)((high[i] - close[lookback-1]) / close[lookback-1]);
input_array[idx++] = (float)((low[i] - close[lookback-1]) / close[lookback-1]);
input_array[idx++] = (float)((close[i] - close[lookback-1]) / close[lookback-1]);
input_array[idx++] = (float)(volume[i] / 1000000.0); // Normalize volume
input_array[idx++] = (float)(rsi[i] / 100.0); // Normalize RSI
input_array[idx++] = (float)((ema20[i] - close[lookback-1]) / close[lookback-1]);
input_array[idx++] = (float)((ema50[i] - close[lookback-1]) / close[lookback-1]);
input_array[idx++] = (float)(atr[i] / close[lookback-1]);
input_array[idx++] = (float)((close[i] - close[i+1]) / close[i+1]); // Price change
input_array[idx++] = (float)(high[i] / low[i]); // High/low ratio
input_array[idx++] = (float)(volume[i] / (volume[i] + volume[i+1] + volume[i+2]) / 3.0); // Volume ratio
}
// Reshape for model: (1, lookback, features)
// ONNX expects shape [1, lookback, features]
float reshaped[];
ArrayResize(reshaped, 1 * lookback * features);
ArrayCopy(reshaped, input_array);
ArrayCopy(input_array, reshaped);
return true;
}
//+------------------------------------------------------------------+
//| Run ONNX model |
//+------------------------------------------------------------------+
bool RunONNXModel(float &input_data[], float &output_data[])
{
if(onnx_handle == INVALID_HANDLE)
return false;
// Set input shape
long input_shape[] = {1, InpLookback, 12}; // Adjust based on your model
if(!OnnxSetInputShape(onnx_handle, 0, input_shape))
{
Print("ERROR: Failed to set input shape. Error: ", GetLastError());
return false;
}
// Run model
if(!OnnxRun(onnx_handle, ONNX_NO_CONVERSION, input_data, output_data))
{
Print("ERROR: Failed to run ONNX model. Error: ", GetLastError());
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Open buy position |
//+------------------------------------------------------------------+
void OpenBuyPosition()
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = InpStopLoss > 0 ? price - InpStopLoss * _Point * 10 : 0;
double tp = InpTakeProfit > 0 ? price + InpTakeProfit * _Point * 10 : 0;
if(trade.Buy(InpLotSize, _Symbol, price, sl, tp, "ONNX Buy Signal"))
{
Print("Buy order opened. Ticket: ", trade.ResultOrder());
}
else
{
Print("Failed to open buy order. Error: ", trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Open sell position |
//+------------------------------------------------------------------+
void OpenSellPosition()
{
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = InpStopLoss > 0 ? price + InpStopLoss * _Point * 10 : 0;
double tp = InpTakeProfit > 0 ? price - InpTakeProfit * _Point * 10 : 0;
if(trade.Sell(InpLotSize, _Symbol, price, sl, tp, "ONNX Sell Signal"))
{
Print("Sell order opened. Ticket: ", trade.ResultOrder());
}
else
{
Print("Failed to open sell order. Error: ", trade.ResultRetcodeDescription());
}
}
//+------------------------------------------------------------------+
//| Manage existing position |
//+------------------------------------------------------------------+
void ManagePosition(double predicted_price, double price_change_pct)
{
if(!PositionSelect(_Symbol))
return;
long position_type = PositionGetInteger(POSITION_TYPE);
double position_open_price = PositionGetDouble(POSITION_PRICE_OPEN);
double current_profit = PositionGetDouble(POSITION_PROFIT);
// Simple management: close if prediction reverses
if(position_type == POSITION_TYPE_BUY && price_change_pct < -InpPredictionThreshold)
{
// Prediction turned bearish, close long
if(trade.PositionClose(_Symbol))
{
Print("Closed long position due to bearish prediction");
}
}
else if(position_type == POSITION_TYPE_SELL && price_change_pct > InpPredictionThreshold)
{
// Prediction turned bullish, close short
if(trade.PositionClose(_Symbol))
{
Print("Closed short position due to bullish prediction");
}
}
}
+197
View File
@@ -0,0 +1,197 @@
# Quick Start Guide - ONNX with MetaTrader 5
Get started with ONNX machine learning models in MT5 in 5 minutes!
## Prerequisites
1. **MetaTrader 5** installed and running
2. **Python 3.8+** installed
3. **MT5 account** (demo or live) with access to historical data
## Step 1: Install Dependencies
```bash
cd ai
pip install -r requirements.txt
```
This installs:
- TensorFlow/Keras for model training
- ONNX runtime for model inference
- MetaTrader5 Python module
- Other required libraries
## Step 2: Verify MT5 Connection
Make sure MT5 is running and you're logged in. The scripts will automatically connect to MT5.
## Step 3: Train Your First Model
Train a price prediction model for Gold (XAUUSD):
```bash
python train_onnx_model.py --symbol XAUUSD --timeframe H1 --epochs 30
```
This will:
- Download 2 years of historical data
- Train an LSTM neural network
- Save the model as `models/XAUUSD_H1_model.onnx`
**Expected time**: 5-15 minutes depending on your hardware.
## Step 4: Test the Model
Make a prediction with your trained model:
```bash
python predict_with_onnx.py --model models/XAUUSD_H1_model.onnx --symbol XAUUSD
```
You should see output like:
```
Current XAUUSD price: 2650.12345
Making 1 prediction(s)...
Predicted next price: 2652.54321
Expected change: 2.41976 (0.09%)
```
## Step 5: Use in MetaTrader 5
### Option A: Copy Model to MT5
1. Copy your ONNX model to MT5's Files folder:
```
<MT5 Data Folder>\MQL5\Files\models\XAUUSD_H1_model.onnx
```
Default locations:
- Windows: `C:\Users\<YourName>\AppData\Roaming\MetaQuotes\Terminal\<TerminalID>\MQL5\Files\`
- Or find it: MT5 → File → Open Data Folder → MQL5 → Files
2. Open `ONNX_EA.mq5` in MetaEditor
3. Compile (F7)
4. Attach to chart:
- Model path: `models\XAUUSD_H1_model.onnx`
- Lookback: `60` (must match training)
- Set your trading parameters
### Option B: Run from MetaEditor
If you have Python integration enabled in MetaEditor:
1. Open `train_onnx_model.py` in MetaEditor
2. Press F7 (Compile) to run
3. The model will be saved to the project folder
## Common Commands
### Train for Different Symbols
```bash
# EUR/USD on 15-minute charts
python train_onnx_model.py --symbol EURUSD --timeframe M15
# Bitcoin on 4-hour charts
python train_onnx_model.py --symbol BTCUSD --timeframe H4
```
### Custom Training Parameters
```bash
python train_onnx_model.py \
--symbol XAUUSD \
--timeframe H1 \
--lookback 100 \
--epochs 100 \
--batch-size 64
```
### Multiple Predictions
```bash
python predict_with_onnx.py \
--model models/XAUUSD_H1_model.onnx \
--symbol XAUUSD \
--predictions 5
```
## Troubleshooting
### "MT5 initialization failed"
- ✅ Make sure MT5 is running
- ✅ Log into your account in MT5
- ✅ Check that the symbol exists (e.g., XAUUSD, not GOLD)
### "No data available"
- ✅ Ensure you have historical data downloaded in MT5
- ✅ Check the date range (script uses last 2 years)
- ✅ Verify symbol name is correct
### "Failed to load ONNX model" in EA
- ✅ Check the file path is correct
- ✅ Ensure model is in MT5's Files folder
- ✅ Verify the model file exists and is not corrupted
### Model predictions seem wrong
- ✅ Ensure `InpLookback` in EA matches training `--lookback`
- ✅ Check that you're using the same symbol/timeframe
- ✅ Verify feature normalization matches training
## Next Steps
1. **Experiment with different models**:
- Try different lookback periods
- Adjust network architecture
- Add more features
2. **Optimize trading parameters**:
- Test different prediction thresholds
- Tune stop loss/take profit
- Adjust confidence levels
3. **Backtest thoroughly**:
- Use MT5 Strategy Tester
- Test on different time periods
- Analyze performance metrics
4. **Monitor and improve**:
- Track prediction accuracy
- Retrain models periodically
- Adjust based on market conditions
## Example Workflow
```bash
# 1. Train model
python train_onnx_model.py --symbol XAUUSD --timeframe H1 --epochs 50
# 2. Test predictions
python predict_with_onnx.py --model models/XAUUSD_H1_model.onnx --symbol XAUUSD
# 3. Copy model to MT5 Files folder
# (Manual step)
# 4. Compile and attach ONNX_EA.mq5 to chart
# 5. Monitor and adjust parameters
```
## Tips
- 🎯 Start with longer timeframes (H1, H4) for more stable predictions
- 📊 Use multiple models for different market conditions
- 🔄 Retrain models periodically (weekly/monthly)
- ⚠️ Always test on demo account first
- 📈 Monitor model performance and adjust parameters
## Need Help?
- Check the main [README.md](README.md) for detailed documentation
- Review the MQL5 ONNX documentation: https://www.mql5.com/en/docs/onnx/onnx_prepare
- Examine the code comments for implementation details
Happy trading! 🚀
+310
View File
@@ -0,0 +1,310 @@
# ONNX Models with MetaTrader 5
A complete framework for training and using ONNX machine learning models in MetaTrader 5 for algorithmic trading.
Based on the [MQL5 ONNX documentation](https://www.mql5.com/en/docs/onnx/onnx_prepare).
## Overview
This framework allows you to:
1. **Train neural network models** in Python using MetaTrader 5 historical data
2. **Export models to ONNX format** for use in MQL5
3. **Use ONNX models in Expert Advisors** for real-time trading predictions
4. **Test predictions** using Python scripts
## Features
- 🧠 **LSTM Neural Networks** for price prediction
- 📊 **Technical Indicators** as features (RSI, EMA, ATR, etc.)
- 🔄 **ONNX Export** for MQL5 integration
- 📈 **Real-time Prediction** in Expert Advisors
- 🎯 **Flexible Configuration** for different symbols and timeframes
## Installation
### 1. Install Python Dependencies
```bash
cd ai
pip install -r requirements.txt
```
### 2. Install MetaTrader 5
- Download and install [MetaTrader 5](https://www.metatrader5.com/en/download)
- Create a demo or live account
- Enable Python integration in MT5 settings:
- Tools → Options → Expert Advisors
- Check "Allow DLL imports"
- Check "Integration with Python" (if available)
### 3. Configure MetaEditor (Optional)
If you want to run Python scripts from MetaEditor:
- MetaEditor → Tools → Options → Compiler
- Set Python executable path
- Or click "Install" to download Python
## Quick Start
### Step 1: Train an ONNX Model
Train a model for price prediction:
```bash
python train_onnx_model.py --symbol XAUUSD --timeframe H1 --lookback 60 --epochs 50
```
This will:
- Fetch 2 years of historical data from MT5
- Prepare features (OHLCV + technical indicators)
- Train an LSTM neural network
- Export the model to `models/XAUUSD_H1_model.onnx`
### Step 2: Test the Model
Make predictions using the trained model:
```bash
python predict_with_onnx.py --model models/XAUUSD_H1_model.onnx --symbol XAUUSD --timeframe H1
```
### Step 3: Use in Expert Advisor
1. Copy the ONNX model to MT5's Files folder:
```
<MT5 Data Folder>\MQL5\Files\models\XAUUSD_H1_model.onnx
```
2. Compile `ONNX_EA.mq5` in MetaEditor
3. Attach the EA to a chart with:
- Model path: `models\XAUUSD_H1_model.onnx`
- Your trading parameters
## Detailed Usage
### Training Models
#### Basic Training
```bash
python train_onnx_model.py \
--symbol XAUUSD \
--timeframe H1 \
--lookback 60 \
--epochs 50 \
--batch-size 32
```
#### Advanced Options
```bash
python train_onnx_model.py \
--symbol EURUSD \
--timeframe M15 \
--lookback 100 \
--epochs 100 \
--batch-size 64 \
--output custom_models
```
**Parameters:**
- `--symbol`: Trading symbol (XAUUSD, EURUSD, BTCUSD, etc.)
- `--timeframe`: M1, M5, M15, M30, H1, H4, D1
- `--lookback`: Number of bars to use for prediction (default: 60)
- `--epochs`: Training epochs (default: 50)
- `--batch-size`: Batch size (default: 32)
- `--output`: Output directory (default: models)
### Making Predictions
#### Single Prediction
```bash
python predict_with_onnx.py \
--model models/XAUUSD_H1_model.onnx \
--symbol XAUUSD \
--timeframe H1
```
#### Multiple Predictions
```bash
python predict_with_onnx.py \
--model models/XAUUSD_H1_model.onnx \
--symbol XAUUSD \
--timeframe H1 \
--predictions 5
```
### Expert Advisor Configuration
The `ONNX_EA.mq5` Expert Advisor includes:
**ONNX Model Settings:**
- `InpModelPath`: Path to ONNX model file
- `InpLookback`: Lookback period (must match training)
- `InpUsePrediction`: Enable/disable model predictions
**Trading Settings:**
- `InpLotSize`: Position size
- `InpMagicNumber`: Magic number for trades
- `InpStopLoss`: Stop loss in pips
- `InpTakeProfit`: Take profit in pips
**Prediction Settings:**
- `InpPredictionThreshold`: Minimum prediction change to trade (0.01% = 0.0001)
- `InpUseConfidence`: Enable confidence filtering
- `InpMinConfidence`: Minimum confidence level (0.0-1.0)
## Model Architecture
The default model uses:
- **Input**: 60 bars × 12 features
- **Architecture**:
- LSTM(128) → Dropout(0.2)
- LSTM(64) → Dropout(0.2)
- LSTM(32) → Dropout(0.2)
- Dense(16, ReLU)
- Dense(1) - Price prediction
- **Features**:
- OHLC prices
- Tick volume
- RSI (14)
- EMA(20), EMA(50)
- ATR(14)
- Price changes
- High/Low ratio
- Volume ratios
## Customization
### Modify Features
Edit `train_onnx_model.py` to add/remove features:
```python
def prepare_features(self, df: pd.DataFrame) -> pd.DataFrame:
feature_df = df[['open', 'high', 'low', 'close', 'tick_volume']].copy()
# Add your custom indicators
feature_df['custom_indicator'] = your_calculation(df)
return feature_df
```
### Change Model Architecture
Modify `build_model()` in `train_onnx_model.py`:
```python
def build_model(self, input_shape: tuple) -> keras.Model:
model = keras.Sequential([
layers.LSTM(256, return_sequences=True, input_shape=input_shape),
# Add your layers here
layers.Dense(1)
])
return model
```
### Adjust Expert Advisor Logic
Edit `ONNX_EA.mq5` to customize trading logic:
- Entry conditions
- Exit conditions
- Position management
- Risk management
## File Structure
```
ai/
├── requirements.txt # Python dependencies
├── train_onnx_model.py # Model training script
├── predict_with_onnx.py # Prediction testing script
├── ONNX_EA.mq5 # MQL5 Expert Advisor
├── README.md # This file
└── models/ # Trained ONNX models (created after training)
```
## Troubleshooting
### MT5 Connection Issues
**Error**: "MT5 initialization failed"
- Ensure MetaTrader 5 is installed and running
- Log into a demo or live account
- Check that the symbol exists in MT5
### Model Loading Issues
**Error**: "Failed to load ONNX model"
- Verify the model file path is correct
- Ensure the model file is in MT5's Files folder
- Check that the model was exported correctly
### Prediction Issues
**Error**: "Failed to prepare input data"
- Ensure enough historical data is available
- Check that lookback period matches training
- Verify indicators can be calculated
### Shape Mismatch Errors
If you get shape mismatch errors:
1. Check that `InpLookback` in EA matches training `--lookback`
2. Verify feature count matches (default: 12 features)
3. Ensure input normalization matches training
## Best Practices
1. **Data Quality**: Use high-quality historical data
2. **Feature Engineering**: Experiment with different indicators
3. **Model Validation**: Always validate on out-of-sample data
4. **Risk Management**: Use stop loss and position sizing
5. **Backtesting**: Test thoroughly before live trading
6. **Monitoring**: Monitor model performance regularly
## Example Workflow
1. **Train Model**:
```bash
python train_onnx_model.py --symbol XAUUSD --timeframe H1
```
2. **Test Predictions**:
```bash
python predict_with_onnx.py --model models/XAUUSD_H1_model.onnx --symbol XAUUSD
```
3. **Backtest in MT5**:
- Use Strategy Tester with `ONNX_EA.mq5`
- Test on historical data
- Analyze results
4. **Optimize Parameters**:
- Adjust prediction threshold
- Tune confidence levels
- Optimize stop loss/take profit
5. **Deploy**:
- Start with small position sizes
- Monitor performance
- Adjust as needed
## References
- [MQL5 ONNX Documentation](https://www.mql5.com/en/docs/onnx/onnx_prepare)
- [ONNX Model Zoo](https://github.com/onnx/models)
- [MetaTrader 5 Python Module](https://pypi.org/project/MetaTrader5/)
- [TensorFlow to ONNX](https://github.com/onnx/tensorflow-onnx)
## Disclaimer
Trading involves substantial risk of loss. This framework is provided for educational purposes only. Always test thoroughly on a demo account before using with real money. Past performance does not guarantee future results.
## License
This framework is provided for educational and research purposes.
+159
View File
@@ -0,0 +1,159 @@
"""
Complete Example Workflow for ONNX + MT5
This script demonstrates the complete workflow:
1. Train an ONNX model
2. Test predictions
3. Show how to use in MT5
Run this to see the full process in action.
"""
import os
import sys
from datetime import datetime
import MetaTrader5 as mt5
# Import our modules
from train_onnx_model import ONNXModelTrainer
from predict_with_onnx import ONNXPredictor
def main():
"""Complete workflow example."""
print("="*60)
print("ONNX + MetaTrader 5 - Complete Workflow Example")
print("="*60)
# Configuration
symbol = 'XAUUSD'
timeframe_str = 'H1'
lookback = 60
epochs = 20 # Reduced for quick demo
# Convert timeframe
timeframe_map = {
'M1': mt5.TIMEFRAME_M1,
'M5': mt5.TIMEFRAME_M5,
'M15': mt5.TIMEFRAME_M15,
'M30': mt5.TIMEFRAME_M30,
'H1': mt5.TIMEFRAME_H1,
'H4': mt5.TIMEFRAME_H4,
'D1': mt5.TIMEFRAME_D1
}
timeframe = timeframe_map[timeframe_str]
# Create output directory
models_dir = 'models'
os.makedirs(models_dir, exist_ok=True)
# Step 1: Train Model
print("\n" + "="*60)
print("STEP 1: Training ONNX Model")
print("="*60)
trainer = ONNXModelTrainer(
symbol=symbol,
timeframe=timeframe,
lookback=lookback
)
try:
print(f"\nTraining model for {symbol} on {timeframe_str} timeframe...")
print(f"Lookback: {lookback} bars")
print(f"Epochs: {epochs}")
print("\nThis may take several minutes...\n")
trainer.train(epochs=epochs, batch_size=32, verbose=1)
# Export model
model_name = f"{symbol}_{timeframe_str}_model.onnx"
model_path = os.path.join(models_dir, model_name)
print(f"\nExporting model to ONNX format...")
trainer.export_to_onnx(model_path)
print(f"\n✓ Model saved to: {model_path}")
except Exception as e:
print(f"\n✗ Training failed: {e}")
import traceback
traceback.print_exc()
trainer.cleanup()
return
finally:
trainer.cleanup()
# Step 2: Test Predictions
print("\n" + "="*60)
print("STEP 2: Testing Predictions")
print("="*60)
predictor = ONNXPredictor(model_path)
try:
# Get current price
symbol_info = mt5.symbol_info(symbol)
if symbol_info:
current_price = symbol_info.bid
print(f"\nCurrent {symbol} price: {current_price:.5f}")
else:
print(f"\nWarning: Could not get current price for {symbol}")
current_price = 0
# Make predictions
print(f"\nMaking predictions...")
predictions = predictor.predict_batch(symbol, timeframe, n_predictions=3)
print("\nPredictions:")
for i, pred in enumerate(predictions, 1):
if current_price > 0:
change = pred - current_price
change_pct = (change / current_price) * 100
print(f" {i}. {pred:.5f} (change: {change:+.5f}, {change_pct:+.2f}%)")
else:
print(f" {i}. {pred:.5f}")
except Exception as e:
print(f"\n✗ Prediction failed: {e}")
import traceback
traceback.print_exc()
finally:
predictor.cleanup()
# Step 3: Instructions for MT5
print("\n" + "="*60)
print("STEP 3: Using in MetaTrader 5")
print("="*60)
print(f"\nTo use this model in MetaTrader 5:")
print(f"\n1. Copy the model file to MT5's Files folder:")
print(f" {model_path}")
print(f" → <MT5 Data Folder>\\MQL5\\Files\\models\\{os.path.basename(model_path)}")
print(f"\n2. Open ONNX_EA.mq5 in MetaEditor")
print(f"\n3. Set EA parameters:")
print(f" - Model Path: models\\{os.path.basename(model_path)}")
print(f" - Lookback: {lookback}")
print(f" - Your trading parameters")
print(f"\n4. Compile and attach to chart")
print(f"\n5. Monitor performance")
print("\n" + "="*60)
print("Workflow completed!")
print("="*60 + "\n")
if __name__ == '__main__':
# Check MT5 connection first
if not mt5.initialize():
print("ERROR: Failed to initialize MT5")
print("Make sure MetaTrader 5 is running and you're logged in.")
sys.exit(1)
try:
main()
except KeyboardInterrupt:
print("\n\nInterrupted by user")
finally:
mt5.shutdown()
+261
View File
@@ -0,0 +1,261 @@
"""
ONNX Model Prediction Script
This script loads a trained ONNX model and makes predictions using MT5 data.
Can be run from MetaEditor or directly in Python.
Usage:
python predict_with_onnx.py --model models/XAUUSD_H1_model.onnx --symbol XAUUSD
"""
import argparse
import numpy as np
import pandas as pd
import MetaTrader5 as mt5
import onnxruntime as ort
from datetime import datetime
from sklearn.preprocessing import MinMaxScaler
import pickle
import os
class ONNXPredictor:
"""
Predictor class for using ONNX models with MT5 data.
"""
def __init__(self, model_path: str, scaler_path: str = None):
"""
Initialize the predictor.
Args:
model_path: Path to ONNX model file
scaler_path: Path to saved scaler (optional, will create if not provided)
"""
self.model_path = model_path
self.scaler_path = scaler_path
# Load ONNX model
if not os.path.exists(model_path):
raise FileNotFoundError(f"ONNX model not found: {model_path}")
self.session = ort.InferenceSession(model_path)
# Get input/output info
self.input_name = self.session.get_inputs()[0].name
self.output_name = self.session.get_outputs()[0].name
self.input_shape = self.session.get_inputs()[0].shape
print(f"Loaded ONNX model: {model_path}")
print(f"Input shape: {self.input_shape}")
print(f"Input name: {self.input_name}")
print(f"Output name: {self.output_name}")
# Load or create scaler
if scaler_path and os.path.exists(scaler_path):
with open(scaler_path, 'rb') as f:
self.scaler = pickle.load(f)
print(f"Loaded scaler from: {scaler_path}")
else:
self.scaler = MinMaxScaler()
print("Using default scaler (will need to fit)")
# Initialize MT5
if not mt5.initialize():
raise RuntimeError(f"MT5 initialization failed: {mt5.last_error()}")
def prepare_features(self, df: pd.DataFrame) -> pd.DataFrame:
"""
Prepare features from raw OHLCV data (same as training).
Args:
df: Raw OHLCV data
Returns:
DataFrame with features
"""
features = ['open', 'high', 'low', 'close', 'tick_volume']
feature_df = df[features].copy()
# Add technical indicators
feature_df['rsi'] = self._calculate_rsi(df['close'], period=14)
feature_df['ema_20'] = df['close'].ewm(span=20).mean()
feature_df['ema_50'] = df['close'].ewm(span=50).mean()
feature_df['atr'] = self._calculate_atr(df, period=14)
feature_df['price_change'] = df['close'].pct_change()
feature_df['high_low_ratio'] = df['high'] / df['low']
feature_df['volume_ma'] = df['tick_volume'].rolling(window=20).mean()
feature_df['volume_ratio'] = df['tick_volume'] / feature_df['volume_ma']
feature_df = feature_df.dropna()
return feature_df
def _calculate_rsi(self, prices: pd.Series, period: int = 14) -> pd.Series:
"""Calculate RSI indicator."""
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def _calculate_atr(self, df: pd.DataFrame, period: int = 14) -> pd.Series:
"""Calculate ATR indicator."""
high_low = df['high'] - df['low']
high_close = np.abs(df['high'] - df['close'].shift())
low_close = np.abs(df['low'] - df['close'].shift())
tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
atr = tr.rolling(window=period).mean()
return atr
def get_latest_data(self, symbol: str, timeframe: int, lookback: int) -> np.ndarray:
"""
Get latest data from MT5 and prepare for prediction.
Args:
symbol: Trading symbol
timeframe: MT5 timeframe
lookback: Number of bars needed
Returns:
Prepared feature array ready for model input
"""
# Fetch data
rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, lookback + 50)
if rates is None or len(rates) < lookback:
raise ValueError(f"Insufficient data for {symbol}")
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
# Prepare features
feature_df = self.prepare_features(df)
# Get last lookback bars
feature_data = feature_df.values[-lookback:]
# Scale features
if hasattr(self.scaler, 'scale_'):
feature_data_scaled = self.scaler.transform(feature_data)
else:
# Fit scaler if not already fitted
print("Warning: Scaler not fitted, fitting on current data...")
feature_data_scaled = self.scaler.fit_transform(feature_data)
# Reshape for model input: (1, lookback, features)
feature_data_scaled = feature_data_scaled.reshape(1, lookback, -1)
return feature_data_scaled.astype(np.float32)
def predict(self, symbol: str, timeframe: int, lookback: int = None) -> float:
"""
Make a prediction for the next price.
Args:
symbol: Trading symbol
timeframe: MT5 timeframe
lookback: Number of bars to use (default: from model input shape)
Returns:
Predicted price
"""
if lookback is None:
lookback = self.input_shape[1] if self.input_shape[1] else 60
# Get and prepare data
input_data = self.get_latest_data(symbol, timeframe, lookback)
# Make prediction
outputs = self.session.run([self.output_name], {self.input_name: input_data})
prediction = outputs[0][0][0]
return float(prediction)
def predict_batch(self, symbol: str, timeframe: int, n_predictions: int = 5) -> list:
"""
Make multiple predictions.
Args:
symbol: Trading symbol
timeframe: MT5 timeframe
n_predictions: Number of predictions to make
Returns:
List of predictions
"""
predictions = []
for _ in range(n_predictions):
pred = self.predict(symbol, timeframe)
predictions.append(pred)
return predictions
def cleanup(self):
"""Clean up MT5 connection."""
mt5.shutdown()
def main():
"""Main function."""
parser = argparse.ArgumentParser(description='Make predictions using ONNX model')
parser.add_argument('--model', type=str, required=True,
help='Path to ONNX model file')
parser.add_argument('--symbol', type=str, default='XAUUSD',
help='Trading symbol')
parser.add_argument('--timeframe', type=str, default='H1',
choices=['M1', 'M5', 'M15', 'M30', 'H1', 'H4', 'D1'],
help='Timeframe')
parser.add_argument('--scaler', type=str, default=None,
help='Path to saved scaler (optional)')
parser.add_argument('--predictions', type=int, default=1,
help='Number of predictions to make')
args = parser.parse_args()
# Convert timeframe
timeframe_map = {
'M1': mt5.TIMEFRAME_M1,
'M5': mt5.TIMEFRAME_M5,
'M15': mt5.TIMEFRAME_M15,
'M30': mt5.TIMEFRAME_M30,
'H1': mt5.TIMEFRAME_H1,
'H4': mt5.TIMEFRAME_H4,
'D1': mt5.TIMEFRAME_D1
}
timeframe = timeframe_map[args.timeframe]
# Create predictor
predictor = ONNXPredictor(args.model, args.scaler)
try:
# Get current price
symbol_info = mt5.symbol_info(args.symbol)
current_price = symbol_info.bid if symbol_info else 0
print(f"\nCurrent {args.symbol} price: {current_price:.5f}")
print(f"Making {args.predictions} prediction(s)...\n")
# Make predictions
if args.predictions == 1:
prediction = predictor.predict(args.symbol, timeframe)
print(f"Predicted next price: {prediction:.5f}")
print(f"Expected change: {(prediction - current_price):.5f} "
f"({((prediction - current_price) / current_price * 100):.2f}%)")
else:
predictions = predictor.predict_batch(args.symbol, timeframe, args.predictions)
print("Predictions:")
for i, pred in enumerate(predictions, 1):
change = pred - current_price
change_pct = (change / current_price * 100) if current_price > 0 else 0
print(f" {i}. {pred:.5f} (change: {change:+.5f}, {change_pct:+.2f}%)")
except Exception as e:
print(f"\nError: {e}")
import traceback
traceback.print_exc()
finally:
predictor.cleanup()
if __name__ == '__main__':
main()
+17
View File
@@ -0,0 +1,17 @@
# ONNX and Machine Learning
onnx>=1.12.0
onnxruntime>=1.12.0
tensorflow>=2.10.0
tf2onnx>=1.13.0
# Data Processing
pandas>=1.3.0
numpy>=1.21.0
scikit-learn>=1.0.0
# MetaTrader 5 Integration
MetaTrader5>=5.0.45
# Visualization and Utilities
matplotlib>=3.4.0
tqdm>=4.64.0
+364
View File
@@ -0,0 +1,364 @@
"""
ONNX Model Training Script for MetaTrader 5
This script trains a neural network model for price prediction and exports it to ONNX format.
Based on MQL5 ONNX documentation: https://www.mql5.com/en/docs/onnx/onnx_prepare
Usage:
python train_onnx_model.py --symbol XAUUSD --timeframe H1 --lookback 60 --epochs 50
"""
import argparse
import os
import sys
from datetime import datetime, timedelta
import numpy as np
import pandas as pd
import MetaTrader5 as mt5
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
import tf2onnx
import onnx
from tqdm import tqdm
class ONNXModelTrainer:
"""
Trainer class for creating ONNX models from MT5 data.
"""
def __init__(self, symbol: str, timeframe: int, lookback: int = 60,
prediction_horizon: int = 1, features: list = None):
"""
Initialize the trainer.
Args:
symbol: Trading symbol (e.g., 'XAUUSD', 'EURUSD')
timeframe: MT5 timeframe constant
lookback: Number of bars to look back for prediction
prediction_horizon: Number of bars ahead to predict
features: List of features to use (default: OHLC + volume)
"""
self.symbol = symbol
self.timeframe = timeframe
self.lookback = lookback
self.prediction_horizon = prediction_horizon
self.features = features or ['open', 'high', 'low', 'close', 'tick_volume']
self.scaler = MinMaxScaler()
self.model = None
# Initialize MT5
if not mt5.initialize():
raise RuntimeError(f"MT5 initialization failed: {mt5.last_error()}")
def fetch_data(self, start_date: datetime, end_date: datetime) -> pd.DataFrame:
"""
Fetch historical data from MT5.
Args:
start_date: Start date for data
end_date: End date for data
Returns:
DataFrame with OHLCV data
"""
print(f"Fetching data for {self.symbol} from {start_date} to {end_date}...")
rates = mt5.copy_rates_range(self.symbol, self.timeframe, start_date, end_date)
if rates is None or len(rates) == 0:
raise ValueError(f"No data available for {self.symbol} in the specified date range")
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
df.set_index('time', inplace=True)
print(f"Fetched {len(df)} bars")
return df
def prepare_features(self, df: pd.DataFrame) -> pd.DataFrame:
"""
Prepare features for training.
Args:
df: Raw OHLCV data
Returns:
DataFrame with features
"""
feature_df = df[self.features].copy()
# Add technical indicators as features
feature_df['rsi'] = self._calculate_rsi(df['close'], period=14)
feature_df['ema_20'] = df['close'].ewm(span=20).mean()
feature_df['ema_50'] = df['close'].ewm(span=50).mean()
feature_df['atr'] = self._calculate_atr(df, period=14)
# Price changes
feature_df['price_change'] = df['close'].pct_change()
feature_df['high_low_ratio'] = df['high'] / df['low']
# Volume features
feature_df['volume_ma'] = df['tick_volume'].rolling(window=20).mean()
feature_df['volume_ratio'] = df['tick_volume'] / feature_df['volume_ma']
# Drop NaN values
feature_df = feature_df.dropna()
return feature_df
def _calculate_rsi(self, prices: pd.Series, period: int = 14) -> pd.Series:
"""Calculate RSI indicator."""
delta = prices.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
rsi = 100 - (100 / (1 + rs))
return rsi
def _calculate_atr(self, df: pd.DataFrame, period: int = 14) -> pd.Series:
"""Calculate ATR indicator."""
high_low = df['high'] - df['low']
high_close = np.abs(df['high'] - df['close'].shift())
low_close = np.abs(df['low'] - df['close'].shift())
tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
atr = tr.rolling(window=period).mean()
return atr
def create_sequences(self, data: np.ndarray, target: np.ndarray) -> tuple:
"""
Create sequences for LSTM/RNN training.
Args:
data: Feature data
target: Target values
Returns:
Tuple of (X, y) sequences
"""
X, y = [], []
for i in range(self.lookback, len(data) - self.prediction_horizon + 1):
X.append(data[i - self.lookback:i])
y.append(target[i + self.prediction_horizon - 1])
return np.array(X), np.array(y)
def build_model(self, input_shape: tuple) -> keras.Model:
"""
Build the neural network model.
Args:
input_shape: Shape of input data (lookback, features)
Returns:
Compiled Keras model
"""
model = keras.Sequential([
layers.LSTM(128, return_sequences=True, input_shape=input_shape),
layers.Dropout(0.2),
layers.LSTM(64, return_sequences=True),
layers.Dropout(0.2),
layers.LSTM(32),
layers.Dropout(0.2),
layers.Dense(16, activation='relu'),
layers.Dense(1) # Predict next close price
])
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=0.001),
loss='mse',
metrics=['mae']
)
return model
def train(self, epochs: int = 50, batch_size: int = 32,
validation_split: float = 0.2, verbose: int = 1):
"""
Train the model.
Args:
epochs: Number of training epochs
batch_size: Batch size for training
validation_split: Fraction of data to use for validation
verbose: Verbosity level
"""
# Fetch data (last 2 years)
end_date = datetime.now()
start_date = end_date - timedelta(days=730)
df = self.fetch_data(start_date, end_date)
feature_df = self.prepare_features(df)
# Prepare data
feature_data = feature_df.values
target_data = df['close'].values[feature_df.index]
# Scale features
feature_data_scaled = self.scaler.fit_transform(feature_data)
# Create sequences
X, y = self.create_sequences(feature_data_scaled, target_data)
# Split data
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=validation_split, shuffle=False
)
print(f"\nTraining data shape: {X_train.shape}")
print(f"Validation data shape: {X_test.shape}")
# Build model
self.model = self.build_model((X_train.shape[1], X_train.shape[2]))
print("\nModel architecture:")
self.model.summary()
# Train model
print("\nTraining model...")
history = self.model.fit(
X_train, y_train,
batch_size=batch_size,
epochs=epochs,
validation_data=(X_test, y_test),
verbose=verbose,
callbacks=[
keras.callbacks.EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True
),
keras.callbacks.ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=5,
min_lr=0.0001
)
]
)
# Evaluate
train_loss = self.model.evaluate(X_train, y_train, verbose=0)
test_loss = self.model.evaluate(X_test, y_test, verbose=0)
print(f"\nTraining Loss: {train_loss[0]:.4f}, MAE: {train_loss[1]:.4f}")
print(f"Validation Loss: {test_loss[0]:.4f}, MAE: {test_loss[1]:.4f}")
return history
def export_to_onnx(self, output_path: str):
"""
Export the trained model to ONNX format.
Args:
output_path: Path to save ONNX model
"""
if self.model is None:
raise ValueError("Model must be trained before exporting")
print(f"\nExporting model to ONNX format: {output_path}")
# Get input shape
input_shape = (1, self.lookback, len(self.features) + 7) # +7 for added features
# Create dummy input
dummy_input = np.random.randn(*input_shape).astype(np.float32)
# Convert to ONNX
spec = (tf.TensorSpec((None, self.lookback, len(self.features) + 7), tf.float32, name="input"),)
output_path_onnx = tf2onnx.convert.from_keras(
self.model,
input_signature=spec,
opset=13,
output_path=output_path
)
print(f"✓ ONNX model saved to: {output_path}")
# Verify ONNX model
try:
onnx_model = onnx.load(output_path)
onnx.checker.check_model(onnx_model)
print("✓ ONNX model validation passed")
except Exception as e:
print(f"⚠ ONNX model validation warning: {e}")
def cleanup(self):
"""Clean up MT5 connection."""
mt5.shutdown()
def main():
"""Main function."""
parser = argparse.ArgumentParser(description='Train ONNX model for MT5 price prediction')
parser.add_argument('--symbol', type=str, default='XAUUSD', help='Trading symbol')
parser.add_argument('--timeframe', type=str, default='H1',
choices=['M1', 'M5', 'M15', 'M30', 'H1', 'H4', 'D1'],
help='Timeframe')
parser.add_argument('--lookback', type=int, default=60,
help='Number of bars to look back')
parser.add_argument('--epochs', type=int, default=50, help='Training epochs')
parser.add_argument('--batch-size', type=int, default=32, help='Batch size')
parser.add_argument('--output', type=str, default='models',
help='Output directory for ONNX model')
args = parser.parse_args()
# Convert timeframe string to MT5 constant
timeframe_map = {
'M1': mt5.TIMEFRAME_M1,
'M5': mt5.TIMEFRAME_M5,
'M15': mt5.TIMEFRAME_M15,
'M30': mt5.TIMEFRAME_M30,
'H1': mt5.TIMEFRAME_H1,
'H4': mt5.TIMEFRAME_H4,
'D1': mt5.TIMEFRAME_D1
}
timeframe = timeframe_map[args.timeframe]
# Create output directory
os.makedirs(args.output, exist_ok=True)
# Create trainer
trainer = ONNXModelTrainer(
symbol=args.symbol,
timeframe=timeframe,
lookback=args.lookback
)
try:
# Train model
trainer.train(epochs=args.epochs, batch_size=args.batch_size)
# Export to ONNX
model_name = f"{args.symbol}_{args.timeframe}_model.onnx"
output_path = os.path.join(args.output, model_name)
trainer.export_to_onnx(output_path)
# Save scaler for consistent normalization
scaler_path = os.path.join(args.output, f"{args.symbol}_{args.timeframe}_scaler.pkl")
import pickle
with open(scaler_path, 'wb') as f:
pickle.dump(trainer.scaler, f)
print(f"✓ Scaler saved to: {scaler_path}")
print(f" Use this with predict_with_onnx.py for consistent normalization")
print(f"\n{'='*60}")
print("Training completed successfully!")
print(f"ONNX model saved to: {output_path}")
print(f"{'='*60}\n")
except Exception as e:
print(f"\nError: {e}")
sys.exit(1)
finally:
trainer.cleanup()
if __name__ == '__main__':
main()