WOW Ports that I am following June 2022
These are screens are those that I follow from: What Works on Wall Street, Fourth Edition: The Classic Guide to the Best-Performing Investment Strategies of All Time.
This is just my interpretation of the books material.
This material is not intended to be relied upon as a forecast, research or investment advice, and is not a recommendation. Past performance is not always indicative of future returns. I may or may not own stocks listed
R System Prep¶
Data was downloaded the day that I run this notebook. Data should be 1 market day old.
This sheet was run on:
Sys.time()
First initialize R environment:
suppressPackageStartupMessages(library(tidyverse))
suppressPackageStartupMessages(library(tidyquant))
suppressPackageStartupMessages(library(rio))
suppressPackageStartupMessages(library(knitr))
suppressPackageStartupMessages(library(kableExtra))
suppressPackageStartupMessages(library(IRdisplay))
#library(kableExtra)
Read Data
#setwd("D:/OneDrive/SITES/www.michaelghens.com/Rdocs")
universe <-
  read.csv(
    "STOCKS.TXT",
    header = FALSE,
    stringsAsFactors = FALSE,
    na.strings = '-9999999999.990'
  )
universe_names <-
  read.csv(
    "STOCKS_KEY.TXT",
    header = FALSE,
    stringsAsFactors = FALSE,
    na.strings = '-9999999999.990'
  )
names(universe) <- universe_names[, 2]
count1 <- nrow(universe)[1]
Fields imported:
universe_names[, 2] %>%
  kbl("html") %>%
  as.character() %>%
  display_html()
Fields:
- EarningsQuality: ([Cash from operations 12m]-[Net income 12m])/[Market Cap Q1]
- 1yr chg debt: [Long-term debt Q1]-[Long-term debt Q5])/[Long-term debt Q5]
- External Financing: [Cash from financing Q1]/[Total assets Q1]
Are caculated fields
To clean up the universe of stocks, they must:
- have a ticker
- market cap
- 13,26,52 week price change
- not be over the counter
- not an ADR stock
- not be a reit stock.
- not be a closed end fund (TBA)
universe <- universe[complete.cases(universe$Ticker),]
universe <- universe[complete.cases(universe$`Market Cap Q1`),]
universe <- universe[complete.cases(universe$`Price Change 13 week`),]
universe <- universe[complete.cases(universe$`Price Change 26 week`),]
universe <- universe[complete.cases(universe$`Price Change 52 week`),]
#exchanges
condition <- c("N - New York", "A - American", "M - Nasdaq")
universe <- filter(universe, Exchange %in% condition)
universe <- filter(universe,`ADR/ADS Stock` == 'FALSE')
universe <- filter(universe,!grepl('REITs',Industry))
count2 <- nrow(universe)[1]
Market Cap Variables¶
Screens need some market cap and momentom constants
- Minimum deflated Market Cap all cap universe
- Mediam 13 and 26 Momentom for bear trap
- Average Market cap for large cap universe
Calculating deflator, mins, means and medians.
options("getSymbols.warning4.0"=FALSE)
#find inflation Market Cap 150 @ 1995
getSymbols("CPIAUCSL", src = "FRED", auto.assign=getOption('getSymbols.auto.assign',TRUE))
deflator  <-
  last(Cl(to.yearly(CPIAUCSL)))[[1]] / Cl(to.yearly(CPIAUCSL))['1995'][[1]]
mincap <- 150 * deflator
median13w <- median(universe$`Price Change 13 week`)
median26w <- median(universe$`Price Change 26 week`)
avgmcap <- mean(universe$`Market Cap Q1`,  na.rm = TRUE)
avgshares <- mean(universe$`Shares Average Q1`,  na.rm = TRUE)
avgcashflowshares <- mean(universe$`Cash flow/share 12m`,  na.rm = TRUE)
avgsales15 <- mean(universe$`Sales 12m`,  na.rm = TRUE) * 1.5
smallstocks <- filter(universe, `Market Cap Q1` <= avgmcap & `Market Cap Q1` >= mincap)
allstocks <- filter(universe, `Market Cap Q1` >= mincap)
largestocks <- filter(universe, `Market Cap Q1` >= avgmcap)
marketleaders <- allstocks %>% filter(Sector != "59  - Utilities") %>% 
  filter(`Shares Average Q1` > avgshares) %>%
  filter(`Cash flow/share 12m` > avgcashflowshares) %>%
  filter(`Sales 12m` > avgsales15)
Function to add rankings
calcvc2 <- function(x) {
  #Calculate VC2
  #subtract ntile from 101 to reverse (correct) Order. So Small is big
  x$`Price/Book.Rank` <-
    100 - round(percent_rank(x$`Price/Book`) * 100, 1)
  x$PE.Rank <- 100 - round(percent_rank(x$PE) * 100, 1)
  x$`Price/Sales.Rank` <-
    100 - round(percent_rank(x$`Price/Sales`) * 100, 1)
  x$`Enterprise Value/EBITDA.Rank` <-
    100 - round(percent_rank(x$`Enterprise Value/EBITDA`) * 100, 1)
  x$`Price/CFPS.Rank` <-
    100 - round(percent_rank(x$`Price/CFPS`) * 100, 1)
  x$`Shareholder Yield.Rank` <-
    round(percent_rank(x$`Shareholder Yield`) * 100, 1)
  
  #Stocks with no rank get 50
  x$`Price/Book.Rank`[is.na(x$`Price/Book.Rank`)] <- 50
  x$PE.Rank[is.na(x$PE.Rank)] <- 50
  x$`Price/Sales.Rank`[is.na(x$`Price/Sales.Rank`)] <- 50
  x$`Enterprise Value/EBITDA.Rank`[is.na(x$`Enterprise Value/EBITDA.Rank`)] <-
    50
  x$`Price/CFPS.Rank`[is.na(x$`Price/CFPS.Rank`)] <- 50
  x$`Shareholder Yield.Rank`[is.na(x$`Shareholder Yield.Rank`)] <- 50
  #Sum the Ranks
  x$SumRank <-
    x$`Price/Book.Rank` + x$PE.Rank + x$`Price/Sales.Rank` + x$`Enterprise Value/EBITDA.Rank` + x$`Price/CFPS.Rank` + x$`Shareholder Yield.Rank`
  x$VC2 <- round(percent_rank(x$SumRank) * 100, 1)
  return(x)
}
allstocks <- calcvc2(allstocks)
largestocks <- calcvc2(largestocks)
marketleaders <- calcvc2(marketleaders)
TrendingValue <- allstocks %>%  filter(VC2 >= 90) %>% arrange(desc(`Price Change 26 week`)) %>% slice_head(n = 25) %>% select(Ticker, `Company name`,Sector,Industry)
TrendingValue %>%
  kable("html") %>%
  as.character() %>%
  display_html()
Cheap Stocks on the mend¶
cheapmend <-
  allstocks %>%  filter(VC2 >= 70) %>% filter(`Price Change 13 week` > median13w) %>% filter(`Price Change 26 week` >
                                        median26w) %>% arrange(desc(`Price Change 26 week`)) %>%             
                                        slice_head(n = 25) %>% select(Ticker, `Company name`)
cheapmend %>%
  kable("html") %>%
  as.character() %>%
  display_html()
mlsy <- marketleaders %>% filter(`Price Change 13 week` > median13w) %>% 
  filter(`Price Change 26 week` >median26w) %>% 
  arrange(desc(`Shareholder Yield`)) %>%
  slice_head(n = 25) %>% 
  select(Ticker, `Company name`,Sector,Industry)
mlsy %>%
  kable("html") %>%
  as.character() %>%
  display_html()
mlvc2 <- marketleaders %>% filter(`Price Change 13 week` > median13w) %>% 
  filter(`Price Change 26 week` >median26w) %>% 
  arrange(desc(VC2)) %>%
  slice_head(n = 25) %>% 
  select(Ticker, `Company name`,Sector,Industry)
mlvc2 %>%
  kable("html") %>%
  as.character() %>%
  display_html()
unique(arrange(rbind(mlvc2,mlsy),Ticker)) %>%
  kable("html") %>%
  as.character() %>%
  display_html()
utilities <- allstocks %>%
  filter(Sector == "59  - Utilities") %>%
  arrange(desc(VC2)) %>%
  slice_head(n =25) %>% 
  select(Ticker, `Company name`,Sector,Industry)
  
noncyc <- filter(allstocks,Sector == "54  - Consumer Non-Cyclicals") %>%
  arrange(desc(`Shareholder Yield`)) %>%
  slice_head(n = 25) %>% 
  select(Ticker, `Company name`,Sector,Industry)
  
arrange(rbind(utilities,noncyc),Ticker)   %>%
  kable("html") %>%
  as.character() %>%
  display_html()
constap <- rbind(slice_head(noncyc,n=3),slice_head(utilities,n=3))
My 24 stock port¶
n <-1
c <-1
while(c < 12)  {
  mlC <- unique(rbind(slice_head(mlvc2,n=n),slice_head(mlsy,n=n)))
  n <- n + 1
  c = nrow(mlC)
}
n <-1
c <-1
rportTemp <- rbind(slice_head(mlC, n=6),constap)
while(c < 25)  {
rport <- unique(rbind(rportTemp,slice_head(TrendingValue,n=n)))
  n <- n + 1
  c = nrow(rport)
}
rport %>%
  kable("html") %>%
  as.character() %>%
  display_html()
Comments
Comments powered by Disqus