+ Reply to Thread
Page 1 of 2 1 2 LastLast
Results 1 to 10 of 13

Thread: MQL4 Mean Reversion Systems

  1. #1
    Administrator Jim's Avatar
    Join Date
    Apr 2010
    Location
    South West England
    Posts
    383

    MQL4 Mean Reversion Systems

    Mean reversion systems are based around the idea that when the price of an asset has undergone a short term movement away from a longer term average it is subsequently likely to move back towards that "mean". For example systems based around overbought/oversold indicators such the RSI operate on this principle.

    Our first such system has been kindly provided by pippa, and what's more the initial backtests have proved to be profitable. I for one am pleased to see that it doesn't use the RSI, or any other MetaTrader built-in overbought/oversold indicator for that matter!

    P.S. I have taken the liberty of moving this system from it's original place over in the Random Entry Systems thread, where it didn't really belong any longer.
    Reality is merely an illusion, albeit a very persistent one - Albert Einstein

  2. #2
    Junior Member
    Join Date
    Jul 2011
    Location
    Near Monaco at the French Cote d`Azur.
    Posts
    17

    The Not-So-Random Entry

    Learning MQL, I took 'GuruEx01' and have added
    > percent risk, and
    > D1 entry logic: large move yesterday, going for retracement today
    backtesting on EURUSD_D1 from 2001.01.01 - 2011.04.30 shows positive results,
    with the best settings around
    > RiskPercent 11..12(=risk 11% of a/c, depends on SL, no error correction for MinLot/MaxLot)
    > TargetProfit 200(=20 pips), StopLoss 190(=19 pips)
    > ATRFactor 1.8 (=ATR yesterday min 1.8 times ATR(10)
    > BarTriggerSize 1.15...1.20(=iClose-iOpen[or reverse], times BarTriggerSize, should be > then iHigh-iLow)
    only enters orders on new bar(D1)

    it's profitable, even on GBPUSD and USDJPY w/ same settings, but on each currency only triggers
    appr 40+ trades in 10 yrs!

    The most difficult for me was the "enter-only-once-per-day" rule, I tried sleep(86400000); at different places, but finally made it with the iVolume < 10 condition.

    Also, when changing/adapting code, I finally resorted to changing only ONE line at a time, then saving and compiling, to minimize errors and to localize them faster.

    Running different versions of this EA on multiple backtests, brought up the question:

    How do you organize/name all these reports and code versions?

    I came up with the following:
    I insert today's date as magic number (20110821)
    I try to place all variables I might want to change, as 'inputs', as those show up on the strategy tester report.
    I save the report with a meaningful name and the most important results(in the name of the file), i.e. profitfactor - payoff - profit -drawdown
    I save multiple optimization runs as .csv to make it easier, later on to extract information for statistics.

    So, what works for you? How do you name/save files & 'optimize'?

    Regards
    pippa
    It takes years to become an overnight success

  3. #3
    Junior Member
    Join Date
    Jul 2011
    Location
    Near Monaco at the French Cote d`Azur.
    Posts
    17
    As I am unable to upload the file, here it is as inserted text:



    Code:
    //+------------------------------------------------------------------+
    //|                                                pippa_D1_mover_GuruEx01.mq4 |
    //|     Copyright © 2009, Marketing Dreams Ltd. All Rights Reserved. |
    //|                                         http://trading-gurus.com |
    //|                                                                  |
    //| GuruTrader™ example 1                                            |
    //| Version 1.0                                                      |
    //|                                                                  |
    //| About as simple a "robot" as it is possible to produce           |
    //| Despite its simplicity it still manages to "predict the future"  |
    //| with 100% accuracy....                                           |
    //| ....in backtesting EUR/USD on one of my demo accounts            |
    //| between January 5th 2009 and April 11th 2009                     |
    //|                                                                  |
    //| Wealth Warning! This expert is for educational purposes only.    |
    //| It should NEVER be used on a live account. Past performance is   |
    //| in no way indicative of future results!                          |
    //+------------------------------------------------------------------+
    #property copyright "Copyright © 2009, Marketing Dreams Ltd."
    #property link      "http://trading-gurus.com"
    
    #define SLEEP_OK     250
    #define SLEEP_ERR    250
    
    //---- input parameters
    extern int     Magic = 20110820;
    extern int     Slippage=30;
    extern int     RiskPercent = 11;    //added pippa
    extern double  BarTriggerSize=1.15;  //added pippa
    extern double  ATRFactor=1.80;    //added pippa
    extern int     ProfitTarget=200;  
    extern int     StopLoss=190;  
    extern double  Lots=0.1;//not in use
    
    //---- static variables
    static int     Dig;
    static double  Points;
    
    static bool    Initialized = FALSE;
    static bool    Running = FALSE;
    static int     OrderNumber;
    static double  LastBid;
    static double  LastAsk;
    
    static color   clBuy = DodgerBlue;
    static color   clSell = Crimson;
    
    //+------------------------------------------------------------------+
    //| Utility functions                                                |
    //+------------------------------------------------------------------+
    #include <stdlib.mqh>
    #include <stderror.mqh>
    #include <WinUser32.mqh>
    
    //+------------------------------------------------------------------+
    //| Expert helper functions                                          |
    //+------------------------------------------------------------------+
    
    //+------------------------------------------------------------------+
    //| Places an order                                                  |
    //+------------------------------------------------------------------+
    int Order(string symbol, int Type, double Entry, double Quantity, 
              double TargetPrice, double StopPrice, string comment="") 
    {
       string TypeStr;
       color  TypeCol;
       int    ErrorCode, Ticket;
       double Price, FillPrice;
    
       Price = NormalizeDouble(Entry, Dig);
       
       switch (Type) {
          case OP_BUY: 
             TypeStr = "BUY";
             TypeCol = clBuy;
             break; 
          case OP_SELL: 
             TypeStr = "SELL";
             TypeCol = clSell;
             break;
          default:    
             Print("Unknown order type ", Type);
             break; 
       }
       double MoneyAvailable=MathRound(AccountEquity());
       Quantity = 0.1 + 0.1 * MathFloor((MoneyAvailable / StopLoss * RiskPercent * 0.01 - 0.1)/ 0.1);   
       Ticket = OrderSend(symbol, Type, Quantity, Price, Slippage,
                  StopPrice, TargetPrice, comment, Magic, 0, TypeCol);
       if (Ticket >= 0) {
          Sleep(SLEEP_OK);
          if (OrderSelect(Ticket, SELECT_BY_TICKET) == TRUE) {
             FillPrice = OrderOpenPrice();
             if (Entry != FillPrice) {
                RefreshRates();
                Print("Slippage on order ", Ticket, " - Requested = ",
                      Entry, ", Fill = ", FillPrice, ", Current Bid = ",
                      Bid, ", Current Ask = ", Ask);
             }         
          }
          else {
             ErrorCode = GetLastError();
             Print("Error selecting new order ", Ticket, ": ",
                   ErrorDescription(ErrorCode), " (", ErrorCode, ")");
          }
          return (Ticket);
       } 	
       	
       ErrorCode = GetLastError();
       RefreshRates();
       Print("Error opening ", TypeStr, " order: ", ErrorDescription(ErrorCode),
             " (", ErrorCode, ")", ", Entry = ", Price, ", Target = ",
             TargetPrice, ", Stop = ", StopPrice, ", Current Bid = ", Bid,
             ", Current Ask = ", Ask);
       Sleep(SLEEP_ERR);
    	
       return (-1);
    }
    
    //+------------------------------------------------------------------+
    //| Performs system initialisation                                   |
    //+------------------------------------------------------------------+
    void InitSystem()
    {
       Running = FALSE;
       
       RefreshRates();
       LastBid = Bid;
       LastAsk = Ask;
       
       Initialized = TRUE;
    }
             
    //+------------------------------------------------------------------+
    //| Checks for entry to a trade                                      |
    //+------------------------------------------------------------------+
    int CheckEntry(double Size)
    {
       if (iVolume(0,0,0) < 11 && iClose(0,0,1) < iOpen(0,0,1) && (iOpen(0,0,1) - iClose(0,0,1)) * BarTriggerSize >= (iHigh(0,0,1) - iLow(0,0,1)) && (iATR(NULL,0,1,1) > iATR(NULL,0,10,2) * ATRFactor)){  // Large move down yesterday, BUY today
          OrderNumber = Order(Symbol(), OP_BUY, Ask, Size,
                Ask + (Points * ProfitTarget), Bid - (Points * StopLoss));
          if (OrderNumber > 0) 
             return(1);
       }
       else if (iVolume(0,0,0) < 11 && iClose(0,0,1) > iOpen(0,0,1)&& (iClose(0,0,1) - iOpen(0,0,1)) * BarTriggerSize >= (iHigh(0,0,1) - iLow(0,0,1)) && (iATR(NULL,0,1,1) > iATR(NULL,0,10,2) * ATRFactor)){  // Large move up yesterday, SELL today
          OrderNumber = Order(Symbol(), OP_SELL, Bid, Size,      
                Bid - (Points * ProfitTarget), Ask + (Points * StopLoss)); 
          if (OrderNumber > 0)
             return(1);
       }
       return(0);
    }
    
    //+------------------------------------------------------------------+
    //| Checks for exit from a trade                                     |
    //+------------------------------------------------------------------+
    int CheckExit()
    {
       int ErrorCode;
    
       if (OrderSelect(OrderNumber, SELECT_BY_TICKET) != TRUE) {
          ErrorCode = GetLastError();
          Print("Error selecting order ", OrderNumber, ": ",
                ErrorDescription(ErrorCode), " (", ErrorCode, ")");
          return(-1);
       }
       else if (OrderCloseTime() > 0) {
          Print("Order ", OrderNumber, " closed: ", OrderClosePrice(),
                ", at ", TimeToStr(OrderCloseTime()));
          return(1);
       }
       else {
          return(0);
       }
    }
       
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int init()
    {
       Dig = MarketInfo(Symbol(), MODE_DIGITS);
       Points = MarketInfo(Symbol(), MODE_POINT);
       
       Print("Digits = ", Dig, ", Points = ", DoubleToStr(Points, 5));
       
       if (!IsDemo() && !IsTesting()) {
          MessageBox("Wealth Warning! This expert is for educational purposes only." +
                " It should NEVER be used on a live account." +
                " Past performance is in no way indicative of future results!");
          Print("Initialization Failure");
          return(-1);
       }
    
       InitSystem();
    
       Print("Initialized OK");
    
       return(0);
    }
    
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    int deinit()
    {
        Print("DeInitialized OK");
       
        return(0);
    }
    
    //+------------------------------------------------------------------+
    //| Expert start function                                            |
    //| Executed on every tick                                           |
    //+------------------------------------------------------------------+
    int start()
    {
       if (!Initialized) {
          return(-1);
       }
       else if (Running) {                    // Are we in a trade at the moment?
          if (CheckExit() > 0) {              // Yes - Last trade complete?
            Initialized = FALSE;             // Yes - Indicate we need to reinitialise
            InitSystem();                    //  and start all over again!
          }
       }
       else {
          if (CheckEntry(Lots) > 0) {         // Entered a trade?
             Running = TRUE;                  // Yes - Indicate that we're in a trade
          }   
       }
       return(0);
    }
    Last edited by Jim; 08-22-2011 at 08:56 PM. Reason: Added [CODE] tags
    It takes years to become an overnight success

  4. #4
    Administrator Jim's Avatar
    Join Date
    Apr 2010
    Location
    South West England
    Posts
    383
    Hi pippa,

    Thanks very much for your example code. I've followed convention in these matters, and I've taken the liberty of wrapping it up inside "Code" tags using the advanced editor. If you want to upload an .MQ4 file in future the best way is to put it inside a .ZIP archive, quite possibly including the .EX4 and additional documentation also.

    For another way of handling the "trade only once a day" problem you could take a look at the use of the "Finished" variable in our "London Breakout robot". That's a bit of a complex example though. Here's the basic idea:


    Code:
    //+------------------------------------------------------------------+
    //| Expert start function                                            |
    //| Executed on every tick                                           |
    //+------------------------------------------------------------------+
    int start()
    {
       if (!Initialized) {
          return(-1);
       }
    
       if (Day() != LastDay) {
          LastDay = Day();
          Finished = FALSE;
       }
    
       if (Running) {                            // Are we in a trade at the moment?
          if (CheckExit() > 0) {              // Yes - Last trade complete?
            Initialized = FALSE;             // Yes - Indicate we need to reinitialise
            InitSystem();                    //  and start all over again!
            Finished = TRUE;
          }
       }
       else if (!Finished) {
          if (CheckEntry(Lots) > 0) {         // Entered a trade?
             Running = TRUE;                  // Yes - Indicate that we're in a trade
          }   
       }
       return(0);
    }
    Cheers,

    Jim
    Reality is merely an illusion, albeit a very persistent one - Albert Einstein

  5. #5
    Administrator Jim's Avatar
    Join Date
    Apr 2010
    Location
    South West England
    Posts
    383
    Hi pippa,

    Quote Originally Posted by pippa View Post
    Also, when changing/adapting code, I finally resorted to changing only ONE line at a time, then saving and compiling, to minimize errors and to localize them faster.
    Unfortunately MetaTrader 4 doesn't include a debugger. MetaQuotes have added one in MT5, which does make this sort of thing a bit easier.

    So, what works for you? How do you name/save files & 'optimize'?
    Firstly I should mention that MT4 isn't my favourite tool for this sort of job, but sticking with Strategy Tester for the moment:

    I use a similar naming convention to you (though I hadn't thought of the magic number idea), but I use the most important input settings in the name of the file.

    As regards "optimization", that topic deserves several threads all to itself! For now I'll mention the dangers of over-optimization and curve fitting. I'll also reiterate that (as in all things concerning trading) I use optimization to try and get a handle on what's the worst that might happen, rather than what's the best. I certainly like to see systems that are profitable over a wide range of input settings, and not just a narrow "peak". Any chance you could let us see what some of your existing optimization results look like? Maybe something like these ones?

    Cheers,

    Jim
    Reality is merely an illusion, albeit a very persistent one - Albert Einstein

  6. #6
    Junior Member
    Join Date
    Jul 2011
    Location
    Near Monaco at the French Cote d`Azur.
    Posts
    17

    Results-R-Us

    Hi,
    here are the results of my tests:
    EURUSD_D1, 10yrs, 46 trades, profitfactor 2.70
    GBPUSD_D1 10yrs, 44 trades, profitfactor 1.41
    risk: 12%
    ATRfactor:1.8
    BarTriggerSize:1.15

    As this is the first/last attempt of attaching files to the post,
    move/delete them if the upload doesn't work as planned.

    Just after uploading noticed the zip-file (strategy tester result) doesn't show the pic, which is the very same I have uploaded, see 2nd thumbnail (EURUSD). Thanks!
    Last edited by pippa; 08-23-2011 at 12:00 AM. Reason: zip-file incomplete
    It takes years to become an overnight success

  7. #7
    Junior Member Mintaka's Avatar
    Join Date
    Apr 2010
    Posts
    29
    Hi Pippa,

    I am trying to reproduce your results. I am using a little different properties. I have one question. What time your daily bars begins or what broker do you use?
    Cheers,
    Mintaka
    If you keep your mind humble, pride will vanish like morning mist - Dilgo Khyentse Rinpoche

  8. #8
    Administrator Jim's Avatar
    Join Date
    Apr 2010
    Location
    South West England
    Posts
    383
    Hi Mintaka,

    Quote Originally Posted by Mintaka View Post
    What time your daily bars begins or what broker do you use?
    That's an extremely relevant question. With exchange traded stocks for example, it's fairly obvious when trading starts for the day and also when it finishes. For spot FX that trades 24/5 and a bit it is not, and simply using midnight broker time as the "start of the trading day" might well not give the best results for this sort of strategy, and will certainly make it impossible to directly compare backtest results between brokers that use different offsets from UTC.

    Cheers,

    Jim
    Reality is merely an illusion, albeit a very persistent one - Albert Einstein

  9. #9
    Junior Member
    Join Date
    Jul 2011
    Location
    Near Monaco at the French Cote d`Azur.
    Posts
    17

    @Mintaka: broker, timeOffset for backtests

    Hi Mintaka,
    time = GMT (UTC)
    at least, this is what I believe it is, as the data was downloaded from forextester.com // historical data

    regarding the broker:
    again, data is from forextester, so, I don't know the source other than that.

    The MT4setup.exe to backtest this data, I downloaded from alpariUK for EURUSD, and from thinkforex.com for all other currencies.

    To me, they look the same (MT4build 402), only difference:
    alpariUK has MinLot 0.1lots and nearly no stopLevel restrictions (as far as I know),
    whereas thinkforex has MinLot 0.01lots and no stopLevel restriction.

    Hope that answers your question,
    Regards
    It takes years to become an overnight success

  10. #10
    Administrator Jim's Avatar
    Join Date
    Apr 2010
    Location
    South West England
    Posts
    383
    Hi pippa,

    Have you considered when the best time might be to start/end your daily bars? Starting daily bars at a different time will certainly affect backtest results, and quite possibly overall profitability too. Although personally I'm not a huge fan of such things, pivot point authority John Person once assured me that the FX trading day finishes at the New York bank settlement time of 5 PM Eastern, which is very rarely midnight GMT!

    Cheers,

    Jim
    Reality is merely an illusion, albeit a very persistent one - Albert Einstein

+ Reply to Thread
Page 1 of 2 1 2 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts