Hi, I am testing a system and getting different results in the backtest report and detailed log. As seen below, in the detailed log the exit signal is reported on 6-10-25 but executed on 3-10-25 (one day before). But in the backtest report, the trade is executed on 6-10-25. This is happening with all the sell trades. Besides I ran the system including custom backtest and checking for exit signals and they are reported on the day that match with the backtest report. Trade delays is set to 0. When checking the Sell vector with the explore tool, I see it in the correct day, but the detailed log is reporting the exit one day before it should.
I generally don’t use the detailed log with a CBT, but instead rely on my own _TRACE statements. Chances are good that you’ve done something in your CBT that’s causing the Detailed Log output to be written out of order, but since you didn’t post your code there’s not much that anyone can do to help you.
Thanks @mradtke for your help, unfortunately I can not share all the code but here is the CBT phase with all the corresponding _TRACE and the result of the Detailed Log for giving more context:
SetCustomBacktestProc("");
if (Status("action") == actionPortfolio) {
bo = GetBacktesterObject();
bo.PreProcess();
MaxOrdersToPlace = 0;
TotalOrdersPlaced = 0;
sectNames = getActiveSectors();
for (i = 0; i < BarCount; i++) {
_TRACE(" -------------------------------------- "+DateTimeToStr(dt[i]));
_TRACE("Open Pos at the beginning of the day "+ NumToStr(bo.GetOpenPosQty()));
for( openpos = bo.GetFirstOpenPos(); openpos; openpos = bo.GetNextOpenPos() )
{
_TRACE(openpos.Symbol+" Open Pos at the beginning of the day "+NumToStr(openpos.Shares));
}
for( item = 0; ( sector = StrExtract( sectNames, item, separator = '|' ) ) != ""; item++ ){
StaticVarSet( key_strat_var + sector, 0 );
}
for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i)){
_TRACE("Signal is exit?: "+ sig.IsExit()+ " signal is entry "+NumToStr(sig.IsEntry())+" signal size "+NumToStr(sig.PosSize));
if (sig.IsExit() && sig.IsLong()){
a_var =sig.IsExit();
b_var =sig.IsLong();
_c =sig.IsExit() && sig.IsLong();
bo.ExitTrade(i, sig.Symbol, sig.Price, 1);
_TRACE("-----> Conditions:"+ a_var+b_var+_c);
_TRACE("-----> Exit: Signal and execution of "+ sig.Symbol+ " px "+NumToStr(sig.Price)+ " qty "+ NumToStr(sig.PosSize));
}
}
MaxOrdersToPlace = MaxPos - bo.GetOpenPosQty();
SigCount = 0;
for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i)){
if(sig.PosSize == -2000){ // Cancel orders with shares = 0 to prevent further signals to be ignored
sig.Price = -1;
_TRACE("Order is canceled due to shares = 0 "+ sig.Symbol);
}
if (sig.IsEntry() && sig.IsLong()){
_TRACEF("---------------> Entry "+sig.Symbol+" "+NumToStr(SigCount)+" "+NumToStr(sig.PosScore)+" pos size "+ NumToStr(sig.PosSize));
SigCount++;
symbolSector = StaticVarGetText(sig.Symbol + "Sector");
currSectorCount = StaticVarGet(key_strat_var + symbolSector);
StaticVarSet( key_strat_var + symbolSector, currSectorCount + 1 );
currSectorCount = StaticVarGet(key_strat_var + symbolSector);
LimitPrice = StaticVarGet(sig.Symbol + "LimitEntryPrice");
LowPrice = Foreign(sig.Symbol, "Low");
if (SigCount > MaxOrdersToPlace){ // Cuando esta condición se alcanza, no se enviará ninguna otra orden
sig.Price = -1;
if (SigCount > MaxOrdersToPlace) _TRACE(" "+sig.Symbol +" anular trade por número de orders"+" Sector: "+ symbolSector+" #ofOrders in Sect "+NumToStr(currSectorCount));
}else if (currSectorCount > MaxPosPerSector AND maxSectorsActive){ // Estas órdenes no se alcanzan a enviar, por lo que se descuenta del SigCount y del diccionario de sectores
sig.Price = -1;
SigCount--;
StaticVarSet( key_strat_var + symbolSector, currSectorCount - 1);
if (currSectorCount > MaxPosPerSector AND maxSectorsActive) _TRACE(" "+sig.Symbol +" anular trade por MaxSector limit Sector: "+ symbolSector+" #ofOrders in Sect "+NumToStr(currSectorCount));
}else if (LimitPrice[i] < LowPrice[i]){ // Esta orden se envía, pero NO se ejecuta porque no alcanza el px límite NOTA: Se le da un espacio al precio límite ya que cuando Limit = Low y la orden hace filled, estaba siendo cancelada en el BT
sig.Price = -1;
TotalOrdersPlaced++;
if (LimitPrice[i] < LowPrice[i]) _TRACE(" "+sig.Symbol +" Order placed, pero no es ejecutada por px lim"+" Sector: "+ symbolSector+" #ofOrders in Sect "+NumToStr(currSectorCount)+ " Limit "+ NumToStr(LimitPrice[i], 1.5)+" Low "+ NumToStr(LowPrice[i], 1.5));
}
else{ //Esta parte sirve sólo para monitoreo
TotalOrdersPlaced++;
_TRACE("Order placed and executed"+NumToStr(SigCount)+" "+ sig.Symbol+" Sector: "+ symbolSector+" #ofOrders in Sect "+NumToStr(currSectorCount)+ " PosSize "+ NumToStr(sig.PosSize));
}
}
}
for( openpos = bo.GetFirstOpenPos(); openpos; openpos = bo.GetNextOpenPos() )
{
_TRACE(openpos.Symbol+" possize "+NumToStr(openpos.Shares));
}
// En el CB no es necesario anular las órdenes que no alcanzaron el límite, porque ya está implícito en el BuyPrice
_TRACE("Open Pos before process signals "+ NumToStr(bo.GetOpenPosQty()));
bo.ProcessTradeSignals(i);
_TRACE("Open Pos after process signals "+ NumToStr(bo.GetOpenPosQty()));
}
}
//=================================================================================
_SECTION_END();
Here is the trace for one symbol ASTS. The close is executed on 8/09/2025, but reported one day before in the Detailed Log. One curious thing is that the real day of the close, the PosSize is Empty when debugging
Here is the detailed log with the reported trades:
In Backtester, there is a setting for something like ‘add artificial future bar’, which is not present in explorer.
Since 3/10/25 was a Friday and 6/10/25 was a Monday, if you have an end of day system, I am wondering if it might be worth you inspecting the outcomes with and without this setting?
Good luck.
In your CBT you are calling bo.ExitTrade(), which is a low-level CBT call. However, you are also calling bo.ProcessTradeSignals(), which is a mid-level CBT call that processes entries, exits, scale-ins, and scale-outs. In other words, your exit signals are being processed twice: once by bo.ExitTrade and once by bo.ProcessTradeSignals.
Note that bo.ProcessTradeSignals() also prints the date to the detailed log. So anything you do before calling that function (like performing your own Exit) will appear before the date even though the exit actually occurred on the date that is printed by bo.ProcessTradeSignals(). So in your OP, the YOU exit actually occurred on Oct 6 (which you would likely see in the regular trade list) and not on Oct 3.
If you need to call bo.ExitTrade, then you should fully implement a low-level CBT by removing bo.ProcessTradeSignals and instead calling bo.EnterTrade() for the entry signals.


