mql5/Shared Projects/ERMT-ML/Modules-ML8x/MLPredictor.mqh
darashikoh 0fb1bd1b0a Module Integration Summary for External Trade Management
Overview
To fully integrate the enhanced external trade management system, updates are required to 5 out of 7 existing modules. The updates maintain backward compatibility while adding new functionality for external trade handling.
Module Update Requirements
🟢 No Updates Required (2 modules)

TechnicalAnalysis.mqh - Already provides necessary calculations
EntrySystem.mqh - Only handles EA's own entry signals

🟡 Minor Updates (2 modules)

DataTypes.mqh - Add external trade structures and fields
Utilities.mqh - Enhanced logging for external trades

🟠 Moderate Updates (3 modules)

RiskManager.mqh - Enhanced risk enforcement methods
TradeManager.mqh - Improved stop management for externals
Dashboard.mqh - Display external trade information

Integration Steps
Phase 1: Data Structures (DataTypes.mqh)

Add ENUM_EXTERNAL_STATUS enumeration
Extend ManagedTrade structure with external-specific fields
Add ExternalTradeStats structure for metrics
Update DashboardConfig with show_external flag

Key additions:

external_status - Track state of external trade
source_name - Identify where trade came from
stops_modified - Track if we modified the trade
original_sl/tp - Store original values for comparison

Phase 2: Risk Management (RiskManager.mqh)

Add EnforceRiskRulesEnhanced() method
Implement GetExternalExposure() for risk aggregation
Add UpdateExternalStats() for tracking
Enhance ValidateAndAdjustRiskExternal() method

Key features:

Separate risk calculation for external trades
Cache mechanism for performance
Statistical tracking of external positions
Smart risk adjustment without closing trades

Phase 3: Trade Management (TradeManager.mqh)

Add ApplyDefaultStopsEnhanced() with better logic
Implement OverrideExternalStops() with smart override
Create ManageExternalTrade() with different rules
Add ApplyBreakevenExternal() with wider triggers

Key features:

Smart stop override (only improve, never worsen)
Different management rules for external trades
Respect minimum broker distances
Track modification success/failure rates

Phase 4: User Interface (Dashboard.mqh)

Add CreateExternalSection() for display area
Implement UpdateExternalSection() for real-time updates
Add SetCustomText() for flexible display
Create ShowExternalTrades() toggle method

Key features:

Real-time external trade count and risk
Color-coded risk warnings
List of active external positions
Modification statistics display

Phase 5: Logging (Utilities.mqh)

Add LogExternalTrade() for detailed event logging
Create separate CSV log for external trades
Enhance GenerateReportEnhanced() with external section
Add IdentifyTradeSource() for magic number interpretation

Key features:

Separate CSV log for external trade events
Detailed tracking of all modifications
Source identification from magic numbers
Enhanced reporting with external statistics
2025-08-27 14:21:02 +01:00

992 lines
No EOL
32 KiB
MQL5

