Home › Forums › Trading System Mentor Course Community › AmiBroker Coding and AFL › Handy CBT code
- This topic is empty.
-
AuthorPosts
-
April 12, 2020 at 4:11 am #102006TrentRothallParticipant
With regards to the recent webinar Nick posted by Alan Clement I thought it might be handy to have a central Location for handy CBT code people are using for different tasks
April 12, 2020 at 4:21 am #111269TrentRothallParticipantThis code is talked about in detail in the webinar mentioned above.
It adds the stats for Buy and Hold to the Portfolio equity chart in the backtest report.
The below code needs to be saved in the ‘Report charts’ folder in the Amibroker Formulas folder
Code://===================================================================================
// Custom Portfolio equity chart
//===================================================================================
Compounding = True;
SetChartOptions(1, chartShowDates|chartLogarithmic);//whiteBackground = GetChartBkColor() == 1677272;
//Highlightcolour = IIf(whiteBackground, colorBlack, colorWhite);FinalEquity = C;
PlotColour = ColorBlend(colorPaleGreen, colorBlack);
SetGradientFill(colorLightOrange, colorPaleGreen);IndexBuyHold = StaticVarGet(“~HCBTIndexBuyandHold”);
IndexTicker = StaticVarGet(“IndexTicker”);Title = “Equity = $” + NumToStr(FinalEquity, 1.0);
Plot( FinalEquity, “Portfolio Equity”, PlotColour, styleGradient | styleLine, Null, Null, 0, -1 );
if( LastValue(IndexBuyHold) != 0)
{
Plot(IndexBuyHold, “Index”, colorBlack, styleThick);
Title = ” Benchmark ” + IndexTicker + ” = $” +NumToStr(IndexBuyHold, 1.0);
}The below code then needs to be added to your system file, once a backtest is ran it will generate the custom ticker to get plotted on the chart
Code://=====================================================================
// CBT EQUITY CHART
//=====================================================================
IndexTicker = “$XAOA.au”;
StaticVarSetText(“IndexTicker”, IndexTicker);SetOption(“UseCustomBacktestProc”, True);
SetCustomBacktestProc(“”);//====================================================================
if ( Status( “action” ) == actionPortfolio )
{
bo = GetBacktesterObject();
bo.Backtest();IndexBuyHold = 0;
IndexBuyHold[0] = bo.InitialEquity;SetForeign(IndexTicker);
IndexDailyChange = C/Ref(C, -1);
RestorePriceArrays();for(i = 1; i < BarCount; i++) { IndexBuyHold[i] = IndexBuyHold[i-1] * IndexDailyChange[i]; } StaticVarSet("~HCBTIndexBuyandHold", IndexBuyHold); }
Note that the custom chart is in Log scale
April 12, 2020 at 4:34 am #111275TrentRothallParticipantThis code adds a indicator value to the backtest trade list. I’ve used it for checking trades and seeing what works and what doesn’t. Good for MR systems.
Code://=================================================================================
// CBT
//=================================================================================
//ASSIGNS THE VALUE OF ThE ATR ON THE setup bar IN THE TRADE LIST// assign indicator values to ticker-specific variables
StaticVarSet( Name() + “ATR”, Ref(ATR1, -1) );SetOption(“UseCustomBacktestProc”, True);
SetCustomBacktestProc(“”);if ( Status( “action” ) == actionPortfolio )
{
bo = GetBacktesterObject();
// run default backtest procedure without generating the trade list
bo.Backtest( True );// iterate through closed trades
for ( trade = bo.GetFirstTrade( ); trade; trade = bo.GetNextTrade( ) )
{
// read ATR values and display as custom metric
symbolATR = StaticVarGet( trade.Symbol + “ATR” );
trade.AddCustomMetric( “Entry ATR”, Lookup( symbolATR, trade.EntryDateTime ) );
}// iterate through open positions
for ( trade = bo.GetFirstOpenPos( ); trade; trade = bo.GetNextOpenPos( ) )
{
// read ATR values and display as custom metric
symboLATR = StaticVarGet( trade.Symbol + “ATR” );
trade.AddCustomMetric( “Entry ATR”, Lookup( symbolATR, trade.EntryDateTime ) );
}// generate trade list
bo.ListTrades( );
}April 12, 2020 at 4:46 am #111276TrentRothallParticipantThis is another from the webinar.
It adds the trades per year to the backtest report down the bottom. I’ve added trades per day too.
Saves some excel work.
Code:SetOption(“UseCustomBacktestProc”, True);
SetCustomBacktestProc(“”);if( Status(“action”) == actionPortfolio)
{
bo = GetBacktesterObject();
bo.Backtest();st = bo.GetPerformanceStats(0);
dt = DateTime();TestStartDate = DateTimeConvert(2, Status(“rangefromdate”));
TestEndDate = LastValue(dt);
YearsInTest = DateTimeDiff(TestEndDate, TestStartDate)/31557600;NumTrades = st.getvalue(“AllQty”);
TradesPerYear = NumTrades/YearsInTest;
PerWeek = TradesPerYear/52;
PerDay = PerWeek/5;bo.AddCustomMetric(“Years in test”, YearsInTest, Null, Null, 1);
bo.AddCustomMetric(“Trades per Year”, TradesPerYear,Null, Null,0);
bo.AddCustomMetric(“Ave Trades Per Day”, PerDay, Null, Null, 2);}
April 13, 2020 at 6:28 am #111277TrentRothallParticipantThis is a extension of the custom portfolio equity chart.
This code plots the underwater equity of the buy and hold ticker created in the CBT code.
The below code needs to be in your system code file
Code:// CBT EQUITY CHART
//=====================================================================
IndexTicker = “$XAOA.au”;
StaticVarSetText(“IndexTicker”, IndexTicker);SetOption(“UseCustomBacktestProc”, True);
SetCustomBacktestProc(“”);//====================================================================
if ( Status( “action” ) == actionPortfolio )
{
bo = GetBacktesterObject();
bo.Backtest();IndexBuyHold = 0;
IndexBuyHold[0] = bo.InitialEquity;SetForeign(IndexTicker);
IndexDailyChange = C/Ref(C, -1);
RestorePriceArrays();for(i = 1; i < BarCount; i++) { IndexBuyHold[i] = IndexBuyHold[i-1] * IndexDailyChange[i]; } StaticVarSet("~HCBTIndexBuyandHold", IndexBuyHold); }
The below code is saved in the report charts folder
Code://=================================================================================
// Custom Underwater Equity chart
// Uses custom ticker created in cbt code
//=================================================================================EQ = C;
MaxEQ = Highest( EQ );
DD = 100 * ( Eq – MaxEQ ) / MaxEq;
MaxDD = Lowest( DD );IndexTicker = StaticVarGet(“~HCBTIndexBuyandHold”); //Call index ticker from cbt code in system
MaxBHEq = Highest(IndexTicker);
BHDD = 100*(IndexTicker – MaxBHEq)/MaxBHEq;
MaxBHdd = Lowest(BHdd);Title = StrFormat(“Buy and hold Drawdown = %.2g%%, Max. drawdown %.2g%%”, BHDD, LastValue( MaxBHDD ) );
SetGradientFill( GetChartBkColor(), colorBlue, 0 );
Plot( DD, “Drawdown “, colorBlue, styleGradient | styleLine );
Plot( MaxDD, “Max DD”, colorRed, styleNoLabel );
Plot( BHdd, “Index DrawDown”, colorBlack);
SetChartOptions( 2, 0, chartGridPercent );
if( Name() != “~~~EQUITY” AND Name() != “~~~OSEQUITY” ) Title = “Warning: wrong ticker! This chart should be used on ~~~EQUITY or ~~~OSEQUITY only”;
April 13, 2020 at 7:28 am #111283GlenPeakeParticipantWow…!
Awesome Trent….!!
You’re on fire!!!
Very nice work.
April 13, 2020 at 9:18 am #111270JulianCohenParticipantTrent,
One thing I noticed with Alan’s work is that he uses the include function….so basically if I understand it correctly, you can write up all the CBT code in a separate file and then call it at the point you want to use it. That way it can be called to different systems without having to have all the lines of code in each system and any change made to the include code is automatically made in the code it is embedded in.
April 13, 2020 at 9:32 am #111284TrentRothallParticipantYes i did notice that too Julian. I started playing around with that earlier. Will suit certain scenarios more than others i think.
I can’t take much credit Glen most of those are from the webinar or the net. I just adapted the DD graph from the original, i like that one though.
April 14, 2020 at 10:43 am #111285AnonymousInactiveTrent,
Stop annoying us on here with all this talk of these well coded charts and get to what we really want to know…. what the hell are you doing to get these awesome results! Damn sweet looking equity and drawdown results that I’m very envious of at the moment!
April 15, 2020 at 2:54 am #111296TrentRothallParticipantSadly my equity curve isn’t looking like that… That is my adjusted system that I am now trading. I only adjusted the exit when the index filter is down but it helps a lot with drawdowns and actually helped the overall return so that was a bonus…
April 15, 2020 at 9:04 am #111304AnonymousInactiveSeems like you’re doing all the right things! Whatever you’re doing, keep doing it!
I altered the code a little on the Underwater Equity curve to ensure that the black curve for the buy and hold comparison sits in front of the gradient filled curve for the system drawdown.
The code you posted sometimes keeps the buy and hold comparison curve hidden behind the system curve, which isn’t ideal…….
Whereas the code I updated now does this…..
Also you will notice with the code I updated I have changed what is printed at the top of the curve in text. I am most interested in the maximum drawdowns, for both the system and the B&H comparison. The ending numbers I don’t really care about being listed in this area because the ending numbers are shown in the flag on the right hand side of the plot anyway, so why print something twice on the plot.
Here is the updated code…
//=================================================================================
// Custom Underwater Equity chart
// Uses custom ticker created in cbt code
//=================================================================================EQ = C;
MaxEQ = Highest( EQ );
DD = 100 * ( Eq – MaxEQ ) / MaxEq;
MaxDD = Lowest( DD );IndexTicker = StaticVarGet(“~HCBTIndexBuyandHold”); //Call index ticker from cbt code in system
MaxBHEq = Highest(IndexTicker);
BHDD = 100*(IndexTicker – MaxBHEq)/MaxBHEq;
MaxBHdd = Lowest(BHdd);Title = StrFormat(” System Max. drawdown %.2g%%, Buy & Hold Max. drawdown %.2g%% “, LastValue( MaxDD ) , LastValue( MaxBHDD ) );
Plot( BHdd, “Index DrawDown”, colorBlack);
SetGradientFill( GetChartBkColor(), colorBlue, 0 );
Plot( DD, “Drawdown “, colorBlue, styleGradient | styleLine );
Plot( MaxDD, “Max DD”, colorRed, styleNoLabel );
SetChartOptions( 2, 0, chartGridPercent );
if( Name() != “~~~EQUITY” AND Name() != “~~~OSEQUITY” ) Title = “Warning: wrong ticker! This chart should be used on ~~~EQUITY or ~~~OSEQUITY only”;
April 16, 2020 at 1:40 am #111305TrentRothallParticipantNice, that looks better.
I’ve been thinking it would be good to have a chart that plots cash vs positions, maybe as a histogram. A simple way to view exposure levels during the test period. Similar to how you can plot the equity in a chart pane. Will have to look into it more
April 22, 2020 at 11:58 pm #111310GlenPeakeParticipantPosting this here with the other handy pieces of code.
This will generate an additional MDD column for each year in your backtest report.
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();Place into your reports directory and number accordingly.
E.g.
April 24, 2020 at 4:25 pm #111271AnonymousInactive
Me in this threadMay 1, 2020 at 8:30 am #111272GlenPeakeParticipantJust putting the MAX Wait Days chart in this thread as well….
Copy the code and place the MAX_Wait_Days.afl file into your REPORTS folder…..and you to can keep track of the number of days since your last Equity Highs!!!!
Code:eqname = “~~~EQUITY”;
if( Name() != eqname ) SetForeign( eqname );
eq = Close;bslh = HighestBars(eq);
MaxWaitBars = Highest(bslh);
Plot(bslh, “#bars since last high”, colorred, styleHistogram, 0, 10 * LastValue( Highest( bslh ) ) );
Plot(MaxWaitBars, “Max Wait Bars”, colorBlue, styleline); -
AuthorPosts
- You must be logged in to reply to this topic.