Files
xMQL4/Docs/Samples/Expert.Advisor.Tutorial.md
T
2024-01-25 04:03:36 +03:30

9.5 KiB

EA Tutorials

in this tutorial we cover this titles step by step:

  1. Create new Expert Advisor
  2. Variables
  3. Functions
  4. Control Structures
  5. Read Indicator Data
  6. Open Trades
  7. Modify Trades
  8. Close Trades

Create new Expert Advisor

in meta editor (f4, tools > meta editor), click on new and select expert adviser.

as you know all mql programs runing based on event handlers.

there are three main event handlers, which used in an EA:

  • OnInit // runs each time tf changes, or ea attached ...
  • OnDeinit // runs when ea removed from chart ...
  • OnTick // most important function, all of business logics implemented here ...

you can see all of it's documents on proppered file.

the main feature of an EA in MQL, is there are some features which helps us. such as notification of signals and auto trading abbility.

Variables

usually used to store some values of specific Data Types. so this is much better to see supported datat types in documentations.

for using variables, you had to define a variable, also you can set init value of it's supported data type. each variable must be specific it's own data type.

each variable defined by assign a name to it.

so by using this name you can assign value to it or read it assigned value ...

Functions

in programming, a function can get some params and do some actions on them and return a result. doing some actions is the permanent part of it's definition. this means a function can only do a simple action and not have any params, and not have any return type.

each function must contain a unioque name.

in scope of project you can call a function by providing it's name and passing required params and also gives it's result.

Control Structures

conditional operators gives an expression and determines it's result is true or false. there are many commands in programming which used a conditional expression to act based on it's result. by this way you can make your own business logic to control programming flow, or data flow or anything you want.

most commonly used conditional command is if command, which used like this syntax:

//
if (conditional_expression) {
    //
    // Blocks of code which run when conditional expression is true ...
} else {
    //
    // Blocks of code which run when conditional expression is false ...
}

//
also we can make loops in programing, a loop is a code blocks which runs until a condition happens.
there are many type of loops in programming languages.

most commonly used loops is create using for command by following this syntax:

for (int i; i <= 6; i++) {
    //
    // Loop Code Block ...
    Print("Loop Itrator: ", i);
}

Read Indicator Data

in this example we specially use RSI indicator. but you can replace this by any other indicator you want, strusture is same;

RSI Indicator provide a value for each candle and draw a line. this value is between 0 and 100;

Note each standard indicator in MQL has a related function, which is usually starts with i{IndicatorName}, such as iRSI, iIchimoku and etc. this functions, return specific values related to Indicator Data. by calling this functions you can capture Indicator data for specific types of inputs.

there are some standard inputs which usually used as params in iFunctions which i describe them in following:

  • Symbol: reffer to which symbol you need to inject it's data from indicator. (_Symbol)
  • Period: reffer to which Time Frame you need to inject symbol's data on it from indicator (CURRENT_PERIOD).
  • ...

as i described before all candle related data, or indicators data, usually stores in Buffers. by calling iFunctions, you retrieve an integer result, which it's an index number that point to a Buffer. for using it's value, you had to create a Buffer on top of it.

//
// here we define a pointer to iFunction buffer ...
// for reading values, each time we need we had to define
// a global pointer and then fill it on Init handler ...
int rsiPointer = iRSI(_Symbol, _Period, 14, PRICE_CLOSE);

//
// define a dynamic size array, which calls Buffer ...
double rsiBuffer[];

//
// fill defined Buffer by iFunction Pointer ...
CopyBuffer(rsiPointer, 0, 1, 1, s);

Note there are some different ways in MQL4 and MQL5 to read the Pointer value. as i think this above described method is for MQL5, since in MQL4 for each bar_index, you shoud to call the iFunction once, by passing the bar to it ...

Open Trades

as i described before, one of the main features an EA Programs, which used commonly is to Open Trade positions and specific conditions.

imagine that we want to send signal for Long and Short positions, based on rsi value. the condition is when rsi value at the current candle is abopve than 70, means Bullish Signal, and otherwise if it is below than 30 means Bearish Signal.

we can handle this in OnTick event handler like this:

//
// Prepare RSI Buffer ...
double rsi[];
CopyBuffer(rsiPointer, 0, 1, 1, rsi);

