//+------------------------------------------------------------------+ //| RL_ONNX_EA.mq5 | //| Copyright 2026, Algorembrant | //| Rembrant Oyangoren Albeos | //+------------------------------------------------------------------+ #property copyright "Algorembrant, Rembrant Oyangoren Albeos" #property link "https://github.com/Algorembrant" #property version "1.00" #include CTrade trade; // Inputs compatible with the RL training setup input string ONNX_Filename = "RL_Agent_XAUUSD.onnx"; input double RiskPercent = 2.0; long model_handle = INVALID_HANDLE; double max_lot_size = 20.0; int OnInit() { Print("Initializing RL XAUUSDc ONNX EA..."); // Load the ONNX model trained in Google Colab model_handle = OnnxCreate(ONNX_Filename, ONNX_DEFAULT); if(model_handle == INVALID_HANDLE) { Print("Error loading ONNX model ", ONNX_Filename, " : ", GetLastError()); return INIT_FAILED; } trade.SetExpertMagicNumber(2026101); // 2026 methodologies return INIT_SUCCEEDED; } void OnDeinit(const int reason) { if(model_handle != INVALID_HANDLE) OnnxRelease(model_handle); Print("EA Deinitialized."); } void OnTick() { // Strictly execute on close-price only (Wait for new bar generation) static datetime last_time = 0; datetime current_time = iTime(_Symbol, _Period, 0); // If the bar hasn't closed / new bar hasn't opened, do nothing if(current_time == last_time) return; last_time = current_time; // --- 1. Fetch data & Indicators // The ONNX model requires the exact 100+ vectorized attributes as built by pandas_ta in python. // In this production script, we construct the input float array shape based on observation_space. // Ensure length matches `features.shape[1]` exactly. float features[]; int num_features = 100; // MUST MATCH exactly the CSV features ArrayResize(features, num_features); for(int i=0; i 0) return; // StopLoss distance constraints: SL distance never less than spread * 10 double sl_dist = MathMax(closePrice * 0.005, spread * 10.0); // Calculate Sizing (2% Risk) double balance = AccountInfoDouble(ACCOUNT_BALANCE); double risk_amount = balance * (RiskPercent / 100.0); // MT5 Standard contract size computation for Gold (usually $100 per lot per $1) double sl_dollar_risk_per_lot = sl_dist * 100.0; double lots = 0.01; if(sl_dollar_risk_per_lot > 0) lots = risk_amount / sl_dollar_risk_per_lot; // Fragmentize execution cap lots = MathRound(lots * 100.0) / 100.0; if(lots < 0.01) lots = 0.01; // Fragmenting Logic: Open multiple positions if lot size exceeds cap int fragments = 1; double current_fragment_lot = lots; if(lots > max_lot_size) { fragments = (int)MathCeil(lots / max_lot_size); current_fragment_lot = max_lot_size; Print("Notice: Position fragmentization triggered. Total Lot = ", lots, " -> Fragmented into ", fragments, " orders."); } if(action == 0) { // BUY double stoploss = ask - sl_dist; double takeprofit = ask + (sl_dist * 1.5); // TP >= 1R for(int f=0; f max_lot_size) { // Remaining fraction stringency current_fragment_lot = lots - (max_lot_size * (fragments - 1)); } trade.Buy(current_fragment_lot, _Symbol, ask, stoploss, takeprofit, "RL_BUY"); } } else if(action == 1) { // SELL double stoploss = bid + sl_dist; double takeprofit = bid - (sl_dist * 1.5); // TP >= 1R for(int f=0; f max_lot_size) { current_fragment_lot = lots - (max_lot_size * (fragments - 1)); } trade.Sell(current_fragment_lot, _Symbol, bid, stoploss, takeprofit, "RL_SELL"); } } }