Function library and Experts for trailing / Yury Dzyuban – library MetaTrader 4


The algorithm for maintaining and closing a position is known to be almost more important that the rules for opening it. And sometimes a change in the trailing system can cause quite drastic changes in trading performance – either the increase or decrease of the latter. This is a library of functions for maintaining open positions, which I used in the construction of my systems.


The presented functions were based on some of the most popular trailing algorithms, others are, perhaps, my original developments, or at least I have not seen them before. The functions are easy to include/pick, which allows to quickly apply them to an entry system to test different trailing scenarios. The presented functions are elementary and allow, if necessary, to construct more complex trailing algorithms on their basis. The functions are very different, written to simplify the procedure of building new EAs.


So, the functions themselves:

1. Trailing by shadows of N last bars.

void TrailingByShadows(int ticket,int tmfrm,int bars_n, 
                       int indent,bool trlinloss)

The function implements stop loss trailing by the lowest Low (for long positions) or highest High (for short positions) of the specified number of bars on the current timeframe or other than current.

Parameters:

ticket – unique order number (selected before the call to the function using OrderSelect());
tmfrm – the timeframe, the bars of which are used for trailing (options – 1, 5, 15, 30, 60, 240, 1440, 10080, 43200);
bars_n – the number of bars to determine the stop loss level (not less than 1);
indent – the indent(in points) from the selected High/Low to place the stop loss (not less than 0);
trlinloss – whether to move the stop loss in an “unprofitable” area, i.e. in the interval between the initial stop loss and the opening price (true – trail, false – trailing is only activated if the new stop loss is “better” than the opening price, “in profit”).
This type of trailing was originally seen in the description of the tactic by V. Barishpolts “Average breakout on daily charts”, that suggested to trail the stop loss by Low (for buys) or High (for sells) of the latest 2 bars (candles) on a daily timeframe. This algorithm trails surprisingly “nice” (try to “look around” the chart “with your eyes”), allows to survive the rollbacks (the depth depends on the specified number of bars, bars_n) and the periods of volatility deterioration. (By definition) it is triggered when the next bar closes, even if it is used on every tick. I mainly use it on the daily charts to trail 2-4 (most often) latest bars.

2. Trailing by X-bar fractals.

void TrailingByFractals(int ticket,int tmfrm,int frktl_bars,
                        int indent,bool trlinloss)

The function trails the stop loss by the fractal extremums of the specified size (i.e. the number of bars included in the fractal) on the specified timeframe. As it is known, the “classic” fractal (by Williams, if I am not mistaken) is a combination of 5 bars. But then I thought – why not use the “other” sizes – from 3 bars and more, including paired numbers of bars (in the latter case the number of bares after the extremum will be greater than before the extremum when moving “into the past”).

Parameters:

ticket – unique order number (selected before the call to the function using OrderSelect());
tmfrm – the timeframe, the bars of which are used for trailing (options – 1, 5, 15, 30, 60, 240, 1440, 10080, 43200);
bars_n – the number of bars included in the fractal (not less than 3);
indent – the indent(in points) from the extremum of the latest fractal to place the stop loss (not less than 0);
trlinloss – whether to move the stop loss in an “unprofitable” area, i.e. in the interval between the initial stop loss and the opening price (true – trail, false – trailing is only activated if the new stop loss is “better” than the opening price, “in profit”).
In several Russian Forex-related forums it was stated that “fractal based trailing is good on a lower timeframe”. As the fractals are essentially local extremums, trailing by them is also basically trailing by local extremums. The idea is not new and quite robust, and has been used by many famous traders (aforementioned Williams, if I am not mistaken). It allows to survive the rollbacks and “choose” the noticeable movements rather good, does not work well during a flat (from personal experience). Like the previous one, this function “trails” at formed bars. If necessary, the parameters can be changed dynamically (withing the position “lifespan”). For example, during a rapid “growth” of the profit (e.g. at a strong trend), “roughen” its sensitivity by switching to a higher timeframe or by increasing the number of bars in a fractal. Or conversely, increase the sensitivity during volatility falls by switching to a smaller timeframe or by decreasing the number of bars in the fractal. Other options are also possible.
3. Standard trailing – ‘stepped’.

void TrailingStairs(int ticket,int trldistance,int trlstep)

This trailing type is an improvement of the standard one. As far as I know, a similar one was written by KimIV (but since “one’s own is more precious”,… 🙂 It differs from the standard one in that the stop loss is moved not “point-by-point” (e.g. when trailing at the distance of 30 points, at +31 the stop loss will be moved by +1, at +32 it will be moved by +2 etc.) but by “steps” of a specified size. For example, when trailing at the distance of 40 points and with “step” set to 10, upon reaching +40 the stop loss will be moved by +10, then until the profit reaches +50 (40 pt + step) nothing will be changed (i.e. the price is given a certain freedom, which, in fact, is the essence of the algorithm), and only at +50 the stop loss will be moved from +10 at the step to +20, at +60 – to +30 pt and so on.
Parameters:
ticket –
unique order number (selected before the call to the function using OrderSelect());
trldistance – distance from the current price (in points) to start “trailing” (not less than MarketInfo(Symbol(),MODE_STOPLEVEL));
trlstep – the “step” for changing stop loss (in points) (not less than 1).
At trlstep=1 this function will not differ from the standard trailing. The main “feature” of this algorithm, once again, is to provide the price with a certain “freedom of movement” – the stop loss is moved only after the price has “wandered, determined.” This trailing algorithm was originally seen in the description of the “Moving channels” tactic by the aforementioned V.Barishpolts.
4. Standard trailing – ‘knot’.

void TrailingUdavka(int ticket,int trl_dist_1,int level_1,
                    int trl_dist_2,int level_2,int trl_dist_3)

As it is known, there are no unlimited movements without rollbacks (ugh…). And after a certain “spike” (the average value of which can be determined statistically, for example) the price, as a rule, forms a consolidation or a rollback. The idea of this maintenance algorithm is to decrease the trailing distance as the profit increases in such a way, that it would be possible to “peg” more profit when reaching the area of a probable reversal/consolidation. In addition to trading the mentioned “spikes” (which usually take place during news or at breakouts of historical levels), the function can also be used for working within channels, by decreasing the trailing distance when reaching the opposite (relative to the opening) boundary of the channel.


Parameters:
ticket –
unique order number (selected before the call to the function using OrderSelect());
trl_dist_1 – the initial trailing distance (in points) (not less than MarketInfo(Symbol(),MODE_STOPLEVEL), greater than trl_dist_2 and trl_dist_3);
level_1 – the profit level (in points), when reached the trailing distance will be reduced from trl_dist_1 to trl_dist_2 (less than level_2; greater than trl_dist_1);
trl dist_2 – the trailing distance (in points) after the price reaches a profit level of level_1 points (not less than MarketInfo(Symbol(),MODE_STOPLEVEL));
level_2 – the profit level (in points), when reached the trailing distance will be reduced from trl_dist_2 to trl_dist_3 points (greater than trl_dist_1 and greater than level_1);
trl dist_3 – the trailing distance (in points) after the price reaches a profit level of level_1 points (not less than MarketInfo(Symbol(),MODE_STOPLEVEL)).


For example, at values “ticket#, 30, 50, 20, 70, 10” the trailing is initially performed at the distance of 30 points, once the price moves away from the opening price by 50 points, it starts trailing “tighter” – at the distance of 20 points, and if it managed to get past 70 points in the direction of the profit increase, “tighten the knot” (hence then name) the trailing distance to 10 points (which is highly likely to lead to soon closure of the position).

Alternative:  Trade History Export to CSV - indicator MetaTrader 4
5. Trailing by time.
void TrailingByTime(int ticket,int interval,int trlstep,
                    bool trlinloss)

Trails by time, irrespective of the current result of the position and the market situation. At a set time intervals (whole minutes) it tries (if possible) to move the stop loss by the specified step. Using this trailing method separately was not very successful (at least for me, maybe it will be different for someone else), although, when combined with other trailing methods or when activated by a certain condition, it might be useful.

Parameters:
ticket –
unique order number (selected before the call to the function using OrderSelect());
interval – the number of whole minutes after opening the position to try to move the stop loss at the step of trlstep points;
trlstep – the step (in points) to move the stop loss after every interval minutes;
trlinloss – in this case, if trlinloss==true, then start trailing from stop loss, otherwise from the opening price (if the stop loss was not set, ==0, then always trail from the opening price).
6. Trailing by ATR.
void TrailingByATR(int ticket,int atr_timeframe,int atr1_period,
                   int atr1_shift,int atr2_period,int atr2_shift,
                   double coeff,bool trlinloss)
ATR – (Average True Range) is one of the volatility indicators; the greater the value, the higher the average volatility over the specified time period (of the indicator); measured in points. Trailing by ATR in most cases allows to change the stop loss according to (“adequately”, “adaptively”) the price behavior type – at high volatility (visible spikes) the price is “let go”, when “marking time” it is kept “tighter”. The trailing uses 2 ATRs, that are supposed to have different periods – one short (e.g. 5), the other – long (e.g. 20). The calculation of the stop loss always uses the greater value of the 2 ATRs – this is done in order to prevent several low-volatility bars in a row (for example, prior to news release) from moving the stop loss too close to the current price.

Parameters:
ticket –
unique order number (selected before the call to the function using OrderSelect());
atr_timeframe – the timeframe to calculate the ATR value (options – 1, 5, 15, 30, 60, 240, 1440, 10080, 43200);
atr1_period – the period of the first ATR (greater than 0; can be same as atr2_period, but it is recommended to set it to a different value, as mentioned above);
atr1_shift – the “window” shift for the first ATR, in which the ATR value is calculated, specified number of bars back (non-negative integer) relative to the current bar;
atr2_period – the period of the second ATR (greater than 0);
atr2_shift – the “window” shift for the second ATR in which the ATR value is calculated, specified number of bars back (non-negative integer) relative to the current bar;
coeff – the stop loss is calculated as ATR*coeff, i.e. this is the coefficient for determining the number of the ATR distances from the current price to place the stop loss;
trlinloss – >whether to move the stop loss in an “unprofitable” area, i.e. in the interval between the initial stop loss and the opening price (true – trail, false – trailing is only activated if the new stop loss is “better” than the opening price, “in profit”).
It is also a popular trailing method, that differs (in most cases advantageously) from the standard with the “adaptivity” to the current market situation.

7. ‘Ratchet’ trailing (by Barishpolts).

void TrailingRatchetB(int ticket,int pf_level_1,int pf_level_2,
                      int pf_level_3,int ls_level_1,
                      int ls_level_2,int ls_level_3,
                      bool trlinloss)

A ratchet key, wheel is the one that “moves only in one direction”. The name is mine, in the description by Barishpolts it is mentioned as the “second trailing tactic” (as opposed to the “first”, with “standard” – further stop losses), in the version by KimIV – so-called “three-level” trailing. The idea: quick transfer to breakeven and stepped trailing at a small profit (different trailing methods are suggested after that, for example, the standard one, or my standard-“stepped” or any of the above). The feasibility of such trailing – “the absolute majority of positions make profit at least for some time”, therefore move the stop loss to breakeven as soon as possible. If it “closes” prematurely but the opening signals are still present, a re-entry is possible. In general, there will be numerous trades closed in breakeven and possibly some with good profit – on the trades which had a strong movement in the profitable direction after opening. The author emphasizes that this trailing is not for “pipsing”, but for achieving trading with low % of unprofitable trades.
Parameters:
ticket –
unique order number (selected before the call to the function using OrderSelect());
pf_level_1 – the profit level (in points) to move the stop loss to breakeven + 1 point;
pf_level_2 – the profit level (in points) to move the stop loss from +1 to the distance of pf_level_1 points from the opening price;
pf_level_3 – the profit level (in points) to move the stop loss from pf_level_1 to pf_level_2 points from the opening price (this concludes the function operation);
ls_level_1 – the distance from the opening price towards the loss to place the stop loss when the position profit reaches +1 (i.e at +1 the stop loss will be moved to ls_level_1);
ls_level_2 – the distance from the opening price in the loss to place the stop loss at the condition that the price had initially moved below ls_level_1, and then rose higher (i.e. there was a loss, but it started decreasing – do not allow it to increase again);
ls_level_3 – the distance from the opening price in the loss to place the stop loss at the condition that the price had initially moved below ls_level_2, and then rose higher;
trlinloss – >whether to move the stop loss in an “unprofitable” area, i.e. in the interval between the initial stop loss and the opening price (true – trail, false – trailing is only activated if the new stop loss is “better” than the opening price, “in profit”).

The author of the idea suggested to use the following values on EURUSD: “5, 10, 25”, i.e. at +5 (i.e. “compensated” the spread and gained 5 more points of profit) the stop loss is moved to +1 (during manual trading it is recommended to “keep this number in head”, so as not to tempt the dealer), at +10 points the stop loss is moved to +5, at +25 points of profit the stop loss is moved to +10, and the price is “let go” (it can be tightened by other methods). The similar part of the function for the loss interval has not been described by the author, it was developed by his followers in the discussion. There is evidence that the author (quite successfully) uses this methodology for trading on his investment project, which is possibly one of factors of very high profit % in his trading. At the same time, it should be noted that this trailing algorithm is quite specific and may not suit all.


8. Trailing by price channel (suggested by rebus).

void TrailingByPriceChannel(int iTicket,int iBars_n,int iIndent)

Parameters:
iTicket –
unique order number (selected before the call to the function using OrderSelect());
iBars_n – the channel period (the number of bars to look for the highest High and lowest Low – the upper and lower boundaries of the channel, respectively);
iIndent – the indent (in points) to place the stop loss from the channel boundary.

The results of trailing by price channel virtually coincide with the trailing by candle shadows (see above), and to some extent resemble the trailing by fractals, although it differs in “concept” and “feasibility”.

9. Trailing by moving average.

void TrailingByMA(int iTicket,int iTmFrme,int iMAPeriod,int iMAShift,
                  int MAMethod,int iApplPrice,int iShift,int iIndent)
The idea is basically “half a step away” from the trailing by price channel. The function is passed the position ticket, the required timeframe, the offset from the MA (in points) to place the stop loss, and MA parameters (similar to the ones in the standard iMA()). Considering the nature of the moving averages, it is easy to guess that this algorithm is able to generate rather good tightening during trends, although, during flats it “confuses” the price and often leads to premature closures. However, it is possible to change the trailing parameters (the method and period of averaging in particular) adequately to meet the market situation (taking volatility into account, for example).
Parameters:
iTicket –
unique order number (selected before the call to the function using OrderSelect());
iTmFrme – the chart period to calculate the moving average; allowed input options: 1 (M1), 5 (M5), 15 (M15), 30 (M30), 60 (H1), 240 (H4), 1440 (D), 10080 (W), 43200 (MN);
iMAPeriod – the period of averaging for calculation of the moving average;
iMAShift – shift of the indicator relative to the price chart;
iMAMethod – method of averaging; allowed input options: 0 (MODE_SMA), 1 (MODE_EMA), 2 (MODE_SMMA), 3 (MODE_LWMA);
iApplPrice – applied price; input options: 0 (PRICE_CLOSE), 1 (PRICE_OPEN), 2 (PRICE_HIGH), 3 (PRICE_LOW), 4 (PRICE_MEDIAN), 5 (PRICE_TYPICAL), 6 (PRICE_WEIGHTED);
iShift – shift relative to the current bar by the specified number of periods back;
iIndent – the indent (in points) from the MA value to place the stop loss.

10. “Fifty-fifty” trailing.

void TrailingFiftyFifty(int iTicket,int iTmFrme,double dCoeff,
                        bool bTrlinloss)

The idea is as follows: when another bar closes, decrease the distance between the stop loss and the current price dCoeff times (the initial value was 0,5, hence the name). For example, there is an open buy position with the stop loss of 40 points. When the bar where the market entry was made is closed, the Bid becomes higher than the opening price by 42 points. If the only “in profit” (bTrlinloss==true) trailing mode was selected, take the distance from the opening price to the current price – 42 points, multiply it by dCoeff (for example, 0.5), and by getting 21 points, move the stop loss to +21. Suppose that the profit amounted to +71 points at the closure of the next bar. Then the difference between the current stop loss and the price is 71-21=50, half of this value is 50*0.5=25, so the new stop loss must be placed 25 points higher than the previous one (21+25=46 points from the opening price).

Alternative:  Fractals and Alligator - EA MetaTrader 4

When using the described trailing mode, “in profit” (bTrlinloss==true), the stop loss is moved only on condition that the new stop loss is “better” than the opening price. If bTrlinloss is set to false, then the trailing will be performed in a loss area as well (i.e. in the interval between the opening price and the stop loss, which, by the way, must be necessarily defined (not equal to 0) for this element to work). That is, if the above variant is used, then at the closure of the next bar the stop loss will be moved to 0.5 distance not between the opening and current price, but between the stop loss and the current price (at a stop loss of 40 points and profit of 42 points this distance will be equal to (40+42)/2 = 82/2 = 41 points, the stop loss will be placed at +1 point from the opening price. At the second bar at profit of 71 points: a) 71 – 1 = 70, b) 70*0.5 = 35, c) 1 + 35 = 36 points It can be seen that this variant will start at a greater “distance” and will fall behind the first one. Its main function is to tighten the stop loss during negative developments. For example, if after the closure of the first bar the profit amounted to -10 points, then at bTrlinloss==true: a) find the distance from the price to the stop loss, |-40 + (-10)| = 30 points, b) calculate the half of this value – 30*0.5 = 15 points and c) move the stop loss towards the profit at this distance: -40 + 15 = -25.

