dt-e8 MA-crossover, built for Zorro v1.20

Posted By: dusktrader

dt-e8 MA-crossover, built for Zorro v1.20 - 11/27/13 22:21

I'm working on rebuilding dt-e7 (aka "demo5"). I have made a number of changes to my build process and wanted to share. This tradebot is being built under Zorro 1.20 and I expect to trade it live once it's done. I'll share my build process along the way and you can feel free to add improvements or any input really.

The former iterations of this tradebot did not properly handle the Margin=0 situation, instead taking 1 Lot trades. I believe this affected the optimization too much, so I've started over from scratch on this build (note in Zorro v1.20, Margin=0 will no longer open a live trade).

I initially started with EURUSD, but was not very satisfied with the results. I then moved to NZDJPY and was happier with that basis, so I used that asset as the core to build out from. Therefore, in dt-e8 EURUSD is completely unused.

The infrastructure is constantly evolving and (hopefully) improving as well. Almost everything works now, several bugs squashed, and no more known issues as of Zorro 1.20.

I've identified the 7 pairs now that I'll use for this tradebot: USDJPY; EURAUD; EURCAD; AUDUSD; AUDCHF; AUDJPY; NZDJPY

Just for fun, I've calculated the "what if" scenario, if this tradebot were to go live today. But it's only optimized for 1 asset, not the other 6 (that's the work still left to do...) But I can use this scenario as a benchmark for comparison... to see how much better the tradebot will become when its fully optimized.

Quote:
Walk-Forward Test: dt-e8 portfolio 2008..2013
Read dt-e8.fac dt-e8_1.par dt-e8_2.par dt-e8_3.par dt-e8_4.par
Profit 6565$ MI 148$ DD 764$ Capital 1069$
Trades 2768 Win 32% Avg +240.9p Bars 157
CAGR 73% PF 1.35 SR 1.65 UI 6.0% Error 17%


Code:
function fridayClose(int fridayclose)
{
	//allows Friday trading up until NYSE 3pm; close trades and don't allow after this
	if(fridayclose && dow() == FRIDAY && lhour(ET) >= 15) 
		{
			exitLong("*");
			exitShort("*");
			return 1; //condition met; indicate no further trades
		}
	return 0; //condition not met; safe to take new trades
}

function hourOpen(int hourblockstart, int hourblockend)
{
	//blocks new open trades between selected hours
	//uses NYSE time, including DST
	if ( (lhour(ET) >= hourblockstart) && (lhour(ET) < hourblockend) )
		return 0; //between blocked hours, do not allow trade opens
	else
		return 1; //no conditions met, allow trades by default
}

function todayOpenCombo(var dayopencombo)
{
	//allows optimizer to specify the best combo of days for opens
	//bit position 0 = Monday
	//bit position 1 = Tuesday
	//bit position 2 = Wednesday
	//bit position 3 = Thursday
	//bit position 4 = Friday
	//bit position 5 = Sunday
	//given a combination #, the function will return whether
	//current dow() is in the combination

	int dayopencombobits = dayopencombo+.5; //truncate to rounded int
	int today = dow() - 1; //Mon is 0
	if (today == 6) today = 5; //bump Sun to 5 (no Sat, keep binary range 0-63)

	if (dayopencombobits & (1 << today)) return 1; //current dow() is in the combo
		else return 0; //current dow() not in combo, do not allow trade opens
}

function todayCloseCombo(var dayclosecombo)
{
	//allows optimizer to specify the best combo of days to close by NYSE 4pm
	//bit position 0 = Monday
	//bit position 1 = Tuesday
	//bit position 2 = Wednesday
	//bit position 3 = Thursday
	//bit position 4 = Friday
	//bit position 5 = Sunday
	//given a combination #, the function will determine if we are beyond
	//a combo close time, close all trades if necessary, and return 1
	//if no further trades allowed today

	int dayclosecombobits = dayclosecombo+.5; //truncate to rounded int
	int today = dow() - 1; //Mon is 0
	if (today == 6) today = 5; //bump Sun to 5 (no Sat, keep binary range 0-63)

	if ((dayclosecombobits & (1 << today)) && lhour(ET) >= 16) 
	{
		exitLong("*");
		exitShort("*");
		return 1; //current dow() is in the combo; indicate no further trades
	}
	else return 0; //current dow() not in combo, safe to take new trades
}

function marketOpenCombo(var marketopencombo)
{
	//allows optimizer to specify best markets to initiate trades
	//bit position 0 = New York 8am-5pm Eastern
	//bit position 1 = Sydney 5pm-2am Eastern
	//bit position 2 = Tokyo 7pm-4am Eastern
	//bit position 3 = London 3am-12pm Eastern
	//given a combination #, the function will determine if current time is within
	//a market part of the combination (returns 1 to allow trading if true)
	
	int marketcombobits = marketopencombo+.5; //truncate to rounded int
	if ( (lhour(ET) >=8) && (lhour(ET) <17) && (marketcombobits & (1 << 0)) ) return 1; //inside New York
	if ( (lhour(ET) >=17) || (lhour(ET) <2) && (marketcombobits & (1 << 1)) ) return 1; //inside Sydney
	if ( (lhour(ET) >=19) || (lhour(ET) <4) && (marketcombobits & (1 << 2)) ) return 1; //inside Tokyo
	if ( (lhour(ET) >=3) && (lhour(ET) <12) && (marketcombobits & (1 << 3)) ) return 1; //inside London
	return 0; //default - current market not in combination, don't allow trade opens
}

function checkTradesPerCycle()
{
	//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;
}

function calculateMargin(int direction)
{
	//calculate risk Margin based on OptimalF and trade direction
	Capital = 1000; //simulated account balance
	var riskCapital = 300; //basis to trade with

	if (direction && OptimalF>.001) //long trade, historically profitable
		{
		Lots = 1; //allow live trading
		return OptimalFLong * riskCapital;
		}
	else if (!direction && OptimalF>.001) //short trade, historically profitable
		{
		Lots = 1; //allow live trading
		return OptimalFShort * riskCapital;
		}
	else
		Lots = -1; //non-historically profitable = phantom live trades only

	return 0; //no Margin allocated for non-historically profitable
}

function getOpt(string param)
{
	switch (Asset)
	{
		case "EURUSD":
			switch (param)
			{
				case "timecycle": return optimize(75,65,85,1,0);
				case "timefactor": return optimize(2.4,0.2,5,0.2,0);
				case "stop": return optimize(7.5,2,15,0.5,-1);
				case "trail": return optimize(8,3,11,0.5);
				case "maxtrades": return 5; //limit trades per signal
				case "marketopencombo": return optimize(13,1,15,1); //15)every market
				case "dayopencombo": return 63; //optimize(61,1,63,1); //63)every day
				case "dayclosecombo": return 0; //optimize(33,1,63,1); //0)none; 63)every day
				case "fridayclose": return 1; //no trades after NYSE 3pm Friday
				case "reversedir": return 0; //trade opposite signals: 0)normal trade direction
				case "hedge": return 0; //Hedge mode: 0)none, 4)virtual
				case "hourblockstart": return 0; //block trade opens beginning at NY hour
				case "hourblockend": return 0; //block trade opens ending at NY hour
				case "lossstreaks": return 21; //0)no limit
				case "emode": return 0; //equity-curve trading: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
			}
		case "NZDJPY":
			switch (param)
			{
				case "timecycle": return optimize(70,60,80,1,0);
				case "timefactor": return optimize(2.4,0.2,5,0.2,0);
				case "stop": return optimize(4,1,7,0.5,-2);
				case "trail": return optimize(7,3,11,0.5);
				case "maxtrades": return 7; //limit trades per signal
				case "marketopencombo": return 15; //optimize(9,1,15,1); //15)every market
				case "dayopencombo": return 63; //optimize(13,1,63,1); //63)every day
				case "dayclosecombo": return 0; //optimize(34,1,63,1); //0)none; 63)every day
				case "fridayclose": return 0; //no trades after NYSE 3pm Friday
				case "reversedir": return 0; //trade opposite signals: 0)normal trade direction
				case "hedge": return 4; //Hedge mode: 0)none, 4)virtual
				case "hourblockstart": return 0; //block trade opens beginning at NY hour
				case "hourblockend": return 0; //block trade opens ending at NY hour
				case "lossstreaks": return 19; //0)no limit
				case "emode": return 1; //equity-curve trading: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
			}
		default: //use with Step 3a: prospecting
			switch (param)
			{
				case "timecycle": return optimize(70,60,80,1,0);
				case "timefactor": return optimize(2.4,0.2,5,0.2,0);
				case "stop": return optimize(4,1,7,0.5,-2);
				case "trail": return optimize(7,3,11,0.5);
				case "maxtrades": return 7; //limit trades per signal
				case "marketopencombo": return 15; //optimize(9,1,15,1); //15)every market
				case "dayopencombo": return 63; //optimize(13,1,63,1); //63)every day
				case "dayclosecombo": return 0; //optimize(34,1,63,1); //0)none; 63)every day
				case "fridayclose": return 0; //no trades after NYSE 3pm Friday
				case "reversedir": return 0; //trade opposite signals: 0)normal trade direction
				case "hedge": return 0; //Hedge mode: 0)none, 4)virtual
				case "hourblockstart": return 0; //block trade opens beginning at NY hour
				case "hourblockend": return 0; //block trade opens ending at NY hour
				case "lossstreaks": return 0; //0)no limit
				case "emode": return 0; //equity-curve trading: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
			}
	}
}

function checkEquity()
{
	int emode = getOpt("emode");
	if (!emode) return; //no equity-curve trading

	//emode 1 = standard: sets phantom/normal mode only (via Lots)
	//emode 2 = switch hitter: always in market (Lots=1), fades direction (via dir)
	//emode 3 = reward success with weighting: increase trades based on degree of improvement
	//emode 4 = mean reversion: trade when equity curve falls (Lots=1), sit out when it rises (Lots=-1)
	vars EquityCurve = series(EquityLong+EquityShort); //includes all phantom equity
	var dir; //indicates normal trade direction (dir=1) or reverse (dir=-1)

	//narrower curves
	//var slow = 50;
	//var fast = 10;

	//wider curves
	//var slow = 100;
	//var fast = 10;

	//mega-wide curves
	var slow = 200;
	var fast = 10;

	//uber-wide curves
	//var slow = 300;
	//var fast = 10;

	//optimized curves
	//var slow = optimize(50,50,300,12);
	//var fast = 10;

	vars EquityLP = series(LowPass(EquityCurve,fast));
	var EquityLPfalling = LowPass(EquityLP,slow);
	var EquityLPrisingBigger = LowPass(EquityLP,slow*3.2);
	var EquityLPrisingBig = LowPass(EquityLP,slow*1.5);
	//plot("EquityLPslow",LowPass(EquityLP,slow),1,BLUE);
	//plot("EquityLPfast",LowPass(EquityLP,fast),0,GREEN);
	
	if(EquityLP[0] < EquityLPfalling && falling(EquityLP)) { //drawdown
		if (emode==1) Lots = -1; //set phantom trade mode
		if (emode==2) return 1; //fade: take signals when losing
		if (emode==3) { //reward success with weighting
			Lots = -1; //set phantom trade mode
			return 1; //allow max 1 phantom trade in drawdown
		}
		if (emode==4) Lots = 1; //mean-reversion: start trading when equity curve falls
		
	}
	else { //positive equity curve
		if (emode==1) Lots = 1; //set normal trade mode
		if (emode==2) return -1; //fade: take reverse signals when winning
		if (emode==3) { //reward success with weighting
			Lots = 1; //set normal trade mode
			if (EquityLP[0] > EquityLPrisingBigger && rising(EquityLP)) return 3; //very big rising
			else if (EquityLP[0] > EquityLPrisingBig && rising(EquityLP)) return 2; //big rising
			else return 1; //rising but not yet significantly
		}
		if (emode==4) Lots = -1; //mean-reversion: stop trading when equity curve rises
	}
}

function checkStreak()
{
	//disallow trading this asset if loss streak threshold breached
	if (getOpt("lossstreaks") && ((LossStreakLong>=getOpt("lossstreaks")) || (LossStreakShort>=getOpt("lossstreaks"))))
	{
		Margin = 0;
		printf("\nWarning: %s breached loss streak limit of %i; may need reTrain",Asset,getOpt("lossstreaks"));
	}
}

function checkModifiers()
{
	int reversedir = getOpt("reversedir"); //default 0=normal trade direction
	int fridayclose = getOpt("fridayclose"); //enforce auto-close and no trades after NYSE 3pm Friday
	int hourblockstart = getOpt("hourblockstart"); //block trade opens beginning at NY hour
	int hourblockend = getOpt("hourblockend"); //block trade opens ending at NY hour
	int dayopencombo = getOpt("dayopencombo"); //combo of days to open; 63=every day
	int dayclosecombo = getOpt("dayclosecombo"); //combo of days to close after NYSE 4pm; 0=none; 63=every day
	int marketopencombo = getOpt("marketopencombo"); //combo of markets to allow trade opens; 15=every market

	if ( (!fridayClose(fridayclose) //close NYSE 3pm on Friday
		|| !todayCloseCombo(dayclosecombo) ) //close NYSE 4pm on selected days
		&& todayOpenCombo(dayopencombo) //open on selected days only
		&& marketOpenCombo(marketopencombo) //open during selected markets only
		&& hourOpen(hourblockstart,hourblockend) ) //open during selected hours only
			return 1; //ok to place new trades
	else
		return 0; //no trade, restricted by a modifier	
}


function run()
{
	AssetList = "Assets-IBFXnano.dta";
	//AssetList = "Assets-IBFXnano-spread100.dta";
	//AssetList = "Assets-IBFXnano-spread300.dta";
	//AssetList = "Assets-FXCMmicro.dta";
	//AssetList = "Assets-FXCMmicro-spread100.dta";
	set(PARAMETERS+ALLCYCLES+FACTORS);
	StartDate = 20080101;
	EndDate = 20131125;
	GapDays = 3; //alert if more than 3 days gap in data
	BarPeriod = 15;
	LookBack = 600;
	DataSplit = 70; //70% training, 30% OOS test
	NumWFOCycles = 5;
	if(is(TESTMODE)) NumSampleCycles = 15; //oversampling on Test only, not Train
	if (Train) { RollLong = 0; RollShort = 0; } //help prevent asymmetry in parameters & profit factors
	checkTradesPerCycle(); //stop Train early if not enough trades
	int reinvestprofits = 1; //invoke margin setting during trade logic
   
	while(asset(loop("USDJPY","EURAUD","EURCAD","AUDUSD","AUDCHF","AUDJPY","NZDJPY")))
	//asset("NZDJPY");
	{
		int maxtrades = getOpt("maxtrades");
		checkEquity(); //equity-curve trading
		Hedge = getOpt("hedge");
		
		//edge trading logic
		var TimeCycle = getOpt("timecycle");
		var TimeFactor = getOpt("timefactor");
		//Stop = BarPeriod*PIP; //simple stop level
		Stop = ATR(100) * getOpt("stop");
		Trail = ATR(100) * getOpt("trail");

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

		if (checkModifiers()) //only evaluate signals if no restrictions in force
		{
			if (crossOver(MA1,MA2) && rising(MA1)) //long signal
			{
				if (reinvestprofits) Margin = calculateMargin(1); //long
				checkStreak(); //disallow trading if loss streak limit breached
				//enterLong(); //standard entry
				if (!getOpt("reversedir")) reverseLong(maxtrades); else reverseShort(maxtrades);
			}
			else if(crossUnder(MA1,MA2) && falling(MA2)) //short signal
			{
				if (reinvestprofits) Margin = calculateMargin(0); //short
				checkStreak(); //disallow trading if loss streak limit breached
				//enterShort(); //standard entry
				if (!getOpt("reversedir")) reverseShort(maxtrades); else reverseLong(maxtrades);
			}
		}
	}

	PlotWidth = 1100;
	PlotHeight1 = 600;
}



Attached picture dt-e8-before-optimizing.png
Attached File
Posted By: Geek

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 11/28/13 15:57

Nice work dusktrader, thanks for sharing, appreciated.

Although the code is quite complex for a learner like myself, it really helps.

Looking forward to following the build process.
Posted By: dusktrader

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 11/28/13 16:57

Please feel free to ask any questions about any parts you don't understand. I am actually a total n00b myself, I've just been working on this nonstop. I'm always looking for ways to make it easier to understand. I've found that even very slight changes (or mistakes) can cause dramatic swings in how the tradebot performs. For that reason, I try to have every process well thought out. If you look at the spreadsheet process, you'll see I have a very specific order of tasks and requirements. There is usually a reason for each one, so please do ask if you are trying to follow and have any question.

Btw I think I started on Zorro 1.12, so I haven't been around that long!
Posted By: dusktrader

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 12/06/13 14:52

I'm really happy with this now, and I'm doing the final Train for my demo account. This bot is "done" now, at least in its current form.

I've made a couple enhancements since the first post in this thread:
The bot now uses very fresh data, up until 11/23/2013. Also, I have started using the OPENEND flag.

After fully optimizing the 7 pairs, I noticed that some pairs were given a very low OptimalF fraction from looking at the .fac file:
Code:
AUDCHF              .054  1.07  176/380    7.4
AUDCHF:L            .061  1.08  113/256    6.1
AUDCHF:S            .036  1.04   63/124    1.3
AUDJPY              .136  1.13  127/236    6.0
AUDJPY:L            .157  1.13   89/163    4.3
AUDJPY:S            .103  1.12   38/73     1.8
AUDUSD              .139  1.29   75/211   19.6
AUDUSD:L            .116  1.25   53/141   12.7
AUDUSD:S            .218  1.41   22/70     6.9
EURAUD              .612  1.74   40/114   23.8
EURAUD:L            .459  1.52   25/79    11.9
EURAUD:S            .994  2.28   15/35    12.0
EURCAD              .339  1.29  107/171   15.3
EURCAD:L            .374  1.32   75/110   10.2
EURCAD:S            .283  1.26   32/61     5.1
NZDJPY              .117  1.19  160/373   18.8
NZDJPY:L            .196  1.34  110/258   23.6
NZDJPY:S            .000  0.84   50/115   -4.8
USDJPY              .999  1.77   59/84     9.0
USDJPY:L            .999  2.64   42/52    10.9
USDJPY:S            .000  0.63   17/32    -1.


So as an experiment, I told Zorro not to trade anything that produced an OptF less than .1 (originally I had used .001 as the threshold). I was very happy with these results, as you can see in the comparison metrics graphic. It shows that by requiring a minimum 0.1 OptF to trade, one pair was dropped. That only affected the return in a negligible way, but reduced trades by 26% which is a huge reduction in risk for very small opportunity cost.

There are many other ideas I would like to implement, but I'm ready to throw this bot on a demo account and let it play. The next bot I'll design will become dt-e9 (evolution 9).

Aside from the fact that I'd like to work on a new core logic (I'm thinking to experiment with IBS, which is listed in another thread here somewhere)... I do also have several ideas I'm working on for the infrastructure:
* Equity-curve trading works now, but it could be better. I will plan to implement some improvements here;
* Available margin check: I am always looks for features like this, which will help constrain the tradebot to its statistical simulation bounds. Though the bot performs well in simulation, I would like to ensure that it automatically restricts itself in the event that live trading does not behave as expected (global thermonuclear war??)
* File-based state information: I would like to implement a feature to easily save certain state information in a file. While this is currently being done on some level with the .trd files, that is a bit foreign to me and I don't know if we can even access that information. The info I want to save would include metrics such as loss streaks, that could then be used as ongoing constraints even if Zorro were stopped/started multiple times (which is realistic)
* I'd also like to play more with the prospecting process. I developed this during dt-e8, so it is definitely in its infancy. One thing I learned is that, despite my efforts to pick a good starting point to prospect from (NZDJPY)... it seems my pick was only mediocre at best (at least according to OptimalF). I've got some ideas I'd like to try on the next bot. I think the danger in this will always be avoiding too much selection bias.


