Elegant solution to create a Universe of stocks with all the stocks belonging to top30% Sub-Industries?

Hi,

I would like to create a universe that -for example- keeps all the stocks in the top30% SubIndustries in terms of Pr13W%Chg
Think of it as “all the stocks belonging to SubIndustries that have best performed recently” (excluding dividends)

NB: There are 160 SubIndustries based on https://www.portfolio123.com/app/taxonomy/stock/usa/subindustry

I tried the following 2 lines in the screener (starting with all fundamentals)
setvar(@SubIndusRank, Frank(“Aggregate(“Pr13W%Chg”,#SubIndustry, #Avg,16.5,#Exclude,false,true,1)”,#all,#desc))
@SubIndusRank>=70

The first line is an attempt to compute -for each stock in all fundamentals- the rank of its SubIndustry based on price change over the last 13 weeks (excluding dividends)
The second line keeps all the stocks belonging to any and all SubIndustries ranked in the top 30% by Pr13W%Chg (top30% of 160 SubIndustries = circa top 50)

I get → ERROR: Invalid criteria in Rule 1. Error near ‘Aggregate’: Aggregate - Missing operands

I made the screen public → https://www.portfolio123.com/app/screen/summary/193610?mt=1

Then I could convert that into a universe

Any help is most welcomed…

Thanks,

Jerome

P123 does not allow nested quotes. So you can’t combine the F’s with with any other factor that requires quotes.

Maybe try calling a custom series and then calling Aggregate(“some function”, #previous,#avg)

If you make that a variable you won’t lose your initial universe…

Hi Jerome,

I don’t think you can make a Universe with that restriction. You can get some of the behavior with the Screener; see https://www.portfolio123.com/app/screen/summary/193613?st=1&mt=1

Unfortunately, FOrder as it’s used in the Screener doesn’t work in simulation.

To make a sim work, you can put the Pr13WPctChgSubInd formula in a ranker but that has other complications and restrictions.

Best,
Walter

Take a look at Forder , in particular the last parameter distinct being set to TRUE. This should do the trick

FOrder(“close(0,#SubIndustry)/close(60,#SubIndustry)”,#all,#desc,TRUE) < 50

I created a screen https://www.portfolio123.com/app/screen/summary/193615?mt=1

So why doesn’t this work in a sim?

FOrder(“$Pr13WPctChgSubInd”,#All,#Desc,True)<100

Where $Pr13WPctChgSubInd = Aggregate(“Pr13W%Chg”,#SubIndustry,#Avg,16.5,#Exclude,false,true,1)

wwasilev , sorry didn’t see your solution. It’s very similar. I’m using our pre-built subindustry series accessing them via the Close() function, you are computing them on the fly . The other difference is that we do cap weighting.

What do you mean it doesn’t work in a sim?

Defining $Pr13WPctChgSubInd = Aggregate(“Pr13W%Chg”,#SubIndustry,#Avg,16.5,#Exclude,false,true,1)
and then using the custom formula in a buy rule like

FOrder("$Pr13WPctChgSubInd",#All,#Desc,True)<100

results in an error report; Could not find uid 9234 in function Aggregate – map size is 0

Formula functions need to run before rules. The logic is not looking inside custom formulas to find them, probably by design. In any event using close(bar,#SubIndustry) to calculate return achieves the same.

That’s because Close accepts #SubIndustry. What’s the solution for factors that don’t? As an example, say instead of Pr13W%Chg (or close(0,#SubIndustry)/close(60,#SubIndustry)) , I wanted to use the ratio OpIncQ/OpIncPYQ. Is there a P123 solution for that?

Have you tried using SetVar instead of custom formulas ? Should work .

Like;

SetVar(@MyAvg,Aggregate("OpIncQ/OpIncPYQ",#SubIndustry,#Avg,16.5,#Exclude,false,true,1))
FOrder("@MyAvg",#All,#Desc,True)<100

That fails with; Value not set for temp variable @MyAvg uid 7804

Don’t the cross-section functions run prior to the remaining rules alike SetVar?

Walter

The above code appears to work in a custom Universe. All right! Not sure why the sim is problematic.

So, if I’m not mistaken, depending where “Aggregate(“Pr13W%Chg”,#SubIndustry,#Avg,16.5,#Exclude,false,true,1)” is defined (custom formula or SetVar), the following is true for its use in FOrder;

screener: both custom formula and setvar work
universe: only setvar works
simulation: neither custom formula or setvar work

Is that right?

Walter

EDIT: FOrder(“$Pr13WPctChgSubInd”,#All,#Desc,True)<100 seems to work when $Pr13WPctChgSubInd is invoked in a prior rule. I seem to remember that from an earlier discussion.

Screener and universe should be the same.

Talked it over, and looks like there’s no way to rank an industry formula vs. other industries in a buy/sell rule. The easiest solution is probably to add specific functions that rank industries, like AggregateRank, AggregatePos, etc.

Thanks

In a buy rule use;

$Pr13WPctChgSubInd | True 
FOrder("$Pr13WPctChgSubInd",#All,#Desc,True)<100

Leaving out the first rule, causes an error. Same is true for the Screener and Universe.

Walter

Thank you very much both Marco and Walter. It is amazing what we can do on this platform.

Now: replacing in Marco’s original example screen
showvar(@subindorder,FOrder(“close(0,#SubIndustry)/close(60,#SubIndustry)”,#all,#desc,true))
by
showvar(@SubIndorder,Aggregate(“close(0)/close(60)”,#SubIndustry,#Avg,0,#exclude,false,true,0))

should give the same result, no?

But with Marco’s screen, there are 1843 out of all-fundamentals 6131 stocks that pass
With my Aggregate substitute, I have only 1781 passing stocks.

I tried various parameters for aggregate (cutting the tails or not, #exclude or #winsor, etc)

What am I missing?

Thank you.

Jerome

Anyone?

The Aggregate function will give a single answer for every stock in the subindustry. The FOrder is assigning one value to each stock.

If I just grab every stock for which close(0,#subindustry)/close(60,#subindustry) is greater than the subindustry aggregate, I get 3431 companies.

That number is going to be affected by the number of companies in each subindustry and exactly where the aggregate ends up. I always think of Air Freight and Regional Banks when dealing with this stuff: Air Freight has 14 companies, while Regional Banks has 448. The number that exceed the Aggregate are going to vary, but obviously it’s not going to hit the 50% mark every time. Marco’s screen will.