Calculando Quién está Sobrevalorado en el Mercado

Prácticamente los que deciden el valor de las cuotas en las casas de las apuestas son los mismos usuarios que gastan su dinero al momento de decidir quién ganará, empatará o perderá.

No solo en el mercado de 1X2 (Local, Empate, Visita) sino también en otros tipos de apuestas, tales como Over/Under, Handicap Asiático, etc.

Cuando digo que el valor es establecido por los apostadores quiere decir que, gracias a la fluctuación de dinero y apuestas, la cuota gana o pierde valor.

Por ejemplo, los partidos del Real Madrid ante equipos modestos tienden a ser muy bajas las cuotas. Con esto en mente, existe una realidad y lo que el mercado espera sobre los equipos actuales.

¿Entonces de qué se trata todo esto?

Resuta ser que el futbol no es tan predecible del todo…cierto? Teniendo esta premisa en mente, te voy a enseñar el cómo calcular esto y también lo voy a explicar con ejemplos.

Primero, piensa qué equipos en la actualidad deberían de estar en las primeras posiciones de la tabla general (No veas las tablas, no hagas trampa!)

Seguramente en la liga española pensaste en el Barcelona, en el Real Madrid o en el Atlético de Madrid. Si nos vamos a Italia, piensas en la Juventus, en la Roma, en el Inter…Y así sucesivamente.

¿Pero cómo saber si un equipo está sobrevalorado o infravalorado en el mercado? Para ello, vamos a realizar un análisis de la temporada anterior (2018/2019) para mostrarte a lo que me refiero.

Usemos la Premier League como primer ejemplo. La información proviene de la página de football-data.co.uk

Primero, calculamos la tabla general de la temporada 2018/2019:

library(tidyverse)

# Manipulando info
df_e01819 <- df_e01819_data %>% 
    select(div:ftr, bb_mx_h, bb_mx_d, bb_mx_a) %>% 
    
    # juntar equipos
    bind_rows(
        df_e01819_data %>% 
            select(team = home_team, opp = away_team, GF = fthg, GA = ftag),
        
        df_e01819_data %>% 
            select(team = away_team, opp = home_team, GF = ftag, GA = fthg)
    )

# Agrupando y creando variables
df_e01819 <- df_e01819 %>% 
    
    # NA's
    mutate(GD = GF-GA) %>%
    drop_na(team) %>%
    # mutate_all(funs(replace_na(., 0))) %>% 
    mutate_all(list(~ replace_na(., 0))) %>% 
    
    # variables
    group_by(team) %>%
    summarize(GP = n(),
              gf = sum(GF),
              ga = sum(GA),
              gd = sum(GD),
              W = sum(GD > 0),
              D = sum(GD == 0),
              L = sum(GD < 0)
    ) %>%
    
    # ordenando
    ungroup() %>% 
    mutate(Pts = (W*3) + D) %>%
    arrange(desc(Pts), -gd)

Puedes darle scroll hacia los lados si es que no ves todo el resultado

## # A tibble: 20 x 9
##    team              GP    gf    ga    gd     W     D     L   Pts
##    <chr>          <int> <dbl> <dbl> <dbl> <int> <int> <int> <dbl>
##  1 Man City          38    95    23    72    32     2     4    98
##  2 Liverpool         38    89    22    67    30     7     1    97
##  3 Chelsea           38    63    39    24    21     9     8    72
##  4 Tottenham         38    67    39    28    23     2    13    71
##  5 Arsenal           38    73    51    22    21     7    10    70
##  6 Man United        38    65    54    11    19     9    10    66
##  7 Wolves            38    47    46     1    16     9    13    57
##  8 Everton           38    54    46     8    15     9    14    54
##  9 Leicester         38    51    48     3    15     7    16    52
## 10 West Ham          38    52    55    -3    15     7    16    52
## 11 Watford           38    52    59    -7    14     8    16    50
## 12 Crystal Palace    38    51    53    -2    14     7    17    49
## 13 Newcastle         38    42    48    -6    12     9    17    45
## 14 Bournemouth       38    56    70   -14    13     6    19    45
## 15 Burnley           38    45    68   -23    11     7    20    40
## 16 Southampton       38    45    65   -20     9    12    17    39
## 17 Brighton          38    35    60   -25     9     9    20    36
## 18 Cardiff           38    34    69   -35    10     4    24    34
## 19 Fulham            38    34    81   -47     7     5    26    26
## 20 Huddersfield      38    22    76   -54     3     7    28    16

