Gamestudio Links
Zorro Links
Newest Posts
loading historical data 1st time
by AndrewAMD. 04/14/23 12:54
Trade at bar open
by juanex. 04/13/23 19:43
Bug in Highpass2 filter
by rki. 04/13/23 09:54
Adding Limit Orders For IB
by scatters. 04/11/23 16:16
FisherN
by rki. 04/11/23 08:38
AUM Magazine
Latest Screens
SHADOW (2014)
DEAD TASTE
Tactics of World War I
Hecknex World
Who's Online Now
4 registered members (AndrewAMD, fogman, Grant, juanex), 972 guests, and 7 spiders.
Key: Admin, Global Mod, Mod
Newest Members
rki, FranzIII, indonesiae, The_Judge, storrealba
18919 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Improvements to the tradebot infrastructure #432471
11/06/13 16:03
11/06/13 16:03
Joined: Jul 2013
Posts: 522
D
dusktrader Offline OP
User
dusktrader  Offline OP
User
D

Joined: Jul 2013
Posts: 522
EDIT Nov 11th: I've updated to include AUDJPY now, and also reprocessed AUDCHF. I don't think I set the parameter ranges correctly on the first AUDCHF (the one that yielded 0%). Going through the process repeatedly really helps me solidify the steps, and encourages consistency of process for me. Note that Hedge flipping is currently not used due to a fix I'm waiting on in Zorro 1.20. Also, I've commented-out the streaks-limit code because I'm researching a possible issue related to that.

I wanted to make some improvements to the infrastructure I'm building, to make this slop-bot concept more dynamic. (Sidenote: I recommend you read through this post first because it details all the steps to reach this point.

For a proof-of-concept example, I've begun processing the pairs that were used in the last iteration of the slop-bot. After only the first 3, I'm really impressed with how well this seems to be coming along. It is already a better slop-bot than what was built before, and I anticipate adding more pairs will only be further improvement. It will take a fair amount of effort to complete the remaining 4 pairs and detail the exact process I used. As usual, I did make several adjustments/improvements to that process (spreadsheet attached).

First let me discuss the obvious changes I made to the infrastructure, listed below:

The biggest improvement is that optimizable parameters are now completely extracted from the core edge logic. This means you can identify and set optimal parameter ranges and other settings that work best with each asset personality (rather than a one-size-fits-all approach that was used before).

Also, other features like equity-curve trading and margin calculations have also been extracted into functions, which further simplifies the plug-n-play nature of the core edge logic section.

I've attached the updated spreadsheet showing my process. After the first column is complete (EURUSD), I went back and added additional columns for each new asset personality. Some steps were skipped (as noted) and I've indicated those that were definitely processed with ***.


Quote:
Walk-Forward Test: dt-demo5 portfolio 2008..2013
Read dt-demo5.fac dt-demo5_1.par dt-demo5_2.par dt-demo5_3.par dt-demo5_4.par
Profit 5706$ MI 140$ DD 617$ Capital 986$
Trades 1397 Win 32% Avg +402.9p Bars 150
CAGR 75% PF 1.41 SR 1.67 UI 4.8% Error 19%
Time 00:02:58


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 = 350; //basis to trade with
	
	if (direction && OptimalF>.001) //long trade, historically profitable
		return OptimalFLong * riskCapital;
	else if (!direction && OptimalF>.001) //short trade, historically profitable
		return OptimalFShort * riskCapital;
	else if (is(TRADEMODE)) //non-historically profitable = phantom live trades only
		Lots = -1;

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

