BitEdge

Build A Betting Bot With The Cloudbet API

 

Cloudbet (review, American bettors are geo-blocked) is not only one of the best websites for sports betting, it also provides an excellent interface for programmatic betting. The Cloudbet API is so simple to use and so well documented we believe even people inexperienced with coding are capable of using it to build a betting bot. In this post we will show how you can use this API to retrieve odds for upcoming events and to place bets with the Python programming language.

Finding your API key and getting test funds

Your Cloudbet API key is a token unique to your account which is used to authenticate your API requests. You can retrieve your API key by navigating to Preferences > API on the Cloudbet website. Never share this API key with anyone since it could be used to steal funds from your Cloudbet account.

While developing your betting application, it can be useful to experiment with test funds so you don’t need to be spending real crypto. To get test funds you will need to contact Cloudbet support which can be done by clicking your profile icon in the top-right corner of Cloudbet’s site and selecting “Live chat”. Tell support you would like some test funds to test their API and they will credit your account with 1000 “play Euros”.

Cloudbet API documentation

The Cloudbet API is extremely well documented at https://www.cloudbet.com/api/. On this page you will find the endpoints supported by the API. Clicking on any of these endpoints will reveal the parameters that must be supplied when making requests to the endpoint and what to expect in the response. Note that there are more endpoints documented at the links under the “Additional Resources” heading.

To make a request to any of these endpoints you need to prefix it with https://sports-api.cloudbet.com/pub. For example, to get fixtures using the /v2/odds/fixtures endpoint you would make a request to https://sports-api.cloudbet.com/pub/v2/odds/fixtures.

Installing Python

The Python programming language makes it a breeze to interact with the Cloudbet API. To use Python you will need:

  1. Python 3 installed on your machine. If you are on Windows you can download it here. If you are on Linux or macOS you likely have it installed already but if you don’t it can be installed with your package manager (we recommend homebrew for macOS).
  2. The requests Python library. This can be installed with:
python3 -m pip install --user requests

Listing events

Let’s suppose we wish to try a betting strategy where we bet on any soccer team with odds over 10. The first thing we need to do is get a list of events we can bet on. We can use the /v2/odds/fixtures endpoint to find the events. The Cloudbet API documentation reveals that requests to this endpoint need to provide:

  • sport: A sport key that can be found with the /v2/odds/sports endpoint. We will set this to soccer.
  • date: The date of the events formatted as yyyy-mm-dd. We will just supply the current date.
  • limit: This limits the number of events that are returned. We will set it to 50 to make our script run a bit faster but you can leave off this parameter to get all events for the specified date.

The code needed to perform the request in Python is:

# import the libraries we will need
from datetime import datetime
from pprint import pprint
import uuid
import requests

# create a requests session with the authentication header
session = requests.Session()
session.headers["X-API-Key"] = YOUR_API_KEY

# get today's date formatted as yyyy-mm-dd
date = datetime.utcnow().strftime("%Y-%m-%d")
# perform the request
url = "https://sports-api.cloudbet.com/pub/v2/odds/fixtures"
response = session.get(url, params={"sport": "soccer", "date": date, "limit": "50"})
# extract and print the JSON response
response_data = response.json()
pprint(response_data)

To run this code:

  1. Copy and paste it into a file called cloudbet_api_example.py
  2. Change YOUR_API_KEY to be the API key for your Cloudbet account
  3. In a terminal, run:
python3 cloudbet_api_example.py

You should see something like:

$ python3 cloudbet_api_example.py
{'competitions': [{'category': {'key': 'brazil', 'name': 'Brazil'},
                   'events': [{'away': {'abbreviation': 'INT',
                                        'key': 'c24fe-internacional-rs',
                                        'name': 'SC Internacional RS',
                                        'nationality': 'BRA',
                                        'researchId': ''},
                               'cutoffTime': '2021-11-25T00:30:00Z',
                               'home': {'abbreviation': 'FLU',
                                        'key': 'c24f2-fluminense-rj',
                                        'name': 'Fluminense FC RJ',
                                        'nationality': 'BRA',
                                        'researchId': ''},
                               'id': 9900369,
                               'key': 'c24f2-fluminense-rj-v-c24fe-internacional-rs',
                               'name': 'Fluminense FC RJ V SC Internacional RS',
                               'status': 'TRADING_LIVE'},
                              {'away': {'abbreviation': 'CAP',
                                        'key': 'c24d2-atletico-paranaense',
                                        'name': 'CA Paranaense PR',
                                        'nationality': 'BRA',
                                        'researchId': ''},
...

This response contains a lot of data that we aren’t interested in so it is helpful to construct a new list of events with only the fields we care about. To do this we replace the last line of our script (pprint(response_data)) with the following:

events = []
for competition in response_data["competitions"]:
    competition_name = competition["category"]["name"] + " - " + competition["name"]
    for event in competition["events"]:
        events.append({
            "id": event["id"],
            "name": event["name"],
            "competition": competition_name,
        })
pprint(events)

Now if we run the script again the output is much easier to read:

$ python3 cloudbet_api_example.py
[{'competition': 'Brazil - Brasileiro Serie A',
  'id': 9900369,
  'name': 'Fluminense FC RJ V SC Internacional RS'},
 {'competition': 'Brazil - Brasileiro Serie A',
  'id': 9794691,
  'name': 'Sao Paulo FC SP V CA Paranaense PR'},
 {'competition': 'USA - Major League Soccer',
  'id': 10061529,
  'name': 'Colorado Rapids V Portland Timbers'},
 {'competition': 'Mexico - Primera Division, Apertura',
  'id': 10074678,
  'name': 'Pumas UNAM V CF America'},
...

Retrieving odds

The next step is to get the odds for the events. We can do this with the /v2/odds/events/{id} endpoint. The documentation reveals the only required parameter is the event id which goes in the url, however we can reduce the amount of data we get back by using the markets parameter to request only the “match odds” markets. The data we get back is highly nested so we need to dig through it to find the selections we are interested in. We store all the selections in a list and print them out:

selections = []
for event in events:
    url = f"https://sports-api.cloudbet.com/pub/v2/odds/events/{event['id']}"
    response = session.get(url, params={"markets": "soccer.match_odds"})
    response_data = response.json()
    event_selections = (
        response_data
        .get("markets", {})
        .get("soccer.match_odds", {})
        .get("submarkets", {})
        .get("period=ft", {})
        .get("selections", [])
    )
    for event_selection in event_selections:
        selections.append({
            "event_id": event["id"],
            "event": event["name"],
            "competition": event["competition"],
            "home": response_data["home"]["name"],
            "away": response_data["away"]["name"],
            "outcome": event_selection["outcome"],
            "price": event_selection["price"],
            "status": event_selection["status"],
        })
pprint(selections)

Replacing the last pprint line in cloudbet_api_example.py with the code above and running the script confirms we are getting the data we need:

$ python3 cloudbet_api_example.py
[{'competition': 'Brazil - Brasileiro Serie A',
  'event': 'Fluminense FC RJ V SC Internacional RS',
  'event_id': 9900369,
  'home': 'Fluminense FC RJ',
  'away': 'SC Internacional RS',
  'outcome': 'home',
  'price': 1.483,
  'status': 'SELECTION_ENABLED'},
 {'competition': 'Brazil - Brasileiro Serie A',
  'event': 'Fluminense FC RJ V SC Internacional RS',
  'event_id': 9900369,
  'home': 'Fluminense FC RJ',
  'away': 'SC Internacional RS',
  'outcome': 'draw',
  'price': 3.85,
  'status': 'SELECTION_ENABLED'},
 {'competition': 'Brazil - Brasileiro Serie A',
  'event': 'Fluminense FC RJ V SC Internacional RS',
  'event_id': 9900369,
  'home': 'Fluminense FC RJ',
  'away': 'SC Internacional RS',
  'outcome': 'away',
  'price': 8.17,
  'status': 'SELECTION_ENABLED'},
...

Placing bets

Our betting strategy is to bet on any team with odds over 10. The next block of code will filter out selections with odds less than this, as well as selections for the draw outcome and selections that cannot be bet on.

long_odds_selections = [
    s for s in selections
    if s["outcome"] != "draw" and s["price"] > 10 and s["status"] == "SELECTION_ENABLED"
]
pprint(long_odds_selections)

This should produce a list of the selections we wish to bet on:

$ python3 cloudbet_api_example.py
[{'competition': "International - FIFA Women's WC Qualifiers (UEFA)",
  'event': 'Bosnia & Herzegovina V Denmark',
  'event_id': 10011950,
  'home': 'Bosnia & Herzegovina',
  'away': 'Denmark',
  'outcome': 'home',
  'price': 24.96,
  'status': 'SELECTION_ENABLED'},
 {'competition': "International - FIFA Women's WC Qualifiers (UEFA)",
  'event': 'North Macedonia V Northern Ireland',
  'event_id': 9552743,
  'home': 'North Macedonia',
  'away': 'Northern Ireland',
  'outcome': 'home',
  'price': 16.77,
  'status': 'SELECTION_ENABLED'},
 {'competition': 'Uruguay - Segunda Division',
  'event': 'Central Espanol FC V Rampla Juniors',
  'event_id': 10069877,
  'home': 'Central Espanol FC',
  'away': 'Rampla Juniors',
  'outcome': 'away',
  'price': 72.942,
  'status': 'SELECTION_ENABLED'},
...

To place the bets we use the /v3/bets/place endpoint which requires the following parameters:

  • eventId: The id of the event we wish to bet on.
  • marketUrl: A string representing the market and side we wish to be on. In our case it will be soccer.match_odds/home or soccer.match_odds/away.
  • price: The minimum price we are willing to accept for the bet. If this is higher than the selection’s current price then the bet will be rejected.
  • currency: This is a currency code like BTC or PLAY_EUR that can be found using the /v1/account/currencies endpoint.
  • stake: How much we wish to bet.
  • referenceId: A randomly generated id that can be used to ensure an application doesn’t mistakenly place the same bet multiple times. It can be generated with the uuid module.

Note that all parameters must be provided as strings. Our code to place the bets looks like:

for selection in long_odds_selections:
    request_data = {
        "eventId": str(selection["event_id"]),
        "marketUrl": "soccer.match_odds/" + selection["outcome"],
        "currency": "PLAY_EUR",
        "price": str(selection["price"]),
        "stake": "0.5",
        "referenceId": str(uuid.uuid4()),
    }
    url = "https://sports-api.cloudbet.com/pub/v3/bets/place"
    response_data = session.post(url, json=request_data).json()
    print(
        "Bet on {team} @ {price} in {competition} - {event}: {bet_status}".format(
            **selection,
            team=selection[selection["outcome"]],
            bet_status=response_data["status"],
        )
    )

When we run our script we see confirmation that our bets are being accepted:

$ python3 cloudbet_api_example.py
Bet on Bosnia & Herzegovina @ 24.96 in International - FIFA Women's WC Qualifiers (UEFA) - Bosnia & Herzegovina V Denmark: ACCEPTED
Bet on North Macedonia @ 16.77 in International - FIFA Women's WC Qualifiers (UEFA) - North Macedonia V Northern Ireland: ACCEPTED
Bet on Rampla Juniors @ 72.942 in Uruguay - Segunda Division - Central Espanol FC V Rampla Juniors: ACCEPTED
...

If we log into the Cloudbet website we can see our bets listed under Open Bets:

Checking bet results

We can also use the Cloudbet API to check the status of our bets. We create a new script named cloudbet_api_check_bets.py with the following code:

import requests

session = requests.Session()
session.headers["X-API-Key"] = YOUR_API_KEY

url = "https://sports-api.cloudbet.com/pub/v3/bets/history"
response_data = session.get(url).json()
print(f"{'EVENT':36} {'MARKET':23} {'STAKE':6} {'PRICE':7} {'STATUS':9} {'PROFIT'}")
for bet in response_data["bets"]:
    print(
        "{eventName:36} {marketUrl:23} {stake:6} {price:7} {status:9} {returnAmount}"
        .format_map(bet)
    )

When we run this script we get a table displaying our bets:

$ python3 cloudbet_api_check_bets.py

EVENT                                MARKET                  STAKE  PRICE   STATUS    PROFIT
Central Espanol FC V Rampla Juniors  soccer.match_odds/away  0.5    72.942  ACCEPTED  0
North Macedonia V Northern Ireland   soccer.match_odds/home  0.5    16.77   ACCEPTED  0
Bosnia & Herzegovina V Denmark       soccer.match_odds/home  0.5    24.96   ACCEPTED  0

Building your own bot

The complete code for the example above can be downloaded here. This example uses a very naive betting strategy which is unlikely to be profitable but it demonstrates all the API calls needed to build a more sophisticated betting bot with a more intelligent strategy.

We demonstrated how to use the betting history endpoint to retrieve the status of our bets. Since this endpoint reveals the results of previous bets, it could also be used to build a betting bot that learns and evolves its strategy over time. We encourage you to try building your own bot – with a bit of creativity you may be able to come up with a winning formula to beat the market. Let us know how you go!



Source link

Leave a Comment

Your email address will not be published. Required fields are marked *