Una de las temporadas más interesantes al ver cómo dos equipos jugaron casi a la perfección para la obtención del título.

Pero bueno…Volviendo al tema, ¿realmente todos los equipos merecieron tener esa cantidad de puntos?

No necesariamente!

Resulta ser que teniendo las expectativas del mercado (las cuotas impuestas) podemos calcular la puntuación “real” de cada equipo.

Me explico…

Las expectativas del mercado (o de las casas de apuestas) están basadas en las cuotas ofertadas. Por ejemplo, si las probabilidades de Local, Empate y Visita son 41%, 27% y 32% respectivamente, la expectativa de puntos del mercado sería calculado de la siguiente manera:

  • Equipo Local: 3 * 0.41 + 0.27 = 1.5 puntos
  • Equipo Visitante: 3 * 0.32 + 0.27 = 1.23 puntos

Si lo sé, no existen los medios puntos, pero con este cálculo podemos saber los equipos sobrevalorados o infravalorados!

Vamos a calcularlo tomando las diferencias de puntos actuales vs puntos esperados:

## # A tibble: 20 x 4
##    team           xp_points   Pts pts_diff
##    <chr>              <dbl> <dbl>    <dbl>
##  1 Man City            92.9    98     5.13
##  2 Liverpool           84.8    97    12.2 
##  3 Chelsea             75.1    72    -3.08
##  4 Tottenham           69.6    71     1.45
##  5 Arsenal             66.5    70     3.51
##  6 Man United          68.3    66    -2.28
##  7 Wolves              51.2    57     5.79
##  8 Everton             53.1    54     0.88
##  9 Leicester           50.9    52     1.12
## 10 West Ham            45.3    52     6.7 
## 11 Watford             45.8    50     4.15
## 12 Crystal Palace      45.8    49     3.23
## 13 Newcastle           40.2    45     4.80
## 14 Bournemouth         44.0    45     1.04
## 15 Burnley             34.8    40     5.19
## 16 Southampton         43.7    39    -4.73
## 17 Brighton            38.6    36    -2.57
## 18 Cardiff             32.2    34     1.80
## 19 Fulham              36.0    26   -10.0 
## 20 Huddersfield        30.6    16   -14.6

Como puedes observar, los que están en verde son los que fueron infravalorados, mientras los que están en rojo son los sobrevalorados.

Por ejemplo, el Liverpool consiguió 97 puntos a pesar de que las casas de apuestas informaba que iban a conseguir 87 puntos!

Esto quiere decir que el Liverpool, para los apostadores en general, fue un equipo infravalorado.

La otra cara de la moneda es el Chelsea. Esto es lo que me encanta de las apuestas porque es ahí donde aprovechas las deficiencias! (Gracias Marketing)

Le agradezco al Marketing porque hoy en día todos sabemos que el Chelsea es un equipo de varios trofeos, un equipo de nombre en la mente de cualquier simpatizante de este deporte.

Por lo mismo, las casas de apuestas y los apostadores tuvieron la idea de que el Chelsea merecía un poco más puntos, pero no lo fue así.

A lo que me refiero es que el mercado da a entender que algunos equipos en particular no son del gusto mientras que otros si son de su agrado.

¿Y las otras ligas cómo se comportaron?

Te puedo mostrar con gráficas de cada liga (5 grandes ligas de Europa) de la temporada 2018/2019.

Puntos a destacar:

  • Bundesliga — Wolfsburg, Dusseldorf y Dortmund fueron infravalorados mientras que Schalke 04 fue sobrevalorado

  • La Liga — Alaves y Getafe con justa razón estuvieron infravalorados, mientras que Villarreal y Real Madrid sobrevalorados.

  • Ligue One — Increíble lo del Lille, y extremadamente increíble lo del Mónaco (Gracias de nuevo marketing por el Mónaco)

  • Premier League — Extraño ver al Liverpool en esa posición, mientras la otra cara de la moneda fueron equipos relativamente modestos.

  • Serie A — Terminó la Juventus de sorprender a las casas de apuestas, por otro lado, se esperaba más de la Fiorentina.

Quiero aclarar algo antes de terminar…No siempre es una premisa que la puntuación sea la imagen perfecta. Lo digo porque en el caso de la Fiorentina, los números (Diferencia de goles, tiros, tiros a puerta, etc) resultaban ser favorables para esta escuadra.

No obstante, algunos equipos (Como el Mónaco o el Real Madrid) son producto de la fama que tienen los equipos.

A final de cuentas, este cálculo es para tener una idea de quién está sobrevalorado o infravalorado en el mercado de las apuestas respecto a la tabla general

Por último, les dejo las gráficas de la temporada 2019/2020 con su respectivo código en R:

# Función para calcular puntos esperados ----
expected_pts_calculation_1920 <- function(data){
    
    # Primera sección ----
    xp_calc <- data %>% 
        select(div:ftr, max_h, max_d, max_a) %>% 
        
        # Calculando puntos esperados
        mutate(xp_home_pts = (3 * (1/max_h)) + (1/max_d),
               xp_away_pts = (3 * (1/max_a)) + (1/max_d)) %>% 
        
        select(home_team:ftr, xp_home_pts, xp_away_pts)
    
    # Segunda sección ----
    xp_calc <- xp_calc %>% 
        
        # Unión
        bind_rows(
            xp_calc %>% 
                select(team = home_team, opp = away_team, GF = fthg, GA = ftag,
                       xp_pts = xp_home_pts),
            
            xp_calc %>% 
                select(team = away_team, opp = home_team, GF = ftag, GA = fthg,
                       xp_pts = xp_away_pts)
            
        ) %>% 
        
        # NA's
        mutate(GD = GF-GA) %>%
        drop_na(team) %>%
        mutate_all(list(~ replace_na(., 0))) %>% 
        
        # Summary
        group_by(team) %>%
        summarize(GP = n(),
                  gd = sum(GD),
                  W = sum(GD > 0),
                  D = sum(GD == 0),
                  L = sum(GD < 0),
                  xp_points = sum(round(xp_pts, 2))
        ) %>%
        
        # Ordenar
        ungroup() %>% 
        mutate(Pts = (W*3) + D) %>%
        arrange(desc(Pts), -gd) %>% 
        
        # Calculando diferencias
        select(team, xp_points, Pts) %>% 
        mutate(pts_diff = Pts - xp_points)
    
    
    # Return
    return(xp_calc)
    
    
}

# Data ----
my_data_list_1920 <- list(info_1920$`1920/D1`,
                          info_1920$`1920/SP1`,
                          info_1920$`1920/F1`,
                          info_1920$`1920/E0`,
                          info_1920$`1920/I1`)


# Loop con función Map y ggplot para graficar
info_nested <- map(my_data_list_1920, expected_pts_calculation_1920) %>% 
    set_names("Bundesliga", "La Liga", "Ligue One", "Premier League", "Serie A") %>% 
    enframe(name = "League", value = "Data") %>% 
    
    # ggplot
    mutate(plot = 
               map2(.y = League,
                    .x = Data,
                    
                    # ggplot
                    ~ ggplot(
                        data =
                            .x,
                        aes(x = reorder(team, pts_diff), 
                            y = pts_diff)) +
                        
                        # geoms
                        geom_col(aes(fill = pts_diff < 0)) +
                        coord_flip() +
                        scale_fill_manual(guide = FALSE,
                                          values = c("#84fd7f", "#ff6666")) +
                      
                        geom_text(aes(label = sprintf(
                          "%0.2f", round(pts_diff, digits = 2)),
                                      hjust = ifelse(pts_diff >= 0, 1, -0)), 
                                  size = 3,
                                  color = "black") +
                        
                        # labs
                        labs(x = "", y = "Diferencia de puntos (Actuales - Esperados)",
                        title = "Diff de Puntos Esperados por la Casa de Apuestas",
                        subtitle = str_glue("{.y}"),
                        caption = "TiroIndirecto.com") +
                        
                        # theme
                        theme(panel.border = element_blank(),
                        panel.grid.major = element_blank(),
                        panel.grid.minor = element_blank(),
                        axis.line = element_line(colour = "white"),
                        panel.background = element_rect(fill = "white", colour = "white"),
                        axis.title.x = element_text(face = 'bold', vjust = -0.1),
                        axis.title.y = element_text(face = 'bold', vjust = 1),
                        axis.text.y = element_text(face = 'italic', size = 10),
                        axis.text.x = element_text(size = 10),
                        plot.title = element_text(size = 15, face = "bold"),
                        plot.subtitle = element_text(size = 11)
                        )
                        
                
                ))

¿Quieres hablar más del tema o tienes algun comentario? Puedes contactarme y con gusto te responderé!

Author

Samo

No hay sensación más bella que el ver la pelota rodando