Au.Tra.Sy blog – Automated Trading System

Systematic Trading research and development, with a flavour of Trend Following

Au.Tra.Sy blog – Automated trading System header image 2

Amibroker e-ratio code

November 9th, 2009 · 16 Comments · Code, Development, Software

I recently posted about the e-ratio as a tool to measure parts of a trading system (the code files to compute the e-ratio in TradersStudio and Excel are also available). The e-ratio is supposed to be a quick tool to check how signals might add some edge to a trading system. However computing the e-ratio in TradersStudio is slow (4+ hours for one signal over 100 different durations).

So I decided to give the “legendary fast” Amibroker a test to see if it could better TradersStudio’s performance. After some “playing and learning”, I have finalised the code to compute the e-ratio. My big thanks go to the ASX gorilla whose own version forms a large part of my code.

Below is the code explanation and downloadable afl file.

Directly from the ASX Gorilla’s website as a prelude to the code:

My implementation of the Edge Ratio involves two profound Amibroker fudges. The first is the use of the AddToComposite function to create a composite ticker symbol in which to hold the ATR array of a given stock for later retrieval within the Custom Back Tester via the Foreign function.

The second fudge is the use of the VarSet/VarGet function to create a quasi array. This was necessary to overcome the limitation where array elements cannot exceed in number the value of barcount-1.

The first part is to actually code up your Buy signal (in our case a Donchian Channel Breakout). The Sell signals are tested separately:

//BUY RULES: implemented with Buy Stop on Upper Donchian Channel(17)
BuyStop = Ref(HHV(High, 17),-1);
Buy = Cross( High, BuyStop );
BuyPrice = Max( BuyStop, Low ); // make sure buy price >= Low

Exiting positions is done on a fixed duration basis:

//Never Sell so that the position is stopped out after N bar instead
Sell = 3 > 5;
//Stop the positon and close it after N bars
//(eratio = N that we step from 1 to 100 in optimisation)
ApplyStop( stopTypeNBar, stopModeBars, eratio );

The first fudge mentioned above to store the ATR:

Normaliser = ATR(17);
AddToComposite(Normaliser, "~atr_"+Name(), "C", 1+2+8);

And the “meat” of the code: the chunk that implements the custom back-testing to:

  1. Loop through the signals and store the Entry ATR value.
  2. Loop through all trades and retrieve MFE, MAE and ATR.
  3. Compute the e-ratio based on values from all trades.
SetCustomBacktestProc(""); //activate the custom backtester
if(Status("action") == actionPortfolio) //called when backtesting/optimising
{
	bo = GetBacktesterObject();
	bo.PreProcess(); // run default backtest procedure
	TradeATR = NumTrades = ATRArr = 0; //init variables
	for( bar=0; bar < BarCount-1; bar++)
	{
		bo.ProcessTradeSignals(bar);

		for ( sig=bo.GetFirstSignal(bar); sig; sig=bo.GetNextSignal(bar) )
		{
			if (sig.isEntry())
			{
				NumTrades++;
				ATRArr = Foreign("~atr_"+sig.Symbol, "C");
				VarSet("TradeATR" + NumTrades, ATRArr[bar]);

				_TRACE("Symbol " + sig.Symbol + " ATR: " + VarGet("TradeATR" + NumTrades));
			}
		}
	}

	AvgMAE = AccumMAE = AvgMFE = AccumMFE = NumTrades = 0;

	// iterate through closed trades
	for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )
	{
		NumTrades++;
		EntryATR = VarGet ("TradeATR" + NumTrades);
		if ( EntryATR != 0 )
		{
			_TRACE("EntryATR: " + WriteVal(EntryATR));
			_TRACE("AccumMAE : " + WriteVal(AccumMAE));
			AccumMAE = AccumMAE + (trade.GetMAE()*trade.EntryPrice/(100*EntryATR));
			AccumMFE = AccumMFE + (trade.GetMFE()*trade.EntryPrice/(100*EntryATR));
		}

		trade.AddCustomMetric("My MAE", trade.GetMAE()*trade.EntryPrice/100);
		trade.AddCustomMetric("My MFE", trade.GetMFE()*trade.EntryPrice/100);
		trade.AddCustomMetric("Entry ATR", EntryATR*10000);
	}

	AvgMAE = AccumMAE / NumTrades;
	AvgMFE = AccumMFE / NumTrades;

	_TRACE(WriteVal(AccumMAE ));
	_TRACE(WriteVal(NumTrades));
	_TRACE(WriteVal(AvgMAE));

	Eratio = abs(AvgMFE/AvgMAE);

	_TRACE(WriteVal(Eratio));

	bo.AddCustomMetric( "Avg MAE", AvgMAE );
	bo.AddCustomMetric( "Avg MFE", AvgMFE );
	bo.AddCustomMetric( "Eratio", Eratio);

	bo.PostProcess();
}

If you want to run this code, you can download the e-ratio "gorilla" afl file and simply update the BUY signals to whatever you fancy testing.

The next post will be a direct speed comparison between TradersStudio and Amibroker for computing the e-ratio on the same underlying data and with the same signal. I expect Amibroker to win the fight hands-down as it appeared "way" faster!


Get posts by RSS
Bookmark and Share


Like this post? You may want to read these:

Tags: ·····

16 Comments so far ↓

  • Woodshedder

    Good stuff Jez. I’m going to add you to the blogroll to remind myself to check your blog regularly.

    I haven’t fully explored the e ratio, but I’m wondering, how is it different from just plotting the avg. % trade over an n-bar exit?

    Thanks for the code Jez!

  • Jez

    Thanks woodshedder!

    I find that the e-ratio is a better evaluation of the “potential” of a trade/signal in Risk/Reward term as it uses Maximum Excursions (both on upside and downside)
    For example you could have both trades that complete with 1% profit when stopping at N days, but one the trades could be dropping to -10% for most of its life while the other one could stay at around +5%. If they both finish at +1%, a simple average would not differentiate and highlight that the second trade/signal offers more potential.
    The e-ratio would tell you a bit more about how the trade “behaved” during its life – and the e-ratio profile over different days allows you to get a feel for the best duration of the edge. It is not a “holy grail” metrics but I think a useful “prism” through which you can look at a signal in a back-test.
    Below is the link to explain the basics of the e-ratio.
    http://www.automated-trading-system.com/e-ratio-trading-edge/

  • Woodshedder

    Cool. That explanation makes sense. I’ll have to plug the code in to AmiBroker and give it a try.
    Thanks again!

  • Nuanda

    it’s not clear to me why you are multiplying by the entry price compared to the original code.

    your version
    ——————-
    trade.GetMAE()*trade.EntryPrice/(100*EntryATR)
    trade.GetMFE()*trade.EntryPrice/(100*EntryATR)

    ASX Gorilla’s version
    ——————-
    trade.GetMAE()/EntryATR
    trade.GetMFE()/EntryATR

    I have the feeling your version is an enhancement since it’s comparing MAE/MFE in dollar amount versus the ATR which is also espressed in dollar amount. Correct me if I’m wrong.

    Regards,

    Paolo

  • Jez

    Nuanda,

    Well spotted! Very thorough checking ;-)
    You are exactly right and I think this was a slight bug in the ASX gorilla version:

    The ATR is expressed in dollar terms while the MAE/MFE is expressed as a percentage of price (in Amibroker). As a result you need to calculate the MAE/MFE in dollar terms to “compare apples and apples”; and you do that by multiplying the ATR(pct) with the Entry Price divided by 100.

  • David Fitch

    Jez,
    Working through your AFL . Found it intriguing. While I’m told it “Edge” doesn’t help EOD systems, I’d like to find for myself. To put my questions in context, I’m a long time user of AB but have only recently been drug kicking and screaming into the quant end of things and in particular, CBT.

    That said, why are there trades in the _Trace field that are not round numbers, 1,2,3. But instead 1.6551, 1.0570 ?
    Just get’n my head around what’s happening here.
    Thanks
    Dave

  • Jez

    Hi David,

    If you look at the code, the following line produces that Debug output:
    _TRACE(”Symbol ” + sig.Symbol + ” Number of Trades ” + VarGet(”TradeATR” + NumTrades));

    The string is output as “number of trades” but the VarGet function actually retrieves the ATR value, hence not a round number – this was copied from the original code and is slightly misleading so Ihave updated the code linked to in this post.

    Cheers and good luck with the “quant end of things” ;-)

    Jez

  • Dave

    Jez,
    NumTrades++. I usually use this at end of loop, not the beginning. IE Step #1=Bar 0, not bar 1. In your code its in two places. Changing it from top to bottom of loop does not change ATR values per signal but does change subsequent AccumMAE ,AvgMFE,eratio, and EntryATR in first trade on single ticker test.
    Thanks
    Dave

  • Jez

    Dave – Thanks for the input. I’ll check it out later

  • Dave

    Jez,
    Follow up on NumTrades++. I suspect reason for putting the expression at start of loop was to get proper denominator in, AvgMAE=AccumMAE/NumTrades and AvgMFE=AccumMFE/NumTrades

    But this still gives different values than placing the Numtrades++ at end of both loops and adding 1 to the denominator, ie Numtrades+1.
    Thanks
    Dave

  • Jez

    Dave – your explanation seems to make sense and as this is part of the code I reused from the Gorilla ASX, I cant confirm on top of my head why this was implemented that way.

    I’ll definitely try your suggestion (ie +1) and revert back with code update if required (after my football game that is…)
    Thanks again!

  • Raj

    Looks like ASX Gorilla’s blog is by invitation only. Any idea, how one gets invited to this? Thanks for the wonderful blog. I have you in my Google Reader.

  • Jez

    Hi Raj,
    Thanks for the comments. I checked the ASX blog and it appears that – as you mention it – it has changed to an “invite-only” status (ie I cant access it either any more). It actually seemed “abandonned” when I found it (ie last update was from 2007 I believe) so I am not sure what’s up with it. I guess you could request an invite and check it out… ;-)

  • Rajiv

    Thanks. The only problem is that I am not even sure how to request an invite i.e. he does not even give that option. Thanks again for the fantastic blog. I use Metastock and AB currently. After reading your blog, I may look at TraderStudio. Also, check out StrataSearch. It’s essentially a software designed mostly to mix and match various systems. I am testing it right now, and the only complain I have is that the learning curve seems a bit steep.

  • Jez

    @Rajiv
    little warning: TradersStudio does not offer any free trial… Also I have been wondering for a little while now, whether I made the right choice (I was also considering Trading Blox but was put up by the price difference: $3,000 for Trading Blox) so I might revisit this :(

  • Rajiv

    Thanks for the heads up. I will do some more research. The only advantage TradersStudio has is that I could use Metastock data. Anyway, there are some other software to consider: Multi Charts (uses Easy Language), Ninja Trader, and Nuro Shell. Multi Charts is a bit pricy though — close to $1600. Personally, I think that AB of MS is a good enough software. Besides a mechanical system, one needs money management skills and the discipline. I am leaning toward combining at least three different systems — trend, mean reversion and divergence.

Leave a Comment