Skip to content

Instantly share code, notes, and snippets.

@currencysecrets
Last active September 11, 2022 02:51
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save currencysecrets/6622644 to your computer and use it in GitHub Desktop.
Save currencysecrets/6622644 to your computer and use it in GitHub Desktop.
ATR Trailing Stop method - these are the ATR trailing stop functions I use to calculate my automatic stops. Aspects within this code that need to be added are the checking of the Trading Content being free and (optional) better error reporting.
//+------------------------------------------------------------------+
//| calculate-atr-trailing-stop.mq4
//| Copyright 2013, Currency Secrets
//| http://www.currencysecrets.com
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, Currency Secrets"
#property link "http://www.currencysecrets.com"
//--- input parameters
extern int extLookBack = 50; // bars to look back for the ATR indicator
extern double extATRMult = 2; // ATR multiplier
extern int extSlippage = 10; // slippage allowed for trades
int start() {
string sym = Symbol();
int per = PERIOD_H4;
// entry logic here ...
// ...
// end entry logic!
// checking open trades here on every tick...
checkOpenTrades( per, sym );
// end check of open trades on every tick!
return(0);
}
void checkOpenTrades( int per, string sym = "" ) {
if ( sym == "" ) { sym = Symbol(); }
int t = OrdersTotal();
double stop, trail;
for ( int i = 0; i < t; i += 1 ) {
if ( OrderSelect( i, SELECT_BY_POS, MODE_TRADES) ) {
if ( OrderSymbol() == sym ) {
stop = OrderStopLoss(); // current stop loss of order
if ( OrderType() == OP_BUY ) {
// we have an active long position
// ideally this is the best and only way to go...
trail = Ask - getStopDist( per );
// ... however, we will also check this method too...
trail = MathMax( trail, getTrailingStop( per, OrderOpenTime(), true, sym ) );
// check if there's a difference of a least one point in our favour - otherwise don't worry about it
if ( trail - stop > Point ) {
// check trade context...
// ...
// end check trade content
// check stop price isn't too close to market
if ( Bid - trail > MarketInfo( sym, MODE_STOPLEVEL ) * Point ) {
// modify active order's stop price
if ( OrderModify( OrderTicket(), OrderOpenPrice(), trail, OrderTakeProfit(), 0 ) == false ) {
// ALERT ERROR!
Print( "ERR in MOD LONG trade for " + sym + " = " + GetLastError() );
}
} else {
// otherwise may want to check to see if you can exit at market if too close
if ( trail > Bid ) {
if ( OrderClose( OrderTicket(), OrderLots(), Bid, extSlippage ) == false ) {
Print( "ERR in CLOSE LONG at market for " + sym + " = " + GetLastError() );
}
}
}
}
}
if ( OrderType() == OP_SELL ) {
// we have an active short position
// ideally this is the best and only way to go...
trail = Bid + getStopDist( per );
// ... however, we will check this method too...
trail = MathMin( trail, getTrailingStop( per, OrderOpenTime(), false, sym ) );
// check if there's a difference of a least one point in our favour - otherwise don't worry about it
if ( stop - trail > Point ) {
// check trade context...
// ...
// end check trade context
// check stop price isn't too close to market
if ( trail - Ask > MarketInfo( sym, MODE_STOPLEVEL ) * Point ) {
// modify active order's stop price
if ( OrderModify( OrderTicket(), OrderOpenPrice(), trail, OrderTakeProfit(), 0 ) == false ) {
// ALERT ERROR!
Print( "ERR in MOD SHORT trade for " + sym + " = " + GetLastError() );
}
} else {
// otherwise may want to see if you can exit at market if too close
if ( Ask > trail ) {
if ( OrderClose( OrderTicket(), OrderLots(), Ask, extSlippage ) == false ) {
Print( "ERR in CLOSE SHORT at market for " + sym + " = " + GetLastError() );
}
}
}
}
}
}
}
}
}
double getStopDist( int per, int bar = 1, string sym = "" ) {
if ( sym == "" ) { sym = Symbol(); }
return( N( extATRMult * iATR( sym, per, extLookBack, bar ) ) );
}
double getTrailingStop( int per, datetime openTime, bool isLong, string sym = "" ) {
if ( sym == "" ) { sym = Symbol(); }
// this function will return the trailing stop of the symbol
// dir = TRUE for longs; FALSE for shorts
double result;
int startBar = getOpenBar( openTime, per );
if ( isLong ) {
result = iHigh( sym, per, startBar ) - getStopDist( per, startBar, sym );
} else {
result = iLow( sym, per, startBar ) + getStopDist( per, startBar, sym );
}
for ( int i = startBar; i > 0; i -= 1 ) {
if ( isLong ) {
// for LONG orders
// loop through the bars since opentime
result = MathMax( iHigh( sym, per, i ) - getStopDist( per, i, sym ), result );
} else {
// for SHORT orders
result = MathMin( iLow( sym, per, i ) + getStopDist( per, i, sym ), result );
}
}
return( N( result ) );
}
int getOpenBar( datetime openTime, int per, string sym = "" ) {
if ( sym == "" ) { sym = Symbol(); }
// each bar has the opening time at the start of the bar
// eg if openTime is 12:01PM we will know at 4:00PM (when the
// bar is greater than the opening time of trade)
int b = iBars( sym, per );
for ( int i = 0; i < b; i += 1 ) {
if ( openTime >= iTime( sym, per, i ) ) {
return( i );
}
}
return( 0 );
}
double N( double price, int num = -1 ) {
if ( num == -1 ) { num = Digits; }
return( NormalizeDouble( price, num ) );
}
@silentnailgun
Copy link

silentnailgun commented May 1, 2018

Great code, thanks!
Only bug I had was in case there's no stop loss placed yet: the program doesn't place a new one because of the condition in lines 46 & 77.
My fix was:
if ( trail - stop > Point || !stop) {
if ( stop - trail > Point || !stop) {

Thank you!

@crgone1
Copy link

crgone1 commented Dec 2, 2019

Is there any way to add activation only when a defined number of pips in profit? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment