Step 1c: Goal: identify optimizable parameters
No WFO; No oversample; Simple Stop; Std entry
In this step, I want 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. In this example, the parameters that affect core logic are called TimeCycle and TimeFactor. The parameters 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 15 minutes, and select the first parameter to be optimized. (TIP: so that I don't forget what the original optimal parameter was, I will set this value as the "start" value in the optimizer call.)

Code:
function run()
{
	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20130531;
	BarPeriod = 15;
   
	//edge trading logic
	var TimeCycle = optimize(61,50,100,1,0);
	var TimeFactor = 2.8; //optimize(2.8,1,5,0.2,0);
	Stop = BarPeriod*PIP; //simple stop level
	LookBack = 100*5;

	vars Price = series(price(0));
	vars MA1 = series(SMA(Price,TimeCycle));
	vars MA2 = series(SMA(Price,TimeCycle*TimeFactor));

	if(crossOver(MA1,MA2))
		enterLong(); //standard entry
	else if(crossUnder(MA1,MA2))
		enterShort(); //standard entry
}




And then I set the "reasonable range" of that parameter (in this case, TimeCycle was set at 55-75, with the optimal value of 63 in the "start" position). Now just repeat this process for the other parameter:

Code:
function run()
{
	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20130531;
	BarPeriod = 15;
   
	//edge trading logic
	var TimeCycle = 63; //optimize(63,55,75,1,0);
	var TimeFactor = optimize(2.8,1,5,0.2,0);
	Stop = BarPeriod*PIP; //simple stop level
	LookBack = 100*5;

	vars Price = series(price(0));
	vars MA1 = series(SMA(Price,TimeCycle));
	vars MA2 = series(SMA(Price,TimeCycle*TimeFactor));

	if(crossOver(MA1,MA2))
		enterLong(); //standard entry
	else if(crossUnder(MA1,MA2))
		enterShort(); //standard entry
}


For this parameter, since the range is already very small, I decided not to constrain it any further. I actually expanded it to start with a value below 1 as well, to give it a little more room.


Finally, after identifying all optimizable core-logic parameters and constraining their ranges, 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. For this reason, the results could now appear better than before, since we've set the reasonable ranges.
Code:
function run()
{
	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20130531;
	BarPeriod = 15;
   
	//edge trading logic
	var TimeCycle = optimize(63,55,75,1,0);
	var TimeFactor = optimize(2.6,0.2,5,0.2,0);
	Stop = BarPeriod*PIP; //simple stop level
	LookBack = 100*5;

	vars Price = series(price(0));
	vars MA1 = series(SMA(Price,TimeCycle));
	vars MA2 = series(SMA(Price,TimeCycle*TimeFactor));

	if(crossOver(MA1,MA2))
		enterLong(); //standard entry
	else if(crossUnder(MA1,MA2))
		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, only focusing specifically on the Stop and Trail. 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.

The LookBack is now also adjusted to 600, which is required for the ATR(200) that I used. Here is the resultant code after all these adjustments:
Code:
function run()
{
	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20130531;
	BarPeriod = 15;
   
	//edge trading logic
	var TimeCycle = optimize(63,55,75,1,0);
	var TimeFactor = optimize(2.6,0.2,5,0.2,0);
	//Stop = BarPeriod*PIP; //simple stop level
	Stop = ATR(200) * optimize(1.99,1,15,0.5,-3); // allow 3% tolerance for preferring low stop distances
	Trail = ATR(200) * optimize(8.5,3,13,0.5);
	LookBack = 600;

	vars Price = series(price(0));
	vars MA1 = series(SMA(Price,TimeCycle));
	vars MA2 = series(SMA(Price,TimeCycle*TimeFactor));

	if(crossOver(MA1,MA2))
		//enterLong(); //standard entry
		reverseLong(1);
	else if(crossUnder(MA1,MA2))
		//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 here. Though the manual indicates values higher than 6 should not produce better results, I have found that I prefer a value of 15. My understanding is that higher values are not any risk, they only increase the Test time.

It's important to note that (at least in my findings), oversampling does not work well during a Train. To accommodate this, I've added 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 learned that it is important to get "enough" trades per cycle, so I've added some code that warns me (and stops the Train) if it falls below a threshold of 30 trades per cycle.

Code:
function run()
{
	set(PARAMETERS);
	StartDate = 20080101;
	EndDate = 20130531;
	BarPeriod = 15;
	LookBack = 600;
	if(is(TESTMODE)) NumSampleCycles = 15; //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 TimeCycle = optimize(63,55,75,1,0);
	var TimeFactor = optimize(2.6,0.2,5,0.2,0);
	//Stop = BarPeriod*PIP; //simple stop level
	Stop = ATR(200) * optimize(1.99,1,15,0.5,-3); // allow 3% tolerance for preferring low stop distances
	Trail = ATR(200) * optimize(8.5,3,13,0.5);

	vars Price = series(price(0));
	vars MA1 = series(SMA(Price,TimeCycle));
	vars MA2 = series(SMA(Price,TimeCycle*TimeFactor));

	if(crossOver(MA1,MA2))
		//enterLong(); //standard entry
		reverseLong(maxtrades);
	else if(crossUnder(MA1,MA2))
		//enterShort(); //standard entry
		reverseShort(maxtrades);
}



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 tradebot. With each change, I check the Test result to make sure nothing has gone haywire (and backtrack if it does).
Quote:
Walk-Forward Test: dt-demo1 EURUSD 2008..2013
Read dt-demo1_EURUSD_1.par dt-demo1_EURUSD_2.par dt-demo1_EURUSD_3.par dt-demo1_EURUSD_4.par
Profit 17$ MI 0$ DD 15$ Capital 16$
Trades 569 Win 28% Avg +2.9p Bars 51
AR 33% PF 1.16 SR 0.60 UI 19.6% Error 28%