Detailed Logging with a Low-Level CBT

Recently a student of my CBT course asked why he wasn’t seeing the usual output (including dates) when he selected AmiBroker’s “Detailed Log” option and ran a backtest that utilizes a low-level CBT. The answer is that much of the Detailed Log output comes from AmiBroker’s ProcessTradeSignals method, which isn’t used in a low-level CBT. However, it’s fairly straightforward to add your own Detailed Log output using AmiBroker’s RawTextOutput() method.

First, we only want to print detailed log output when in fact the user has selected the Detailed Log option. So before entering your bar-by-bar loop in the low-level CBT, check the reporting mode and initialize a DateTime array:

doDetailedLog = GetOption("PortfolioReportMode") == 1;
dt = DateTime();

Then, near the top of your bar-by-bar loop you can do something like this:

if (doDetailedLog)
{
    bo.RawTextOutput(NumToStr(dt[bar], formatDateTime));
   
    cntEntrySig = bo.GetSignalQty(bar,1);
    cntExitSig = bo.GetSignalQty(bar,2);           
    bo.RawTextOutput("\t"+"# Entry Signals="+cntEntrySig+".  # Exit Signals="+cntExitSig+".");
   
    entrySigList = "\tEntry Signals(score): ";
    exitSigList = "\tExit Signals: ";
   
    for (sig = bo.GetFirstSignal(bar); sig; sig = bo.GetNextSignal(bar))
    {
        if (sig.IsEntry())
        {
            if (sig.IsLong)
                dir = "Buy";
            else
                dir = "Short";
               
            entrySigList += sig.Symbol+"="+dir+"("+sig.PosScore+"), ";
        }
        if (sig.IsExit())
        {
            // bo.RawTextOutput("\t Exit Sig: "+sig.Symbol+" Price="+sig.Price+" isExit="+sig.isExit+" isLong="+sig.IsLong+" reason="+sig.Reason+" type="+sig.type);
            if (sig.IsLong)
                dir = "Sell";
            else
                dir = "Cover";
               
            exitSigList += sig.Symbol+"="+dir+", ";
        }
    }
    bo.RawTextOutput(entrySigList);
    bo.RawTextOutput(exitSigList);
}

That code snippet will produce detailed log output that looks like this:

6/8/2020
    Entry signals(score):VRTX=Buy(47.67402), RGEN=Buy(40.9388), SAM=Buy(37.74713), IPHI=Buy(35.13559),
    Exit signals:DXCM=Sell, HAIN=Sell, IMMU=Sell, SMG=Sell,
    Exit Long, IMMU, Price: 32.38, (Avg. exit pr. 32.38), Shares: 63, Commission: 0, (Total comm.: 0), Profit: 56.07 (2.83 %), Entry rank:40.37352, Equity: 10152.24, Fx rate: 1
    Exit Long, DXCM, Price: 368.62, (Avg. exit pr. 368.62), Shares: 5, Commission: 0, (Total comm.: 0), Profit: 118.85 (6.89 %), Entry rank:53.69659, Equity: 10152.24, Fx rate: 1
    Enter Long, VRTX, Price: 265.01, Shares: 7, Commission: 0, Rank: 47.67402, Equity 10290.56, Margin Loan: 0, Fx rate: 1
    Enter Long, RGEN, Price: 116.76, Shares: 17, Commission: 0, Rank: 40.9388, Equity 10290.56, Margin Loan: 0, Fx rate: 1
    4 Open Positions: , MASI (+9), , MDB (+10), , VRTX (+7), , RGEN (+17), Market Value: 7808.75, Equity: 10334.43, Cash: 2525.68, Margin: 0.00, Net Cash Balance: 2525.68,
Note that we still get some output from AmiBroker itself too: the “Enter Long…” lines shown above were not written by our code, nor was the “4 Open Positions…” line.

Of course, the Detailed Log output is limited only by your imagination. Some developers use bo.RawTextOutput and the Detailed Log as an alternative to using _TRACE statements, which means that you can see all of your output without using AmiBroker’s Log/Trace window or an external tool like Debug View.

Leave a Comment

Scroll to Top