Forums › Trading System Mentor Course Community › AmiBroker Coding and AFL › Custom backtester code
- This topic is empty.
-
AuthorPosts
-
May 10, 2016 at 8:01 pm #101499AnonymousInactive
i noticed in a few recent journallings some mention of “the custom backtester” and thought it might be good to have a place to share some ideas on it. so here it is!
May 10, 2016 at 8:14 pm #103939AnonymousInactivethe following code was just an experiment in nice formatting of some backtesting stats collected in one place at the bottom of the analysis report. im sure others can improve on it. the colours or parameters can be easily changed to suit your taste.
code just needs to be saved somewhere and pointed to in your backtester settings:
Code:SetCustomBacktestProc(“”);/* Now custom-backtest procedure follows */
if( Status(“action”) == actionPortfolio )
{
bo = GetBacktesterObject();
bo.Backtest(); // run default backtest procedure
st = bo.GetPerformanceStats(0); // get stats for all trades// parameters to output
car = NumToStr(st.GetValue(“CAR”),1.2);
maxDD = NumToStr(st.GetValue(“MaxSystemDrawdownPercent”),1.2);
carMDD = NumToStr(st.GetValue(“CAR/MDD”),1.2);
numTrades = NumToStr(st.GetValue(“AllQty”),1.0);
winningTrades = NumToStr(st.GetValue(“WinnersPercent”),1.2);
losingTrades = NumToStr(st.GetValue(“LosersPercent”),1.2);// setup some colours and html formatting to output
carOutput = WriteIf(st.GetValue(“CAR”) > 10,StrFormat(“” + car + “%%“),WriteIf(st.GetValue(“CAR”) > 0,StrFormat(“” + car + “%%“),StrFormat(““+car+”%%“)));
maxDDOutput = WriteIf(st.GetValue(“MaxSystemDrawdown”) > 30,StrFormat(““+maxDD+”%%“),WriteIf(st.GetValue(“MaxSystemDrawdown”) >= 10,StrFormat(““+maxDD+”%%“),StrFormat(““+maxDD+”%%“)));
carMDDOutput = WriteIf(st.GetValue(“CAR/MDD”) > 2,StrFormat(““+carMDD+”“),WriteIf(st.GetValue(“CAR/MDD”) >= 1,StrFormat(““+carMDD+”“),StrFormat(““+carMDD+”“)));
numTradesOutput = WriteIf(st.GetValue(“WinnersPercent”) > 1,StrFormat(““+numTrades+”“),StrFormat(““+numTrades+”“));
winningTradesOutput = WriteIf(st.GetValue(“WinnersPercent”) >= 50,StrFormat(““+winningTrades+”%%“),StrFormat(““+winningTrades+”%%“));
losingTradesOutput = WriteIf(st.GetValue(“LosersPercent”) <= 50,StrFormat("“+losingTrades+”%%“),StrFormat(““+losingTrades+”%%“));// print to report
bo.AddCustomMetric(“CAGR”, carOutput);
bo.AddCustomMetric(“Max. system drawdown”, maxDDOutput);
bo.AddCustomMetric(“CAR/MDD”, carMDDOutput);
bo.AddCustomMetric(“Total Trades”, numTradesOutput);
bo.AddCustomMetric(“Winning Trades”, winningTradesOutput);
bo.AddCustomMetric(“Losing Trades”, losingTradesOutput);
}November 19, 2016 at 5:38 am #103942LeeDanelloParticipantA good one to add is expectancy. Custom metrics
Code:SetCustomBacktestProc(“”);
if( Status(“action”) == actionPortfolio )
{
bo = GetBacktesterObject();
bo.Backtest(); // run default backtest procedure
st = bo.GetPerformanceStats(0); // get stats for all trades// parameters to output
car = NumToStr(st.GetValue(“CAR”),1.2);
maxDD = NumToStr(st.GetValue(“MaxSystemDrawdownPercent”),1.2);
carMDD = NumToStr(st.GetValue(“CAR/MDD”),1.2);
numTrades = NumToStr(st.GetValue(“AllQty”),1.0);
winningTrades = NumToStr(st.GetValue(“WinnersPercent”),1.2);
losingTrades = NumToStr(st.GetValue(“LosersPercent”),1.2);
expectancy = st.GetValue(“WinnersAvgProfit”)*st.GetValue(“WinnersPercent”)/100 + st.GetValue(“LosersAvgLoss”)*st.GetValue(“LosersPercent”)/100;// setup some colours and html formatting to output
carOutput = WriteIf(st.GetValue(“CAR”) > 10,StrFormat(“” + car + “%%“),WriteIf(st.GetValue(“CAR”) > 0,StrFormat(“” + car + “%%“),StrFormat(““+car+”%%“)));
maxDDOutput = WriteIf(st.GetValue(“MaxSystemDrawdown”) > 30,StrFormat(““+maxDD+”%%“),WriteIf(st.GetValue(“MaxSystemDrawdown”) >= 10,StrFormat(““+maxDD+”%%“),StrFormat(““+maxDD+”%%“)));
carMDDOutput = WriteIf(st.GetValue(“CAR/MDD”) > 2,StrFormat(““+carMDD+”“),WriteIf(st.GetValue(“CAR/MDD”) >= 1,StrFormat(““+carMDD+”“),StrFormat(““+carMDD+”“)));
numTradesOutput = WriteIf(st.GetValue(“WinnersPercent”) > 1,StrFormat(““+numTrades+”“),StrFormat(““+numTrades+”“));
winningTradesOutput = WriteIf(st.GetValue(“WinnersPercent”) >= 50,StrFormat(““+winningTrades+”%%“),StrFormat(““+winningTrades+”%%“));
losingTradesOutput = WriteIf(st.GetValue(“LosersPercent”) <= 50,StrFormat("“+losingTrades+”%%“),StrFormat(““+losingTrades+”%%“));
expectancy = WriteIf(expectancy < 0,StrFormat("” +”$“+”“+NumToStr(expectancy,1.2)),StrFormat(“” +”$“+”“+NumToStr(expectancy,1.2))); // print to report
bo.AddCustomMetric(“CAGR”, carOutput);
bo.AddCustomMetric(“Max. system drawdown”, maxDDOutput);
bo.AddCustomMetric(“CAR/MDD”, carMDDOutput);
bo.AddCustomMetric(“Total Trades”, numTradesOutput);
bo.AddCustomMetric(“Winning Trades”, winningTradesOutput);
bo.AddCustomMetric(“Losing Trades”, losingTradesOutput);
bo.AddCustomMetric( “Expectancy”, expectancy );
}November 20, 2016 at 1:24 am #103943JulianCohenParticipantWhen you say pointed to in the backtester settings, can you provide an example please?
November 20, 2016 at 3:06 am #103940LeeDanelloParticipantGo to the analysis tab and click the spanner and point to the saved custom backtester afl.
November 20, 2016 at 5:17 am #105831JulianCohenParticipantNoice…Thanks a lot
September 26, 2017 at 1:01 am #103941ScottMcNabParticipantI seem to recall seeing a backtest table that not only had CAGR but also maxDD for each year but cant find it in the forum ….does anyone have the code to do this please ?
September 26, 2017 at 5:59 am #107718JulianCohenParticipantI think it’s this one
Code:EnableTextOutput( 3 ); // enable HTML output into report (Version 5.84 or higher!)function CalendarDays()
{
ddsince1900 = DaysSince1900();
result = ddsince1900 – ddsince1900[0];
return result;
}// — MaxDD —
EQ = C;
MaxEQ = Highest( EQ );
DD = EQ – MaxEQ;
MaxDD = Lowest( DD );
DDpct = 100 * ( EQ – MaxEQ ) / MaxEQ;
MaxDDpct = Lowest( DDpct );// — CAR —
bi = BarIndex();
fbr = Status( “firstbarinrange” );
lbr = Status( “lastbarinrange” );
fbrbi = LastValue( ValueWhen( fbr, bi ) );
lbrbi = LastValue( ValueWhen( lbr, bi ) );
cd = CalendarDays();
Days = cd[ lbrbi ] – cd[ fbrbi ];
CAR = 100 * ( ( eq / eq[ fbrbi ] ) ^ ( 365 / Days ) – 1 );fillText = StrFormat( ” “);
Title = StrFormat( “Equity = $ %.2f%%, CAR = %.2f%%, MaxDD = $ %.2f%%, (= %.2f%%)”, EQ, CAR, MaxDD, MaxDDpct );
SetGradientFill( colorDarkGreen, ColorRGB( 0, 204, 0 ), 0 );
Plot( EQ, “Portfolio Equity”, colorDarkGreen, styleGradient | styleLine );
// — drawdown trenches in red —
PlotOHLC( MaxEQ, MaxEQ, EQ, MaxEQ, “”, colorRed, styleCloud );// — paint log graph —
SetChartOptions( 2, chartLogarithmic );////////////////////////////////////////////////////////////////////////////
////////////////////////////
// From: 3. Profit Table.afl
////////////////////////////yr = Year();
mo = Month();YearChange = yr != Ref( yr, 1 );
MonChange = mo != Ref( mo, 1 );FirstYr = 0;
LastYr = 0;startbar = 0;
////////////////////////////
// SKIP non-trading bars
////////////////////////////for ( i = 0; i < BarCount; i++ ) { if ( eq[ i ] ) { startbar = i; break; } } //////////////////////////// // collect yearly / monthly changes in equity // into dynamic variables //////////////////////////// LastYrValue = eq[ startbar ]; LastMoValue = eq[ startbar ]; MaxYrProfit = MinYrProfit = 0; MaxMoProfit = MinMoProfit = 0; MaxYearEQ = YearDD = MaxYearDD = 0; for ( i = startbar + 1; i < BarCount; i++ ) { MaxYearEQ = Max( EQ[ i ], MaxYearEQ ); YearDD = Nz( 100 * ( EQ[ i ] - MaxYearEQ ) / MaxYearEQ ); MaxYearDD = Min( YearDD, MaxYearDD ); if ( YearChange[ i ] || i == BarCount - 1 ) { Chg = 100 * ( -1 + eq[ i ] / LastYrValue ); VarSet( "ChgYear" + yr[ i ], Chg ); MaxYrProfit = Max( MaxYrProfit, Chg ); MinYrProfit = Min( MinYrProfit, Chg ); if ( FirstYr == 0 ) FirstYr = yr[ i ]; LastYr = yr[ i ]; LastYrValue = eq[ i ]; VarSet("MaxYearDD"+ yr[ i - 1 ], MaxYearDD ); MaxYearEQ = YearDD = MaxYearDD = 0; } if ( MonChange [ i ] || i == BarCount - 1 ) { mon = mo[ i ]; Chg = 100 * ( -1 + eq[ i ] / LastMoValue ); VarSet( "ChgMon" + yr[ i ] + "-" + mon, Chg ); VarSet( "SumChgMon" + mon, Chg + Nz( VarGet( "SumChgMon" + mon ) ) ); VarSet( "SumMon" + mon, 1 + Nz( VarGet( "SumMon" + mon ) ) ); MaxMoProfit = Max( MaxMoProfit, Chg ); MinMoProfit = Min( MinMoProfit, Chg ); LastMoValue = eq[ i ]; } } MonthNames = "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec"; function GenProfitTableHTML( ) { printf( "
n” );
printf( “
n” ); Header = “Year,” + MonthNames + “,Yr%%,” + “MDD”;
for ( Col = 0; ( Colname = StrExtract( Header, Col ) ) != “”; Col++ )
{
printf( “” + Colname + “ ” );
}printf( “
n” );
for ( y = FirstYr; y <= LastYr; y++ ) { //Color = ColorRGB( IIf( row == 0 || col == 0 || col == 13, 220, 255 ), 255, IIf( row % 2, 255, 220 ) ); // new row if ( y % 2 ) printf( "
n ” );
else
printf( “n ” ); printf( “%g
“, y );
for ( m = 1; m <= 12; m++ ) { Chg = VarGet( "ChgMon" + y + "-" + m ); if ( NOT IsNull( Chg ) ) { if ( Chg >= 0 )
printf( “%.1f%% “, Chg );
else
printf( “%.1f%% “, Chg );
}
else
printf( “N/A ” );
}if ( y % 2 )
printf( “” );
else
printf( “” ); x = VarGet( “ChgYear” + y );
z = VarGet(“maxYearDD” + y );if ( x >= 0 )
printf( “%.1f%%“, x );
else
printf( “%.1f%%“, x );
Printf( “%.1f%% “, z );
printf( “n” ); // end row
}printf( “
n” ); // new row printf( “
Avg|Mx ” );
for ( m = 1; m <= 12; m++ ) { x = Nz( VarGet( "SumChgMon" + m ) / VarGet( "SumMon" + m ) ); if ( x >= 0 )
printf( “%.1f%% “, x );
else
printf( “%.1f%% “, x );
}
if ( CAR[ BarCount-1 ] >= 0 )
printf( “%.1f%% “, CAR[ BarCount-1 ] );
//PrintInCell( StrFormat(“%.1f”, CAR[ BarCount-1 ] ), Row, 13, ColorRGB( 255, 128, 0 ) );
else
printf( “%.1f%% “, CAR[ BarCount-1 ] );
//PrintInCell( StrFormat(“%.1f”, CAR[ BarCount-1 ] ), Row, 13, ColorRGB( 0, 204, 0 ) );
printf( “%.1f%% “, MaxDDpct[ BarCount-1 ] );
//PrintInCell( StrFormat(“%.1f”, MaxDDpct[ BarCount-1 ] ), Row, 14, ColorRGB( 255, 255, 0) );
//printf( “” );
printf( “
n” );
}
///////////////////////////
// This function checks if currently selected symbol
// is portfolio equity
//////////////////////////
function CheckSymbol()
{
if ( Name() != “~~~EQUITY” AND Name() != “~~~OSEQUITY” )
{
printf( “For accurate results switch to ~~~EQUITY symbol
” );
}
}CheckSymbol();
////////////////////////////
// Main program
////////////////////////////
GenProfitTableHTML();September 26, 2017 at 6:48 am #107719ScottMcNabParticipantYikes…thanks Julian..
-
AuthorPosts
- You must be logged in to reply to this topic.