Hi @Tomasz - I have tried the combinations you mentioned. Still cannot get any messages related to "ScaleIn or ScaleOut" in the "DETAILED LOG" or see scaled trades. I have made few additional fixes & trace comments. From the log, I see the portfolio does have excess cash when ScaleIn/Scaleout is initiated. I must be missing something but cannot pinpoint it. I appreciate much your time and another look from you.
// Detect watchlist
wlnumber = GetOption( "FilterIncludeWatchlist" );
watchlist = GetCategorySymbols( categoryWatchlist, wlnumber );
numAssets = StrCount( watchlist, "," ) + 1;
_TRACE("!CLEAR!");
// Backtester Settings
SetOption("InitialEquity", 100000);
SetOption("MinShares", 100 );
SetOption("FuturesMode", False);
SetOption("AllowPositionShrinking", False);
SetOption("ActivateStopsImmediately", False);
SetOption("ReverseSignalForcesExit", False);
SetOption("AllowSameBarExit", False);
SetOption("CommissionMode", 2); // 2 = per trade
SetOption("CommissionAmount", 9.95); //per trade
SetOption("AccountMargin", 100); // 100 = no margin
SetOption("UseCustomBacktestProc", True );
SetTradeDelays( 1, 1, 1, 1);
BuyPrice = SellPrice = ShortPrice = CoverPrice = Open;
// inputs
maLength = Param("MA Length", 9, 3, 12, 1 );
isOptimize = ParamToggle( "Optimize", "No|Yes", 0);
if (isOptimize)
{
maLength = Optimize("MA Length", 9, 3, 12, 1 );
}
maxPositions = numAssets;
PositionSize = 100 /maxPositions;
// Portfolio settings
SetBacktestMode(backtestRegular );
SetOption("MaxOpenPositions", maxPositions);
SetPositionSize(PositionSize, spsPercentOfEquity );
// signals
Buy = Cross(Close, MA(Close, maLength));
Sell = Cross(MA(Close, maLength), Close);
Buy = ExRem(Buy, Sell);
Sell = ExRem(Sell, Buy);
//############ Functions follows ########
//function ScaleOutFromMoneyFund(bar, bo, symbol, cash)
//{
// mfPosition = bo.FindOpenPos(symbol);
// if(mfPosition != null)
// {
// if(mfPosition.GetPositionValue() < cash) cash = mfPosition.GetPositionValue();
// price = mfPosition.GetPrice(bar, "C");
// bo.ScaleTrade(bar, symbol, False, price, cash); // ScaleOut
// _TRACE("ScaleOut... Bar:" + bar + " Symbol:" + symbol + " Price:" + price + " Cash:" + cash);
// }
//}
function cashRequired(bar, bo)
{
cashNeeded = 0;
for (sig = bo.GetFirstSignal(bar); sig; sig = bo.GetNextSignal(bar)) // Loop through signals at this bar
{
pSize = sig.PosSize;
if(pSize < 0) pSize = (-pSize/100) * bo.Equity; // Convert from percent to dollar value
if(sig.IsEntry()) cashNeeded = cashNeeded + pSize;
if(sig.IsExit()) cashNeeded = cashNeeded - pSize;
}
return cashNeeded;
}
// ########## Custom-backtest procedure follows ##########
if( Status("action") == actionPortfolio )
{
moneyFundSymbol = "IEF";
moneyFundClose = Foreign(moneyFundSymbol, "Close");
bo = GetBacktesterObject(); // Get backtester object
bo.PreProcess(); // Do pre-processing (always required)
for(i = 0; i < BarCount; i++) // Loop through all bars
{
_TRACE("Bar: " + i + " ======================= ");
price = moneyFundClose[i];
cashNeeded = cashRequired(i, bo); // Get cash needed for entry signals
// Scale out from Money Fund for required cash.
scaleOutCash = cashNeeded - bo.Cash - 1000;
if(scaleOutCash < 0) scaleOutCash = 0;
_TRACE("CashAvailable: " + bo.Cash + ", CashNeeded: " + cashNeeded + ", ToScaleOutCash: " + scaleOutCash);
if(scaleOutCash > 1000)
{
bo.ScaleTrade(i, moneyFundSymbol, False, price, scaleOutCash); // ScaleOut
_TRACE("SCALE OUT... Symbol: " + moneyFundSymbol + ", Price: " + price + ", ScaleOutCash: " + scaleOutCash);
}
bo.ProcessTradeSignals( i ); // Process trades at bar (always required)
// Scale in to Money Fund if we have more than $1000 of cash left.
scaleInCash = bo.Cash - cashNeeded - 1000;
_TRACE("CashAvailable: " + bo.Cash + ", CashNeeded: " + cashNeeded + ", ScaleInCash: " + scaleInCash);
if( bo.Cash - cashNeeded > 1000 )
{
bo.ScaleTrade(i, moneyFundSymbol, True, price, scaleInCash); // ScaleIn
_TRACE("SCALE IN... Symbol: " + moneyFundSymbol + ", Price: " + price + ", ToScaleInCash: " + scaleInCash + ", CashRemaining:" + (bo.Cash - scaleInCash));
}
}
bo.PostProcess(); // Do post-processing (always required)
st = bo.GetPerformanceStats(0); // get stats for all trades
// Expectancy = (%Win * AvgProfit - %Los * AvgLos)/Avg Loss
expectancy = st.GetValue("WinnersAvgProfit")*st.GetValue("WinnersPercent")/100 +
st.GetValue("LosersAvgLoss")*st.GetValue("LosersPercent")/100;
expectancy = expectancy/(-st.GetValue("LosersAvgLoss"));
// Here we add custom metric to backtest report
bo.AddCustomMetric( "Expectancy", expectancy );
}
Log:
