Curso Grátis - Acessando a API da Betfair

Bem vindo ao nosso curso grátis sobre como acessar a API da Betfair e começar a extrair os seus próprios dados para apoiar a sua tomada de decisão no trade esportivo e dar os primeiros passos na análise de dados com Python.

Antes de iniciarmos, vamos nos apresentar. A Academia dos Bots tem por objetivo trazer cursos voltados para análise de dados de futebol, criação de bots para apoio na tomada de decisão nas apostas, extração de dados da internet por meio de crawlers, modelagem estatística voltada para o futebol e muito mais, tudo isto utilizando Python, R e SQL.

Ao longo deste material, aprenderemos de maneira simples e intuitiva como é o funcionamento básico da API e como realizar a primeira extração das odds de algum jogo.

Importante - Este material é parte integrante da série de vídeos que encontra-se neste link https://www.youtube.com/channel/UCvQwP2UX2b6Ov_F7eagUleQ

A estrutura da API da Betfair

Antes de mais nada, você sabe o que é uma API? De maneira resumida, uma API permite que uma aplicação A tenha acesso a recursos da aplicação B, sem ter a necessidade de conhecer todo o processo de desenvolvimento e realização de integrações complexas. Em nosso caso, nós somos a aplicação A que irá buscar os dados da aplicação B (Betfair).

Para termos uma noção do que queremos acessar, vamos olhar a origem dos dados e entender como ele está estruturado. Observando o site, logo de cara nos deparamos com uma infinidade de informações.

teste alt

Aqui, vamos fazer o nosso primeiro filtro: queremos obter as cotações (odds) de algum mercado (gols, Match Odds, cantos, etc.) de um jogo (evento) pertencente a uma competição de algum esporte. Percebeu a relação? Para acessar os dados, assim que entender esta relação nosso trabalho ficará muito mais simples.

Na Betfair, teremos uma sequência de etapas a serem realizadas e que estão diretamente relacionadas com a relação citada anteriormente. Abaixo, vamos entender este processo por meio de um diagrama:

fluxo

Legal este fluxo né!? Vamos colocar a mão na massa?!

Imports e arquivos de configuração

import datetime
import pandas as pd
import betfairlightweight
import time
username = "seu_email_betfair"
pw = "sua_senha_betfair"
app_key = "sua_appkey"

Abrindo uma conexão

#Abrindo a conexão com a lib betfairlightweight
trading = betfairlightweight.APIClient(username, pw, app_key=app_key, cert_files=('./certs/tt_app_test.crt','./certs/client-2048.key'))
trading.login()
<LoginResource>

Listando Eventos

# Definindo os filtros de Mercado
filtros_mercado = betfairlightweight.filters.market_filter(
    event_type_ids=['1'], # ID para Futebol
    competition_ids=[321319], #Competições
    market_start_time={
        'to': (datetime.datetime.utcnow() + datetime.timedelta(days=1)).strftime("%Y-%m-%dT%TZ")
    }
)

#listando os eventos a partir dos filtros pré definidos acima
eventos_futebol = trading.betting.list_events(
    filter=filtros_mercado
)

#listando as competições de futebol disponíveis
competicoes_futebol = trading.betting.list_competitions(
    filter=filtros_mercado
)

planilha_eventos_futebol = pd.DataFrame({
    'NomeEvento': [obj_evento.event.name for obj_evento in eventos_futebol],
    'IDEvento': [obj_evento.event.id for obj_evento in eventos_futebol],
    'LocalEvento': [obj_evento.event.venue for obj_evento in eventos_futebol],
    'CodPais': [obj_evento.event.country_code for obj_evento in eventos_futebol],
    'TimeZone': [obj_evento.event.time_zone for obj_evento in eventos_futebol],
    'DataAbertura': [obj_evento.event.open_date for obj_evento in eventos_futebol],
    'TotalMercados': [obj_evento.market_count for obj_evento in eventos_futebol],
    'DataLocal': [obj_evento.event.open_date.replace(tzinfo=datetime.timezone.utc).astimezone(tz=None) 
                        for obj_evento in eventos_futebol]
})