Attached picture dt-e8_allpairs-optf-minimum.png
Attached picture OptF-minimum.png
Attached File
Attached File
dt-e8.zip  (35 downloads)
Posted By: Anonymous

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 12/25/13 10:15

I was trying to go over the code for the modifiers yesterday. Most of it made clear sense to me. But there were some conditions, mainly the bitwise ones that I have no idea how they work.
Code:
function todayCloseCombo(var dayclosecombo)
{
	//allows optimizer to specify the best combo of days to close by NYSE 4pm
	//bit position 0 = Monday
	//bit position 1 = Tuesday
	//bit position 2 = Wednesday
	//bit position 3 = Thursday
	//bit position 4 = Friday
	//bit position 5 = Sunday
	//given a combination #, the function will determine if we are beyond
	//a combo close time, close all trades if necessary, and return 1
	//if no further trades allowed today

	int dayclosecombobits = dayclosecombo+.5; //truncate to rounded int
	int today = dow() - 1; //Mon is 0
	if (today == 6) today = 5; //bump Sun to 5 (no Sat, keep binary range 0-63)

	if ((dayclosecombobits & (1 << today)) && lhour(ET) >= 16) 
	{
		exitLong("*");
		exitShort("*");
		return 1; //current dow() is in the combo; indicate no further trades
	}
	else return 0; //current dow() not in combo, safe to take new trades
}


The above code will be a great example if you can elaborate.
Code:
int dayclosecombobits = dayclosecombo+.5;


and this
Code:
if ((dayclosecombobits & (1 << today)) && lhour(ET) >= 16)

Posted By: dusktrader

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 01/13/14 10:58

Hi liftoff, I'm very sorry I somehow missed your post in this thread. Must've been too much eggnog!

Anyway, feel free to reply back if you still have more questions about this.

Bitwise operators are not something I'm an expert at, but I spent some time studying them and decided they could be really useful in certain situations, such as finding optimal combinations. I think of them as a panel of dip switches... they can each be on or off, and there are many different combinations.

Code:
int dayclosecombobits = dayclosecombo+.5;

I need the value to be an integer and I also wanted it rounded. Sometimes optimizer returns non-whole numbers so I always want the closest integer. For example it could return 7.98 and in that case I would want to use integer 8. If you add .5 to any var, and then truncate the entire decimal portion, you always end up with the rounded integer (assuming you round from .5 or higher, as I do). Someone else on the forum pointed out that if you set an int to a var value, that Zorro will just truncate the decimal portion -- that saves a step of having to use a round function.

Code:
if ((dayclosecombobits & (1 << today)) && lhour(ET) >= 16)

The if operation is checking to see if the bit position assigned to "today" is currently set in dayclosecombobits. If it is, and if the current (Eastern) time is >= 16:00 hours, then the condition is true.
Posted By: Anonymous

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 01/13/14 16:44

All clear, thanks. (Y)
Posted By: ibra

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 01/13/14 20:41

Originally Posted By: dusktrader

Wall of Code


Geez... And you are calling yourself a total n00b.
Heck, what am I then!?

Great work!
Posted By: Mandark

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/16/14 02:16

Dusk, First off thank you for donating your code to the community! Awesome stuff and I'm learning a lot from dissecting it (And that is a KILLER spreadsheet!). Small problem, the code posted does not compile (stuck at dt-e8 compiling....). I have all the history data loaded so I'm not sure what could be the cause.
Posted By: Mandark

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/16/14 17:06

Disregard, took a bit but I noticed that your currency's do not have a "/" inbetween on the while statement while mine need it for FXCM.
Posted By: dusktrader

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/17/14 01:03

Good catch Mandark, you are right -- the / should be your issue. My broker (IBFX) does not use the slash but other brokers like FXCM do.

I am currently working on some enhancements for dt-e8 which I will post soon once they are complete. There are a couple bugs for sure in the code listed in this thread, so look through it carefully if you plan to use it.
Posted By: ibra

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/17/14 10:02

Hi Dusk!

Awesome code as always! Wish I was a fast-learner like you!


Quote:

I then moved to NZDJPY and was happier with that basis


Regarding the quote above: How are you able to use NZDJPY pair? I only have the following pair to choose from in my Zorro: audusd, eurusd, gbpusd, eurchf, usdcad, usdchf and usdjpy.

