I think it turned out quite well, and I’ll admit that I had some help from artificial intelligence.
I’m aware that the use of AI is often discouraged in this forum, mainly because it can limit a deeper understanding of the underlying code. That’s a fair point. However, I’m still learning, and with the help of AI I’m making significantly faster progress than I used to.
I would really appreciate your support, and in return I’m happy to share my own developments with you.
Here is a profit table that evaluates the results of the trading system based on the S&P 500, including the performance difference. I hope it’s useful and that I can contribute something of value to the forum as well.
EnableTextOutput( 3 ); // enable HTML output into report (Version 5.84 or higher!)
eq = C;
// SPX Buy & Hold Kurse laden (mit Fallbacks)
spxTicker = "$SPX";
spxClose = Foreign( spxTicker, "C" );
if( LastValue( spxClose ) == 0 OR IsNull( LastValue( spxClose ) ) )
spxClose = Foreign( "^GSPC", "C" );
if( LastValue( spxClose ) == 0 OR IsNull( LastValue( spxClose ) ) )
spxClose = Foreign( "SPY", "C" );
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 ];
LastYrValueSPX = spxClose[ startbar ];
MaxYrProfit = MinYrProfit = 0;
MaxMoProfit = MinMoProfit = 0;
// Gesamt-Compound-Return vorbereiten
TotalSysMultiplier = 1.0;
TotalSpxMultiplier = 1.0;
YearCount = 0;
for ( i = startbar + 1; i < BarCount; i++ )
{
if ( YearChange[ i ] || i == BarCount - 1 )
{
Chg = 100 * ( -1 + eq[ i ] / LastYrValue );
VarSet( "ChgYear" + yr[ i ], Chg );
// SPX-Jahresrendite
if( LastYrValueSPX > 0 AND spxClose[ i ] > 0 )
{
ChgSPX = 100 * ( -1 + spxClose[ i ] / LastYrValueSPX );
VarSet( "ChgYearSPX" + yr[ i ], ChgSPX );
TotalSpxMultiplier = TotalSpxMultiplier * ( 1 + ChgSPX/100 );
}
TotalSysMultiplier = TotalSysMultiplier * ( 1 + Chg/100 );
YearCount++;
MaxYrProfit = Max( MaxYrProfit, Chg );
MinYrProfit = Min( MinYrProfit, Chg );
if ( FirstYr == 0 )
FirstYr = yr[ i ];
LastYr = yr[ i ];
LastYrValue = eq[ i ];
LastYrValueSPX = spxClose[ i ];
}
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( "<table border='1' bordercolor='#000000' cellspacing='0' cellpadding='3'style='border-collapse:collapse;'>\n" );
printf( "<tr bgcolor='#eeffee' >\n" );
Header = "Year," + MonthNames + ",Yr%%,SPX%%,Diff%%";
for ( Col = 0; ( Colname = StrExtract( Header, Col ) ) != ""; Col++ )
{
printf( "<td><b>" + Colname + "</b></td>" );
}
printf( "</tr>\n" );
for ( y = FirstYr; y <= LastYr; y++ )
{
// new row
if ( y % 2 )
printf( "<tr bgcolor='#ffffff'>\n<td bgcolor='#eeffff'>" );
else
printf( "<tr bgcolor='#ffffee'>\n<td bgcolor='#eeffee'>" );
printf( "<b>%g</b></td>", y );
for ( m = 1; m <= 12; m++ )
{
Chg = VarGet( "ChgMon" + y + "_" + m );
if ( NOT IsNull( Chg ) )
{
if ( Chg >= 0 )
printf( "<td nowrap>%.1f%%</td>", Chg );
else
printf( "<td nowrap><font color='880000'>%.1f%%</font></td>", Chg );
}
else
printf( "<td>N/A</td>" );
}
// === Jahresrendite System ===
if ( y % 2 )
printf( "<td nowrap bgcolor='#eeffff'>" );
else
printf( "<td nowrap bgcolor='#eeffee'>" );
xSys = VarGet( "ChgYear" + y );
if ( xSys >= 0 )
printf( "<b>%.1f%%</b></td>", xSys );
else
printf( "<font color='880000'><b>%.1f%%</b></font></td>", xSys );
// === Jahresrendite SPX Buy & Hold ===
if ( y % 2 )
printf( "<td nowrap bgcolor='#e6f0ff'>" );
else
printf( "<td nowrap bgcolor='#d9e6ff'>" );
xSpx = VarGet( "ChgYearSPX" + y );
if ( NOT IsNull( xSpx ) )
{
if ( xSpx >= 0 )
printf( "<font color='0000aa'>%.1f%%</font></td>", xSpx );
else
printf( "<font color='880000'>%.1f%%</font></td>", xSpx );
}
else
printf( "N/A</td>" );
// === Differenz System - SPX (Outperformance) ===
if ( y % 2 )
printf( "<td nowrap bgcolor='#fffbe6'>" );
else
printf( "<td nowrap bgcolor='#fff5cc'>" );
if ( NOT IsNull( xSpx ) )
{
diff = xSys - xSpx;
if ( diff >= 0 )
printf( "<b><font color='008800'>+%.1f%%</font></b></td>", diff );
else
printf( "<b><font color='880000'>%.1f%%</font></b></td>", diff );
}
else
printf( "N/A</td>" );
printf( "</tr>\n" ); // end row
}
// === Durchschnittszeile ===
printf( "<tr bgcolor='#eeffee' >\n" );
printf( "<td><b>Avg</b></td>" );
for ( m = 1; m <= 12; m++ )
{
x = Nz( VarGet( "SumChgMon" + m ) / VarGet( "SumMon" + m ) );
if ( x >= 0 )
printf( "<td nowrap><b>%.1f%%</b></td>", x );
else
printf( "<td nowrap><font color='880000'><b>%.1f%%</b></font></td>", x );
}
// CAGR System
if( YearCount > 0 )
{
CagrSys = 100 * ( ( TotalSysMultiplier ^ ( 1 / YearCount ) ) - 1 );
CagrSpx = 100 * ( ( TotalSpxMultiplier ^ ( 1 / YearCount ) ) - 1 );
CagrDiff = CagrSys - CagrSpx;
// CAGR System Zelle
if( CagrSys >= 0 )
printf( "<td nowrap bgcolor='#eeffee'><b>%.1f%%</b></td>", CagrSys );
else
printf( "<td nowrap bgcolor='#eeffee'><font color='880000'><b>%.1f%%</b></font></td>", CagrSys );
// CAGR SPX Zelle
if( CagrSpx >= 0 )
printf( "<td nowrap bgcolor='#d9e6ff'><b><font color='0000aa'>%.1f%%</font></b></td>", CagrSpx );
else
printf( "<td nowrap bgcolor='#d9e6ff'><b><font color='880000'>%.1f%%</font></b></td>", CagrSpx );
// CAGR Diff Zelle
if( CagrDiff >= 0 )
printf( "<td nowrap bgcolor='#fff5cc'><b><font color='008800'>+%.1f%%</font></b></td>", CagrDiff );
else
printf( "<td nowrap bgcolor='#fff5cc'><b><font color='880000'>%.1f%%</font></b></td>", CagrDiff );
}
else
{
printf( "<td> </td><td> </td><td> </td>" );
}
printf( "</tr></table>\n" );
// === Legende unter der Tabelle ===
printf( "<p style='font-size:11px;color:#555;'>" );
printf( "<b>Yr%%</b> = Jahresrendite System " );
printf( "<b>SPX%%</b> = Jahresrendite SPX Buy & Hold " );
printf( "<b>Diff%%</b> = Outperformance (System - SPX) " );
printf( "Letzte Zeile: CAGR über gesamten Backtest-Zeitraum." );
printf( "</p>" );
}
///////////////////////////
// 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<br>" );
}
}
CheckSymbol();
////////////////////////////
// Main program
////////////////////////////
GenProfitTableHTML();
