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.
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:
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)