//+------------------------------------------------------------------+ //| Brent EA.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //Libraries #include CTrade ExtTrade; #include ATRTrailingStop ExtATRTrailingStop; //Inputs input double atr_multiple = 5.0; input double lot_multiple = 1.0; input double profit_target = 10; input double max_loss = 20; input int position_size = 2; //Set this value between 0 and 1 to control how much data is used double consumption = 0.01; //We want to know which symbol has the least number of bars. double brent_bars = (double) NormalizeDouble((iBars("UK Brent Oil",PERIOD_CURRENT) * consumption),0); double wti_bars = (double) NormalizeDouble((iBars("WTI_OIL",PERIOD_CURRENT) * consumption),0); //Select the lowest double max_bars = (brent_bars < wti_bars) ? brent_bars : wti_bars; //How far into the future are we forecasting int look_ahead = (int)NormalizeDouble((max_bars / 4), 0); //How many bars should we fetch? int fetch = (int)(max_bars - look_ahead) - 1; //Matrix A stores our inputs. y is the output. x is the coefficients. matrix A = matrix::Zeros(fetch,6); matrix y = matrix::Zeros(fetch,1); vector wti_price = vector::Zeros(fetch); vector brent_price = vector::Zeros(fetch); vector spread; vector intercept = vector::Ones(fetch); matrix x = matrix::Zeros(6,1); double forecast = 0; double ask = 0; double bid = 0; double min_volume = 0; string brent = "BRN"; // تغییر به نام نماد Brent در بروکر شما string wti = "WTI"; // تغییر به نام نماد WTI در بروکر شما bool model_initialized = false; int OnInit() { //Initialise trailing stops if(atr_multiple > 0) ExtATRTrailingStop.Init(atr_multiple); min_volume = SymbolInfoDouble(brent,SYMBOL_VOLUME_MIN); return(INIT_SUCCEEDED); //--- } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- ask = SymbolInfoDouble(brent,SYMBOL_ASK); bid = SymbolInfoDouble(brent,SYMBOL_BID); if(model_initialized) { if(PositionsTotal() == 0) { forecast = 0; forecast = ModelForecast(); InterpretForecast(); } else { ManageTrades(); } } else { model_initialized = InitializeModel(); } } //+------------------------------------------------------------------+ void ManageTrades() { if(AccountInfoDouble(ACCOUNT_PROFIT) > profit_target) CloseAll(); if(AccountInfoDouble(ACCOUNT_PROFIT) < (-1 * max_loss)) CloseAll(); } void InterpretForecast() { if(forecast != 0) { double current_close = iClose(brent, PERIOD_CURRENT, 0); Print("Comparing Forecast: ", forecast, " with Current Close: ", current_close); if(forecast > current_close) { check_buy(); } else if(forecast < current_close) { check_sell(); } } else { Print("Forecast is zero, no action taken."); } } void check_buy() { if(PositionsTotal() == 0) { for(int i = 0; i < position_size; i++) { if(ExtTrade.Buy(lot_multiple * min_volume, brent, ask, 0, 0, "BUY")) Print("Buy order placed successfully."); else Print("Buy order failed. Error: ", GetLastError()); } } } void check_sell() { if(PositionsTotal() == 0) { for(int i = 0; i < position_size; i++) { if(ExtTrade.Sell(lot_multiple * min_volume, brent, bid, 0, 0, "SELL")) Print("Sell order placed successfully."); else Print("Sell order failed. Error: ", GetLastError()); } } } void CloseAll(void) { for(int i=PositionsTotal()-1; i>=0; i--) { if(PositionSelectByTicket(PositionGetTicket(i))) { if(PositionGetSymbol(i) == brent) { ulong ticket; ticket = PositionGetTicket(i); ExtTrade.PositionClose(ticket); } } } } void close_buy(){ ulong ticket; int type; if(PositionsTotal() > 0){ for(int i = 0; i < PositionsTotal();i++){ ticket = PositionGetTicket(i); type = (int)PositionGetInteger(POSITION_TYPE); if(type == POSITION_TYPE_BUY){ ExtTrade.PositionClose(ticket); } } } } void close_sell(){ ulong ticket; int type; if(PositionsTotal() > 0){ for(int i = 0; i < PositionsTotal();i++){ ticket = PositionGetTicket(i); type = (int)PositionGetInteger(POSITION_TYPE); if(type == POSITION_TYPE_SELL){ ExtTrade.PositionClose(ticket); } } } } bool InitializeModel() { if(SymbolSelect(brent, true) && SymbolSelect(wti, true)) { int brent_bars_real = iBars(brent, PERIOD_CURRENT); int wti_bars_real = iBars(wti, PERIOD_CURRENT); int max_bars_real = (brent_bars_real < wti_bars_real) ? brent_bars_real : wti_bars_real; int adjusted_max_bars = (int)(max_bars_real * consumption); look_ahead = (int)(adjusted_max_bars / 4); fetch = adjusted_max_bars - look_ahead - 1; if(fetch <= 0 || look_ahead <= 0) { Print("Error: Insufficient bars for model initialization. Max bars: ", max_bars_real); return false; } Print("Symbols Available. Bars: ", max_bars_real, " Fetch: ", fetch, " Look ahead: ", look_ahead); if(!y.CopyRates(brent, PERIOD_CURRENT, COPY_RATES_CLOSE, 1, fetch) || !brent_price.CopyRates(brent, PERIOD_CURRENT, COPY_RATES_CLOSE, (1 + look_ahead), fetch) || !wti_price.CopyRates(wti, PERIOD_CURRENT, COPY_RATES_CLOSE, (1 + look_ahead), fetch)) { Print("Error: Failed to copy historical data."); return false; } spread = brent_price - wti_price; Print("The Current Spread: ", spread); A.Resize(3, fetch); A.Row(brent_price, 0); A.Row(spread, 1); intercept.Resize(fetch); // اطمینان از اندازه درست intercept A.Row(intercept, 2); if(A.Rows() != 3 || A.Cols() != fetch) { Print("Error: A matrix size mismatch after initialization. Rows: ", A.Rows(), " Cols: ", A.Cols()); return false; } A = A.Transpose(); // [fetch, 3] y = y.Transpose(); // [fetch, 1] if(A.Cols() == 0 || y.Cols() == 0) { Print("Error occurred when copying historical data"); Print("A rows: ", A.Rows(), " y rows: ", y.Rows(), " A columns: ", A.Cols(), " y cols: ", y.Cols()); Print("A: ", A); Print("y: ", y); return false; } // محاسبه ضرایب مدل matrix pinv = A.PInv(); x = pinv.MatMul(y); Print("Model Coefficients (x): ", x); // بررسی مقادیر نامعتبر در x for(int i = 0; i < x.Rows(); i++) { if(MathIsValidNumber(x[i][0]) == false) { Print("Error: Invalid value in x at index ", i, ": ", x[i][0]); return false; } } Print("No errors occurred when copying historical data"); Print("Finished Fitting The Model"); return true; } Print("Failed to select symbols"); return false; } double ModelForecast() { if(model_initialized) { if(!brent_price.CopyRates(brent, PERIOD_CURRENT, COPY_RATES_CLOSE, 0, 1) || !wti_price.CopyRates(wti, PERIOD_CURRENT, COPY_RATES_CLOSE, 0, 1)) { Print("Error: Failed to copy forecast data."); return 0; } spread = brent_price - wti_price; Print("The Spread: ", spread); A.Resize(3, 1); A.Row(brent_price, 0); A.Row(spread, 1); vector intercept_one = vector::Ones(1); A.Row(intercept_one, 2); A = A.Transpose(); // [1, 3] // بررسی اندازه x if(x.Rows() != 3 || x.Cols() != 1) { Print("Error: Invalid x matrix size. Rows: ", x.Rows(), " Cols: ", x.Cols()); return 0; } double _forecast = (A[0][0] * x[0][0]) + (A[0][1] * x[1][0]) + (A[0][2] * x[2][0]); Print("Forecast: ", _forecast, " Current Close: ", iClose(brent, PERIOD_CURRENT, 0)); if(!MathIsValidNumber(_forecast)) { Print("Error: Forecast is invalid (nan or inf)."); return 0; } return _forecast; } return 0; }