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;
}