planilha_eventos_futebol
NomeEvento IDEvento LocalEvento CodPais TimeZone DataAbertura TotalMercados DataLocal
0 Remo v Goias 31065570 None BR GMT 2021-11-15 23:00:00 29 2021-11-15 20:00:00-03:00
1 Brusque FC v CRB 31065555 None BR GMT 2021-11-15 19:00:00 29 2021-11-15 16:00:00-03:00
2 Nautico PE v Sampaio Correa FC 31065571 None BR GMT 2021-11-15 21:00:00 29 2021-11-15 18:00:00-03:00
3 Vila Nova v Vasco da Gama 31065574 None BR GMT 2021-11-15 21:00:00 29 2021-11-15 18:00:00-03:00
4 Botafogo v Operario PR 31065572 None BR GMT 2021-11-15 19:00:00 29 2021-11-15 16:00:00-03:00
5 Londrina v Ponte Preta 31065573 None BR GMT 2021-11-15 19:00:00 29 2021-11-15 16:00:00-03:00

Listando Mercados

id_evento = 31065573

filtro_catalogo_mercados = betfairlightweight.filters.market_filter(event_ids=[id_evento])

catalogos_mercado = trading.betting.list_market_catalogue(
    filter=filtro_catalogo_mercados,
    max_results='100',
    sort='FIRST_TO_START',
    market_projection=['RUNNER_METADATA']
)


# Create a DataFrame for each market catalogue
planilha_mercados = pd.DataFrame({
    'NomeMercado': [market_cat_object.market_name for market_cat_object in catalogos_mercado],
    'IDMercado': [market_cat_object.market_id for market_cat_object in catalogos_mercado],
    'TotalCorrespondido': [market_cat_object.total_matched for market_cat_object in catalogos_mercado],
    'Home' : [market_cat_object.runners[0].runner_name for market_cat_object in catalogos_mercado],
    'Home_id' : [market_cat_object.runners[0].selection_id for market_cat_object in catalogos_mercado],
    'Away' : [market_cat_object.runners[1].runner_name for market_cat_object in catalogos_mercado],
    'Away_id' : [market_cat_object.runners[1].selection_id for market_cat_object in catalogos_mercado],
    'Draw' : [market_cat_object.runners[2].runner_name if len(market_cat_object.runners) > 2 else '' for market_cat_object in catalogos_mercado],
    'Draw_id' : [market_cat_object.runners[2].selection_id if len(market_cat_object.runners) > 2 else 0 for market_cat_object in catalogos_mercado]
})

planilha_mercados
NomeMercado IDMercado TotalCorrespondido Home Home_id Away Away_id Draw Draw_id
0 Match Odds 1.190674822 22022.02562 Londrina 4525642 Ponte Preta 204603 The Draw 58805
1 Total Goals Odd/Even 1.190674823 73.33000 Odd 955466 Even 955467 0
2 Londrina +1 1.190674824 0.00000 Londrina +1 7074785 Ponte Preta -1 6747717 Draw 151478
3 First Half Goals 0.5 1.190674825 1431.10828 Under 0.5 Goals 5851482 Over 0.5 Goals 5851483 0
4 Over/Under 7.5 Goals 1.190674818 0.00000 Under 7.5 Goals 1485572 Over 7.5 Goals 1485573 0
5 Over/Under 8.5 Goals 1.190674819 0.00000 Under 8.5 Goals 2407528 Over 8.5 Goals 2407529 0
6 First Half Goals 2.5 1.190674820 1172.18005 Under 2.5 Goals 47972 Over 2.5 Goals 47973 0
7 Both teams to Score? 1.190674821 3296.69681 Yes 30246 No 110503 0
8 Asian Handicap 1.190674779 6717.90796 Londrina 4525642 Ponte Preta 204603 Londrina 4525642
9 Double Chance 1.190674813 88.65597 Home or Draw 6384646 Draw or Away 6384647 Home or Away 6384648
10 Draw no Bet 1.190674814 336.43804 Londrina 4525642 Ponte Preta 204603 0
11 Ponte Preta +1 1.190674815 0.00000 Ponte Preta +1 6747718 Londrina -1 7074788 Draw 151478
12 Londrina Win to Nil 1.190674816 0.00000 Yes 30246 No 110503 0
13 Ponte Preta Win to Nil 1.190674817 0.00000 Yes 30246 No 110503 0
14 Goal Lines 1.190674744 1464.62009 Under 7044483 Over 7044482 Under 7044483
15 Over/Under 3.5 Goals 1.190674778 4918.60975 Under 3.5 Goals 1222344 Over 3.5 Goals 1222345 0
16 Half Time/Full Time 1.190674835 1364.08466 Londrina/Londrina 7074784 Londrina/Draw 7074787 Londrina/Ponte Preta 18282792
17 Over/Under 1.5 Goals 1.190674836 3010.34316 Under 1.5 Goals 1221385 Over 1.5 Goals 1221386 0
18 Londrina Clean Sheet 1.190674837 0.00000 Yes 30246 No 110503 0
19 Ponte Preta Clean Sheet 1.190674838 0.00000 Yes 30246 No 110503 0
20 Over/Under 5.5 Goals 1.190674830 109.62835 Under 5.5 Goals 1485567 Over 5.5 Goals 1485568 0
21 Correct Score 1.190674831 3653.74058 0 - 0 1 0 - 1 4 0 - 2 9
22 Over/Under 2.5 Goals 1.190674832 3823.93951 Under 2.5 Goals 47972 Over 2.5 Goals 47973 0
23 Over/Under 4.5 Goals 1.190674833 10483.40346 Under 4.5 Goals 1222347 Over 4.5 Goals 1222346 0
24 Half Time Score 1.190674834 358.14372 0 - 0 1 1 - 1 3 2 - 2 7
25 Over/Under 0.5 Goals 1.190674826 1942.51170 Under 0.5 Goals 5851482 Over 0.5 Goals 5851483 0
26 First Half Goals 1.5 1.190674827 732.56670 Under 1.5 Goals 1221385 Over 1.5 Goals 1221386 0
27 Over/Under 6.5 Goals 1.190674828 1.02662 Under 6.5 Goals 2542448 Over 6.5 Goals 2542449 0
28 Half Time 1.190674829 880.54664 Londrina 4525642 Ponte Preta 204603 The Draw 58805

Obtendo Odds

df_final = pd.DataFrame()
for i in range(0,60):
    order_filter = betfairlightweight.filters.ex_best_offers_overrides(
        best_prices_depth=3
    )

    price_filter = betfairlightweight.filters.price_projection(
        price_data=['EX_BEST_OFFERS'],
        ex_best_offers_overrides=order_filter
    )

    # Obtendo odds para o mercado
    market_books = trading.betting.list_market_book(
        market_ids=['1.190674822'],
        price_projection=price_filter
    )

    #Lista de runners
    runners = market_books[0].runners

    back = []
    for i in range(0,3):
        try:
            back.append([runner_book.ex.available_to_back[i].price
                                    if runner_book.ex.available_to_back
                                    else 1.01
                                    for runner_book
                                    in runners])
        except:
            back.append([1.01,1.01])

    lay = []
    for i in range(0,3):
        try:
            lay.append([runner_book.ex.available_to_lay[i].price
                                    if runner_book.ex.available_to_lay
                                    else 1.01
                                    for runner_book
                                    in runners])
        except:
            lay.append([[1.01,1.01,1.01]])


    df_back = pd.DataFrame(back,columns=['Casa','Visitante','Empate'])
    df_back['data'] = datetime.datetime.now()
    df_back['Jogo'] = planilha_eventos_futebol.query('IDEvento=="31065573"').NomeEvento.values[0]
    df_final = df_final.append(df_back)
    time.sleep(2)

Exportando arquivo final

df_final.to_csv('2021_11_15_serieb_londrina_vs_ponte.csv',index=False)