Trailing in a loss causes the number of premature closure to increase (with a small loss too), although the account is protected from getting large losses.

Parameters:
iTicket –
unique order number (selected before the call to the function using OrderSelect());
iTmFrme – the chart period, the bars of which will be used for trailing; allowed input options: 1 (M1), 5 (M5), 15 (M15), 30 (M30), 60 (H1), 240 (H4), 1440 (D), 10080 (W), 43200 (MN);

dCoeff – the coefficient that determines the number of times to decrease the distance between the price at the moment the bar closes and the current stop loss;

bTrlinloss – activate trailing in unprofitable areas.


11. “KillLoss” trailing.

void KillLoss(int iTicket,double dSpeedCoeff)
I came up with the idea of such maintenance during the development of a combined type of trailing, which included several of the above (namely the “ratchet” trailing by Barishpolts and trailing by fractals). According to the idea, it was designed to work only in loss areas (when the position is in a loss). For example, if the entry was evidently incorrect, the loss increases rapidly, the price swiftly approaches the initial stop loss, it might be advisable to limit the possible loss by moving the stop loss towards the price at the speed equal to or grater than that of the price. This is what the KillLoss function does. Once started, it “remembers” the distance between the stop loss and the price in a global variable of the terminal, and in the future if the price approaches the stop loss by X points, moves the stop loss to X points * dSpeedCoeff coefficient towards it. The mentioned coefficient can be both a constant (e.g. 1 – the stop loss will be moved 1 point per each point of the price approach, or 1.5 – the stop loss will move towards the price 1,5 times faster that the price speed), and a variable value that changes depending on the market conditions (e.g. its volatility – “if the market is volatile and the loss is growing, cut the stop loss faster”). When the price roll back in the direction of profit (the loss decreases) the KillLoss function does nothing. P.S. Keep in mind that the function uses 2 global variables of the terminal during its operation – sldiff and zeticket, the latter of which is also used in some of the above trailing functions. Be careful, if necessary (e.g. during a joint or alternate use of these functions) change the name of the global variable in one of them.

All the above functions are collected in the TrailingFuncLib.mq4 library file, attached to the header of the article. It is more convenient for me to use a library, although it is somewhat slower, however you can include the functions in your programs. I also attached the sample EA named MyFractals with the functions included. Someone might also be interested in the EA.


11.08.2007. For those, who trade “semi-automatically” by controlling part of the trading manually (for example,position opening, simply because some tactics are barely algorithmizable) and another part of the trading by using scripts and MQL4 experts (for example, positions maintenance and closure), I have developed EAs based on each of the above trailing functions of the library. They are in the TrailingExperts.zip archive. So now, after manually opening, you can simply run an EA with the required trailing type, by specifying the ticket (unique number of the position) and setting the necessary parameters. And, if necessary, you can also easily change one type of trailing to another, as the market situation changes, simply by running another expert. More detailed instructions can be found in the comments of each EA. I really hope that these programs will be useful in your work.


I have started learning the MQL4 language relatively recently (at the end of March 2007). Therefore I will gladly accept any constructive notes, tips, suggestions, ideas, etc. regarding the functions above. I hope they will be useful to you.
Best regards,
Yuri Dzyuban.


📈 ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks