Step 1a: Goal: identify marginally-profitable edge
No WFO; No oversample; Simple Stop; Std entry

So in step one we test the trading logic naked to see if it has an edge. A straight backtest, no Oversampling, a simple stop with no defined appropriate logic. Std entry also follows the generic nature of the stop.

Code:
function run()
{
	//Parameters
  	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20131220;
	BarPeriod = 60;
	
//edge trading logic
  var  BarsPassed = optimize(1000,500,1500,10); // refers to the barspassed to the LowPass function.
  
  vars Price = series(price());
  vars Trend = series(LowPass(Price,BarsPassed));

  Stop = 4*ATR(100); //simple stop level
    
  if(valley(Trend))
    enterLong(); //standard entry
  else if(peak(Trend))
    enterShort(); //standard entry
}



Code:
TF-e1 EUR/USD 2008..2013
Read TF-e1_EURUSD.par
Profit 438$  MI 6$  DD 138$  Capital 104$
Trades 464  Win 22%  Avg +12.4p  Bars 76
AR 73%  PF 1.41  SR 0.63  UI 20.0%  Error 38%



Running this simple code produces a return of over 73% meaning it has an edge or exploits some inefficiency in the market. I therefore proceed to 1b.

Step 1b: optimize the BarPeriod
I prefer longer time frames because it is my belief that they reduce errors in backtesting *belief based on no research*. I will let Zorro however test and tell me which barperiods produce the best results based on the current nature of the strategy.
I want to manually review the optimization chart for this step, so I hardcode the number of bars argument passed into the LowPass function, which I can do by getting the found-best values out of the Data/script.par file. The .par file tells me 810 is the best figure to use.

Training then with only 1 optimized parameter (the BarPeriod) will cause Zorro to produce the optimallity chart that I can use. I can see clearly from this chart that BarPeriod 60 is indeed the best of the bunch.
Code:
function run()
{
	//Parameters
  	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20131220;
	BarPeriod = optimize(60,60,1440,60);
	
	//edge trading logic
  var  BarsPassed = 810; //optimize(810,500,1500, 10) ... refers to the barspassed to the LowPass function.
  
  vars Price = series(price());
  vars Trend = series(LowPass(Price,BarsPassed));

  Stop = 4*ATR(100); //simple stop level
    
  if(valley(Trend))
    enterLong(); //standard entry
  else if(peak(Trend))
    enterShort(); //standard entry
}


The graph does show that the system is profitable over a lot of time frames but the highest profit and number of trades is achieved when I use the one hour. So I will stick to that.


Step 1c: Goal: identify optimizable parameters
No WFO; No oversample; Simple Stop; Std entry
In this step, I want to focus on all the parameters that might play a role in the edge logic specifically. I need to try to keep a global view of my ultimate intent, which is to produce a multi-asset tradebot. The parameters that work for my current asset (I have started with EURUSD) may not be appropriate for other assets, so I want to give them the flexibility to move around for other asset personalities, and for market changes over time.

Therefore, ideally, I want to try to identify parameters that do affect core logic and give them flexibility to adjust (via Zorro's optimizer), but at the same time I want to constrain them based on a reasonable range that will be identified from the parameter optimization charts. Zorro will only produce an opt chart if I am optimizing 1 parameter, so I need to first hardcode the other parameters and then individually check each one to review its opt chart. With this strategy, the parameter that affects core logic is called BarPassed. The parameter should already be hardcoded from our last Step 1b, because we needed to do that in order to check that BarPeriod opt chart. So now I will hardcode BarPeriod back to 60 minutes, and select the first parameter to be optimized. (TIP: so that I don't forget what the original optimal parameter was, I set this value as the "start" value in the optimizer call.)

Code:
function run()
{
	//Parameters
  	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20131220;
	BarPeriod = 60; // optimize(60,60,1440,60);
	
	//edge trading logic
  var  BarsPassed = 820; // optimize(820,500,1500, 10);
  
  vars Price = series(price());
  vars Trend = series(LowPass(Price,BarsPassed));

  Stop = 4*ATR(100); //simple stop level
    
  if(valley(Trend))
    enterLong(); //standard entry
  else if(peak(Trend))
    enterShort(); //standard entry
}





I initially set the "reasonable range" of the parameter BarsPassed to 750-1200, with the optimal value of 820 in the "start" position. Since this is the only logic parameter we are optimizing, I was not too comfortable putting such a narrow constraint on the parameter. I therefore left the range as it was initially.
I am done optimizing core-logic parameters, I now re-Train and re-Test. In multi-parameter Trains, Zorro only looks at one parameter at a time, and relies on the "start" value for all other parameters. Since we are optimizing only one parameter in this section mainly because of the nature of this code, we end up with basically the same returns.
Code:
function run()
{
	//Parameters
  	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20131220;
	BarPeriod = 60; // optimize(60,60,1440,60);
	
	//edge trading logic
  var  BarsPassed = 820; // optimize(820,500,1500, 10);
  
  vars Price = series(price());
  vars Trend = series(LowPass(Price,BarsPassed));

  Stop = 4*ATR(100); //simple stop level
    
  if(valley(Trend))
    enterLong(); //standard entry
  else if(peak(Trend))
    enterShort(); //standard entry
}



Step 1d
No WFO; No oversample; Rev entry
In this step, I add the enhancements of reverseLong() and reverseShort() to replace the simple entries. These helper functions have special features that are desirable and explained in Workshop 5.

Also in this step, I perform the same optimization as in Step 1c, focusing specifically on the Stop. To find a good-working ATR value for this tradebot, I tested the following varieties before settling on ATR(200): 300, 200, 150, 100, 50, 25, 10. At this point I was thinking of just creating a new variable and setting it to pass optimized values to the
ATR function, but I was a bit hestitant as this might qualify as curve fitting. I will
look into the possibility when I improve at this.I settled on 200.
Here is the resultant code after all these adjustments:
Code:
function run()
{
	//Parameters
  	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20131220;
	BarPeriod = 60; // optimize(60,60,1440,60);
	
	//edge trading logic
  var  BarsPassed = 820; // optimize(820,500,1500, 10);
  
  vars Price = series(price());
  vars Trend = series(LowPass(Price,BarsPassed));

  Stop = optimize(5,1,15,1,-5)*ATR(100);
    
  if(valley(Trend))
    //enterLong(); //standard entry
	   reverseLong(1);
  else if(peak(Trend))
    //enterShort(); //standard entry
		reverseShort(1);
}



Step 1e
Yes WFO; Yes oversample, Rev entry
In this step, I've added a variable to control maxtrades (a feature of the reverseLong() and reverseShort() helper functions). I can get an idea of how many trades the system might take from looking at the Performance Report on Step 1c. I will manually adjust the value up and down to determine how many trades are most appropriate.

Also in this step, I've added oversampling. This is described in the manual. I will use an oversampling value of 3.

Going by dusktraders findings, I will be using his if code to set oversampling on only during Test. To accommodate this, I add some code to make sure NumSampleCycles is never set during a Train, but always set during a Test.

Additionally, this step adds Rolling Walk-Forward-Optimization. I have added dusktradesrs code that warns me (and stops the Train) if it falls below a threshold of 30 trades per cycle.
Code:
function run()
{
	//Parameters
  	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20131220;
	BarPeriod = 60; // optimize(60,60,1440,60);
	
	if(is(TESTMODE)) NumSampleCycles = 3; //oversampling on Test only, not Train
	if (Train) { RollLong = 0; RollShort = 0; } //help prevent asymmetry in parameters & profit factors
	DataSplit = 70; //70% training, 30% OOS test
	NumWFOCycles = 5;
	int maxtrades = 1;

	//require minimum 30 trades per WFO cycle or stop training
	static int LastWFOCycle = 0, LastNumTrades = 0;
	if(Train && (WFOCycle != LastWFOCycle) )
	{
		if(LastNumTrades > 0 and LastNumTrades < 30)
		{
			char tradecount[100];
			sprintf(tradecount,"Not enough trades per cycle: %d",LastNumTrades);
			quit(tradecount);
		}
		LastWFOCycle = WFOCycle;
	}
	LastNumTrades = NumWinTotal+NumLossTotal;
	
	//edge trading logic
  var  BarsPassed = 820; // optimize(820,500,1500, 10);
  
  vars Price = series(price());
  vars Trend = series(LowPass(Price,BarsPassed));

  Stop = optimize(5,1,15,1,-5)*ATR(100);
    
  if(valley(Trend))
   	   reverseLong(1);
  else if(peak(Trend))
   		reverseShort(1);
}


In this step, I am looking for only a "reasonable positive return", because future adjustments will have a major impact on profitability. As you can see, I'm incrementally changing the composition of the strategy. With each change, I check the Test result to make sure nothing has gone haywire (and backtrack if it does).
Code:
Walk-Forward Test: TF-e1 EUR/USD 2008..2013
Read TF-e1_EURUSD_1.par TF-e1_EURUSD_2.par TF-e1_EURUSD_3.par TF-e1_EURUSD_4.par
Profit 238$  MI 5$  DD 113$  Capital 106$
Trades 271  Win 24%  Avg +11.5p  Bars 82
AR 60%  PF 1.43  SR 0.63  UI 21.7%  Error 43%


Off to go grab a meal. I will be back to go through the next processes in a couple of hours. The reason I am doing this on here is to get the more advanced coders and traders to point out shortfalls in my reasoning in how I am adapting dusktraders approach. So all inputs are welcome.