Заметки по betfair.com

Общие положения

API-NG включает в себя три API:

  1. API управления счетом - Betting API.
  2. API управления ставками - Accounts API.
  3. API для партнеров и вендоров - Vendor API.

Можно поэкспериментировать с онлайн визуализаторами следующих api:

  1. API управления счетом - Betting API.
  2. API управления ставками - Accounts API.
  3. API Heartbeat - Heartbeat API.

Структура проекта

Основное:

  1. Созданные SSL сертификаты должны лежать в подкаталоге "certs"

Авторизация на сайте Betfair

Для ручной интерактивной авторизации у нас должны быть:

  1. Наш логин (в коде будет, как login)
  2. Наш пароль (в коде будет, как password)

Для использования API у каждого приложения должно быть два ключа, по которым идентифицируется приложение. Один "live App Key", другой "delayed App Key". В каждом HHTP запросе в заголовке мы должны передавать один ключ. Вот так:

X-Application: APP_KEY_ASSIGNED

Создать необходимые ключи можно следуя инструкции.

Для автономной авторизации у нас должны быть:

  1. Наш логин (в коде будет, как LOGIN)
  2. Наш пароль (в коде будет, как PASSWORD)
  3. Ключ-идентификатор нашего приложения (в коде будет, как APP_KEY_LIVE)
  4. Созданные SSL сертификаты, которые должны лежать в подкаталоге "certs"
Простой пример авторизации
              
          # -*- coding: utf-8 -*-
          import requests
          import json
          
          APP_KEY_LIVE = ""
          LOGIN = ""
          PASSWORD = ""
          
          def login(username, password):
            # returns session token or -1 if fails
            # возвращает идентификатор сессии или при неудаче -1
          
            login_url = 'https://identitysso.betfair.com/api/certlogin'
            mydata = 'username=%s&password=%s' % (username, password)
            cert_files = ('certs/client-2048.crt', 'certs/client-2048.key')
            headers = {
            'X-Application': APP_KEY_LIVE,
            'Content-Type': 'application/x-www-form-urlencoded'
          }
          
            resp = requests.post(login_url, data=mydata, cert=cert_files, headers=headers)
            resp_json = resp.json()
            if resp_json['loginStatus'] == 'SUCCESS':
              return resp_json['sessionToken']
            else:
              return -1
          
          SESSION_TOKEN = login(LOGIN, PASSWORD)
          print(SESSION_TOKEN)
          
          

Дополнительная информация по теме авторизации

Пример функции выхода:
              
          # -*- coding: utf-8 -*-
          def logout():
              #logout from betfair api-ng. returns string.
              logout_url = 'https://identitysso.betfair.com/api/logout'
              headers = {
              'Accept': 'application/json',
              'X-Application': APP_KEY_LIVE,
              'X-Authentication': SESSION_TOKEN
          }
              resp = requests.post(logout_url, headers=headers)
              resp_json = resp.json()
              if resp_json['status'] == 'SUCCESS':
                  return "SUCCESS LOGOUT"
              else:
                  raise Exception(str(resp))
          
          

Дополнительная информация по теме выхода.

В итоге получилась такая небольшая библиотека.

          
          # -*- coding: utf-8 -*-
          import requests
          import json
          import urllib
          
          class APINGLib(object):
              APP_KEY_LIVE = ""
          
              def __init__(self, login, password):
          
                  self.LOGIN = login
                  self.PASSWORD = password
                  self.SESSION_TOKEN = self.login()
          
              def login(self):
                  # returns session token or -1 if fails
                  # возвращает идентификатор сессии или при неудаче -1
          
                  login_url = 'https://identitysso.betfair.com/api/certlogin'
                  mydata = 'username=%s&password=%s' % (self.LOGIN, self.PASSWORD)
                  cert_files = ('certs/client-2048.crt', 'certs/client-2048.key')
                  headers = {
                      'X-Application': self.APP_KEY_LIVE,
                      'Content-Type': 'application/x-www-form-urlencoded'
                  }
          
                  resp = requests.post(login_url, data=mydata, cert=cert_files, headers=headers)
                  resp_json = resp.json()
                  if resp_json['loginStatus'] == 'SUCCESS':
                      return resp_json['sessionToken']
                  else:
                      return -1
          
              def logout(self):
                  # logout from betfair api-ng. returns string.
                  logout_url = 'https://identitysso.betfair.com/api/logout'
                  headers = {
                      "Accept": "application/json",
                      "X-Application": self.APP_KEY_LIVE,
                      "X-Authentication": self.SESSION_TOKEN
                  }
                  resp = requests.post(logout_url, headers=headers)
                  resp_json = resp.json()
                  if resp_json['status'] == 'SUCCESS':
                      return "SUCCESS LOGOUT"
                  else:
                      raise Exception(str(resp))
          
              def send_http_request(self, request):
                  url = "https://api.betfair.com/exchange/betting/json-rpc/v1 "
                  headers = {
                      'Accept': 'application/json',
                      'Content-Type': 'application/json',
                      'X-Application': self.APP_KEY_LIVE,
                      'X-Authentication': self.SESSION_TOKEN
                  }
                  if type(request) == type(dict()):
                      request = json.dumps(request) # convert dict to json format
                  request1 = urllib.request.Request(url, request.encode('utf-8'), headers=headers)
                  resp = urllib.request.urlopen(request1)
                  resp_json = json.loads(resp.read().decode('utf-8'))['result']
                  return resp_json
          
          

