Announcement

Collapse
No announcement yet.

4 EMA backtesting strategy woes

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • 4 EMA backtesting strategy woes

    OK here's the basic premise:

    I have an 89 EMA and a 144 EMA which define the trend for me.

    I also have a 5 EMA and a 13 EMA which give me buy and sell signals.

    The goal in this study is to only trade with the trend, so basicly when the 144 EMA is above the 89 EMA only short signals will be generated by the 5 and 13 EMA crossovers. When the 144 EMA is below the 89 EMA only long signals will be given by the 5 and 13 EMA crossover.

    Set 1 = Check to see that 144 EMA has been generated
    Set 2 = Check to see if 144 EMA is above 89 EMA
    Set 3 = Check to see if 13 EMA is above 5 EMA, if yes short and sell long
    Set 4 = Check to see if 144 EMA is below 89 EMA
    Set 5 = Check to see if 13 EMA is below 5 EMA, if yes go long and cover short

    Now... I thought I knew what I was doing. I've atached the .efs script I've been working on but it only makes 1 or 2 trades for the testing period and when I look at the chart (60 min EUR A0-FX), there are many many more. Help!

    PHP Code:
    //{{EFSWizard_Description

    //

    //    This formula was generated by the Alert Wizard

    //

    //}}EFSWizard_Description





    //{{EFSWizard_Declarations
    var vEMA5_of_HLC3 = new MAStudy(50"HLC/3"MAStudy.EXPONENTIAL);
    var 
    vEMA13_of_HLC3 = new MAStudy(130"HLC/3"MAStudy.EXPONENTIAL);
    var 
    vEMA89_of_HL2 = new MAStudy(890"HL/2"MAStudy.EXPONENTIAL);
    var 
    vEMA144_of_HL2_2 = new MAStudy(1440"HL/2"MAStudy.EXPONENTIAL);
    var 
    vLastAlert = -1;
    //}}EFSWizard_Declarations





    function preMain() {

       
    /**

        *  This function is called only once, before any of the bars are loaded.

        *  Place any study or EFS configuration commands here.

        */

    //{{EFSWizard_PreMain
        
    setPriceStudy(true);
        
    setStudyTitle("MA Xover Trend Study");
        
    setCursorLabelName("EMA 5 -1"0);
        
    setCursorLabelName("EMA 13"1);
        
    setCursorLabelName("EMA 89"2);
        
    setCursorLabelName("EMA 144"3);
        
    setDefaultBarStyle(PS_SOLID0);
        
    setDefaultBarStyle(PS_SOLID1);
        
    setDefaultBarStyle(PS_SOLID2);
        
    setDefaultBarStyle(PS_SOLID3);
        
    setDefaultBarFgColor(Color.blue0);
        
    setDefaultBarFgColor(Color.red1);
        
    setDefaultBarFgColor(Color.yellow2);
        
    setDefaultBarFgColor(Color.white3);
        
    setDefaultBarThickness(20);
        
    setDefaultBarThickness(21);
        
    setDefaultBarThickness(22);
        
    setDefaultBarThickness(23);
        
    setPlotType(PLOTTYPE_LINE0);
        
    setPlotType(PLOTTYPE_LINE1);
        
    setPlotType(PLOTTYPE_LINE2);
        
    setPlotType(PLOTTYPE_LINE3);
    //}}EFSWizard_PreMain



    }



    function 
    main() {

       
    /**

        *  The main() function is called once per bar on all previous bars, once per

        *  each incoming completed bar, and if you don't have 'setComputeOnClose(true)'

        *  in your preMain(), it is also called on every tick.

        */



    //{{EFSWizard_Expressions
        //{{EFSWizard_Expression_1
            
    if (
                
    vEMA144_of_HL2_2.getValue(MAStudy.MA) == null
            
    onAction1()
        
    //}}EFSWizard_Expression_1
        
        //{{EFSWizard_Expression_2
            
    else if (
                
    Strategy.isLong() == false &&
                
    vEMA89_of_HL2.getValue(MAStudy.MA, -1) < vEMA144_of_HL2_2.getValue(MAStudy.MA, -1) &&
                
    vEMA89_of_HL2.getValue(MAStudy.MA) > vEMA144_of_HL2_2.getValue(MAStudy.MA)
            ) 
    onAction2()
        
    //}}EFSWizard_Expression_2
        
        //{{EFSWizard_Expression_3
            
    else if (
                
    Strategy.isLong() == false &&
                
    vEMA5_of_HLC3.getValue(MAStudy.MA, -1) < vEMA13_of_HLC3.getValue(MAStudy.MA, -1) &&
                
    vEMA5_of_HLC3.getValue(MAStudy.MA) > vEMA13_of_HLC3.getValue(MAStudy.MA)
            ) 
    onAction3()
        
    //}}EFSWizard_Expression_3
        
        //{{EFSWizard_Expression_4
            
    else if (
                
    Strategy.isShort() == false &&
                
    vEMA89_of_HL2.getValue(MAStudy.MA, -1) > vEMA144_of_HL2_2.getValue(MAStudy.MA, -1) &&
                
    vEMA89_of_HL2.getValue(MAStudy.MA) < vEMA144_of_HL2_2.getValue(MAStudy.MA)
            ) 
    onAction4()
        
    //}}EFSWizard_Expression_4
        
        //{{EFSWizard_Expression_5
            
    else if (
                
    Strategy.isShort() == false &&
                
    vEMA5_of_HLC3.getValue(MAStudy.MA, -1) > vEMA13_of_HLC3.getValue(MAStudy.MA, -1) &&
                
    vEMA5_of_HLC3.getValue(MAStudy.MA) < vEMA13_of_HLC3.getValue(MAStudy.MA)
            ) 
    onAction5();
        
    //}}EFSWizard_Expression_5
        
    //}}EFSWizard_Expressions





    //{{EFSWizard_Return
        
    return new Array(
            
    vEMA5_of_HLC3.getValue(MAStudy.MA),
            
    vEMA13_of_HLC3.getValue(MAStudy.MA),
            
    vEMA89_of_HL2.getValue(MAStudy.MA),
            
    vEMA144_of_HL2_2.getValue(MAStudy.MA)
        );
    //}}EFSWizard_Return



    }



    function 
    postMain() {

       
    /**

        *  The postMain() function is called only once, when the EFS is no longer used for

        *  the current symbol (ie, symbol change, chart closing, or application shutdown).

        */

    }



    //{{EFSWizard_Actions
        //{{EFSWizard_Action_1
        
    function onAction1() {
            
    vLastAlert 1;
        }
        
    //}}EFSWizard_Action_1
        
        //{{EFSWizard_Action_2
        
    function onAction2() {
            
    vLastAlert 2;
        }
        
    //}}EFSWizard_Action_2
        
        //{{EFSWizard_Action_3
        
    function onAction3() {
            
    Strategy.doShort(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
            
    Strategy.doSell(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
            
    vLastAlert 3;
        }
        
    //}}EFSWizard_Action_3
        
        //{{EFSWizard_Action_4
        
    function onAction4() {
            
    vLastAlert 4;
        }
        
    //}}EFSWizard_Action_4
        
        //{{EFSWizard_Action_5
        
    function onAction5() {
            
    Strategy.doLong(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
            
    Strategy.doCover(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
            
    vLastAlert 5;
        }
        
    //}}EFSWizard_Action_5
        
    //}}EFSWizard_Actions 
    Attached Files
    Last edited by techinvest; 11-26-2005, 07:46 AM.

  • #2
    techinvest
    If you are backtesting a SAR strategy you don't need to first close the current trade and then enter a new one. You can simply reverse the trade by making a call in the opposite direction. See the Notes in this article in the EFS KnowledgeBase.
    As to your example you should adjust it along the following logic

    Set 1 = Check that 144 EMA has been generated
    Set 2 = Check if 144ema > 89ema AND 13ema > 5ema AND Strategy.isShort is false
    If the condition is true then go Short
    Set 3 = Check if 144ema < 89ema AND 13ema < 5ema AND Strategy.isLong is false
    If the condition is true then go Long

    Once you implement this logic your formula should work correctly.
    You may also want to add two further conditions to exit the current trade if the shorter moving averages cross in the opposite direction

    Set 4 = Check if 144ema > 89ema AND 13ema < 5ema AND Strategy.isShort is true
    If the condition is true then Cover
    Set 5 = Check if 144ema < 89ema AND 13ema > 5ema AND Strategy.isLong is true
    If the condition is true then Sell

    Hope this helps
    Alex

    Comment


    • #3
      Thanks Alexis! I'll try this this afternoon, and see. I watch the support you guys (and ladies ) give around here and it's just amazing. Thanks again!

      Originally posted by Alexis C. Montenegro
      techinvest
      If you are backtesting a SAR strategy you don't need to first close the current trade and then enter a new one. You can simply reverse the trade by making a call in the opposite direction. See the Notes in this article in the EFS KnowledgeBase.
      As to your example you should adjust it along the following logic

      Set 1 = Check that 144 EMA has been generated
      Set 2 = Check if 144ema > 89ema AND 13ema > 5ema AND Strategy.isShort is false
      If the condition is true then go Short
      Set 3 = Check if 144ema < 89ema AND 13ema < 5ema AND Strategy.isLong is false
      If the condition is true then go Long

      Once you implement this logic your formula should work correctly.
      You may also want to add two further conditions to exit the current trade if the shorter moving averages cross in the opposite direction

      Set 4 = Check if 144ema > 89ema AND 13ema < 5ema AND Strategy.isShort is true
      If the condition is true then Cover
      Set 5 = Check if 144ema < 89ema AND 13ema > 5ema AND Strategy.isLong is true
      If the condition is true then Sell

      Hope this helps
      Alex

      Comment


      • #4
        techinvest
        You are most welcome
        Alex

        Comment


        • #5
          OK you told me to implement my strategy this way and that's exactly the strategy I had in mind. Thanks for the correct groupings.

          Set 1 = Check that 144 EMA has been generated
          Set 2 = Check if 144ema > 89ema AND 13ema > 5ema AND Strategy.isShort is false
          If the condition is true then go Short
          Set 3 = Check if 144ema < 89ema AND 13ema < 5ema AND Strategy.isLong is false
          If the condition is true then go Long
          Set 4 = Check if 144ema > 89ema AND 13ema < 5ema AND Strategy.isShort is true
          If the condition is true then Cover
          Set 5 = Check if 144ema < 89ema AND 13ema > 5ema AND Strategy.isLong is true
          If the condition is true then Sell


          OK, by problem is this: the entries and exits by the 5, -1 EMA and the 13 EMA seem to be fine, but the 89 and 144 EMA crossings are giving me a little trouble. It seems that after they cross it takes quite some time for the conditions to be found valid. Here's an example:



          Where I see the conditions being met @ 5AM on 10/20 (point A), the backtester sees them becoming valid many hours later (point B). The exits which depend only on the 5, -1 and the 13 EMA crossings seem to be OK (point C). Why is there such a lag?

          Here's my revised efs code:

          PHP Code:
          //{{EFSWizard_Description

          //

          //    This formula was generated by the Alert Wizard

          //

          //}}EFSWizard_Description





          //{{EFSWizard_Declarations
          var vEMA5_of_HLC3 = new MAStudy(5, -1"HLC/3"MAStudy.EXPONENTIAL);
          var 
          vEMA13_of_HLC3 = new MAStudy(130"HLC/3"MAStudy.EXPONENTIAL);
          var 
          vEMA89_of_HL2 = new MAStudy(890"HL/2"MAStudy.EXPONENTIAL);
          var 
          vEMA144_of_HL2_2 = new MAStudy(1440"HL/2"MAStudy.EXPONENTIAL);
          var 
          vLastAlert = -1;
          //}}EFSWizard_Declarations





          function preMain() {

             
          /**

              *  This function is called only once, before any of the bars are loaded.

              *  Place any study or EFS configuration commands here.

              */

          //{{EFSWizard_PreMain
              
          setPriceStudy(true);
              
          setStudyTitle("MA Xover Trend Study");
              
          setCursorLabelName("EMA 5 -1"0);
              
          setCursorLabelName("EMA 13"1);
              
          setCursorLabelName("EMA 89"2);
              
          setCursorLabelName("EMA 144"3);
              
          setDefaultBarStyle(PS_SOLID0);
              
          setDefaultBarStyle(PS_SOLID1);
              
          setDefaultBarStyle(PS_SOLID2);
              
          setDefaultBarStyle(PS_SOLID3);
              
          setDefaultBarFgColor(Color.blue0);
              
          setDefaultBarFgColor(Color.red1);
              
          setDefaultBarFgColor(Color.yellow2);
              
          setDefaultBarFgColor(Color.white3);
              
          setDefaultBarThickness(20);
              
          setDefaultBarThickness(21);
              
          setDefaultBarThickness(22);
              
          setDefaultBarThickness(23);
              
          setPlotType(PLOTTYPE_LINE0);
              
          setPlotType(PLOTTYPE_LINE1);
              
          setPlotType(PLOTTYPE_LINE2);
              
          setPlotType(PLOTTYPE_LINE3);
          //}}EFSWizard_PreMain



          }



          function 
          main() {

             
          /**

              *  The main() function is called once per bar on all previous bars, once per

              *  each incoming completed bar, and if you don't have 'setComputeOnClose(true)'

              *  in your preMain(), it is also called on every tick.

              */



          //{{EFSWizard_Expressions
              //{{EFSWizard_Expression_1
                  
          if (
                      
          vEMA144_of_HL2_2.getValue(MAStudy.MA) == null
                  
          onAction1()
              
          //}}EFSWizard_Expression_1
              
              //{{EFSWizard_Expression_2
                  
          else if (
                      
          Strategy.isShort() == false &&
                      
          vEMA89_of_HL2.getValue(MAStudy.MA) > vEMA144_of_HL2_2.getValue(MAStudy.MA) &&
                      
          vEMA5_of_HLC3.getValue(MAStudy.MA) > vEMA13_of_HLC3.getValue(MAStudy.MA)
                  ) 
          onAction2()
              
          //}}EFSWizard_Expression_2
              
              //{{EFSWizard_Expression_3
                  
          else if (
                      
          Strategy.isLong() == false &&
                      
          vEMA89_of_HL2.getValue(MAStudy.MA) < vEMA144_of_HL2_2.getValue(MAStudy.MA) &&
                      
          vEMA5_of_HLC3.getValue(MAStudy.MA) < vEMA13_of_HLC3.getValue(MAStudy.MA)
                  ) 
          onAction3()
              
          //}}EFSWizard_Expression_3
              
              //{{EFSWizard_Expression_4
                  
          else if (
                      
          Strategy.isShort() == true &&
                      
          vEMA5_of_HLC3.getValue(MAStudy.MA) > vEMA13_of_HLC3.getValue(MAStudy.MA)
                  ) 
          onAction4()
              
          //}}EFSWizard_Expression_4
              
              //{{EFSWizard_Expression_5
                  
          else if (
                      
          Strategy.isLong() == true &&
                      
          vEMA5_of_HLC3.getValue(MAStudy.MA) < vEMA13_of_HLC3.getValue(MAStudy.MA)
                  ) 
          onAction5();
              
          //}}EFSWizard_Expression_5
              
          //}}EFSWizard_Expressions





          //{{EFSWizard_Return
              
          return new Array(
                  
          vEMA5_of_HLC3.getValue(MAStudy.MA),
                  
          vEMA13_of_HLC3.getValue(MAStudy.MA),
                  
          vEMA89_of_HL2.getValue(MAStudy.MA),
                  
          vEMA144_of_HL2_2.getValue(MAStudy.MA)
              );
          //}}EFSWizard_Return



          }



          function 
          postMain() {

             
          /**

              *  The postMain() function is called only once, when the EFS is no longer used for

              *  the current symbol (ie, symbol change, chart closing, or application shutdown).

              */

          }



          //{{EFSWizard_Actions
              //{{EFSWizard_Action_1
              
          function onAction1() {
                  
          vLastAlert 1;
              }
              
          //}}EFSWizard_Action_1
              
              //{{EFSWizard_Action_2
              
          function onAction2() {
                  
          Strategy.doLong(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
                  
          vLastAlert 2;
              }
              
          //}}EFSWizard_Action_2
              
              //{{EFSWizard_Action_3
              
          function onAction3() {
                  
          Strategy.doShort(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
                  
          vLastAlert 3;
              }
              
          //}}EFSWizard_Action_3
              
              //{{EFSWizard_Action_4
              
          function onAction4() {
                  
          Strategy.doCover(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
                  
          vLastAlert 4;
              }
              
          //}}EFSWizard_Action_4
              
              //{{EFSWizard_Action_5
              
          function onAction5() {
                  
          Strategy.doSell(""Strategy.CLOSEStrategy.THISBARStrategy.DEFAULT, 0);
                  
          vLastAlert 5;
              }
              
          //}}EFSWizard_Action_5
              
          //}}EFSWizard_Actions 
          And attached, just in case you need it that way.


          Th
          Attached Files

          Comment


          • #6
            techinvest
            First of all I would suggest against using averages with negative offsets. While on historical data they may seem to be generating signals that are ahead of the market that is only a false impression. Furthermore unless you specifically set your conditions to look back an amount of bars equal to the offset - which you are not doing and which would negate the apparent advantage - they will return unrealistic results in back testing as they are looking into the future (see this post for a brief example on how negative offsets can false back testing results)
            As to the issues you are seeing check your conditions as they do not match the ones I suggested in my prior reply.
            Alex

            Comment


            • #7
              OK, I got it! Thanks for the help...

              ... but I have another question (of course). How would I add the lookback condition? I want as realistic a picture as I can get of this strategy.

              Also, I know it sounds a bit odd, but just for arguments sake. If I added an offset of +1 to the other EMA would it give me a more realistic picture?


              Originally posted by Alexis C. Montenegro
              techinvest
              First of all I would suggest against using averages with negative offsets. While on historical data they may seem to be generating signals that are ahead of the market that is only a false impression. Furthermore unless you specifically set your conditions to look back an amount of bars equal to the offset - which you are not doing and which would negate the apparent advantage - they will return unrealistic results in back testing as they are looking into the future (see this post for a brief example on how negative offsets can false back testing results)
              As to the issues you are seeing check your conditions as they do not match the ones I suggested in my prior reply.
              Alex

              Comment


              • #8
                techinvest
                The appropriate solution IMO is to not use a negative offset If you need to have a relative offset between the two averages then you can achieve the same result by removing the negative offset from one average and applying a positive offset of equal value to the other average.
                Run the following two sets of code on the same chart and you will see that the results are identical.
                In the first script a negative offset is applied to the shorter average. In this example the conditions are set to look back the appropriate number of bars otherwise the back test would be unrealistic as it would be forward looking
                In the second script a positive offset is instead applied to the longer average. In this case the conditions do not require any particular arrangement as they are always based on the current bar. IMO this is the preferred solution as it is less conducive to errors when setting conditions etc.
                Alex


                PHP Code:
                var MA1 = new MAStudy(5, -1"Close"MAStudy.SIMPLE);
                var 
                MA2 = new MAStudy(100"Close"MAStudy.SIMPLE);

                function 
                main(){

                    if(
                MA1.getValue(MAStudy.MA,-1) > MA2.getValue(MAStudy.MA,-1) && !Strategy.isLong())
                        
                Strategy.doLong("Long",Strategy.CLOSE,Strategy.THISBAR);
                        
                    if(
                MA1.getValue(MAStudy.MA,-1) < MA2.getValue(MAStudy.MA,-1) && Strategy.isLong())
                        
                Strategy.doSell("Sell",Strategy.CLOSE,Strategy.THISBAR);
                    
                    if(
                Strategy.isLong()) 
                        
                setBarBgColor(Color.yellow);
                        
                    return new Array (
                MA1.getValue(MAStudy.MA,0),MA2.getValue(MAStudy.MA,0));

                PHP Code:
                var MA1 = new MAStudy(50"Close"MAStudy.SIMPLE);
                var 
                MA2 = new MAStudy(101"Close"MAStudy.SIMPLE);

                function 
                main(){

                    if(
                MA1.getValue(MAStudy.MA,0) > MA2.getValue(MAStudy.MA,0) && !Strategy.isLong())
                        
                Strategy.doLong("Long",Strategy.CLOSE,Strategy.THISBAR);
                        
                    if(
                MA1.getValue(MAStudy.MA,0) < MA2.getValue(MAStudy.MA,0) && Strategy.isLong())
                        
                Strategy.doSell("Sell",Strategy.CLOSE,Strategy.THISBAR);
                    
                    if(
                Strategy.isLong()) 
                        
                setBarBgColor(Color.yellow);
                        
                    return new Array (
                MA1.getValue(MAStudy.MA,0),MA2.getValue(MAStudy.MA,0));

                Comment


                • #9
                  Wow... thank you very much Alexis.

                  Unfortunatley I think I've run out of questions for the moment , thanks again.

                  Comment

                  Working...
                  X