Last active
February 4, 2017 19:36
-
-
Save currencysecrets/3907816 to your computer and use it in GitHub Desktop.
MQL4: Exit Strategy Tester (Script)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//+------------------------------------------------------------------+ | |
//| Breakout Strategy Tester.mq4 | | |
//| Copyright 2012, MetaQuotes Software Corp. | | |
//| http://www.metaquotes.net | | |
//+------------------------------------------------------------------+ | |
// | |
// With this script we will be doing the following: | |
// 1. Get all the trades (be wary of reversal trades!) | |
// 2. | |
#property copyright "Copyright 2012, MetaQuotes Software Corp." | |
#property link "http://www.metaquotes.net" | |
int TF = PERIOD_H4; | |
double PL1; | |
double ROR1; | |
double riskSize = 100; | |
//+------------------------------------------------------------------+ | |
//| script program start function | | |
//+------------------------------------------------------------------+ | |
int start() | |
{ | |
//---- | |
getTrades(); | |
//---- | |
return(0); | |
} | |
//+------------------------------------------------------------------+ | |
void getTrades() { | |
int tot = OrdersHistoryTotal(), oBar, vIniStop = 6, vExit = 12, ordType, win, winA, trades; | |
string sym; | |
double PL = 0; | |
double PLx = 0; | |
double pipVal, p, px, DD, DDx, HiPL, HiPLx, ROR, RORx, iniStop, exit, diff, lotSize; | |
// first we'll progress through the historical trades | |
for ( int x = 1; x <= vExit; x++ ) { | |
for ( int ini = 1; ini <= vIniStop; ini++ ) { | |
// reset all reporting variables | |
PL = 0; DD = 0; PLx = 0; HiPL = 0; HiPLx = 0; DDx = 0; ROR = 0; RORx = 0; win = 0; trades = 0; winA = 0; | |
for ( int i = 0; i <= tot; i++ ) { | |
if ( OrderSelect(i, SELECT_BY_POS, MODE_HISTORY) ) { | |
if ( OrderType() <= 1 ) { | |
sym = OrderSymbol(); | |
pipVal = MarketInfo(sym, MODE_TICKVALUE); | |
oBar = entryBar(sym, OrderOpenTime()); | |
getInitialStop(sym, OrderType(), oBar, OrderOpenPrice(), vIniStop ); | |
iniStop = getInitialStop( sym, OrderType(), oBar, OrderOpenPrice(), ini ); | |
lotSize = calcPositionSize( sym, OrderOpenPrice(), iniStop, riskSize ); | |
exit = testExits(sym, oBar, OrderOpenPrice(), OrderType(), iniStop, x); | |
if ( OrderType() == OP_BUY ) { | |
p = (OrderClosePrice() - OrderOpenPrice()) * OrderLots() * (1 / MarketInfo(sym, MODE_POINT)) * pipVal; | |
px = (exit - OrderOpenPrice()) * lotSize * (1 / MarketInfo(sym, MODE_POINT)) * pipVal; | |
PL += p; | |
diff = (exit - OrderOpenPrice()) / (MarketInfo(sym, MODE_TICKSIZE) * 10); | |
} else if ( OrderType() == OP_SELL ) { | |
p = (OrderOpenPrice() - OrderClosePrice()) * OrderLots() * (1 / MarketInfo(sym, MODE_POINT)) * pipVal; | |
px = (OrderOpenPrice() - exit) * lotSize * (1 / MarketInfo(sym, MODE_POINT)) * pipVal; | |
PL += p; | |
diff = (OrderOpenPrice() - exit) / (MarketInfo(sym, MODE_TICKSIZE) * 10); | |
} | |
if ( px > 0 ) { win += 1; } | |
trades += 1; | |
HiPL = MathMax( HiPL, MathMax( 0, PL )); | |
DD = MathMin( DD, MathMin( 0, PL - HiPL )); | |
PLx += px; | |
HiPLx = MathMax( HiPLx, MathMax( 0, PLx )); | |
DDx = MathMin( DDx, MathMin( 0, PLx - HiPLx )); | |
ROR += p / riskSize; | |
RORx += px / riskSize; | |
// Print( TimeToStr(OrderOpenTime()) + " " + OrderSymbol() + " " + OrderType() + | |
// " actual P/L=$" + DoubleToStr(OrderProfit(), 2) + " new P/L=$" + DoubleToStr(px, 2) + | |
// " diff P/L=$" + DoubleToStr(px - OrderProfit(), 2) + | |
// " actual Qty=" + DoubleToStr(OrderLots(), 2) + " new Qty=" + DoubleToStr(lotSize, 2) + | |
// " diff Qty=" + DoubleToStr(lotSize - OrderLots(), 2) + | |
// " actual Exit=" + DoubleToStr(OrderClosePrice(), 5) + " new Exit=" + | |
// DoubleToStr(exit, 5) + " diff=" + DoubleToStr(diff, 1) ); | |
} | |
} | |
} | |
//Print( "Current P/L = $" + DoubleToStr(PL, 2) + "; ROR = " + DoubleToStr(ROR/tot, 1) + " ; RF = " + | |
//DoubleToStr( PL / MathAbs(DD), 1) + " ; DD= $" + DoubleToStr(DD, 1) ); | |
Print( "New strategy (ini=" + ini + ";exit=" + x + "): P/L = $" + DoubleToStr(PLx, 2) + "; ROR = " + DoubleToStr(RORx/tot, 1) + " ; RF = " + | |
DoubleToStr( PLx / MathAbs(DDx), 1) + " ; DDx= $" + DoubleToStr(DDx, 2 ) + " ; S/R = " + DoubleToStr( win * 100 / trades, 0) + " %" ); | |
} | |
} | |
} | |
double calcPositionSize(string sym, double entry, double stop, double risk) { | |
double dist = MathAbs( entry - stop ) + (MarketInfo(sym, MODE_SPREAD) * MarketInfo(sym, MODE_POINT)); | |
int dec = MathLog(1 / MarketInfo( Symbol(), MODE_LOTSTEP )) / MathLog(10); | |
double qty = NormalizeDouble((risk / dist) * MarketInfo(sym, MODE_POINT), dec); | |
return( qty ); | |
} | |
int entryBar( string sym, datetime entryTime ) { | |
int result = 0; | |
int bars = iBars(sym, TF); | |
for ( int i = bars; i >= 0; i-- ) { | |
if ( iTime( sym, TF, i ) > entryTime ) { | |
result = i+1; // entry was the previous bar | |
break; | |
} | |
} | |
return( result ); | |
} | |
double getInitialStop( string sym, int type, int entryBar, double oPrice, int version ) { | |
double result; | |
int bar, bars; | |
if ( type == OP_BUY ) { | |
switch ( version ) { | |
case 1: | |
result = iLow(sym, TF, iLowest(sym, TF, MODE_LOW, 2, entryBar+1)); | |
break; | |
case 2: | |
result = iLow(sym, TF, iLowest(sym, TF, MODE_LOW, 5, entryBar+1)); | |
break; | |
case 3: | |
bars = iBars(sym, TF); | |
for ( bar = entryBar; bar < bars; bar++ ) { | |
if ( iLow(sym, TF, bar) > iLow(sym, TF, bar+1) && | |
iLow(sym, TF, bar+1) <= iLow(sym, TF, bar+2) ) { | |
// check if the opening price is below initial stop, if so use min price | |
if ( oPrice <= iLow(sym, TF, bar+1) ) { | |
result = iLow(sym, TF, iLowest(sym, TF, MODE_LOW, bar+1 - entryBar, entryBar)); | |
} else { | |
result = iLow(sym, TF, bar+1); | |
} | |
break; | |
} | |
} | |
break; | |
case 4: | |
result = iClose(sym, TF, entryBar+1) - iATR(sym, TF, 30, entryBar+1); | |
break; | |
case 5: | |
result = oPrice - (500 * MarketInfo(sym, MODE_POINT)); | |
break; | |
case 6: | |
result = iLow(sym, TF, iLowest(sym, TF, MODE_LOW, 30, entryBar+1)); | |
break; | |
} | |
} else if ( type == OP_SELL ) { | |
switch ( version ) { | |
case 1: | |
result = iHigh(sym, TF, iHighest(sym, TF, MODE_HIGH, 2, entryBar+1)); | |
break; | |
case 2: | |
result = iHigh(sym, TF, iHighest(sym, TF, MODE_HIGH, 5, entryBar+1)); | |
break; | |
case 3: | |
bars = iBars(sym, TF); | |
for( bar = entryBar; bar < bars; bar++ ) { | |
if ( iHigh(sym, TF, bar) < iHigh(sym, TF, bar+1) && | |
iHigh(sym, TF, bar+1) >= iHigh(sym, TF, bar+2) ) { | |
// if opening price is above initial stop change to use max price | |
if ( oPrice >= iHigh(sym, TF, bar+1) ) { | |
result = iHigh(sym, TF, iHighest(sym, TF, MODE_HIGH, bar+1 - entryBar, entryBar)); | |
} else { | |
result = iHigh(sym, TF, bar+1); | |
} | |
break; | |
} | |
} | |
break; | |
case 4: | |
result = iClose(sym, TF, entryBar+1) + iATR(sym, TF, 30, entryBar+1); | |
break; | |
case 5: | |
result = oPrice + (500 * MarketInfo(sym, MODE_POINT)); | |
break; | |
case 6: | |
result = iHigh(sym, TF, iHighest(sym, TF, MODE_HIGH, 30, entryBar+1)); | |
break; | |
} | |
} | |
return( result ); | |
} | |
double testExits( string sym, int entryBar, double oPrice, int type, double iStop, int version ) { | |
double result = iStop; | |
double trail = iStop; | |
double swing = iStop; | |
int i; | |
switch ( version ) { | |
case 1: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
if ( iLow(sym, TF, i) > iLow(sym, TF, i+1) && iLow(sym, TF, i+1) <= iLow(sym, TF, i+2) ) { | |
trail = MathMax( trail, iLow(sym, TF, i+1) ); | |
} | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
if ( iHigh(sym, TF, i) < iHigh(sym, TF, i+1) && iHigh(sym, TF, i+1) >= iHigh(sym, TF, i+2) ) { | |
trail = MathMin( trail, iHigh(sym, TF, i+1) ); | |
} | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 2: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
if ( iHigh(sym, TF, iHighest(sym, TF, MODE_HIGH, entryBar - i + 1, i)) == iHigh(sym, TF, i) ) { | |
trail = MathMax( trail, swing ); | |
} | |
if ( iLow(sym, TF, i) > iLow(sym, TF, i+1) && iLow(sym, TF, i+1) <= iLow(sym, TF, i+2) ) { | |
swing = iLow(sym, TF, i+1); | |
} | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
if ( iLow(sym, TF, iLowest(sym, TF, MODE_LOW, entryBar - i + 1, i)) == iLow(sym, TF, i) ) { | |
trail = MathMin( trail, swing ); | |
} | |
if ( iHigh(sym, TF, i) < iHigh(sym, TF, i+1) && iHigh(sym, TF, i+1) >= iHigh(sym, TF, i+2) ) { | |
swing = iHigh(sym, TF, i+1); | |
} | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, i); | |
break; | |
} | |
} | |
break; | |
case 3: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
if ( iLow(sym, TF, i) > iLow(sym, TF, i+1) && iLow(sym, TF, i+1) > iLow(sym, TF, i+2) && | |
iLow(sym, TF, i+2) <= iLow(sym, TF, i+3) ) { | |
trail = MathMax( trail, iLow(sym, TF, i+2)); | |
} | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
if ( iHigh(sym, TF, i) < iHigh(sym, TF, i+1) && iHigh(sym, TF, i+1) < iHigh(sym, TF, i+2) && | |
iHigh(sym, TF, i+2) >= iHigh(sym, TF, i+3) ) { | |
trail = MathMin( trail, iHigh(sym, TF, i+2)); | |
} | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 4: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
if ( iLow(sym, TF, i) >= iLow(sym, TF, i+1) && iHigh(sym, TF, i) <= iHigh(sym, TF, i+1) ) { | |
trail = MathMax( trail, iLow(sym, TF, i+1)); | |
} | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
if ( iHigh(sym, TF, i) <= iHigh(sym, TF, i+1) && iLow(sym, TF, i) >= iLow(sym, TF, i+1) ) { | |
trail = MathMin( trail, iHigh(sym, TF, i+1)); | |
} | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 5: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
trail = MathMax( trail, iBands(sym,TF,30,0.5,0,MODE_CLOSE,MODE_UPPER, i)); | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
trail = MathMin( trail, iBands(sym, TF, 30, 0.5, 0, MODE_CLOSE, MODE_LOWER, i)); | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 6: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
trail = MathMax( trail, iLow(sym, TF, iLowest(sym, TF, MODE_LOW, 30, i))); | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
trail = MathMin( trail, iHigh(sym, TF, iHighest(sym, TF, MODE_HIGH, 30, i))); | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 7: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
trail = MathMax( trail, iHigh(sym, TF, iLowest(sym, TF, MODE_HIGH, 30, i))); | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
trail = MathMin( trail, iLow(sym, TF, iHighest(sym, TF, MODE_LOW, 30, i))); | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 8: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
trail = MathMax(trail, iHigh(sym, TF, i) - (5 * iATR(sym, TF, 30, i))); | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
trail = MathMin(trail, iLow(sym, TF, i) + (5 * iATR(sym, TF, 30, i))); | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 9: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
if ( iLow(sym, TF, i) > iLow(sym, TF, i+1) && iHigh(sym, TF, i) < iHigh(sym, TF, i+1) ) { | |
trail = MathMax( trail, iLow(sym, TF, i+1)); | |
} | |
if ( iClose(sym, TF, i) < iOpen(sym, TF, i+1) && iClose(sym, TF, i+1) - iOpen(sym, TF, i+1) > (2 * iATR(sym, TF, 30, i+2))) { | |
trail = MathMax( trail, iLow(sym, TF, i)); | |
} | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
if ( iHigh(sym, TF, i) < iHigh(sym, TF, i+1) && iLow(sym, TF, i) > iLow(sym, TF, i+1) ) { | |
trail = MathMin( trail, iHigh(sym, TF, i+1)); | |
} | |
if ( iClose(sym, TF, i) > iOpen(sym, TF, i+1) && iOpen(sym, TF, i+1) - iClose(sym, TF, i+1) > (2 * iATR(sym, TF, 30, i+2))) { | |
trail = MathMin( trail, iHigh(sym, TF, i)); | |
} | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 10: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
trail = MathMax(trail, iMA(sym, TF, 30, 0, MODE_SMA, MODE_CLOSE, i)); | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
trail = MathMin( trail, iMA(sym, TF, 30, 0, MODE_SMA, MODE_CLOSE, i)); | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
case 11: | |
for( i = entryBar-1; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
trail = MathMax(trail,iSAR(sym, TF, 1, 2, i)); | |
} | |
} else if ( type == OP_SELL ) { | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
trail = MathMin(trail, iSAR(sym, TF, 0.5, 20, i)); | |
} | |
} | |
} | |
break; | |
case 12: | |
for(i = entryBar; i >= 0; i-- ) { | |
if ( type == OP_BUY ) { | |
if ( i == entryBar ) { | |
if ( oPrice < (iClose(sym, TF, i) + iOpen(sym, TF, i))/2 ) { | |
trail = MathMax( trail, iLow(sym, TF, i) ); | |
} | |
} | |
if ( getExitPrice(sym, TF, trail, i, TRUE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, TRUE); | |
break; | |
} else { | |
if ( iLow(sym, TF, i) > iLow(sym, TF, i+1) && iLow(sym, TF, i+1) <= iLow(sym, TF, i+2) ) { | |
trail = MathMax( trail, iLow(sym, TF, i+1) ); | |
} | |
} | |
} else if ( type == OP_SELL ) { | |
if ( i == entryBar ) { | |
if ( oPrice > (iClose(sym, TF, i) + iOpen(sym, TF, i))/2 ) { | |
trail = MathMin( trail, iHigh(sym, TF, i) ); | |
} | |
} | |
if ( getExitPrice(sym, TF, trail, i, FALSE) > 0 ) { | |
result = getExitPrice(sym, TF, trail, i, FALSE); | |
break; | |
} else { | |
if ( iHigh(sym, TF, i) < iHigh(sym, TF, i+1) && iHigh(sym, TF, i+1) >= iHigh(sym, TF, i+2) ) { | |
trail = MathMin( trail, iHigh(sym, TF, i+1) ); | |
} | |
} | |
} else if ( i == 0 ) { | |
result = iClose(sym, TF, 0); | |
break; | |
} | |
} | |
break; | |
} | |
return ( result ); | |
} | |
double getExitPrice(string sym, int TF, double trail, int bar, bool long) { | |
double result = 0; | |
trail = NormalizeDouble(trail, MarketInfo(sym, MODE_DIGITS)); | |
if ( long == TRUE ) { | |
if ( iLow(sym, TF, bar) <= trail ) { | |
if ( iOpen(sym, TF, bar) < trail ) { | |
result = iOpen(sym, TF, bar); | |
} else { | |
result = trail; | |
} | |
} | |
} else if ( long == FALSE ) { | |
if ( iHigh(sym, TF, bar) >= trail ) { | |
if ( iOpen(sym, TF, bar) > trail ) { | |
result = iOpen(sym, TF, bar); | |
} else { | |
result = trail; | |
} | |
} | |
} | |
return ( result ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment