The following code is an attempt to implement the requested dynamic portfolio size method, using the RUAroc benchmark and the market regime filter (now: always true). The code has a couple of extras: benchmark fund, top size, and position size mode are user adjustable through the Parameters window. Exploration view is possible for: all bars, end of months, or last bar only. The code is designed for EOD data.
NB! Somewhere is a bug in hiding, because the position size values are greyed out in exploration view. Hence the dynamic coloring doesn't work (yet?) and is switched off. Anyone?
/* DynamicPortfolioSize_v1.afl */
// --- begin of code ---
// --- detect tradelist ---
wlnumber = GetOption( "FilterIncludeWatchlist" );
watchlist = GetCategorySymbols( categoryWatchlist, wlnumber );
NumberOfFunds = StrCount( watchlist, "," ) + 1;
NoF = NumberOfFunds;
// --- input benchmark fund ---
_benchmark = ParamStr( "Benchmark Symbol", "IWV" );
// --- rebalance frequency ---
frequency = ParamList( "Rebalance Frequency:", "Monthly|Bi-Monthly|Quarterly|Annually", 0 );
// --- detect period ends ---
MonthEnd = Month() != Ref( Month(), 1 );
BiMonthEnd = Month()%2 == 0 AND MonthEnd;
QuarterEnd = Month()%3 == 0 AND MonthEnd;
YearEnd = Month()%12 == 0 AND MonthEnd;
// --- init rebalancing frequency ---
if ( frequency == "Monthly" ) Rebalance = MonthEnd;
if ( frequency == "Bi-Monthly" ) Rebalance = BiMonthEnd;
if ( frequency == "Quarterly" ) Rebalance = QuarterEnd;
if ( frequency == "Annually" ) Rebalance = YearEnd;
Rebalance = Rebalance OR Status( "LastBarInTest" );
// --- top selection ---
TopSize = Param( "Number of Top Positions:", NoF, 1, NoF, 1 );
PosSizeMode = ParamToggle( "Position Size Mode:", "Fixed|Spread", 0 );
// --- backtester settings ---
SetBacktestMode( backtestRegular );
SetOption( "CommissionAmount", 0.00 );
SetOption( "InitialEquity", 100000 );
SetTradeDelays( 0, 0, 0, 0 );
SetOption( "MaxOpenLong", NoF );
SetOption( "MaxOpenPositions", NoF );
SetOption( "AllowPositionShrinking", True );
SetOption( "AllowSameBarExit", True );
SetOption( "ReverseSignalForcesExit", False );
SetOption( "HoldMinBars", 1 );
SetOption("ExtraColumnsLocation", 11 );
RoundLotSize = 1;
// --- init values ---
count = SumPosSize = 0;
// --- asset selection and capital allocation routine ---
// based on https://groups.yahoo.com/neo/groups/amibroker/conversations/topics/178791
if ( ( Status( "stocknum" ) == 0 OR Status("stocknum") == -1 ) ) // AND Status("actionex") != actionPortfolio )
{
// --- remove staticvars ---
StaticVarRemove( "RUA*" );
StaticVarRemove( "bull*" );
StaticVarRemove( "sym*" );
StaticVarRemove( "ROC*" );
StaticVarRemove( "count*" );
StaticVarRemove( "Rank*" );
StaticVarRemove( "Pos*" );
StaticVarRemove( "Sum*" );
// --- import data for benchmark fund (default: IWV) ---
RUA = Foreign( _benchmark, "C" );
RUAroc = ROC( RUA, 100 );
StaticVarSet( "RUAroc", RUAroc );
// --- setup of market regime filter ---
// bullmarket = Foreign( "~BULLBEAR","C" ) == 2;
bullmarket = 1; // <--- remove this line and de-comment prior line
StaticVarSet( "bullmarket", bullmarket );
// --- loop for collecting outperformance data ---
for ( i = 0; ( symbol = StrExtract( watchlist, i ) ) != ""; i++ )
{
// --- retrieve stored values ---
RUAroc = StaticVarGet( "RUAroc" );
SetForeign( symbol );
// --- load quotes ---
Data = Close;
// --- test outperformance ---
symROC = ROC( Data, 100 ) / RUAroc;
ROCthresh = IIf( symROC > 1, symROC , 0 );
// --- count number of outperforming funds ---
count = IIf( symROC > 1, count + 1, count );
RestorePriceArrays();
// --- store threshold value ---
StaticVarSet( "symROC" + symbol, ROCthresh );
StaticVarSet( "ROCthresh" + symbol, ROCthresh );
}
// --- store count ---
StaticVarSet( "count", count );
// --- generate ranks ---
StaticVarGenerateRanks( "Rank_", "ROCthresh", 0, 1224 );
// --- loop for position sizing ---
for ( i = 0; ( symbol = StrExtract( watchlist, i ) ) != ""; i++ )
{
// --- retrieve stored values ---
Rank_ROCthresh = StaticVarGet( "Rank_ROCthresh" + symbol );
ROCthresh = StaticVarGet( "ROCthresh" + symbol );
count = StaticVarGet( "count" ) + 0.00000001;
bullmarket = StaticVarGet( "bullmarket" );
// --- position sizing ---
// fixed pos.size:
if ( PosSizeMode ) PosSize = IIf( Rank_ROCthresh <= TopSize AND ROCthresh > 0 AND bullmarket, 100 / NoF, 0 );
// spread total over outperforming funds:
else PosSize = IIf( Rank_ROCthresh <= TopSize AND ROCthresh > 0 AND bullmarket, IIf( Count >= 1, 100 / Min( count, TopSize ), 0 ), 0 );
PosSize = IIf( Status( "BarInRange" ), PosSize, 0 );
SumPosSize = SumPosSize + PosSize;
// --- store values ---
StaticVarSet( "PosSize" + symbol, PosSize );
}
StaticVarSet( "SumPosSize", SumPosSize );
}
// --- retrieve values ---
symbol = Name();
RUAroc = StaticVarGet( "RUAroc" );
Rank_ROCthresh = StaticVarGet( "Rank_ROCthresh" + symbol );
symROC = StaticVarGet( "symROC" + symbol );
ROCthresh = StaticVarGet( "ROCthresh" + symbol );
PosSize = StaticVarGet( "PosSize" + symbol );
SumPosSize = StaticVarGet( "SumPosSize" );
count = StaticVarGet( "count" );
bullmarket = StaticVarGet( "bullmarket" );
// --- set position sizes ---
SetPositionSize( PosSize, spsPercentOfEquity );
// --- re-balance at the end/close of every month ---
Buy = Rebalance AND PosSize > 0;
Sell = Rebalance;
Short = Cover = 0;
BuyPrice = Close;
SellPrice = Close;
// --- exploration filter ---
ExploreFilter = ParamList( "Rebalance Frequency:", "All Bars|End of Month|Last Bar" );
if ( ExploreFilter == "All Bars" ) Filter = 1;
if ( ExploreFilter == "End of Month" ) Filter = Month() != Ref( Month(), 1 ) OR Status( "LastBarInTest" );
if ( ExploreFilter == "Last Bar" ) Filter = Status( "LastBarInTest" );
// --- sort for exploration only (not on backtest) ---
if ( Status( "actionex" ) == actionExplore )
{
SetSortColumns( 2, 7 );
// --- columns for exploration ---
ColorROC = IIf( ROCthresh > 1, colorBrightGreen, colorWhite );
ColorPos = IIf( PosSize > 0 , colorGold , colorWhite );
AddColumn( RUAroc , "RUAroc" , 3.3 );
AddColumn( ROC(Close,100) , "ROC(100) (%)" , 3.3 );
AddColumn( symROC , "symROC" , 3.3, 1, ColorROC );
AddColumn( ROCthresh , "ROCthresh" , 3.3, 1, ColorROC );
AddColumn( Rank_ROCthresh , "Rank" , 1.0 );
//AddColumn( PosSize , "PosSize (%)" , 3,3, 1, ColorPos );
AddColumn( PosSize , "PosSize (%)" , 3,3 );
AddColumn( SumPosSize , "SumPosSize (%)" , 3.3 );
AddColumn( count , "# Total.Count" , 1.0 );
AddColumn( bullmarket , "Market Filter" , 1.0 );
}
// --- end of code ---
type or paste code here