Теперь с помощью нее можно уже получать доступ к актуальной информации. Выведем все события на которые можно ставить.

          
          # -*- coding: utf-8 -*-
          # file: listEventTypes.py
          import APINGLib
          
          LOGIN = ""
          PASSWORD = ""
          
          api = APINGLib.APINGLib(LOGIN, PASSWORD)
          
          dict_event_req = {
              "jsonrpc": "2.0",
              "method": "SportsAPING/v1.0/listEventTypes",
              "params": {
                  "filter": {}
              },
              "id": 1
          }
          
          eventTypesResponse = api.send_http_request(dict_event_req)
          
          for event in eventTypesResponse:
              print(event)
          
          

Результат должен быть примерно такой:

          {'marketCount': 18, 'eventType': {'id': '468328', 'name': 'Handball'}}
          {'marketCount': 9051, 'eventType': {'id': '1', 'name': 'Soccer'}}
          {'marketCount': 522, 'eventType': {'id': '2', 'name': 'Tennis'}}
          {'marketCount': 74, 'eventType': {'id': '3', 'name': 'Golf'}}
          {'marketCount': 272, 'eventType': {'id': '4', 'name': 'Cricket'}}
          {'marketCount': 12, 'eventType': {'id': '5', 'name': 'Rugby Union'}}
          {'marketCount': 60, 'eventType': {'id': '6', 'name': 'Boxing'}}
          {'marketCount': 387, 'eventType': {'id': '7', 'name': 'Horse Racing'}}
          {'marketCount': 60, 'eventType': {'id': '8', 'name': 'Motor Sport'}}
          {'marketCount': 1, 'eventType': {'id': '7524', 'name': 'Ice Hockey'}}
          {'marketCount': 8, 'eventType': {'id': '10', 'name': 'Special Bets'}}
          {'marketCount': 23, 'eventType': {'id': '11', 'name': 'Cycling'}}
          {'marketCount': 176, 'eventType': {'id': '7522', 'name': 'Basketball'}}
          {'marketCount': 57, 'eventType': {'id': '1477', 'name': 'Rugby League'}}
          {'marketCount': 187, 'eventType': {'id': '4339', 'name': 'Greyhound Racing'}}
          {'marketCount': 1, 'eventType': {'id': '3088925', 'name': 'Fishing'}}
          {'marketCount': 24, 'eventType': {'id': '2378961', 'name': 'Politics'}}
          {'marketCount': 66, 'eventType': {'id': '6231', 'name': 'Financial Bets'}}
          {'marketCount': 9, 'eventType': {'id': '998917', 'name': 'Volleyball'}}
          {'marketCount': 55, 'eventType': {'id': '998918', 'name': 'Bowls'}}
          {'marketCount': 43, 'eventType': {'id': '26420387', 'name': 'Mixed Martial Arts'}}
          {'marketCount': 181, 'eventType': {'id': '3503', 'name': 'Darts'}}
          {'marketCount': 1, 'eventType': {'id': '72382', 'name': 'Pool'}}
          {'marketCount': 60, 'eventType': {'id': '2152880', 'name': 'Gaelic Games'}}
          {'marketCount': 2, 'eventType': {'id': '300000', 'name': 'Commonwealth Games'}}
          {'marketCount': 1, 'eventType': {'id': '6422', 'name': 'Snooker'}}
          {'marketCount': 23, 'eventType': {'id': '6423', 'name': 'American Football'}}
          {'marketCount': 2, 'eventType': {'id': '315220', 'name': 'Poker'}}
          {'marketCount': 132, 'eventType': {'id': '7511', 'name': 'Baseball'}}
          

Теперь выведем все события из раздела "Special Bets". Из предыдущего запроса мы знаем, что eventTypeIds его равен 10, а всего событий должно быть marketCount, т.е. 8.

          
          # -*- coding: utf-8 -*-
          # file: listMarketCatalogue.py
          import APINGLib
          
          LOGIN = ""
          PASSWORD = ""
          
          api = APINGLib.APINGLib(LOGIN, PASSWORD)
          
          listMarket_req = {
              "jsonrpc": "2.0",
              "method": "SportsAPING/v1.0/listMarketCatalogue",
              "params": {
                  "filter": {
                      "eventTypeIds": [10]
                  },
                  "maxResults": "100"
              },
          }
          
          listMarketResponse = api.send_http_request(listMarket_req)
          
          for event in listMarketResponse:
              print(event)
          
          

