//+------------------------------------------------------------------+ //| Andean Oscillator.mq4 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //#property strict // There is no property strict !! //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ extern datetime BeginCollectTime = D'2023.06.14 15:20:00'; // We begin collecting data for the EMA from this time extern datetime BeginTradeTime = D'2023.06.14 15:20:00'; // We begin trading from this time; this time must be at least 9 minutes ahead of BeginCollectTime extern double BaseATRMultiplier = 3; extern double StopATRMultiplier = 1.15; extern double ProfitATRMultiplier = 2.05; extern double RiskPercent = 2; extern double BidAskDistance = 0.00011; double nz(double v, double r){ if(v == EMPTY_VALUE) v = r; return r; } int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { datetime CurrentTime = TimeCurrent(); static int MinutesCounter = 1; static bool SignalForBuy = false; // We only want to buy one open trade, we use this flag for this purpose. static bool SignalForSell = false; // We only want to buy one sell trade, we use this flag for this purpose. static double BearishComponent[200]; static double BullishComponent[200]; static double Signal[200]; static double MaxBullBear[200]; double Length = 50; double SignalLength = 9; int SignalLengthInt = 9; double Alpha = 2/(Length+1); double AlphaS = 2/(SignalLength+1); double SignalNominator; // For the EMA calculation double SignalDenominator; // For the EMA calculation static double up1[200]; // Arrays for the Andean Oscillator calculator static double up2[200]; static double dn1[200]; static double dn2[200]; double BarOpen; double BarClose; double ATR; double Balance; double LotSize; double StopLoss; double TakeProfit; double ClosePrice; static int Ticket1 = 0; static int Ticket2 = 0; int i; up1[0] = 0; up2[0] = 0; dn1[0] = 0; dn2[0] = 0; BearishComponent[0] = 0; BullishComponent[0] = 0; Signal[0] = 0; if (CurrentTime > BeginCollectTime + (MinutesCounter*60)) // We do the following operations once per 1 minute, after a candle closes { Alert("One minute has passed."); Balance = AccountBalance(); // We calculate lot size, stoploss and take profit here. ATR = iATR(0,0,14,1); ClosePrice = iClose(NULL,0,1); StopLoss = BaseATRMultiplier*StopATRMultiplier*ATR; TakeProfit = BaseATRMultiplier*ProfitATRMultiplier*ATR; LotSize = NormalizeDouble(((Balance*(RiskPercent/100))/(BaseATRMultiplier*StopATRMultiplier*ATR))*0.00001,2); //=========================== We calculate the Andean Oscillator parameters here ========================================================================================================================== BarOpen = iOpen(NULL,0,1); BarClose = iClose(NULL,0,1); // This is the Andean Oscillator indicator from Tradingview: /* up1 := nz(math.max(C, O, up1[1] - (up1[1] - C) * alpha), C) up2 := nz(math.max(C * C, O * O, up2[1] - (up2[1] - C * C) * alpha), C * C) dn1 := nz(math.min(C, O, dn1[1] + (C - dn1[1]) * alpha), C) dn2 := nz(math.min(C * C, O * O, dn2[1] + (C * C - dn2[1]) * alpha), C * C) //Components bull = math.sqrt(dn2 - dn1 * dn1) bear = math.sqrt(up2 - up1 * up1) signal = ta.ema(math.max(bull, bear), sig_length) */ // Here we calculate the Andean Oscillator in MQL4 (calculation of Components): up1[MinutesCounter+1] = nz(MathMax(BarClose, MathMax(BarOpen, up1[MinutesCounter] - ((up1[MinutesCounter] - BarClose)*Alpha))),BarClose); up2[MinutesCounter+1] = nz(MathMax(BarClose*BarClose, MathMax(BarOpen*BarOpen, up2[MinutesCounter] - (up2[MinutesCounter] - (BarClose*BarClose)*Alpha))),BarClose*BarClose); dn1[MinutesCounter+1] = nz(MathMin(BarClose, MathMin(BarOpen, dn1[MinutesCounter] + ((BarClose-dn1[MinutesCounter])*Alpha))),BarClose); dn2[MinutesCounter+1] = nz(MathMin(BarClose*BarClose, MathMin(BarOpen*BarOpen, dn2[MinutesCounter] + (((BarClose*BarClose)-dn2[MinutesCounter])*Alpha))),BarClose*BarClose); BullishComponent[MinutesCounter] = MathSqrt(dn2[MinutesCounter] - (dn1[MinutesCounter] * dn1[MinutesCounter])); BearishComponent[MinutesCounter] = MathSqrt(up2[MinutesCounter] - (up1[MinutesCounter] * up1[MinutesCounter])); MaxBullBear[MinutesCounter] = MathMax(BullishComponent[MinutesCounter],BearishComponent[MinutesCounter]); // Here we calculate the Andean Oscillator in MQL4 (calculation of Signal): SignalNominator = 0; SignalDenominator = 0; for (i=1; i<=SignalLengthInt; i++) { SignalNominator = SignalNominator + (MaxBullBear[MinutesCounter - (SignalLengthInt-i)] * MathPow(1-AlphaS,i-1) ); // Formula for calculation of exponential moving averages SignalDenominator = SignalDenominator + MathPow(1-AlphaS,i-1); // this formula is from here: https://www.alpharithms.com/moving-averages-083315/ } Signal[MinutesCounter] = NormalizeDouble(SignalNominator / SignalDenominator,3); //=========================== End of calculating the Andean Oscillator parameters here ========================================================================================================================== if (CurrentTime > BeginTradeTime ) // At this time, 9 candles have already passed with data collection, so we can begin trading with the right 9-period EMA { Alert("BearishComponent = ", BearishComponent[MinutesCounter]); // We check here, if the components are calculated correctly Alert("BullishComponent = ", BullishComponent[MinutesCounter]); Alert("Signal = ", Signal[MinutesCounter]); if (SignalForBuy == false) // Send BUY order only once. { if ( BullishComponent[MinutesCounter] - Signal[MinutesCounter] >= 3 ) // If the Bullish Component of Andean is larger than the Signal Component of Andean by 3, then we buy. { SignalForBuy = true; // This flag makes sure, that we send BUY order only once Alert("Vétel: ", LotSize); Ticket1 = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 12, ClosePrice - StopLoss - BidAskDistance, ClosePrice + TakeProfit - BidAskDistance, "Buy Order"); Alert("Ticket number: ", Ticket1); } } if (SignalForSell == false) // Send SELL order only once. { if ( BearishComponent[MinutesCounter] - Signal[MinutesCounter] >= 3 ) // If the Bearish Component of Andean is larger than the Signal Component of Andean by 3, then we sell. { SignalForSell = true; // This flag makes sure, that we send BUY order only once Alert("Eladás: ", LotSize); Ticket2 = OrderSend(Symbol(), OP_SELL, LotSize, Bid, 12, ClosePrice + StopLoss + BidAskDistance, ClosePrice - TakeProfit + BidAskDistance, "Buy Order"); Alert("Ticket number: ", Ticket2); } } } MinutesCounter = MinutesCounter + 1; // We step one minute further, this ensures, that the above block is only executed once per minute } }