- Joined
- 12 November 2007
- Posts
- 1,629
- Reactions
- 47
A mean reversion system tested on Norgate Premium Data's 496 stock list of ASX. Date range 1/1/1999 through 6/15/2016. 17.5 years (which is way too long to expect the same system to work without adjustment)
The code was recovered from a directory that was left untouched for two years.
Profitable on 407, not profitable on 89, traded individually.
Allowing all trades on all stocks, there are 141675 trades -- a little more than one trade per stock per month.
83% are profitable.
Average gain per trade is 0.40%.
Average holding period is 3 days.
View attachment 67112
The AmiBroker code
// BuyAfterAnNDaySequenceMultiPosition.afl
//
// This is a modificatiion of Listing 3.2
// BuyAfterAnNDaySequenceMultiPosition.afl
// contained in the book
// "Mean Reversion Trading Systems"
// which is copyright © 2013 Blue Owl Press, Inc
//
// The author of the book and programmer
// of the code is Dr. Howard B. Bandy.
//
// Please read and understand the disclaimer
// associated with all materials related to the book.
//
// To obtain a copy of the book,
// visit the book's website:
// www.MeanReversionTradingSystems.com
//
// This code is provided for the convenience of
// readers of the book.
// Please respect the copyright.
// Do not post this listing without
// the express written consent of Dr. Bandy
//
SetOption( "ExtraColumnsLocation", 1 );
SetOption ( "CommissionMode", 2 ); // $ per trade
SetOption( "CommissionAmount", 0 );
SetOption( "InitialEquity", 1000000 );
SetPositionSize( 10000, spsValue );
MaxPos = 500;
SetOption( "MaxOpenPositions", MaxPos );
//SetBacktestMode( backtestRegularRawMulti );
SetBacktestMode( backtestRegular );
SetTradeDelays( 0, 0, 0, 0 );
BuyPrice = Close;
SellPrice = Close;
// ObFn == K-ratio, CAR/MDD, expectancy
// Define a day as rising based on the closing price
Rising = C > Ref( C, -1 );
Falling = C < Ref( C, -1 );
// The number of days in the sequence
N = Optimize( "N", 2, 1, 7, 1 );
// Direction. 1 == Rising, 0 == Falling
Direction = 0; // Optimize( "Direction", 0, 0, 1, 1 );
// Exit variables
// Maximum holding period
HoldDays = Optimize( "HoldDays", 7, 1, 7, 1 );
// Profit target
ProfitTarget = Optimize( "ProfitTarget", 1.0, 0.2, 4, 0.2 );
// Detect an N day sequence
if ( Direction == 1 )
{
NDaySequence = Sum( Rising, N ) >= N;
}
else
{
NDaySequence = Sum( Falling, N ) >= N;
}
Buy = NDaySequence;
Sell = 0;
ApplyStop( stopTypeProfit, stopModePercent, ProfitTarget );
ApplyStop( stopTypeNBar, stopModeBars, HoldDays );
// Plots
Plot( C, "C", colorBlack, styleCandle );
shapes = IIf( Buy, shapeUpArrow, shapeNone );
shapecolors = IIf( Buy, colorGreen, colorWhite );
PlotShapes( shapes, shapecolors );
/////////////// end /////////////////
Best,
Howard
This Mean Reversion system is simple and the results shown are quite good but I can't get a positive result for Ausralian stocks. I realise the test is done on American stocks but really, the rules are so basic it should be at least up on other stock markets. No stop loss so I used percentage 10. Fills are better assumed to happen at Open or Close price rather than a nominal limit order at 0.5 * ATR() so I left that out.
http://alvarezquanttrading.com/2014...-a-mean-reversion-strategy-with-good-results/
Any thoughts on what was done to rate this 3 bars lower strategy so high?
Code:PositionSize = -100/10; PositionScore = mtRandom(); SetTradeDelays(1,1,1,1); Turnover = MA(C * V, 10) > 5000000; BuyRule1 = C > MA(C, 100); BuyRule2 = C < MA(C, 5); BuyRule3 = Sum(L < Ref(L, -1), 3) == 3; SellRule = C > Ref(C, -1); Buy = BuyRule1 & BuyRule2 & BuyRule3 & Turnover; Sell = SellRule; ApplyStop(0, 1, 10, 2);
You don't know what proper is?Radge first wrote about this system.
Using the LMT order will be better to increase the ave win size and you dont need the stop.
When wrote properly it works well in both markets
You don't know what proper is?
So the original (simple) code that Alvarez posted on that link I provided was not the original code?
View attachment 67115
A mean reversion system tested on Norgate Premium Data's 496 stock list of ASX. Date range 1/1/1999 through 6/15/2016. 17.5 years (which is way too long to expect the same system to work without adjustment)
The code was recovered from a directory that was left untouched for two years.
Profitable on 407, not profitable on 89, traded individually.
Allowing all trades on all stocks, there are 141675 trades -- a little more than one trade per stock per month.
83% are profitable.
Average gain per trade is 0.40%.
Average holding period is 3 days.
View attachment 67112
The AmiBroker code
// BuyAfterAnNDaySequenceMultiPosition.afl
//
// This is a modificatiion of Listing 3.2
// BuyAfterAnNDaySequenceMultiPosition.afl
// contained in the book
// "Mean Reversion Trading Systems"
// which is copyright © 2013 Blue Owl Press, Inc
//
// The author of the book and programmer
// of the code is Dr. Howard B. Bandy.
//
// Please read and understand the disclaimer
// associated with all materials related to the book.
//
// To obtain a copy of the book,
// visit the book's website:
// www.MeanReversionTradingSystems.com
//
// This code is provided for the convenience of
// readers of the book.
// Please respect the copyright.
// Do not post this listing without
// the express written consent of Dr. Bandy
//
SetOption( "ExtraColumnsLocation", 1 );
SetOption ( "CommissionMode", 2 ); // $ per trade
SetOption( "CommissionAmount", 0 );
SetOption( "InitialEquity", 1000000 );
SetPositionSize( 10000, spsValue );
MaxPos = 500;
SetOption( "MaxOpenPositions", MaxPos );
//SetBacktestMode( backtestRegularRawMulti );
SetBacktestMode( backtestRegular );
SetTradeDelays( 0, 0, 0, 0 );
BuyPrice = Close;
SellPrice = Close;
// ObFn == K-ratio, CAR/MDD, expectancy
// Define a day as rising based on the closing price
Rising = C > Ref( C, -1 );
Falling = C < Ref( C, -1 );
// The number of days in the sequence
N = Optimize( "N", 2, 1, 7, 1 );
// Direction. 1 == Rising, 0 == Falling
Direction = 0; // Optimize( "Direction", 0, 0, 1, 1 );
// Exit variables
// Maximum holding period
HoldDays = Optimize( "HoldDays", 7, 1, 7, 1 );
// Profit target
ProfitTarget = Optimize( "ProfitTarget", 1.0, 0.2, 4, 0.2 );
// Detect an N day sequence
if ( Direction == 1 )
{
NDaySequence = Sum( Rising, N ) >= N;
}
else
{
NDaySequence = Sum( Falling, N ) >= N;
}
Buy = NDaySequence;
Sell = 0;
ApplyStop( stopTypeProfit, stopModePercent, ProfitTarget );
ApplyStop( stopTypeNBar, stopModeBars, HoldDays );
// Plots
Plot( C, "C", colorBlack, styleCandle );
shapes = IIf( Buy, shapeUpArrow, shapeNone );
shapecolors = IIf( Buy, colorGreen, colorWhite );
PlotShapes( shapes, shapecolors );
/////////////// end /////////////////
Best,
Howard
Done it before my first post. The original code (without the stop loss & including the limit order) results 01/2015 to 01/2016 on XKO ...
View attachment 67116
I see a couple of issues with the code above.
1- commissions for most Aussies will be around .1%
2- Excess signals (Exrem) not included in the code.
I don't have a delisted stock list so as is I am testing on stocks that were not in present day XKO back in Jan. 2015. The further back the start date the greater the survivorship bias.Didn't see that sorry, how about over a longer term?
1) That's it! Just had to trick the thing. Thanks for pointing it out. I lowered brokerage and get a positive result. I always test with higher brokerage to compensate for getting in at the "assumed" price in test phase.
2) Exrem makes very little difference. Random or rank/score is another discussion worth having.
As Alvarez noted, one would have to be on screen or alerted when price went to 0.5 * atr below yesty close. It is the limit order that doesn't back test true in my opinion.
// 3 Lower Lows similar to N. Radge rules
SetOption("InitialEquity", 50000);
SetOption("AllowSameBarExit", 0); // Sell not on buy bar
SetOption("UsePrevBarEquityForPosSizing", 1);
SetOption("AllowPositionShrinking", 1);
SetOption("MinPosValue", 4000); // 4k minimum trade or no trade taken
SetOption("CommissionMode", 2); // Dollar amount commission mode
SetOption("CommissionAmount", 20); // Commsec is $19.95 under 10k trade
SetTradeDelays(1,1,1,1); // Buy next bar at buy price set below. Sell next bar
PositionSize = -100/10;
PositionScore = mtRandom();
Turnover = MA(C * V, 21) > 5000000;
BuyRule1 = C > MA(C, 100);
BuyRule2 = C < MA(C, 5);
BuyRule3 = Sum(L < Ref(L, -1), 3) == 3;
SellRule = C > Ref(C, -1);
Buy = BuyRule1 & BuyRule2 & BuyRule3 & Turnover;
BuyPrice = C - (ATR(10) * 0.5);
Sell = SellRule;
Buy = ExRem(Buy, Sell);
Sell = ExRem(Sell, Buy);
Filter = Buy OR Sell;
AddColumn(IIf(Buy, C - (ATR(10) * 0.50), Null), "Buy", 1.3, colorBlue);
AddColumn(IIf(Sell, C, Null), "Sell", 1.3, colorDarkRed);
Okay so this needs to be forward tested under present time trading conditions to see if the actual price and quantity desired is achievable.
Code:// 3 Lower Lows similar to N. Radge rules SetOption("InitialEquity", 50000); SetOption("AllowSameBarExit", 0); // Sell not on buy bar SetOption("UsePrevBarEquityForPosSizing", 1); SetOption("AllowPositionShrinking", 1); SetOption("MinPosValue", 4000); // 4k minimum trade or no trade taken SetOption("CommissionMode", 2); // Dollar amount commission mode SetOption("CommissionAmount", 20); // Commsec is $19.95 under 10k trade SetTradeDelays(1,1,1,1); // Buy next bar at buy price set below. Sell next bar PositionSize = -100/10; PositionScore = mtRandom(); Turnover = MA(C * V, 21) > 5000000; BuyRule1 = C > MA(C, 100); BuyRule2 = C < MA(C, 5); BuyRule3 = Sum(L < Ref(L, -1), 3) == 3; SellRule = C > Ref(C, -1); Buy = BuyRule1 & BuyRule2 & BuyRule3 & Turnover; [COLOR="#FF0000"]BuyPrice = C - (ATR(10) * 0.5); [/COLOR]Sell = SellRule; Buy = ExRem(Buy, Sell); Sell = ExRem(Sell, Buy); Filter = Buy OR Sell; AddColumn(IIf(Buy, C - (ATR(10) * 0.50), Null), "Buy", 1.3, colorBlue); AddColumn(IIf(Sell, C, Null), "Sell", 1.3, colorDarkRed);
Interesting!
I asked you a question back at post #38 of this thread and your response in post #39 was "Tried that and buying the low of the day doesn't produce a positive result"
Did you even check the Entry code to see whether it differed from yours?
Obviously not as your "BuyPrice" code is still wrong!
If you want to monitor the system going forward at least use the correct code for the "BuyPrice".
Whilst I might not have the correct code for AmiBroker you should be able to work it out from the code below.
Alter the "SetTradeDelays" Buy to 0 (zero) and change the code to reflect the following
BuyPrice = Min(O,Ref(C-ATR(10)*0.5,-1));
Cheers,
Rob
Buy
Set a limit buy order for the next day if price falls another .5 times 10-day average true range.
Here is the quote of the entry rule ...
If price falls another .5 * atr(10). It has to be after the signal bar of three lower lows.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?