mql5/Shared Projects/ERMT-ML/Modules-ML8x/MLPredictor.mqh

992 lines
32 KiB
MQL5
Raw Permalink Normal View History

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
//+------------------------------------------------------------------+
//| 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