Maybe cause you use Zorro S?

Thanks!

Ibra
Posted By: dusktrader

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/17/14 10:56

Hi ibra,
what I did was took a look at the (currently) 2 brokers I have available to use with Zorro: FXCM and IBFX. Both have several pairs for trading (about 27 on IBFX). However, with FXCM you have access to quality data for free through Zorro. Using the built-in script Download.c, you can configure Zorro to download the .bar history files to your local system.

Now that I have all that on my local system, I am able to design bots and then trade them on either platform.

You can do all downloading/design work without Zorro S. You can trade also with FXCM and the free Zorro. Trading on MT4 does require Zorro S or monthly subscription.
Posted By: dusktrader

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/19/14 14:19

I'm attaching here the latest revision of dt-e8. This is a (very) simple trendfollower. In observing it trade for several months now, I've noticed that it really likes market chaos. It can be a little depressing to watch it lose -- a little here, a little there... but then when chaos strikes, it grabs onto the momentum and rides with it.

One issue I've noticed is that it doesn't always keep some huge gains it makes from that momentum, instead letting them evaporate. That is a good segway for me to start learning about TMF's (trade mgmt function). I'd like to explore a TMF that can, at the very least, close a trade once it reaches (a good amount of profit).

Anyway, this Feb2014 version of dt-e8 is better than the original version posted in this thread. The core logic remains the same (sloppy, boring MA-crossover), but there have been several fixes/improvements in the infrastructure around that code.

