Files
xMQL4/Docs/Samples/CCI.EA.SL.TP.Tutorial.md
T
2024-01-25 04:03:36 +03:30

12 KiB

CCI EA With SL and TP

this tutorial consists 5 part:

  1. Create a CCI EA with SL and TP;
  2. add a Moving Average Filter on a higher Timeframe;
  3. add a Partial Close;
  4. add a Break Event Stop;
  5. Backtesting;

Create a CCI EA with SL and TP

CCI is an Oscillator which provides some usefull data about iver baughts and over solds. each of this situations can used as a signal.

the general idea in this tutorial is to use this states as a signal and then open and close positions based on them ...

Create a Expert Advisor and named it what you want.

now we have to read CCI data. create a pointer to it's iFunction and then create a buffer based on it on OnTick function. we can now create a buy and sell conditions and check where this happens to open the positions.

the idea is when cci going above special level we get buy signal and when going below special level we get sell signal.

for implement this mechanism, first add two input for buyLevel and sellLevel and give them default values.

#include <Trade/Trade.mqh>

//
CTrade trader;

//
input double Lots = 1;
input double TpPoints = 100;
input double SlPoints = 100;

//
input double CciBuyLevel = -150;
input double CciSellLevel = 150;

//
int barsTotal;

//
int OnInit() {
    //
    barsTotal = iBars(_Symbol, CciTimeFrame);

    //
    OnTick();

    //
    return INIT_SUCCEEDED;
}

//
void OnTick() {
    //
    // for every single tick, we check current amount of bars
    // for preventing double signaling on single bar ...
    int bars = iBars(_Symbol, CciTimeframe);
    if (barsTotal < bars) {
        //
        barsTotal = bars;

        //
        double cci[];
        CopyBuffer(cciPointer, 0, 1, 2, cci);

        //
        // Buy Signal Condition ...
        if (cci[1] < CciBuyLevel && cci[0] > CciBuyLevel) {
            //
            // Do Buy Trade ...
            
            //
            // retrieve ask price ...
            // since trader.Buy alway use market price (ask price) ...
            double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); 

            //
            // Normalize ask price ...
            ask = NormalizeDouble(ask, _Digits);

            //
            // Calculating Tp based on Ask price ...
            double tp = ask + TpPoints * _Point;
            tp = NormalizeDouble(tp, _Digits);


            //
            // Calculating Sl based on Ask price ...
            double sl = ask - SlPoints * _Point;
            sl = NormalizeDouble(sl, _Digits);

            //
            trader.Buy(Lots, _Symbol, ask, sl, tp, "CCI Buy ...");
        } else
        //
        // Sell Signal Condition ...
        if (cci[1] > CciSellLevel && cci[0] < CciSellLevel) {
            //
            // Do Sell Trade ...

            //
            // retrieve bid price ...
            // since trader.Sell alway use market price (bid price) ...
            double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); 

            //
            // Normalize bid price ...
            bid = NormalizeDouble(bid, _Digits);

            //
            // Calculating Tp based on Bid price ...
            double tp = bid - TpPoints * _Point;
            tp = NormalizeDouble(tp, _Digits);


            //
            // Calculating Sl based on Bid price ...
            double sl = bid + SlPoints * _Point;
            sl = NormalizeDouble(sl, _Digits);

            //
            trader.Sell(Lots, _Symbol, bid, sl, tp, "CCI Sell ...");
        }

        //
        // Show data on Chart side ...
        Comment("\nCCI[0]: ", cci[0],
                "\nCCI[1]: ", cci[1]
        );
    }
}

add a Moving Average Filter on a higher Timeframe

moving average is another usefull indicator which provides a way to following market trend direction. the idea is to accdept signals in direction of ma result. so we have to implement Moving average in our EA then use it's values for filtering signals, this is what we call MA Verifications.

attached proper inputs related to MA Indicator to your advisor.

then create a Pointer(Handler) for iFunction of MA indicator.

we have to check for buy signals, that the ask price is above than moving average. and for sell signals the bid price is below than moving average, then if this conditions are full filled, enter the positions.

void OnTick() {
    ...

    //
    // reading ma series, buffer ...
    double ma[];
    CopyBuffer(maPointer, 0, 1, 1, ma);

    //
    // Buy Signal Condition ...
    if (cci[1] < CciBuyLevel && cci[0] > CciBuyLevel) {
        //
        // Do Buy Trade ...
        
        //
        // retrieve ask price ...
        // since trader.Buy alway use market price (ask price) ...
        double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); 

        //
        // Filter by Moving Average ...
        if (ask > ma[0]) {
            ...
        }
    } else
    //
    // Sell Signal Condition ...
    if (cci[1] > CciSellLevel && cci[0] < CciSellLevel) {
        //
        // Do Sell Trade ...

        //
        // retrieve bid price ...
        // since trader.Sell alway use market price (bid price) ...
        double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); 

        //
        // Filter by Moving Average ...
        if (bid < ma[0]) {
            ...
        }
    }

    ...

    //
    // Show data on Chart side ...
    Comment("\nCCI[0]: ", cci[0],
            "\nCCI[1]: ", cci[1],
            "\nMA[0]: ", ma[0],
    );
}

add a Partial Close

partial close positions is an idea to save money more than usual in trading exit strategy. actually implementing CTrade instance provide this for us. and we can use it in our EAs.