function getOpt(int param)
{
	switch (Asset)
	{
		case "EURUSD":
			switch (param)
			{
				case 1: return optimize(75,65,85,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(1.99,1,15,0.5,-3); //Stop
				case 4: return optimize(5,3,13,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 1; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return 63; //optimize(57,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(20,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return 15; //optimize(13,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 18; //limit # of loss streaks; 0=no limit
				case 14: return 0; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "NZDJPY":
			switch (param)
			{
				case 1: return optimize(76,65,85,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(2.01,1,9,0.5,-3); //Stop
				case 4: return optimize(11,8,14,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return optimize(13,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(34,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return 15; //optimize(9,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 19; //limit # of loss streaks; 0=no limit
				case 14: return 0; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "AUDUSD":
			switch (param)
			{
				case 1: return optimize(77,63,83,1,0); //TimeCycle
				case 2: return optimize(2.4,1.6,5,0.2,0); //TimeFactor
				case 3: return optimize(6.02,1,15,0.5,-3); //Stop
				case 4: return optimize(4.5,3,13,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return 63; //optimize(54,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(33,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return 15; //optimize(12,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 8; //limit # of loss streaks; 0=no limit
				case 14: return 1; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "AUDCHF":
			switch (param)
			{
				case 1: return optimize(59,49,69,1,0); //TimeCycle
				case 2: return optimize(2.4,2,5,0.2,0); //TimeFactor
				case 3: return optimize(4.01,1,15,0.5,-2); //Stop
				case 4: return optimize(7.5,3,13,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return 63; //optimize(42,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(4,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return optimize(13,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 13; //limit # of loss streaks; 0=no limit
				case 14: return 1; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "AUDJPY":
			switch (param)
			{
				case 1: return optimize(68,58,78,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(6.01,3,10,0.5,-2); //Stop
				case 4: return optimize(7,3,10,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return optimize(27,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(33,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return optimize(13,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 10; //limit # of loss streaks; 0=no limit
				case 14: return 0; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
	}
}

function checkEquity()
{
	int emode = getOpt(14);
	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 checkModifiers()
{
	int reversedir = getOpt(6); //default 0=normal trade direction
	int fridayclose = getOpt(7); //enforce auto-close and no trades after NYSE 3pm Friday
	int hourblockstart = getOpt(8); //block trade opens beginning at NY hour
	int hourblockend = getOpt(9); //block trade opens ending at NY hour
	int dayopencombo = getOpt(10); //combo of days to open; 63=every day
	int dayclosecombo = getOpt(11); //combo of days to close after NYSE 4pm; 0=none; 63=every day
	int marketopencombo = getOpt(12); //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()
{
	set(PARAMETERS+FACTORS);
	StartDate = 20080101;
	EndDate = 20130531;
	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 maxtrades = getOpt(5);
	checkEquity(); //equity-curve trading
	int reinvestprofits = 1; //invoke margin setting during trade logic
   
	//asset("AUDCHF");
	while(asset(loop("NZDJPY","EURUSD","AUDUSD","AUDCHF","AUDJPY")))
	{
		//edge trading logic
		var TimeCycle = getOpt(1);
		var TimeFactor = getOpt(2);
		//Stop = BarPeriod*PIP; //simple stop level
		Stop = ATR(200) * getOpt(3); //allow 3% tolerance for preferring low stop distances
		Trail = ATR(200) * getOpt(4);
		//if (getOpt(13) && ((LossStreakLong>=getOpt(13)) || (LossStreakShort>=getOpt(13)))) Lots = -1; //limit loss streaks
		Hedge = getOpt(15);

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

		if (checkModifiers())
		{
			//OK to trade, let's evaluate signals then
			if (crossOver(MA1,MA2) && rising(MA1))
			{
				if (reinvestprofits) Margin = calculateMargin(1); //long
				//enterLong(); //standard entry
				reverseLong(maxtrades);
			}
			else if(crossUnder(MA1,MA2) && falling(MA2))
			{
				if (reinvestprofits) Margin = calculateMargin(0); //short
				//enterShort(); //standard entry
				reverseShort(maxtrades);
			}
		}
	}

	PlotWidth = 1100;
	PlotHeight1 = 800;
}


Attached Files
Data.zip (32 downloads)
dt-demo5-NZDJPY-EURUSD-AUDUSD-AUDCHF-AUDJPY.png
Last edited by dusktrader; 11/11/13 23:43.
Re: Improvements to the tradebot infrastructure [Re: dusktrader] #432743
11/13/13 16:47
11/13/13 16:47
Joined: Jul 2013
Posts: 75
R
royal Offline
Junior Member
royal  Offline
Junior Member
R

Joined: Jul 2013
Posts: 75
When I try to TRAIN/TEST the script (named as MA_Crossover) I get the following Error message:

MA_Crossover compiling..........
Subscribe asset NZDJPY
FXCM.dll => FXCM interface opened
Login FXCM.... at UTC 13.11. 16:45
Asset NZDJPY not found
Logout.. ok

Then the TRAIN/TEST just stops and nothing more happens. What am I doing wrong? frown

Re: Improvements to the tradebot infrastructure [Re: royal] #432745
11/13/13 16:55
11/13/13 16:55
Joined: Jun 2013
Posts: 1,609
D
DdlV Offline
Serious User
DdlV  Offline
Serious User
D

Joined: Jun 2013
Posts: 1,609
Hi royal. dusktrader is not using FXCM. To run the script on FXCM, you'll need to change the asset names to the names FXCM uses (in general, with "/").

HTH.

Re: Improvements to the tradebot infrastructure [Re: DdlV] #432746
11/13/13 17:04
11/13/13 17:04
Joined: Jul 2013
Posts: 75
R
royal Offline
Junior Member
royal  Offline
Junior Member
R

Joined: Jul 2013
Posts: 75
Ah thanks DdlV! Damn "/" grin
FXCM has no Price for NZD/JPY anyway wink
So I have to test the script with other assets frown

Re: Improvements to the tradebot infrastructure [Re: royal] #432756
11/14/13 01:01
11/14/13 01:01
Joined: Jul 2013
Posts: 522
D
dusktrader Offline OP
User
dusktrader  Offline OP
User
D

Joined: Jul 2013
Posts: 522
Yes that's right, the slash is the issue. FXCM does have all the assets but you'll have to first download the data for pairs like NZD/JPY.

If you've already downloaded all the data, then you can 'cheat' by just editing the .fac and .par files in Data.zip that I uploaded (just add the slash to each asset name). Then you won't have to re-train.

Re: Improvements to the tradebot infrastructure [Re: dusktrader] #432802
11/15/13 16:04
11/15/13 16:04
Joined: Jul 2013
Posts: 522
D
dusktrader Offline OP
User
dusktrader  Offline OP
User
D

Joined: Jul 2013
Posts: 522
EDIT Nov 19th: I've added USDCHF now and also fixed a glitch in the CalculateMargin() function. I'll be working next on testing this with v1.20 beta.

(it seems the system will no longer let me edit a post once there is a reply... so I'll followup here with the latest info):

I've gone back and reprocessed AUDUSD as well now. I did this after noticing that the OptimalF value assigned to this asset was .000 (essentially meaning it would never trade that asset).

I think it is extremely important to get the parameter ranges and optimal start values correct (Step 1c). Otherwise, it just goes downhill from there.

After carefully reprocessing AUDUSD, I'm seeing much better results now. All assets are assigned a positive OptimalF value, and the strategy's overall health looks improved. I've also made several improvements to the spreadsheet which is attached here.

(I still have 2 more assets to process, and I may go back and make sure the initial assets beyond EURUSD were processed correctly as well. Consistent design process is critical.)

Quote:
Walk-Forward Test: dt-demo5 portfolio 2008..2013
Read dt-demo5.fac dt-demo5_1.par dt-demo5_2.par dt-demo5_3.par dt-demo5_4.par
Profit 6544$ MI 161$ DD 544$ Capital 1015$
Trades 1638 Win 30% Avg +393.0p Bars 146
CAGR 81% PF 1.39 SR 1.73 UI 4.1% Error 20%
Time 00:03:49


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 = 325; //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(int param)
{
	switch (Asset)
	{
		case "EURUSD":
			switch (param)
			{
				case 1: return optimize(75,65,85,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(1.99,1,15,0.5,-3); //Stop
				case 4: return optimize(5,3,13,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 1; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return 63; //optimize(57,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(20,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return 15; //optimize(13,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 18; //limit # of loss streaks; 0=no limit
				case 14: return 0; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "NZDJPY":
			switch (param)
			{
				case 1: return optimize(76,65,85,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(2.01,1,9,0.5,-3); //Stop
				case 4: return optimize(11,8,14,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return optimize(13,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(34,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return 15; //optimize(9,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 19; //limit # of loss streaks; 0=no limit
				case 14: return 0; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "AUDUSD":
			switch (param)
			{
				case 1: return optimize(54,44,64,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(3,0.5,5.5,0.5,-2); //Stop
				case 4: return optimize(8.5,3,13,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return 63; //optimize(42,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(5,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return optimize(9.01,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 24; //limit # of loss streaks; 0=no limit
				case 14: return 0; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "AUDCHF":
			switch (param)
			{
				case 1: return optimize(59,49,69,1,0); //TimeCycle
				case 2: return optimize(2.4,2,5,0.2,0); //TimeFactor
				case 3: return optimize(4.01,1,15,0.5,-2); //Stop
				case 4: return optimize(7.5,3,13,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return 63; //optimize(42,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(4,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return optimize(13,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 13; //limit # of loss streaks; 0=no limit
				case 14: return 1; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "AUDJPY":
			switch (param)
			{
				case 1: return optimize(68,58,78,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(6.01,3,10,0.5,-2); //Stop
				case 4: return optimize(7,3,10,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return optimize(27,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(33,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return optimize(13,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 10; //limit # of loss streaks; 0=no limit
				case 14: return 0; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
		case "USDCHF":
			switch (param)
			{
				case 1: return optimize(104,85,115,1,0); //TimeCycle
				case 2: return optimize(2.4,0.2,5,0.2,0); //TimeFactor
				case 3: return optimize(8.5,6,12,0.5); //Stop
				case 4: return optimize(10.5,7.5,13,0.5); //Trail
				case 5: return 1; //maxtrades
				case 6: return 0; //reversedir: default 0=normal trade direction
				case 7: return 0; //fridayclose: enforce auto-close and no trades after NYSE 3pm Friday
				case 8: return 0; //hourblockstart: block trade opens beginning at NY hour
				case 9: return 0; //hourblockend: block trade opens ending at NY hour
				case 10: return optimize(58,1,63,1); //dayopencombo: combo of days to open; 63=every day
				case 11: return 0; //optimize(33,1,63,1); //dayclosecombo: combo of days to close after NYSE 4pm; 0=none; 63=every day
				case 12: return optimize(13,1,15,1); //marketopencombo: combo of markets to allow trade opens; 15=every market
				case 13: return 14;//limit # of loss streaks; 0=no limit
				case 14: return 4; //emodes: 0)none; 1)standard; 2)switch hitter; 3)weighted; 4)mean reversion
				case 15: return 0; //Hedge mode: 0=none, 4=virtual
			}
	}
}

function checkEquity()
{
	int emode = getOpt(14);
	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 checkModifiers()
{
	int reversedir = getOpt(6); //default 0=normal trade direction
	int fridayclose = getOpt(7); //enforce auto-close and no trades after NYSE 3pm Friday
	int hourblockstart = getOpt(8); //block trade opens beginning at NY hour
	int hourblockend = getOpt(9); //block trade opens ending at NY hour
	int dayopencombo = getOpt(10); //combo of days to open; 63=every day
	int dayclosecombo = getOpt(11); //combo of days to close after NYSE 4pm; 0=none; 63=every day
	int marketopencombo = getOpt(12); //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-spread25.dta";
	//AssetList = "Assets-IBFXnano-spread100.dta";
	//AssetList = "Assets-IBFXnano-spread300.dta";
	//AssetList = "Assets-FXCMmicro.dta";
	//AssetList = "Assets-FXCMmicro-spread25.dta";
	set(PARAMETERS+FACTORS);
	StartDate = 20080101;
	EndDate = 20130531;
	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 maxtrades = getOpt(5);
	checkEquity(); //equity-curve trading
	int reinvestprofits = 1; //invoke margin setting during trade logic
   
	//while(asset(loop("NZDJPY","EURUSD","AUDUSD","AUDCHF","AUDJPY","USDCHF","USDJPY")))
	//asset("USDCHF");
	while(asset(loop("NZDJPY","EURUSD","AUDUSD","AUDCHF","AUDJPY","USDCHF")))
	{
		//edge trading logic
		var TimeCycle = getOpt(1);
		var TimeFactor = getOpt(2);
		//Stop = BarPeriod*PIP; //simple stop level
		Stop = ATR(200) * getOpt(3); //allow 3% tolerance for preferring low stop distances
		Trail = ATR(200) * getOpt(4);
		//if (getOpt(13) && ((LossStreakLong>=getOpt(13)) || (LossStreakShort>=getOpt(13)))) Lots = -1; //limit loss streaks
		Hedge = getOpt(15);

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

		if (checkModifiers())
		{
			//OK to trade, let's evaluate signals then
			if (crossOver(MA1,MA2) && rising(MA1))
			{
				if (reinvestprofits) Margin = calculateMargin(1); //long
				//enterLong(); //standard entry
				reverseLong(maxtrades);
			}
			else if(crossUnder(MA1,MA2) && falling(MA2))
			{
				if (reinvestprofits) Margin = calculateMargin(0); //short
				//enterShort(); //standard entry
				reverseShort(maxtrades);
			}
		}
	}

	PlotWidth = 1100;
	PlotHeight1 = 800;
}


Attached Files
Data.zip (27 downloads)
dt-demo5-NZDJPY-EURUSD-AUDUSD-AUDCHF-AUDJPY-USDCHF.png
Last edited by dusktrader; 11/19/13 19:40.

Moderated by  Petra 

Gamestudio download | chip programmers | Zorro platform | shop | Data Protection Policy

oP group Germany GmbH | Birkenstr. 25-27 | 63549 Ronneburg / Germany | info (at) opgroup.de

Powered by UBB.threads™ PHP Forum Software 7.7.1