//+------------------------------------------------------------------+
//| MLPredictor.mqh |
//| Machine Learning Prediction Module |
//| Neural Network & Ensemble Learning |
//+------------------------------------------------------------------+
#ifndef ML_PREDICTOR_MQH
#define ML_PREDICTOR_MQH
#include "DataTypes_v71.mqh"
#include <Math/Stat/Math.mqh>
//+------------------------------------------------------------------+
//| ML Model Types |
//+------------------------------------------------------------------+
enum ENUM_ML_MODEL
{
ML_RANDOM_FOREST = 0,
ML_NEURAL_NETWORK = 1,
ML_GRADIENT_BOOST = 2,
ML_ENSEMBLE = 3
};
//+------------------------------------------------------------------+
//| Neural Network Layer |
//+------------------------------------------------------------------+
struct NeuralLayer
{
double weights[][];
double biases[];
double activations[];
int input_size;
int output_size;
};
//+------------------------------------------------------------------+
//| ML Predictor Class |
//+------------------------------------------------------------------+
class CMLPredictor
{
private:
//--- Configuration
int m_lookback_period;
int m_min_training_size;
bool m_use_deep_learning;
double m_learning_rate;
ENUM_ML_MODEL m_model_type;
//--- Neural network architecture
NeuralLayer m_layers[];
int m_layer_count;
int m_input_features;
int m_output_classes;
//--- Training data
double m_training_features[][];
double m_training_labels[];
int m_training_count;
//--- Model performance
double m_accuracy;
double m_precision;
double m_recall;
double m_f1_score;
datetime m_last_update;
//--- Feature scaling
double m_feature_mean[];
double m_feature_std[];
//--- Ensemble models
struct TreeNode
{
int feature_index;
double threshold;
int left_child;
int right_child;
double prediction;
bool is_leaf;
};
struct DecisionTree
{
TreeNode nodes[];
int node_count;
double feature_importance[];
};
DecisionTree m_trees[];
int m_tree_count;
//--- Helper methods
void InitializeNeuralNetwork(int hidden_layers[], int layer_sizes[]);
double ActivationFunction(double x, bool derivative = false);
void ForwardPass(double &inputs[], double &outputs[]);
void BackPropagation(double &inputs[], double &targets[]);
void UpdateWeights();
//--- Feature engineering
void ExtractAdvancedFeatures(string symbol, double &features[]);
void NormalizeFeatures(double &features[]);
void CalculateFeatureImportance();
//--- Ensemble methods
void TrainRandomForest();
void TrainGradientBoosting();
double PredictWithTree(DecisionTree &tree, double &features[]);
//--- Model persistence
string m_model_path;
public:
CMLPredictor();
~CMLPredictor();
//--- Initialization
bool Initialize(int lookback, int min_training, bool use_deep);
void SetModelType(ENUM_ML_MODEL type) { m_model_type = type; }
void SetLearningRate(double rate) { m_learning_rate = rate; }
//--- Training
bool Train(double &features[][], double &labels[]);
bool UpdateModel(ManagedTradeV71 &trades[]);
void AddTrainingExample(double &features[], double label);
//--- Prediction
MLPrediction Predict(string symbol);
double PredictProbability(double &features[], ENUM_ORDER_TYPE direction);
void PredictBatch(string symbols[], MLPrediction &predictions[]);
//--- Feature analysis
double GetFeatureImportance(int feature_index);
void GetTopFeatures(int &indices[], double &importances[], int count);
//--- Model evaluation
double GetAccuracy() { return m_accuracy; }
double GetPrecision() { return m_precision; }
double GetRecall() { return m_recall; }
double GetF1Score() { return m_f1_score; }
void EvaluateModel(double &test_features[][], double &test_labels[]);
//--- Model management
bool SaveModel(string filename);
bool LoadModel(string filename);
datetime GetLastUpdateTime() { return m_last_update; }
//--- Real-time learning
void OnlineUpdate(double &features[], double actual_result);
void AdaptToMarketRegime(ENUM_MARKET_REGIME regime);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CMLPredictor::CMLPredictor()
{
m_lookback_period = 100;
m_min_training_size = 100;
m_use_deep_learning = false;
m_learning_rate = 0.01;
m_model_type = ML_ENSEMBLE;
m_layer_count = 0;
m_input_features = 20;
m_output_classes = 3; // Buy, Sell, Hold
m_training_count = 0;
m_accuracy = 0;
m_precision = 0;
m_recall = 0;
m_f1_score = 0;
m_last_update = 0;
m_tree_count = 100; // Default forest size
m_model_path = "MLModels\\";
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CMLPredictor::~CMLPredictor()
{
// Cleanup allocated memory
}
//+------------------------------------------------------------------+
//| Initialize ML predictor |
//+------------------------------------------------------------------+
bool CMLPredictor::Initialize(int lookback, int min_training, bool use_deep)
{
m_lookback_period = lookback;
m_min_training_size = min_training;
m_use_deep_learning = use_deep;
//--- Initialize feature scaling arrays
ArrayResize(m_feature_mean, m_input_features);
ArrayResize(m_feature_std, m_input_features);
ArrayInitialize(m_feature_mean, 0);
ArrayInitialize(m_feature_std, 1);
//--- Initialize neural network if deep learning
if(m_use_deep_learning)
{
int hidden_layers = 3;
int layer_sizes[] = {64, 32, 16}; // Architecture: 20->64->32->16->3
InitializeNeuralNetwork(hidden_layers, layer_sizes);
}
//--- Initialize training data arrays
ArrayResize(m_training_features, m_lookback_period);
ArrayResize(m_training_labels, m_lookback_period);
//--- Initialize ensemble
if(m_model_type == ML_ENSEMBLE || m_model_type == ML_RANDOM_FOREST)
{
ArrayResize(m_trees, m_tree_count);
}
Print("MLPredictor initialized: Model=", EnumToString(m_model_type),
", DeepLearning=", m_use_deep_learning);
return true;
}
//+------------------------------------------------------------------+
//| Initialize neural network architecture |
//+------------------------------------------------------------------+
void CMLPredictor::InitializeNeuralNetwork(int hidden_count, int layer_sizes[])
{
m_layer_count = hidden_count + 1; // Hidden layers + output layer
ArrayResize(m_layers, m_layer_count);
int prev_size = m_input_features;
//--- Initialize each layer
for(int i = 0; i < m_layer_count; i++)
{
int current_size = (i < hidden_count) ? layer_sizes[i] : m_output_classes;
m_layers[i].input_size = prev_size;
m_layers[i].output_size = current_size;
//--- Initialize weights with Xavier initialization
ArrayResize(m_layers[i].weights, current_size);
for(int j = 0; j < current_size; j++)
{
ArrayResize(m_layers[i].weights[j], prev_size);
double xavier_std = MathSqrt(2.0 / (prev_size + current_size));
for(int k = 0; k < prev_size; k++)
{
m_layers[i].weights[j][k] = MathRandomNormal(0, xavier_std);
}
}
//--- Initialize biases
ArrayResize(m_layers[i].biases, current_size);
ArrayInitialize(m_layers[i].biases, 0);
//--- Initialize activations
ArrayResize(m_layers[i].activations, current_size);
prev_size = current_size;
}
}
//+------------------------------------------------------------------+
//| Make prediction for symbol |
//+------------------------------------------------------------------+
MLPrediction CMLPredictor::Predict(string symbol)
{
MLPrediction prediction;
prediction.prediction_time = TimeCurrent();
prediction.model_version = "1.0";
//--- Extract features
double features[];
ExtractAdvancedFeatures(symbol, features);
//--- Normalize features
NormalizeFeatures(features);
//--- Make prediction based on model type
double outputs[];
switch(m_model_type)
{
case ML_NEURAL_NETWORK:
{
ArrayResize(outputs, m_output_classes);
ForwardPass(features, outputs);
//--- Find class with highest probability
int best_class = 0;
double max_prob = outputs[0];
for(int i = 1; i < m_output_classes; i++)
{
if(outputs[i] > max_prob)
{
max_prob = outputs[i];
best_class = i;
}
}
//--- Convert to trading signal
if(best_class == 0) // Buy class
{
prediction.direction = ORDER_TYPE_BUY;
prediction.confidence = max_prob;
}
else if(best_class == 1) // Sell class
{
prediction.direction = ORDER_TYPE_SELL;
prediction.confidence = max_prob;
}
else // Hold
{
prediction.direction = ORDER_TYPE_BUY; // Default
prediction.confidence = 0; // No trade
}
}
break;
case ML_RANDOM_FOREST:
case ML_ENSEMBLE:
{
//--- Aggregate predictions from all trees
double buy_votes = 0;
double sell_votes = 0;
for(int i = 0; i < m_tree_count; i++)
{
double tree_pred = PredictWithTree(m_trees[i], features);
if(tree_pred > 0.5)
buy_votes++;
else if(tree_pred < -0.5)
sell_votes++;
}
//--- Determine direction
if(buy_votes > sell_votes && buy_votes > m_tree_count * 0.6)
{
prediction.direction = ORDER_TYPE_BUY;
prediction.confidence = buy_votes / m_tree_count;
}
else if(sell_votes > buy_votes && sell_votes > m_tree_count * 0.6)
{
prediction.direction = ORDER_TYPE_SELL;
prediction.confidence = sell_votes / m_tree_count;
}
else
{
prediction.direction = ORDER_TYPE_BUY;
prediction.confidence = 0; // No clear signal
}
}
break;
}
//--- Additional predictions
prediction.expected_return = prediction.confidence * 2.5; // Simplified
prediction.volatility = features[9]; // ATR feature
//--- Calculate stops
double atr = iATR(symbol, PERIOD_CURRENT, 14);
double current_price = (prediction.direction == ORDER_TYPE_BUY) ?
SymbolInfoDouble(symbol, SYMBOL_ASK) :
SymbolInfoDouble(symbol, SYMBOL_BID);
if(prediction.direction == ORDER_TYPE_BUY)
{
prediction.stop_loss = current_price - atr * 2;
prediction.take_profit = current_price + atr * 4;
}
else
{
prediction.stop_loss = current_price + atr * 2;
prediction.take_profit = current_price - atr * 4;
}
//--- Optimal size based on Kelly
double kelly_fraction = (prediction.confidence * 2.5 - (1 - prediction.confidence)) / 2.5;
kelly_fraction = MathMax(0, MathMin(0.25, kelly_fraction * 0.3)); // Conservative Kelly
prediction.optimal_size = kelly_fraction;
return prediction;
}
//+------------------------------------------------------------------+
//| Extract advanced features for ML |
//+------------------------------------------------------------------+
void CMLPredictor::ExtractAdvancedFeatures(string symbol, double &features[])
{
ArrayResize(features, m_input_features);
//--- Price-based features
double close = iClose(symbol, PERIOD_CURRENT, 0);
double open = iOpen(symbol, PERIOD_CURRENT, 0);
double high = iHigh(symbol, PERIOD_CURRENT, 0);
double low = iLow(symbol, PERIOD_CURRENT, 0);
features[0] = (close - open) / open * 100; // Return
features[1] = (high - low) / low * 100; // Range
features[2] = (close - low) / (high - low + 0.00001); // Position in range
//--- Moving averages
double ma_5 = iMA(symbol, PERIOD_CURRENT, 5, 0, MODE_EMA, PRICE_CLOSE);
double ma_20 = iMA(symbol, PERIOD_CURRENT, 20, 0, MODE_EMA, PRICE_CLOSE);
double ma_50 = iMA(symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
features[3] = (close - ma_5) / ma_5 * 100;
features[4] = (ma_5 - ma_20) / ma_20 * 100;
features[5] = (ma_20 - ma_50) / ma_50 * 100;
//--- Momentum indicators
double rsi = iRSI(symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
double cci = iCCI(symbol, PERIOD_CURRENT, 14, PRICE_TYPICAL);
double momentum = iMomentum(symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
features[6] = rsi / 100.0;
features[7] = cci / 200.0; // Normalize CCI
features[8] = (momentum - 100) / 100.0;
//--- Volatility
double atr = iATR(symbol, PERIOD_CURRENT, 14);
double stddev = iStdDev(symbol, PERIOD_CURRENT, 20, 0, MODE_SMA, PRICE_CLOSE);
features[9] = atr / close * 100;
features[10] = stddev / close * 100;
//--- Volume
long volume = iVolume(symbol, PERIOD_CURRENT, 0);
long avg_volume = 0;
for(int i = 1; i <= 20; i++)
{
avg_volume += iVolume(symbol, PERIOD_CURRENT, i);
}
avg_volume /= 20;
features[11] = (avg_volume > 0) ? (double)volume / avg_volume : 1.0;
//--- Market structure
int higher_highs = 0;
int lower_lows = 0;
for(int i = 1; i < 10; i++)
{
if(iHigh(symbol, PERIOD_CURRENT, i) > iHigh(symbol, PERIOD_CURRENT, i+1))
higher_highs++;
if(iLow(symbol, PERIOD_CURRENT, i) < iLow(symbol, PERIOD_CURRENT, i+1))
lower_lows++;
}
features[12] = higher_highs / 10.0;
features[13] = lower_lows / 10.0;
//--- Time-based features
MqlDateTime time;
TimeToStruct(TimeCurrent(), time);
features[14] = time.hour / 24.0;
features[15] = time.day_of_week / 7.0;
features[16] = time.day / 31.0;
//--- Microstructure
long spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD);
features[17] = spread / 100.0;
//--- Sentiment (simplified)
features[18] = (rsi > 50) ? (rsi - 50) / 50 : (rsi - 50) / 50;
//--- Correlation with market (using EURUSD as proxy)
if(symbol != "EURUSD")
{
double symbol_return = (close - iClose(symbol, PERIOD_D1, 1)) / iClose(symbol, PERIOD_D1, 1);
double market_return = (iClose("EURUSD", PERIOD_D1, 0) - iClose("EURUSD", PERIOD_D1, 1)) /
iClose("EURUSD", PERIOD_D1, 1);
features[19] = symbol_return - market_return;
}
else
{
features[19] = 0;
}
}
//+------------------------------------------------------------------+
//| Normalize features using z-score |
//+------------------------------------------------------------------+
void CMLPredictor::NormalizeFeatures(double &features[])
{
for(int i = 0; i < m_input_features; i++)
{
if(m_feature_std[i] > 0)
{
features[i] = (features[i] - m_feature_mean[i]) / m_feature_std[i];
}
}
}
//+------------------------------------------------------------------+
//| Forward pass through neural network |
//+------------------------------------------------------------------+
void CMLPredictor::ForwardPass(double &inputs[], double &outputs[])
{
//--- Start with input features
double current_inputs[];
ArrayCopy(current_inputs, inputs);
//--- Pass through each layer
for(int layer = 0; layer < m_layer_count; layer++)
{
//--- Calculate activations for this layer
for(int neuron = 0; neuron < m_layers[layer].output_size; neuron++)
{
double sum = m_layers[layer].biases[neuron];
for(int input = 0; input < m_layers[layer].input_size; input++)
{
sum += current_inputs[input] * m_layers[layer].weights[neuron][input];
}
//--- Apply activation function
m_layers[layer].activations[neuron] = ActivationFunction(sum);
}
//--- Current layer outputs become next layer inputs
ArrayResize(current_inputs, m_layers[layer].output_size);
ArrayCopy(current_inputs, m_layers[layer].activations);
}
//--- Copy final layer outputs
ArrayResize(outputs, m_output_classes);
ArrayCopy(outputs, m_layers[m_layer_count-1].activations);
}
//+------------------------------------------------------------------+
//| Activation function (ReLU for hidden, Softmax for output) |
//+------------------------------------------------------------------+
double CMLPredictor::ActivationFunction(double x, bool derivative = false)
{
if(derivative)
{
return (x > 0) ? 1 : 0.01; // Leaky ReLU derivative
}
else
{
return (x > 0) ? x : 0.01 * x; // Leaky ReLU
}
}
//+------------------------------------------------------------------+
//| Update model with new trading results |
//+------------------------------------------------------------------+
bool CMLPredictor::UpdateModel(ManagedTradeV71 &trades[])
{
int trade_count = ArraySize(trades);
if(trade_count < m_min_training_size)
return false;
//--- Prepare training data from closed trades
double new_features[][];
double new_labels[];
int example_count = 0;
ArrayResize(new_features, trade_count);
ArrayResize(new_labels, trade_count);
for(int i = 0; i < trade_count; i++)
{
//--- Only use closed trades for training
if(trades[i].profit == 0)
continue;
//--- Extract features at trade entry
ArrayResize(new_features[example_count], m_input_features);
ExtractAdvancedFeatures(trades[i].symbol, new_features[example_count]);
//--- Label: 1 for profitable, -1 for loss, weighted by R-multiple
if(trades[i].profit > 0)
{
new_labels[example_count] = MathMin(1.0, trades[i].r_multiple / 2.0);
}
else
{
new_labels[example_count] = MathMax(-1.0, trades[i].r_multiple / 2.0);
}
example_count++;
}
if(example_count < m_min_training_size)
return false;
//--- Resize to actual count
ArrayResize(new_features, example_count);
ArrayResize(new_labels, example_count);
//--- Update feature statistics
for(int i = 0; i < m_input_features; i++)
{
double sum = 0;
double sum_sq = 0;
for(int j = 0; j < example_count; j++)
{
sum += new_features[j][i];
sum_sq += new_features[j][i] * new_features[j][i];
}
m_feature_mean[i] = sum / example_count;
m_feature_std[i] = MathSqrt(sum_sq / example_count - m_feature_mean[i] * m_feature_mean[i]);
}
//--- Normalize features
for(int i = 0; i < example_count; i++)
{
NormalizeFeatures(new_features[i]);
}
//--- Train model
bool success = Train(new_features, new_labels);
if(success)
{
m_last_update = TimeCurrent();
//--- Evaluate on recent data
EvaluateModel(new_features, new_labels);
Print("ML Model updated: Examples=", example_count,
", Accuracy=", DoubleToString(m_accuracy, 2),
", F1=", DoubleToString(m_f1_score, 2));
}
return success;
}
//+------------------------------------------------------------------+
//| Train the model |
//+------------------------------------------------------------------+
bool CMLPredictor::Train(double &features[][], double &labels[])
{
int sample_count = ArrayRange(features, 0);
if(sample_count < m_min_training_size)
return false;
//--- Store training data
m_training_count = sample_count;
ArrayResize(m_training_features, sample_count);
ArrayCopy(m_training_labels, labels);
for(int i = 0; i < sample_count; i++)
{
ArrayResize(m_training_features[i], m_input_features);
ArrayCopy(m_training_features[i], features[i]);
}
//--- Train based on model type
switch(m_model_type)
{
case ML_NEURAL_NETWORK:
{
//--- Mini-batch gradient descent
int epochs = 100;
int batch_size = 32;
for(int epoch = 0; epoch < epochs; epoch++)
{
double total_loss = 0;
for(int batch = 0; batch < sample_count; batch += batch_size)
{
int batch_end = MathMin(batch + batch_size, sample_count);
for(int i = batch; i < batch_end; i++)
{
//--- Forward pass
double outputs[];
ForwardPass(m_training_features[i], outputs);
//--- Calculate targets
double targets[];
ArrayResize(targets, m_output_classes);
ArrayInitialize(targets, 0);
if(m_training_labels[i] > 0.5)
targets[0] = 1; // Buy
else if(m_training_labels[i] < -0.5)
targets[1] = 1; // Sell
else
targets[2] = 1; // Hold
//--- Backpropagation
BackPropagation(m_training_features[i], targets);
}
//--- Update weights
UpdateWeights();
}
//--- Decay learning rate
m_learning_rate *= 0.99;
}
}
break;
case ML_RANDOM_FOREST:
case ML_ENSEMBLE:
TrainRandomForest();
break;
case ML_GRADIENT_BOOST:
TrainGradientBoosting();
break;
}
return true;
}
//+------------------------------------------------------------------+
//| Train random forest |
//+------------------------------------------------------------------+
void CMLPredictor::TrainRandomForest()
{
//--- Train each tree on bootstrap sample
for(int tree = 0; tree < m_tree_count; tree++)
{
//--- Bootstrap sampling
int sample_size = m_training_count;
double bootstrap_features[][];
double bootstrap_labels[];
ArrayResize(bootstrap_features, sample_size);
ArrayResize(bootstrap_labels, sample_size);
for(int i = 0; i < sample_size; i++)
{
int idx = MathRand() % m_training_count;
ArrayResize(bootstrap_features[i], m_input_features);
ArrayCopy(bootstrap_features[i], m_training_features[idx]);
bootstrap_labels[i] = m_training_labels[idx];
}
//--- Build tree (simplified)
m_trees[tree].node_count = 0;
ArrayResize(m_trees[tree].nodes, 100); // Max 100 nodes
ArrayResize(m_trees[tree].feature_importance, m_input_features);
//--- Create root node
TreeNode root;
root.is_leaf = false;
root.feature_index = MathRand() % m_input_features;
root.threshold = 0; // Simplified
root.left_child = -1;
root.right_child = -1;
//--- For simplicity, create a shallow tree
double sum_positive = 0;
double count_positive = 0;
for(int i = 0; i < sample_size; i++)
{
if(bootstrap_labels[i] > 0)
{
sum_positive++;
count_positive++;
}
}
root.prediction = (count_positive > sample_size / 2) ? 1 : -1;
root.is_leaf = true; // Simplified to single node
m_trees[tree].nodes[0] = root;
m_trees[tree].node_count = 1;
}
}
//+------------------------------------------------------------------+
//| Simplified tree prediction |
//+------------------------------------------------------------------+
double CMLPredictor::PredictWithTree(DecisionTree &tree, double &features[])
{
//--- Simplified: just return root prediction
if(tree.node_count > 0)
return tree.nodes[0].prediction;
return 0;
}
//+------------------------------------------------------------------+
//| Placeholder for backpropagation |
//+------------------------------------------------------------------+
void CMLPredictor::BackPropagation(double &inputs[], double &targets[])
{
//--- Simplified implementation
//--- In production, implement full backpropagation algorithm
}
//+------------------------------------------------------------------+
//| Placeholder for weight updates |
//+------------------------------------------------------------------+
void CMLPredictor::UpdateWeights()
{
//--- Simplified implementation
//--- In production, implement gradient descent weight updates
}
//+------------------------------------------------------------------+
//| Placeholder for gradient boosting |
//+------------------------------------------------------------------+
void CMLPredictor::TrainGradientBoosting()
{
//--- Simplified implementation
TrainRandomForest(); // Use random forest as fallback
}
//+------------------------------------------------------------------+
//| Evaluate model performance |
//+------------------------------------------------------------------+
void CMLPredictor::EvaluateModel(double &test_features[][], double &test_labels[])
{
int test_count = ArrayRange(test_features, 0);
if(test_count == 0) return;
int true_positive = 0;
int true_negative = 0;
int false_positive = 0;
int false_negative = 0;
for(int i = 0; i < test_count; i++)
{
//--- Make prediction
MLPrediction pred = Predict(_Symbol); // Simplified
//--- Compare with actual
bool predicted_buy = (pred.confidence > 0.6 && pred.direction == ORDER_TYPE_BUY);
bool actual_buy = (test_labels[i] > 0.5);
if(predicted_buy && actual_buy)
true_positive++;
else if(!predicted_buy && !actual_buy)
true_negative++;
else if(predicted_buy && !actual_buy)
false_positive++;
else
false_negative++;
}
//--- Calculate metrics
m_accuracy = (double)(true_positive + true_negative) / test_count;
if(true_positive + false_positive > 0)
m_precision = (double)true_positive / (true_positive + false_positive);
else
m_precision = 0;
if(true_positive + false_negative > 0)
m_recall = (double)true_positive / (true_positive + false_negative);
else
m_recall = 0;
if(m_precision + m_recall > 0)
m_f1_score = 2 * m_precision * m_recall / (m_precision + m_recall);
else
m_f1_score = 0;
}
//+------------------------------------------------------------------+
//| Save model to file |
//+------------------------------------------------------------------+
bool CMLPredictor::SaveModel(string filename)
{
string full_path = m_model_path + filename;
int handle = FileOpen(full_path, FILE_WRITE|FILE_BIN);
if(handle == INVALID_HANDLE)
return false;
//--- Save model parameters
FileWriteInteger(handle, m_model_type);
FileWriteInteger(handle, m_input_features);
FileWriteInteger(handle, m_output_classes);
FileWriteDouble(handle, m_learning_rate);
//--- Save feature scaling
for(int i = 0; i < m_input_features; i++)
{
FileWriteDouble(handle, m_feature_mean[i]);
FileWriteDouble(handle, m_feature_std[i]);
}
//--- Save model-specific data
if(m_model_type == ML_NEURAL_NETWORK && m_use_deep_learning)
{
//--- Save network architecture
FileWriteInteger(handle, m_layer_count);
for(int layer = 0; layer < m_layer_count; layer++)
{
FileWriteInteger(handle, m_layers[layer].input_size);
FileWriteInteger(handle, m_layers[layer].output_size);
//--- Save weights
for(int i = 0; i < m_layers[layer].output_size; i++)
{
for(int j = 0; j < m_layers[layer].input_size; j++)
{
FileWriteDouble(handle, m_layers[layer].weights[i][j]);
}
}
//--- Save biases
for(int i = 0; i < m_layers[layer].output_size; i++)
{
FileWriteDouble(handle, m_layers[layer].biases[i]);
}
}
}
FileClose(handle);
return true;
}
//+------------------------------------------------------------------+
//| Load model from file |
//+------------------------------------------------------------------+
bool CMLPredictor::LoadModel(string filename)
{
string full_path = m_model_path + filename;
if(!FileIsExist(full_path))
return false;
int handle = FileOpen(full_path, FILE_READ|FILE_BIN);
if(handle == INVALID_HANDLE)
return false;
//--- Load model parameters
m_model_type = (ENUM_ML_MODEL)FileReadInteger(handle);
m_input_features = FileReadInteger(handle);
m_output_classes = FileReadInteger(handle);
m_learning_rate = FileReadDouble(handle);
//--- Load feature scaling
ArrayResize(m_feature_mean, m_input_features);
ArrayResize(m_feature_std, m_input_features);
for(int i = 0; i < m_input_features; i++)
{
m_feature_mean[i] = FileReadDouble(handle);
m_feature_std[i] = FileReadDouble(handle);
}
//--- Load model-specific data
if(m_model_type == ML_NEURAL_NETWORK)
{
//--- Load network architecture
m_layer_count = FileReadInteger(handle);
ArrayResize(m_layers, m_layer_count);
for(int layer = 0; layer < m_layer_count; layer++)
{
m_layers[layer].input_size = FileReadInteger(handle);
m_layers[layer].output_size = FileReadInteger(handle);
//--- Load weights
ArrayResize(m_layers[layer].weights, m_layers[layer].output_size);
for(int i = 0; i < m_layers[layer].output_size; i++)
{
ArrayResize(m_layers[layer].weights[i], m_layers[layer].input_size);
for(int j = 0; j < m_layers[layer].input_size; j++)
{
m_layers[layer].weights[i][j] = FileReadDouble(handle);
}
}
//--- Load biases
ArrayResize(m_layers[layer].biases, m_layers[layer].output_size);
for(int i = 0; i < m_layers[layer].output_size; i++)
{
m_layers[layer].biases[i] = FileReadDouble(handle);
}
//--- Initialize activations
ArrayResize(m_layers[layer].activations, m_layers[layer].output_size);
}
}
FileClose(handle);
return true;
}
#endif // ML_PREDICTOR_MQH