Job finished
Specification
I would like you to fix my MQL4 expert advisor source code, which now gives wrong results. It calculates the Andean Oscillator parameters. The PineScript code for the Andean Oscillator can be found in Tradingview, but I have also included in my code in the comments. The Alerts should give the correct Andean Oscillator Bullish Component, Bearish Component and Signal, just as they are shown in Tradingview. Feel free to change any part of the code, if necessary. I have also attached the code as a file.
Here is the code:
//+------------------------------------------------------------------+
//| 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
}
}