Stocks - stocks

Data - Investing

stocks_catalog recense les actions suivies sur investing.com : 39 952 sociétés de 91 pays (nom, ISIN, devise, identifiant). L’historique de cours quotidien (OHLCV) est constitué pour la France (stocks_FRA, 749 valeurs), les États-Unis (stocks_USA, 62 valeurs) et 26 grandes capitalisations mondiales (stocks, ci-dessous) — Europe hors France, Suisse, Japon, Corée, Taïwan, Hong Kong — absentes des deux panels précédents. Voir aussi stocks_FRA et stocks_USA.

Le catalogue : sociétés cotées suivies, par pays

Code
cat_df <- stocks_cat |>
  mutate(pays = str_to_title(country)) |>
  count(pays, name = "n") |>
  slice_max(n, n = 26) |>
  add_flag_color("pays") |>
  mutate(slug   = to_slug(pays),
         flag   = ifelse(is.na(slug), NA_character_,
                         file.path("..", "..", "icon", "flag", "round",
                                   paste0(slug, ".png"))),
         color  = ifelse(is.na(color) | toupper(color) %in% c("#FFFFFF", "#FEFEFE"),
                         "grey65", color)) |>
  arrange(n) |> mutate(rk = row_number())

ggplot(cat_df, aes(n, rk)) +
  geom_col(aes(fill = color), width = 0.72, colour = "grey60", linewidth = 0.2,
           orientation = "y") +
  geom_text(aes(label = format(n, big.mark = " ")), hjust = -0.2, size = 2.8,
            colour = "grey30") +
  ggimage::geom_image(aes(x = -max(n) * 0.045, image = flag), size = 0.03,
                      asp = 1.1, na.rm = TRUE) +
  scale_fill_identity() +
  scale_y_continuous(breaks = cat_df$rk, labels = cat_df$pays,
                     expand = expansion(add = 0.8)) +
  scale_x_continuous(expand = expansion(mult = c(0.10, 0.10))) +
  theme_minimal() + xlab("Nombre de sociétés cotées suivies") + ylab("")

Ailleurs qu’en France et aux États-Unis, seule la fiche signalétique est disponible — pas encore l’historique de cours.

Géants de part et d’autre de l’Atlantique

Cours rebasés à 100 début 2005, échelle logarithmique. Couleur = couleur caractéristique du drapeau, icône du pays en fin de série.

Code
sel <- tribble(
  ~symbol, ~lab,         ~src,
  "AAPL",  "Apple",      "USA",  "MSFT", "Microsoft", "USA",
  "JPM",   "JPMorgan",   "USA",  "KO",   "Coca-Cola", "USA",
  "LVMH",  "LVMH",       "FRA",  "OREP", "L'Oréal",   "FRA",
  "SASY",  "Sanofi",     "FRA",  "TOTF", "TotalEnergies", "FRA")

grab <- function(df, src_) df |>
  semi_join(filter(sel, src == src_), "symbol") |> deglitch() |>
  inner_join(filter(sel, src == src_), "symbol") |>
  transmute(lab, src, Date, Close = as.numeric(Close))

px <- bind_rows(grab(stocks_USA, "USA"), grab(stocks_FRA, "FRA")) |>
  filter(Date >= as.Date("2005-01-01"), !is.na(Close), Close > 0) |>
  mutate(pays = ifelse(src == "USA", "United States", "France")) |>
  group_by(lab) |> arrange(Date) |>
  mutate(y = 100 * Close / first(Close)) |> ungroup()

pal  <- qcol(unique(px$lab))
ends <- px |> group_by(lab, pays) |> slice_max(Date, n = 1) |> ungroup() |>
  arrange(y) |> mutate(ly = log10(y))
gap <- 0.055 * diff(range(log10(px$y)))
for (i in seq_len(nrow(ends))[-1])
  if (ends$ly[i] - ends$ly[i - 1] < gap) ends$ly[i] <- ends$ly[i - 1] + gap
ends <- ends |> mutate(ly = 10^(ly - mean(ly - log10(y))),
                       slug = to_slug(pays),
                       flag = file.path("..", "..", "icon", "flag", "round",
                                        paste0(slug, ".png")))

ggplot(px, aes(Date, y, colour = lab, group = lab)) +
  geom_line(linewidth = 0.6) +
  ggimage::geom_image(data = ends, inherit.aes = FALSE,
    aes(x = max(px$Date) + 250, y = ly, image = flag), size = 0.04, asp = 1.5) +
  geom_text(data = ends, aes(x = max(px$Date) + 520, y = ly, label = lab,
                             colour = lab), hjust = 0, size = 3) +
  scale_colour_manual(values = pal, guide = "none") +
  scale_x_date(expand = expansion(mult = c(0.02, 0.24))) +
  scale_y_log10() +
  theme_minimal() + xlab("") + ylab("Cours rebasé (base 100 = janv. 2005)")

Grandes capitalisations mondiales (stocks)

Quelques poids lourds hors France / États-Unis, cours (devise locale) rebasés à 100 début 2015, échelle logarithmique.

Code
sel <- tribble(
  ~symbol, ~lab,
  "ASML", "ASML",        "NOVOb", "Novo Nordisk",
  "NESN", "Nestlé",      "SAP",   "SAP",
  "7203", "Toyota",      "2330",  "TSMC",
  "0700", "Tencent",     "005930","Samsung Elec.")

px <- stocks |>
  semi_join(sel, "symbol") |> deglitch() |>
  inner_join(sel, "symbol") |>
  filter(Date >= as.Date("2015-01-01"), !is.na(Close), Close > 0) |>
  group_by(lab) |> arrange(Date) |>
  mutate(y = 100 * as.numeric(Close) / first(as.numeric(Close))) |> ungroup()

ends <- px |> group_by(lab) |> slice_max(Date, n = 1) |> ungroup() |>
  arrange(y) |> mutate(ly = log10(y))
gap <- 0.05 * diff(range(log10(px$y)))
for (i in seq_len(nrow(ends))[-1])
  if (ends$ly[i] - ends$ly[i - 1] < gap) ends$ly[i] <- ends$ly[i - 1] + gap
ends$ly <- 10^(ends$ly - mean(ends$ly - log10(ends$y)))

ggplot(px, aes(Date, y, colour = lab, group = lab)) +
  geom_line(linewidth = 0.6) +
  geom_text(data = ends, aes(x = max(px$Date), y = ly, label = lab), hjust = 0,
            size = 3, nudge_x = as.numeric(diff(range(px$Date))) * 0.02) +
  scale_colour_manual(values = qcol(unique(px$lab)), guide = "none") +
  scale_x_date(expand = expansion(mult = c(0.02, 0.22))) +
  scale_y_log10() +
  theme_minimal() + xlab("") + ylab("Cours rebasé (base 100 = janv. 2015)")