I've posted a comparison chart below where you can see that the yield on this slopbot is roughly the same as the original version, only much more efficient (and thus safer).

I am still working on the spreadsheet process for the next slopbot, so I'm not ready to share those changes yet. It is a long process of trial-and-error for me, to find what really works. A lot of ideas do not pan out, but some do.

PS: I've completely extracted most helper functions from the main code now, with the exception of the continueStats() routine. This is currently strategy-dependent due to a looping issue I described in another thread.

EDIT Feb 21: When I turned this on my live trading account, I realized there was another bug, which I've fixed in these latest attachments. The bug is that, under certain circumstances, if phantom trading was enabled, it would stay enabled and not turn back to real trading. This was evident when I noticed Zorro taking phantom trades for pairs that should never be phantom-ized. It is fixed now, and the result is positive in that it improved the overall yield on the strategy. Additionally, I've improved the continueStats() routine to now count phantom trades as well (it should have been doing that but wasn't) and I've also managed to move it permanently to the toolbox file where it belongs.


Attached picture comparison.png
Attached picture dt-e8_140221.png
Attached File
dt-e8 (Feb2014).zip  (43 downloads)
Posted By: Radar

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/20/14 09:08

Hey DuskTrader,

Thanks for sharing your work on this. laugh

I an looking at an MA crossover strategy using an adaptive MA based on Fractal Dimensions. I am also looking at using a Fractal Graph Dimension Indicator to filter out ranging periods.

The FGDI shows the strength of a trend, but not the direction, so a faster MA is needed as well.

I currently have mql4 versions of the indicators, which are available here... http://fractalfinance.blogspot.com.au/2009/04/fractal-dimensionsand-fractal-graph.html

Once I've gotten used to using those indicators, I'll look for a good range trading strategy, then attempt to convert the indicators to Lite-C.

Why did I post this here? I thought that maybe you'd like a range indicator to filter entries, and - in conjunction with a faster MA - as an early exit on reversals, rather than waiting for an opposite cross.
Posted By: dusktrader

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/21/14 14:56

Thanks Radar, I'm adding this to my research todo list!
Posted By: ibra

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/22/14 11:35

That's absolutely brilliant dusk!

Good job!

EDIT: @Radar,

You might wanna check out the HTTrendMode developed by John Ehlers. It's located in the Indicators section in the manual.
Posted By: Radar

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 02/25/14 09:11


Thanks, Ibra laugh Will check it out once I can get my head around Lite-C wink
Posted By: boatman

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 06/21/14 11:33

Just wanted to add my thanks for sharing your hard work on this. I had been following a similar design process, although far less organised and well-documented. Your helper functions are awesome too - I'm going to start using them in my code. Hope you don't mind!

I hope that I can progress my abilities with Zorro to the point that I can contribute something back.

Cheers
Posted By: forexcoder

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 03/22/15 12:54

Thanks dusktrader. Your job is excellent. I have only an errore during compiling:
"Error 062: Can't open Assets-IBFXnano.dta(rb)".
Infact in yuor code, after function run(), there is that code:
"AssetList = "Assets-IBFXnano.dta"; "
but in files you shared there isn't any file '.dta'.
Can you help me? Thanks.
Posted By: royal

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 03/22/15 15:40

Just delete this line in the code, it's not needed. (then the normal AssetFix file is used)
Posted By: forexcoder

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 03/22/15 17:33

Thanks Royal. Problem is now ok.
Posted By: forexcoder

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 03/22/15 17:45

I tried to train and test the strategy but no result. That is the response of zorro. Why?

Attached picture Factors.JPG
Posted By: jmb

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 03/26/15 18:40

Hello

dt-e8 looks great! Thank you dusktrader. laugh

I'd like to share a test result, and find out where I've gone wrong.

Pass1

Quote:

Pass1 of the test stopped with the screen result (attached) "Screenshot-Zorro_pass1.png", and the following message:

Time 00:05:35

dt-e8 compiling.................. Assets..
Error 047: EURAUD 7 days gap at Fri 13.06.2008....
Walk-Forward Test: dt-e8 portfolio 2008..2014
Read dt-e8.fac dt-e8_1.par

>>>>> Loss streak breached: USDJPY 10
Profit 1352$ MI 29$ DD 256$ Capital 396$
Trades 141 Win 42% Avg +25.6p Bars 329
CAGR 25% PF 1.90 SR 1.11 UI 10% R2 0.89
Time 00:02:05



I then edited the dt-ea line:

#define ASSETLOOP while(asset(loop("NZDJPY","USDJPY","EURAUD","EURCAD","AUDUSD","AUDCHF","AUDJPY"))) //trade group

I removed the asset entry, "USDJPY", and re-ran the test.


Pass2

Quote:

Again, the screenshot file "Screenshot-Zorro_pass2.png" is attached, and Zorro said:

dt-e8 compiling..................
Error 047: EURAUD 7 days gap at Fri 13.06.2008 Assets.....
Walk-Forward Test: dt-e8 portfolio 2008..2014
Read dt-e8.fac dt-e8_1.par dt-e8_2.par dt-e8_3.par dt-e8_4.par

>>>>> Loss streak breached: AUDUSD 22
Profit 4668$ MI 101$ DD 681$ Capital 472$
Trades 811 Win 38% Avg +14.4p Bars 357
CAGR 57% PF 1.64 SR 1.52 UI 6% R2 0.37
Time 00:04:56


So again I edited dt-e8, removing "AUDUSD" from the same line mentioned above, and re-ran the test.


Pass3

Quote:

As before, the screenshot file "Screenshot-Zorro_pass3.png" is attached, and this time Zorro said:

dt-e8 compiling...................
Error 047: EURAUD 7 days gap at Fri 13.06.2008 Assets....
Walk-Forward Test: dt-e8 portfolio 2008..2014
Read dt-e8.fac dt-e8_1.par dt-e8_2.par dt-e8_3.par dt-e8_4.par

>>>>> Loss streak breached: NZDJPY 16
Profit 1444$ MI 31$ DD 444$ Capital 277$
Trades 289 Win 44% Avg +12.9p Bars 449
CAGR 26% PF 1.62 SR 0.91 UI 11% R2 0.81
Time 00:01:53


I re-edited dt-e8, removing "NZDJPY" from the same line, and re-ran the test.


Pass4

Quote:

Pass4 ran to completion, and Zorro reported:

dt-e8 compiling..................
Error 047: EURAUD 7 days gap at Fri 13.06.2008 Assets...
Walk-Forward Test: dt-e8 portfolio 2008..2014
Read dt-e8.fac dt-e8_1.par dt-e8_2.par dt-e8_3.par dt-e8_4.par
Monte Carlo Analysis... Median AR 128%
Profit 1486$ MI 32$ DD 297$ Capital 171$
Trades 503 Win 39% Avg +8.6p Bars 233
CAGR 27% PF 1.52 SR 1.17 UI 13% R2 0.42
Time 00:05:42



I emailed the Zorro support team, and they said the messages related to "...a series() call at a wrong place."

Unfortunately, I'm quite unable to work out what this may mean! However, I did also wonder if it was something I'd done wrong rather than a series() call fault, since (i) nobody else seems to have this issue, and (ii) it goes away if I don't use USDJPY, AUDUSD, and NZDJPY. Additionally, I'm assuming the EURAUD data hole is irrelevant to this result.

Here is the full result of pass4

Quote:

Walk-Forward Test dt-e8 portfolio - performance report

Bar period 15 min
Simulation period 10.01.2008-12.02.2014
Test period 15.04.2010-12.02.2014
Lookback time 600 bars (6 days)
WFO test cycles 4 x 22679 bars (48 weeks)
Training cycles 5 x 52917 bars (114 weeks)
Monte Carlo cycles 200
Assumed slippage 10.0 sec
Capital invested 1000$

Gross win/loss 4337$ / -2850$ (+4329p)
Average profit 388$/year, 32$/month, 1.49$/day
Max drawdown -297$ 20% (MAE -398$ 27%)
Total down time 83% (TAE 96%)
Max down time 46 weeks from Jan 2013
Largest margin 127$
Trade volume 913064$ (238345$/year)
Transaction costs -240$ spr, 2.92$ slp, 0.00$ rol
Capital required 171$

Number of trades 503 (132/year, 3/week, 1/day)
Percent winning 39%
Max win/loss 639$ / -105$
Avg trade profit 2.96$ 8.6p (+64.1p / -27.1p)
Avg trade slippage 0.01$ 0.0p (+0.3p / -0.2p)
Avg trade bars 233 (+345 / -161)
Max trade bars 1999 (4 weeks)
Time in market 129%
Max open trades 4
Max loss streak 12 (uncorrelated 13)

Annual growth rate 27%
Profit factor 1.52 (PRR 1.34)
Sharpe ratio 1.17
Kelly criterion 3.51
R2 coefficient 0.421
Ulcer index 12.9%
Prediction error 32%
Cycle performance 1.39 1.35 1.37 1.30 1.46 1.51 1.62 1.40

Confidence level AR DDMax Capital

10% 146% 157$ 265$
20% 140% 171$ 278$
30% 136% 179$ 285$
40% 131% 192$ 296$
50% 128% 200$ 304$
60% 123% 212$ 314$
70% 118% 230$ 330$
80% 110% 254$ 352$
90% 106% 271$ 366$
95% 99% 299$ 391$
100% 80% 406$ 485$

Portfolio analysis OptF ProF Win/Loss Wgt% Cycles

AUDCHF avg .028 1.14 2539/5842 298.2 XXXX
AUDJPY avg .052 1.26 1723/2925 700.9 X///
EURAUD avg .149 2.64 184/337 805.8 //\\
EURCAD avg .002 0.96 972/2026 -9.9 /\\\

AUDCHF .026 1.14 2539/5842 298.2 XXXX
AUDCHF:L .021 1.13 1732/3826 155.4 \/X\
AUDCHF:S .036 1.16 807/2016 142.8 /XX/
AUDJPY .064 1.26 1723/2925 700.9 X///
AUDJPY:L .105 1.26 1723/2925 700.9 X///
AUDJPY:S .000 ---- 0/0 0.0 ....
EURAUD .129 2.64 184/337 805.8 //\\
EURAUD:L .034 1.26 97/209 19.1 ./\\
EURAUD:S .264 2.87 87/128 786.7 //\\
EURCAD .000 0.96 972/2026 -9.9 /\\\
EURCAD:L .005 0.96 972/2026 -9.9 /\\\
EURCAD:S .000 ---- 0/0 0.0 ....


Can anyone shed any light on this "series() call" message?

Thank you.

Edit: Sorry. Should have captioned the 3 screenshots, but they do appear in the correct order, pass1, pass2, pass3.

Another edit: Should have said, Zorro v. 1.28.

Attached picture Screenshot-Zorro_pass1.png
Attached picture Screenshot-Zorro_pass2.png
Attached picture Screenshot-Zorro_pass3.png
Posted By: boatman

Re: dt-e8 MA-crossover, built for Zorro v1.20 - 03/31/15 08:00

That error usually pops up when you call series differently in different executions of the run() function. Are there any series calls inside an if() statement?
© 2024 lite-C Forums