What i would like to do is to retrieve data (for example Close price, atr....) from all components of a certain watchlist, during every OpenPos() iteration.
You are re-adding the custom trade metrics on every bar. Try using a high-level CBT with this structure instead:
if (Status("action") == actionPortfolio)
{
// Get backtester object
bo = GetBacktesterObject();
// Run the default AB back test, suppressing the trade list
bo.Backtest(true);
////////////////////////////////////////////////////
// Custom Trade Metrics
////////////////////////////////////////////////////
// Process all closed trades
for (trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade())
{
// Get the array index for this trade's entry and exit date
entryBar = Lookup(BarIndex(),trade.entrydatetime,0);
exitBar = Lookup(BarIndex(),trade.exitdatetime,0);
// Your custom trade metrics here
} // end for all closed trades
// Process open trades
for (trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos())
{
// Get the array index for this trade's entry and exit date.
// Since the trade is still open, the exit date is the last bar of the test
entryBar = Lookup(BarIndex(),trade.entrydatetime,0);
exitBar = BarCount-1;
// Your custom trade metrics here
} // end for all open positions
// Output the trade list, including any custom metrics
bo.ListTrades();
}
Why do you think you need the bo.ScaleTrade() method? Usually scaling in and out can be done from your Phase 1 code using sigScaleIn and sigScaleOut.
The bo.ScaleTrade() method is part of the low-level CBT. What I provided for you was a skeleton for a high-level CBT. You cannot mix high-level and low-level CBT methods. You can read about the different types of CBT here: https://www.amibroker.com/guide/a_custombacktest.html
Because i would like to adjust components exposure using indicators values.
for (trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade())
{
sum = 0;
for ( trade1 = bo.GetFirstOpenPos(); trade1; trade1 = bo.GetNextOpenPos() )
{
symbolATR = StaticVarGet( trade1.Symbol+"ATR" );
sum = sum+symbolATR;
}
for ( trade1 = bo.GetFirstOpenPos(); trade1; trade1 = bo.GetNextOpenPos() )
{
symbolATR = StaticVarGet( trade1.Symbol+"ATR" );
w = (symbolATR/somma)*100;
//trade.AddCustomMetric( "Weight", Lookup( w, trade.EntryDateTime ) );
}
}
In the first loop i sum the indicators value for each stock.
In the second loop calculate weight% for each stock (indicator/sum).
Now i would like to adjust components exposure by Weight: w*bo.equity()
(But, like you said, obviously is impossibile because i cannot mix high/low level backtesting.)
So, every month, i do a "weight adjusted" rebalancing.
Is also possibile to do it with low level backtesting ? Or just on high level ?
I'm trying to find a solution but i'm blocked.
Any input will be very appreciated.
Thank you in any case
NE
The last code example that you provided doesn't make any sense in the context of your previous messages. If you're calling your nested loops after calling bo.Backtest(), then the backtest is complete and the only open trades that you will find with bo.GetFirstOpenPos() / bo.GetNextOpenPos() are the ones which were not closed before the end of your analysis date range. There are likely other issues there as well.
To answer your question, anything that you can do with a high-level CBT can also be done with a mid-level or low-level CBT. Each new level of the CBT from high to low provides more control but also introduces more complexity, and therefore more opportunity for error. Whether you really need a CBT depends on your weighting and rebalancing requirements. But it is certainly possible, for example, to evaluate indicator values for all symbols in your watchlist during your Phase 1 code and to use the sum to determine position sizes. The rebalancing might be pretty difficult without a CBT unless you're willing to fully exit and then reenter positions rather than scaling in and out.
Thank you again for helps.
It's ok for me to fully exit and reenter, and calculate separately the commission impact.
I don't find a convenience to scalein/out during a simulation. Currently, seems more easy to manage for me. I'm trying to work on it.
I really cannot understand why i retrieve an error if my log is 100% correct.
Why bo.scaletrade does not accept W as variable ?
W is a number like "1000" that change every iteration.
Thank you for response fxshrat.
And how can i put my desired value ?
Im trying with bo.EnterTrade( i, sig.Symbol, sig.IsLong(), sig.Price,.... );
But the problem seems the same...
Working on it, seems that i did what i wanted.
The following code works similar to Rotational, with the difference that every component of a watchlist is used, giving a weight proportionated to "positionscore", that in our case is ROC.
SetPositionSize(1,spsPercentOfEquity);
SetCustomBacktestProc("");
if (Status("action") == actionPortfolio)
{
bo = GetBacktesterObject(); // Get backtester object
bo.PreProcess(); // Do pre-processing
for (i = 0; i < BarCount; i++) // Loop through all bars
{
eq = bo.Equity();
sums = 0;
symbolROC = 0;
w = 0;
for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i))
{
if (sig.isEntry())
{
symbolROC = StaticVarGet( sig.Symbol+"ROC" );
sums = (sums+symbolROC);
}
}
for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i))
{
if (sig.isEntry())
{
symbolROC = StaticVarGet( sig.Symbol+"ROC" );
w = (symbolROC/sums)*eq;
bo.EnterTrade(i, sig.Symbol, True, sig.Price, w[i]);
}
}
for (sig = bo.GetFirstSignal(i+1); sig; sig = bo.GetNextSignal(i+1))
{
if (sig.isExit())
{
bo.ExitTrade(i+1,sig.symbol,sig.Price);
}
}
bo.HandleStops(i); // Handle programmed stops at this bar
bo.UpdateStats(i, 1); // Update MAE/MFE stats for bar
bo.UpdateStats(i, 2); // Update stats at bar's end
} // End of for loop over bars
bo.PostProcess(); // Do post-processing
}
StaticVarSet(Name() + "ROC",100-ROC(14));
Buy = 1;
Sell = 0;
Short = Cover = 0;
ApplyStop(stopTypeNBar,stopModeBars,10);
The only question is why, i've to refere to the next signal to let my code works:
for (sig = bo.GetFirstSignal(i+1); sig; sig = bo.GetNextSignal(i+1))
{
if (sig.isExit())
{
bo.ExitTrade(i+1,sig.symbol,sig.Price);
}
}