library(tidyverse)
library(lubridate)
library(scales)
library(ggrepel)
library(tidyquant)
library(jsonlite)
theme_set(theme_minimal())
invisible(Sys.setlocale("LC_TIME", "en_US.UTF-8"))
library(knitr)
library(kableExtra)
library(familyoffice)
stocks <- fo_exchange("six.stocks")
stocks |> saveRDS("data/sixetfs/stocks.RDS")
stocks <- readRDS("data/sixetfs/stocks.RDS")
profiles <- tibble()
i <- 0
while(T) {
cat(i, "\n")
url <- paste0("https://financialmodelingprep.com/stable/profile-bulk?part=", i, "&apikey=", read_lines("data/key.txt"))
temp <- read_csv(url)
if (is.null(temp)) break
if (nrow(temp) == 0) break
if (i > 10) break
profiles <- bind_rows(profiles, temp)
i <- i + 1
}
profiles |> saveRDS("data/sixstocks/profiles.RDS")
profiles <- readRDS("data/sixstocks/profiles.RDS")
swissstocks <- profiles |>
filter(exchange == "SIX",
country == "CH",
currency == "CHF",
!isEtf,
isActivelyTrading,
!isAdr,
!isFund) |>
group_by(companyName) |>
slice_min(price, n = 1) |>
ungroup()
set.seed(123)
swissstocks |>
ggplot(aes(x = fullTimeEmployees+1, y = marketCap/10^6, color = sector, size = marketCap)) +
geom_point(alpha = 0.8) +
geom_point(color = "grey40", shape = 21) +
geom_text_repel(aes(label = ifelse(fullTimeEmployees > 5000, companyName, NA_character_)), size = 2, color = "grey30") +
geom_text_repel(aes(label = ifelse(fullTimeEmployees <= 5000, companyName, NA_character_)), size = 2, color = "grey30", max.iter = 200, max.overlaps = 3) +
scale_x_log10(labels = scales::number_format(), breaks = c(1, 10, 100, 1000, 10000, 100000)) +
scale_y_log10(labels = scales::number_format(), breaks = c(1, 10, 100, 1000, 10000, 100000)) +
labs(title = "Swiss Stock Exchange listed Companies",
subtitle = "Market cap vs. number of employees",
x = "Number of employees",
y = "Market cap (in million CHF)",
color = "Sector") +
theme(legend.position = "none")

swissstocks |>
arrange(sector, desc(marketCap)) |>
group_by(sector) |>
summarise(
marketCapAll = (sum(marketCap)/10^9) |> round(digits = 1) |> paste0(" Mrd."),
top3 = paste0(
head(paste0(companyName, " (", round(marketCap / 1e9, 1), ")"), 3),
collapse = ", "
)
) |>
knitr::kable() |>
kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
sector
|
marketCapAll
|
top3
|
Basic Materials
|
152.4 Mrd.
|
Holcim Ltd (51.7), Sika AG (37.4), Givaudan SA (36.8)
|
Communication Services
|
29.4 Mrd.
|
Swisscom AG (26.6), TX Group AG (2), APG SGA SA (0.6)
|
Consumer Cyclical
|
128.9 Mrd.
|
Compagnie Financière Richemont SA (103.7), The Swatch Group AG (8.7),
SIG Group AG (7.6)
|
Consumer Defensive
|
263.1 Mrd.
|
Nestlé S.A. (199.2), Galderma Group N (26.3), Chocoladefabriken Lindt
& Sprüngli AG (24)
|
Energy
|
0.1 Mrd.
|
Meyer Burger Technology AG (0.1)
|
Financial Services
|
364.7 Mrd.
|
UBS Group AG (103), Zurich Insurance Group AG (78.5), Swiss Re AG (40.5)
|
Healthcare
|
588.6 Mrd.
|
Roche Holding AG (230.8), Novartis AG (188.8), Alcon Inc. (41.3)
|
Industrials
|
266.4 Mrd.
|
ABB Ltd (92.1), Schindler Holding AG (28.1), Kuehne + Nagel
International AG (24.6)
|
Real Estate
|
27.4 Mrd.
|
Swiss Prime Site AG (8), PSP Swiss Property AG (6.2), Allreal Holding AG
(2.8)
|
Technology
|
31.8 Mrd.
|
Logitech International S.A. (13.7), Temenos AG (5.4), ALSO Holding AG
(3.1)
|
Utilities
|
8.3 Mrd.
|
BKW AG (8.2), Edisun Power Europe AG (0.1)
|
# total number of employees
swissstocks |>
group_by(sector) |>
summarise(employees = sum(fullTimeEmployees)) |>
filter(employees > 0) |>
ggplot(aes(x = reorder(sector, employees), y = employees, fill = sector)) +
geom_col() +
geom_text(aes(label = employees |> number()), vjust = -0.1) +
scale_y_continuous(labels = scales::number_format()) +
labs(title = "Total number of employees by sector (worldwide of course)",
subtitle = "Swiss Stock Exchange listed Companies",
x = "Sector",
y = "Number of employees",
fill = "Sector") +
theme(legend.position = "none",
# turn x label 45 degrees
axis.text.x = element_text(angle = 45, hjust = 1))
