(Test) WOW Ports that I am following
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