У меня результат был такой:

          {'totalMatched': 165520.98557999998, 'marketName': 'Winner', 'marketId': '1.114265488'}
          {'totalMatched': 646.6966239999999, 'marketName': 'Male or Female', 'marketId': '1.114265484'}
          {'totalMatched': 280.47312, 'marketName': 'Top 3', 'marketId': '1.114283805'}
          {'totalMatched': 850.039636, 'marketName': 'Top Female', 'marketId': '1.114283806'}
          {'totalMatched': 138.226, 'marketName': 'Top Male', 'marketId': '1.114283807'}
          {'totalMatched': 343.1020639999999, 'marketName': 'Top UK Summer Temperature 2014', 'marketId': '1.114169447'}
          {'totalMatched': 80758.716424, 'marketName': 'Winner', 'marketId': '1.112244045'}
          {'totalMatched': 8279.963588, 'marketName': 'Top 3', 'marketId': '1.112243909'}
          

Типы действия ордеров (PersistenceType)

  1. LAPSE - Действие прекращается, когда рынок переходит в стадию "во время игры". (Lapse the order when the market is turned in-play).
  2. PERSIST - Продолжает существовать в стадии "во время игры". Заявка автоматически размещается во время начала события. (Persist the order to in-play. The bet will be place automatically into the in-play market at the start of the event).
  3. MARKET_ON_CLOSE - Put the order into the auction (SP) at turn-in-play.

Когда мы знаем идентификатор рынка мы можем легко получит по нему всю информацию с помощью listMarketCatalogue

          
          # -*- coding: utf-8 -*-
          # file: listMarketCatalogueAddition_example.py
          import APINGLib
          
          LOGIN = ""
          PASSWORD = ""
          
          api = APINGLib.APINGLib(LOGIN, PASSWORD)
          
          listMarket_req = {
              "jsonrpc": "2.0",
              "method": "SportsAPING/v1.0/listMarketCatalogue",
              "params": {
                  "filter": {
                      "marketIds": ["1.114549032"]
                  },
                  "maxResults": "10",
                  "marketProjection": ["COMPETITION", "EVENT", "EVENT_TYPE", "MARKET_DESCRIPTION", "RUNNER_DESCRIPTION"]
              },
              "id": 1
          }
          
          listMarketResponse = api.send_http_request(listMarket_req)
          print("Competition: " + str(listMarketResponse[0]['competition']['name']))
          print("Market Name: " + str(listMarketResponse[0]['marketName']))
          print("Event: " + str(listMarketResponse[0]['event']['name']))
          print("Event Type: " + str(listMarketResponse[0]['eventType']['name']))
          print(listMarketResponse[0]['runners'])
          
          

Создание SSL сертификата

Для взаимодействия нашей программы на питоне и сайта нам нужно создать сертификат SSL и ключи загрузить в наш аккаунт на betfair.

  1. Заходим на страницу.
  2. Из таблицы выбираем для Вашей операционки и компьютера вариант загрузки программы. Я для своего win64 выбрал: Win64 OpenSSL v1.0.1i. Скачиваем. Запускаем установку. Для правильной установки может потребоваться "Visual C++ 2008 redistributable". Его можно скачать со страницы
  3. После правильной установки у Вас должна быть папка с пакетом программ. При установке по умолчанию у меня это папка C:\OpenSSL-Win64.
  4. Открываем в текстовом редакторе файл из папки c:\openSSL-Win64\bin с именем openssl.cfg
  5. И вставляем в него следующий текст:
              
              [ ssl_client ]
              basicConstraints = CA:FALSE
              nsCertType = client
              keyUsage = digitalSignature, keyEncipherment
              extendedKeyUsage = clientAuth
              
              
  6. Сохраняем файл. Выходим. Переименовываем файл в openssl.cnf
  7. Открываем C:\Windows\system32\cmd.exe. Там набираем c:\openssl-Win64\bin\openssl. Должна открыться программа OpenSSL приглашение к вводу которой выглядит, как 'OpenSSL>'
  8. Вводим команду genrsa -out client-2048.key 2048
  9. Затем команду req -new -config c:\openSSL-Win64\bin\openssl.cnf -key client-2048.key -out client-2048.csr
  10. Запуститься процесс создания Вашего сертификата. Отвечайте на вопросы по смыслу. Вот пример:
              Country Name (2 letter code) [AU]:GB
              State or Province Name (full name) [Some-State]:London
              Locality Name (eg, city) []:London
              Organization Name (eg, company) [Internet Widgits Pty Ltd]:yourcompany.com
              Organizational Unit Name (eg, section) []:Security Team
              Common Name (e.g. server FQDN or YOUR name) []:Test API-NG Certificate
              Email Address []:my.name@mydomain.com
              Please enter the following ‘extra’ attributes
              to be sent with your certificate request
              A challenge password []:
              An optional company name []:
              
  11. Теперь введите команду: x509 -req -days 365 -in client-2048.csr -signkey client-2048.key -out client-2048.crt -extfile c:\openSSL-Win64\bin\openssl.cnf -extensions ssl_client
  12. Теперь осталось загрузить ключ на betfair в Ваш аккаунт. Это можно сделать на странице

Ссылки по темам

  1. Цифровые идентификаторы видов спорта - Официально
  2. Изменение шага цены - Официально
  3. Механизм виртуальных ставок - Официально

http://forum.bdp.betfair.com/showthread.php?t=1224

http://forum.bdp.betfair.com/showthread.php?t=472