I'm trying to debug a strategy with occasional errors like the one shown here. This happens rarely. Most signals are entered and exited with no errors.
The strategy sets the position size in the phase 2 custom backtest with this snippet of code:
numShares = some multiple of 100
sig.PosSize = numShares * sig.Price;
The log window shows trace output from the custom backtest with a dump of the signal object.
I'm not seeing any obvious reason for the error.
@Tomasz Thank you for the suggestion, but enabling AllowPositionShrinking did not help.
See below a small sample program that reproduces the problem. I suspect the problem may be related to floating point number representation. If I change the BuyPrice slightly, the error goes away.
It works flawlessly if I set the position size in shares during phase 1 backtest, but I have some special requirements (not shown) to set the position size with custom formulas in phase 2.
What is the right way to set the position size in phase 2 and avoid the "wrong position size/value" error? The number of shares will always be a multiple of 100, but the entry signal price is unpredictable and may have several digits after the decimal point.
Action = Status("Action");
// -----------------------------------------------------------------------
// BackTester Settings
// -----------------------------------------------------------------------
initialEquity = 200000;
roundSharesToNearest = 100;
accountMargin = 50;
SetTradeDelays(0,0,0,0);
SetOption("AccountMargin", accountMargin);
SetOption("InitialEquity", initialEquity);
SetOption("ActivateStopsImmediately", false);
SetOption("CommissionMode", 3); // price per share
SetOption("CommissionAmount", 0.005); // $ per share
SetOption("AllowPositionShrinking", true);
SetOption("MinPosValue", 1000);
SetOption("AllowSameBarExit", true);
SetOption("ReverseSignalForcesExit", true);
SetOption("UsePrevBarEquityForPosSizing", false);
SetOption("PriceBoundChecking", false);
SetOption("UseCustomBacktestProc", true);
RoundLotSize = roundSharesToNearest;
// -----------------------------------------------------------------------
// Trading System Formula
// -----------------------------------------------------------------------
Short = Cover = 0;
Buy = 1;
Sell = Ref(Buy, -1);
BuyPrice = 179.21; // <<<<<<<< This value affects the outcome
// -----------------------------------------------------------------------
// Set the position size in Phase 2 using special logic.
// -----------------------------------------------------------------------
function SetCustomPositionSize(bo)
{
for (i = 0; i < BarCount; i++)
{
for (sig = bo.GetFirstSignal(i); sig && sig.IsEntry(); sig = bo.GetNextSignal(i))
{
numShares = 100;
sig.PosSize = numShares * sig.Price;
} // signal loop
bo.ProcessTradeSignals(i);
} // bar loop
}
// -----------------------------------------------------------------------
// Custom Backtest
// -----------------------------------------------------------------------
if (Action == actionPortfolio)
{
bo = GetBacktesterObject();
bo.PreProcess();
SetCustomPositionSize(bo);
bo.PostProcess();
bo.AddCustomMetric("Fitness", 1.0);
}
Applying this modification to your code sample will result in buys of 99 shares. Adding a little amount to the PosSize seems a possible way to round it to 100.
sig.PosSize = numShares * sig.Price + 0.005; // This will get 100 shares
// sig.PosSize = numShares * sig.Price; // // this wil get 99
Seems to work, but I suggest waiting until you get an answer from someone really expert with the CBI interface.
It has nothing to do with CBI. Your code as it is written now suffers from rounding errors (sig.PosSize is really LESS than 100 shares and you have forced roundlotsize =100), see http://www.amibroker.com/kb/2010/07/20/about-floating-point-arithmetic/.
You are using .21 which is infinite fraction in binary system, see this: https://www.h-schmidt.net/FloatConverter/IEEE754.html - enter the number there and you will see that in binary representation it is actually 0.20999999344348907470703125, so your requested positionsize is LESS than 100 shares.
If you want fixed number of shares you should be using this:
SetPositionSize( 100, spsShares );
Or as I advised earlier use "allow position shrinking" but then you have to make sure that you never specify too small position value (see @beppe post)