in this section we are going to review how we can do it ...

//
// Define Some Inputs for Partial Close Positions Management ...
input int PartialClosePoints = 70;
input double PartialCloseFactor = 0.5;

...

//
void OnTick() {
    
    ...

    //
    // Calculate Ask and Bid Price values ...
    double ask = ...
    double bid = ...

    //
    // here we loop through all open Positions ...
    for (int i = PositionsTotal() - 1; i >=0; i--) {
        //
        // retrieve position ticket ...
        ulong positionTicket = PositionGetTicket(i);

        //
        // retrieve Position by it's Ticket ...
        if (PositionSelectByTicket(positionTicket)) {
            //
            // now we can check conditions ...
            
            //
            // Retrieve Position Open Price ...
            double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);

            //
            // Retrieve Position Volume ...
            double positionVolume = PositionGetDouble(POSITION_VOLUME);

            //
            // Retrieve Position Type:  Buy or Sell Position ...
            ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
            
            //
            // now we have check position volume, for prevent partialy closing a partial closed position ...
            if (positionVolume == Lots) {
                //
                // Calculate Partially close volume ...
                double lotsToClose = positionVolume * PartialCloseFactor;
                lotsToClose = NormalizeDouble(lotsToClose, 2);

                //
                // Check Position Type and do Partial Close based on Separation Type ...
                if (positionType == POSITION_TYPE_BUY) {
                    //
                    // Partialy Close Buy Positions ...
                    if (bid > positionOpenPrice + PartialClosePoints * _Point) {
                        //
                        // Try to Partially Close Position ...
                        if (trade.PositionClosePartial(positionTicket, lotsToClose)) {
                            //
                            // show a simple message ...
                            Print("Pos ", positionTicket, " was closed partially ...");
                        }
                    }
                } else if (positionType == POSITION_TYPE_SELL) {
                    //
                    // Partialy Close Sell Positions ...
                    if (ask < positionOpenPrice - PartialClosePoints * _Point) {
                        //
                        // Try to Partially Close Position ...
                        if (trade.PositionClosePartial(positionTicket, lotsToClose)) {
                            //
                            // show a simple message ...
                            Print("Pos ", positionTicket, " was closed partially ...");
                        }
                    }
                }
            }
        }
    }
}

add a Break Event Stop

some times is some trades we need to make a position risk free. this means when a position triggered at specified point of profits, move sl to specified point.

for example we have a buy position of 100.100 price. we need to move it's sl when bid price touch 100.150 to 100.105

moving sl of a position called Break Event ...

for this reason we have to specify 2 pqarams:

  • TriggerPoint: this is a value which we change sl of position when or open price of position changed by this point;
  • PufferPoint: this is a value which we change sl based on it.
void OnTick() {
    
    ...

    //
    // here we loop through all open Positions ...
    for (int i = PositionsTotal() - 1; i >=0; i--) {
        //
        // retrieve position ticket ...
        ulong positionTicket = PositionGetTicket(i);

        //
        // retrieve Position by it's Ticket ...
        if (PositionSelectByTicket(positionTicket)) {
            //
            // now we can check conditions ...

            //
            // Retrieve Position Open Price ...
            double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);

            //
            // Retrieve Position TP ...
            double positionTP = PositionGetDouble(POSITION_TP);

            //
            // Retrieve Position SL ...
            double positionSL = PositionGetDouble(POSITION_SL);

            //
            // Retrieve Position Volume ...
            double positionVolume = PositionGetDouble(POSITION_VOLUME);

            //
            // Retrieve Position Type:  Buy or Sell Position ...
            ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);

            //
            // Check Position Type and do Partial Close based on Separation Type ...
            if (positionType == POSITION_TYPE_BUY) {
                //
                // Break Event Buy Positions ...

                //
                // Check if Price recive to value for changing sl ...
                if (bid > positionOpenPrice + BETriggerPoint * _Point) {
                    //
                    // Calculate new SL Price ...
                    double sl = positionOpenPrice + BEPufferPoint * _Points;
                    sl = NormalizeDouble(sl, _Digits);

                    //
                    // Check new Calculated SL be Bigger than current SL ...
                    if (sl > positionSL) {
                        //
                        // Modify Trade and Change it's SL ...
                        if (trader.PositionModify(positionTicket, sl, positionTp)) {
                            //
                            Print("Pos ", poistionTicket, " was saved as Break Event ...");
                        }
                    }
                }
            } else if (positionType == POSITION_TYPE_SELL) {
                //
                // Break Event Sell Positions ...

                //
                // Check if Price recive to value for changing sl ...
                if (ask < positionOpenPrice - BETriggerPoint * _Point) {
                    //
                    // Calculate new SL Price ...
                    double sl = positionOpenPrice - BEPufferPoint * _Points;
                    sl = NormalizeDouble(sl, _Digits);

                    //
                    // Check new Calculated SL be Bigger than current SL ...
                    if (sl < positionSL) {
                        //
                        // Modify Trade and Change it's SL ...
                        if (trader.PositionModify(positionTicket, sl, positionTp)) {
                            //
                            Print("Pos ", poistionTicket, " was saved as Break Event ...");
                        }
                    }
                }
            }
        }
    }
}

Backtesting

you must use Strategy tester in back test ...