//
// Prepare Signal Conditions ...
if (rsi[0] > 70) {
    //
    // Bullish Signal ...
} else if (rsi[0] < 30) {
    //
    // Bearish Signal ...
}

we need to open position based on above Trading Conditions.

at the first step we have to include Trade library in our EA Project.

//
// here we include header file ...
#include <Trade/Trade.mqh>

...

//
// now we have to define an instance of CTrade class to manipulate Positions ...
CTrade trader;
...

after create CTrade instance, we have to use it in right way and right place to manipulate positions:

//
// Prepare Signal Conditions ...
if (rsi[0] > 70) {
    //
    // Bearish Signal ...
    trader.Sell(0.001, _Symbol);
} else if (rsi[0] < 30) {
    //
    // Bullish Signal ...
    trader.Buy(0.01. _Symbol);
}

in above example, we just open positions and there is no access to them for manipulate them. we have to specify unique id to each position and store them somewhere in our EA to next times we have to manage or manipulate positions, simply reffer to them ...

//
// Prepare Signal Conditions ...
if (rsi[0] > 70) {
    //
    // Bearish Signal ...
    trader.Sell(0.001, _Symbol);
    ulong ticket = trader.ResultOrder();
} else if (rsi[0] < 30) {
    //
    // Bullish Signal ...
    // we can provide tp and sl on positions ...
    trader.Buy(0.01. _Symbol);
    ulong ticket = trader.ResultOrder();
}

we can simply check ticket as a global variable and then before opening new position, check it's value and then provide business logic ...

Modify Trades

before do any manipulation on a position, we have to select the position itself ...

PositionSelectByTicket is a Method which used to select a position by providing it's ticket id. this returns a boolean value which determines position selected correctly or not ...

here are some resources related to position.

for modifying an specific position, we have to use this function like following:

//
// assume that this value filled on opening a position ...
ulong positionTicket;

//
// validate position selectedsuccessfully, then try
// to manipulate it ...
if (PositionSelectByTicket(positionTicket)) {
    //
    // Do what ever we want to modify on popsition ...
    
    //
    // reading some Position info ...
    double positionPrice = PositionGetDouble(POSITION_PRICE_OPEN);
    double positionTP = PositionGetDouble(POSITION_TP);
    double positionSL = PositionGetDouble(POSITION_SL);
    
    //
    // detect Position Type ...
    // POSITION_TYPE_BUY
    // POSITION_TYPE_SELL
    int positionType = PositionGetInteger(POSITION_TYPE);
    
    //
    // Check Position has SL ...
    if (positionSL == 0) {
        //
        // here we calculate and define SL and TP for position ...
        double sl = 0; 
        double tp = 0; 

        //
        // then we use PositionModify method to apply our changes on specified Position ...
        trader.PositionModify(positionTicket, sl, tp);
    }
}

Close Trades

some times we need to conditionally close an open position. maybe some times we got a reversal signal or anything else, based on our EA Business Logic. for this we can also check positionTicket must be greater than zero.

in following code, we update above sample to add supports for close last open position, before opening another one ...

//
// Prepare Signal Conditions ...
if (rsi[0] > 70) {
    //
    // close last open position ...
    // this condition means there are an open position ...
    if (positionTicket > 0 && PositionSelectByTicket(positionTicket)) {
        //
        // retrieve Position Type ...
        int positionType = PositionGetInteger(POSITION_TYPE);
        if (positionType == POSITION_TYPE_BUY) {
            //
            // Close Position ...
            trade.PositionClose(positionTicket);

            //
            positionTicket = 0;
        }
    }

    //
    // Bearish Signal ...
    trader.Sell(0.001, _Symbol);
    positionTicket = trader.ResultOrder();
} else if (rsi[0] < 30) {
    //
    // close last open position ...
    // this condition means there are an open position ...
    if (positionTicket > 0 && PositionSelectByTicket(positionTicket)) {
        //
        // retrieve Position Type ...
        int positionType = PositionGetInteger(POSITION_TYPE);
        if (positionType == POSITION_TYPE_SELL) {
            //
            // Close Position ...
            trade.PositionClose(positionTicket);

            //
            positionTicket = 0;
        }
    }

    //
    // Bullish Signal ...
    // we can provide tp and sl on positions ...
    trader.Buy(0.01. _Symbol);
    positionTicket = trader.ResultOrder();
}