// Downloaded From https://www.WiseStockTrader.com
//----------------------------------------------------------------------
// e-ratio code aggregated by Jez Liberty
// http://www.automated-trading-system.com
//
// The code is largely inspired from the ASX Gorilla blog
// http://theasxgorilla.blogspot.com/2007/07/how-to-compute-edge-ratio-in-amibroker.html
//
// implementation of the Edge Ratio, included below, 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.
//----------------------------------------------------------------------


//---------------------------------------------------------------------------------------------------------
// Options default reset (taken from boilerplate.afl on AmibrokerU.com
// Should be included on all code files
//---------------------------------------------------------------------------------------------------------

SetOption("InitialEquity",1000);
SetOption("MinShares", .0001);
SetOption("MinPosValue",0);
SetOption("FuturesMode", False);
SetOption("AllowPositionShrinking", True);
SetOption("ActivateStopsImmediately",False);
SetOption("ReverseSignalForcesExit", True);
SetOption("AllowSameBarExit",True);
SetOption("CommissionMode", 2);
SetOption("CommissionAmount", 0);
SetOption("InterestRate", 0);
SetOption("MarginRequirement", 100);
SetOption("PortfolioReportMode",0);
SetOption("MaxOpenPositions", 1);
SetOption("WorstRankHeld", 1);// Not in settings
SetOption("PriceBoundChecking",False);// Not in settings
SetOption("UsePrevBarEquityForPosSizing",True);
SetOption("UseCustomBacktestProc",False);

SetOption("DisableRuinStop",False);// Not in settings
SetOption("EveryBarNullCheck",False);// Not in settings

SetOption("HoldMinBars",0);// Not in settings
SetOption("HoldMinDays",0);// Not in settings
SetOption("EarlyExitBars",0);// Not in settings
SetOption("EarlyExitDays",0);// Not in settings
SetOption("EarlyExitFee",0);// Not in settings

SetOption("SeparateLongShortRank",False);// Not in settings
SetOption("MaxOpenLong",0);// Not in settings
SetOption("MaxOpenShort",0);// Not in settings

MaxPos= 100 * 100 / GetOption("MarginRequirement");
PositionSize = -MaxPos / GetOption("MaxOpenPositions");

RoundLotSize = 1;  // 0 for Funds, 100 for Stocks
TickSize= 0;  // 0 for no min. size
MarginDeposit = 10;
PointValue= 1;// For futures

ExitAtTradePrice = 0;
ExitAtStop= 1;
ExitNextBar= 2;

ReEntryDelay= 0;

//---------------------------------------------------------------------------------------------------------
// End of options reset - override options below
//---------------------------------------------------------------------------------------------------------

//Override of options to enable e-ratio calc and multiple simultaneous positions
PosQty = 5; // You can define here how many open positions you want
SetOption("MaxOpenPositions", PosQty );
PositionSize = -100/PosQty; // invest 100% of portfolio equity divided by max. position count
SetOption("InitialEquity",10000000);
SetOption("FuturesMode", True);

//-------------------------------------------------------------------------------
//Actual System/Signal tested goes below:
//-------------------------------------------------------------------------------

//BUY RULES: implemented with a Buy Stop based Upper Donchian Channel(20)
BuyStop = Ref(HHV(High, 20),-1);
Buy = Cross( High, BuyStop );
BuyPrice = Max( BuyStop, Low ); // make sure buy price not less than Low

//------------------------------------------------------------------------------
//e-ratio specific code
//------------------------------------------------------------------------------
//eratio is the variable that we "optimise" (step from 1 to 100)
eratio = Optimize("Eratio", 20, 1, 100, 1);

//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 );

//AddToComposite function is used to create a composite ticker symbol.
//In it we hold the ATR array of a given instrument 
//This is for later retrieval within the Custom Back Tester via the Foreign function
Normaliser = ATR(20);
AddToComposite(Normaliser, "~atr_"+Name(), "C", 1+2+8);

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