def query_neural_network_for_bets(X):
    """ input X has to be a np array of shape [number_of_requested_predictions, elements]
    with ts starting at t-000.
    Returns betting recommendation in the form of bet,lay,bet,lay... as booleans in the same order as X
    Return shape for 2 bets and 44 horses would be (2,88)
    """
    config = get_config()
    nn_class = getattr(sys.modules[__name__],
                       config.get('Betting', 'model_class'))
    n = nn_class()
    n.load_model()

    m = MongoManager()
    d = {}
    d['input'] = X.tolist()
    d['timestamp'] = datetime.now()
    predicted = (n.predict(X))
    d['output'] = predicted.tolist()
    log.info("Mean predicted profit across all bets: {}".format(
        np.mean(predicted)))
    if np.isnan(np.mean(predicted)):
        log.error("Tensorflow output: {}".format(predicted))
        log.error("Terminating thread")
        sys.exit()

    place_bet = predicted

    return place_bet, n.model_name
예제 #2
0
    def calculate_payoffs(self):
        self.df = self.df.fillna(0)
        config = get_config()
        fees = config.getfloat("Betting", "fees")
        stake = 1  # hard coded for training for comparison purposes

        """ Creates X and Y in assigning the payoff to Y by removing the winner column from original df """

        payoff_back = np.where(self.df['winner'].values,
                               (stake * self.df['LTP'].values - stake) * (1 - fees),  # back winner
                               -np.ones((self.df['LTP'].values.shape)) * stake)  # back loser
        payoff_back = np.where(self.df['winner'] != -1, payoff_back, 0)  # replace na with 0 payoff

        # payoff when lay: -odds when win, 1 when loss
        payoff_lay = np.where(self.df['winner'].values,
                              -(stake * self.df['LTP'].values - stake),  # lay winner
                              stake * np.ones((self.df['LTP'].values.shape)) * (1 - fees))  # lay loser
        payoff_lay = np.where(self.df['winner'] != -1, payoff_lay, 0)  # replace na with 0 payoff

        # keep the lay odds to analyse the potential risk on the lays we bet on
        winning_lay_risk = np.minimum((self.df['LTP'].values - 1) * (-1), np.zeros(payoff_lay.shape))

        self.df['back'] = payoff_back
        self.df['lay'] = payoff_lay
        self.df['lay_risk'] = winning_lay_risk
예제 #3
0
    def get_score(self):
        config = get_config()
        self.back_pnl = [0]
        self.lay_pnl = [0]
        fees = config.getfloat("Betting", "fees")
        stake = config.getfloat("Betting", "Stake")
        won = np.nan
        loser = np.nan
        LTP = self.ltp

        if won and self.back:  # back on winner
            change = (LTP * stake - stake) * (1 - fees)
            self.back_pnl.append(change)
        if won and self.lay:  # lay on winner
            change = -(LTP * stake - stake)
            self.lay_pnl.append(change)
        if loser and self.back:  # back on loser
            change = -stake  # pylint: disable=E1130
            self.back_pnl.append(change)
        if loser and self.lay:  # lay on loser
            change = stake * (1 - fees)
            self.lay_pnl.append(change)

        total_profit = sum(self.lay_pnl) + sum(self.back_pnl)
        return total_profit
 def setUp(cls):
     container = Container()
     cls.client = container.client
     config = get_config()
     prodkey = config.get("Betfair", "prod_app")
     certfile = config.get("Betfair", "cert_file")
     cls.client = Betfair(prodkey, certfile)
     cls.client.session_token = 'FakeSession'
예제 #5
0
 def do_login(self):
     config = get_config()
     username = config.get("Matchbook", "username")
     password = config.get("Matchbook", "password")
     self.api = APIClient(username, password)
     # try:
     self.api.login()
     sport_ids = self.api.reference_data.get_sports()
     self.horse_racing = list(
         filter(lambda x: x['name'] == 'Horse Racing', sport_ids))[0]['id']
예제 #6
0
def check_for_available_race_and_bet(args):
    from horse_racing.utils.tools import get_config
    config = get_config()
    min_before_start = config.get("Betting", "min_before_start_initial_bet")
    reference_price_for_initial_bet = config.get(
        "Betting", "reference_price_for_initial_bet")
    countrycodes = config.get('Betting', 'bet_countries').split()

    races_to_bet, selection_ids, market_ids, event_ids, race_start_times = \
        find_race_to_bet(min_before_start=int(min_before_start), countrycodes=countrycodes)

    wait_for_start = int(min_before_start) == 0
    if races_to_bet is not None:
        b = BetLogic()
        b.update_prices_and_place_bet(args, races_to_bet, selection_ids,
                                      market_ids, event_ids, race_start_times,
                                      wait_for_start,
                                      reference_price_for_initial_bet)
예제 #7
0
    def update_placed_orders(self, armed=False):
        config = get_config()
        m = MongoManager()

        open_orders = self.container.get_open_orders()

        use_level = config.get("Betting", "use_level").split(',')
        # minutes_to_start
        if len(open_orders) > 0:
            log.info("Currently open order: {}".format(len(open_orders)))
        for market, orders in open_orders.items():
            log.info("Updating order for market: {}".format(market))
            new_prices = self.container.get_single_market(market)
            updated_prices = []
            updated_betids = []
            for o in orders:
                selection_id = o.selection_id
                secs_to_start = m.get_secs_to_start(market)
                log.info("Seconds to start: {}".format(secs_to_start))
                if not secs_to_start or secs_to_start < \
                        -config.getint("Betting", "update_until_secs_after_start"):  # pylint: disable=E1130
                    log.info("Ignoring order\n----------------")
                    continue
                log.info("Selection ID: {}".format(selection_id))
                ltp_price = 0
                lays = [0, 0, 0]
                backs = [0, 0, 0]
                for r in new_prices[0].runners:
                    if r.selection_id != selection_id:
                        continue
                    backs = [
                        r.ex.available_to_back[x].price
                        for x in range(len(r.ex.available_to_back))
                    ]
                    lays = [
                        r.ex.available_to_lay[x].price
                        for x in range(len(r.ex.available_to_lay))
                    ]
                    ltp_price = r.last_price_traded
                log.info("New backs: {}".format(backs))
                log.info("New lays: {}".format(lays))
                min_to_start = math.floor(secs_to_start / 60)
                log.info("Minutes until start: {}".format(min_to_start))
                try:
                    level_at_minutes_to_start = int(use_level[min_to_start])
                    log.info(
                        "Using Level: {}".format(level_at_minutes_to_start))
                except IndexError:
                    log.info(
                        "use_level not set for {} minutes to start. Aborting".
                        format(min_to_start))
                    return

                level_at_minutes_to_start = min(level_at_minutes_to_start,
                                                len(backs) + 1)
                log.info(
                    "Final level to use: {}".format(level_at_minutes_to_start))
                new_price = ltp_price if level_at_minutes_to_start == 0 else backs[
                    level_at_minutes_to_start - 1]

                log.info("Updating to new price: {}".format(new_price))
                new_price = lay_saftey_check(selection_id=o.selection_id,
                                             last_price=ltp_price,
                                             current_lay_price=new_price,
                                             best_back=backs[0])
                new_price = price_adjustment(new_price)
                updated_betids.append(o.bet_id)
                updated_prices.append(new_price)
                if armed:
                    m.update_order_price(o.market_id, o.selection_id, o.bet_id,
                                         min_to_start, new_price)

            if len(updated_betids) > 0:
                log.info("Updated bet_ids: {}".format(updated_betids))
                log.info("Updated prices: {}".format(updated_prices))
                if armed:
                    self.container.replace_orders(market, updated_betids,
                                                  updated_prices)
예제 #8
0
import logging
import socket
import sys
from datetime import timedelta, datetime

import matplotlib
from scipy.stats import ttest_ind
from tqdm import tqdm

from horse_racing.utils.tools import get_config, chunk

config = get_config()
if socket.gethostname() == config.get("Servers", "prod"):
    matplotlib.use(
        'Agg')  # to work with linux, but will prevent showing plot in windows
from horse_racing.utils.mongo_manager import MongoManager
import pandas as pd
import os
import matplotlib.pyplot as plt
import numpy as np
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
from horse_racing.betfair_manager.engine import Container

log = logging.getLogger(__name__)


def propagate_race_results():
    log.info("Propagating race results")
예제 #9
0
def collect_prices(collection_name='price_scrape', single_marketid=False):
    from horse_racing.betfair_manager.engine import Container as BFContainer
    from horse_racing.matchbook_manager.engine import Container as MBContainer

    try:
        bfm = BFContainer()
    except:
        log.error("Unable to log into betfair")

    if not single_marketid:
        try:
            mbm = MBContainer()
        except:
            log.error("Unable to log into matchbook")

    if single_marketid:
        events, markets = bfm.get_single_race(single_marketid)
    else:
        events, markets = bfm.get_all_races()

    try:
        prices = bfm.update_markets(events, markets)
    except AttributeError:
        log.info("No markets to scrape")
        return

    if not single_marketid:
        try:
            mb_prices = mbm.get_races()
        except:
            mb_prices = {}
            log.error("failed to get mb prices")
    else:
        mb_prices = {}

    event_mapping = {}
    bf_selection_name_mapping = {}
    for e, ms in markets.items():
        for m in ms:
            mb_market = None
            try:
                mb_market = mb_prices[(
                    m[1].event.venue,
                    m[1].market_start_time.strftime("%Y-%m-%dT%H:%M:00.000Z"))]
            except KeyError:
                log.info("Didn't find matchbook market for {}@{}".format(
                    m[1].market_start_time, m[1].event.venue))
            event_mapping[m[0]] = e, m[1].market_start_time, m[
                1].event.country_code, mb_market
            bf_selection_name_mapping.update(
                {r.selection_id: r.runner_name
                 for r in m[1]['runners']})

    for p in tqdm(prices):
        # find turf bookmaker odds
        turf_odds_df = pd.DataFrame()
        race_status = {}
        for m_id, m in markets[event_mapping[p.market_id][0]]:
            if m_id != p.market_id:
                continue
            market_start_time = event_mapping[p.market_id][1]
            venue = m.event.venue.lower()
            config = get_config()
            turf_countries = config.get('Scraping', 'turf_countries').split()
            if m.event.country_code not in turf_countries:
                continue
            # TODO, check and process turf odds
            try:
                turf_odds_df, race_status = get_race_odds(
                    venue, market_start_time, m.runners)
            except:
                pass

        mb_market = event_mapping[p.market_id][3]
        for r in p.runners:
            back_prices, back_sizes, lay_prices, lay_sizes = [-1, -1, -1], [
                -1, -1, -1
            ], [-1, -1, -1], [-1, -1, -1]
            try:
                vwap = get_VWAP(r.ex.traded_volume)
            except ZeroDivisionError:
                vwap = 0.
            for i in range(3):

                try:
                    back_prices[i] = r.ex.available_to_back[i].price
                except IndexError:
                    back_prices[i] = None

                try:
                    lay_prices[i] = r.ex.available_to_lay[i].price
                except IndexError:
                    lay_prices[i] = None

                try:
                    back_sizes[i] = r.ex.available_to_back[i].size
                except IndexError:
                    back_sizes[i] = None

                try:
                    lay_sizes[i] = r.ex.available_to_lay[i].size
                except IndexError:
                    lay_sizes[i] = None

            try:
                sp_dict = {
                    'near_price':
                    r.sp.near_price,
                    'far_price':
                    r.sp.far_price,
                    'actual_SP':
                    r.sp.actual_SP,
                    'back_SP_amounts':
                    [(a.price, a.size) for a in r.sp.back_stake_taken],
                    'lay_SP_amounts':
                    [(a.price, a.size) for a in r.sp.back_stake_taken]
                }
            except:
                sp_dict = {}

            seconds_until_start = (event_mapping[p.market_id][1] -
                                   datetime.datetime.now()).total_seconds()
            event_id = event_mapping[p.market_id][0]
            d = {
                'marketid': p.market_id,
                'selection_id': r.selection_id,
                'LTP': r.last_price_traded,
                'back_sizes0': back_sizes[0],
                'back_prices0': back_prices[0],
                'back_sizes1': back_sizes[1],
                'back_prices1': back_prices[1],
                'back_sizes2': back_sizes[2],
                'back_prices2': back_prices[2],
                'lay_sizes0': lay_sizes[0],
                'lay_prices0': lay_prices[0],
                'lay_sizes1': lay_sizes[1],
                'lay_prices1': lay_prices[1],
                'lay_sizes2': lay_sizes[2],
                'lay_prices2': lay_prices[2],
                'timestamp': datetime.datetime.now(),
                'eventid': event_id,
                'marketstarttime': event_mapping[p.market_id][1],
                'countrycode': event_mapping[p.market_id][2],
                'seconds_until_start': seconds_until_start,
                'total_matched': r.total_matched,
                'VWAP': vwap,
            }
            d.update(sp_dict)
            if not turf_odds_df.empty:
                # Add the turf odds
                try:
                    bookie_prices = turf_odds_df.loc[
                        r.selection_id].values.astype(float)
                    bookie_prices[bookie_prices ==
                                  0] = np.nan  # replace 0 with nan

                    d['bookies'] = pd.DataFrame({'name': turf_odds_df.loc[r.selection_id].index,
                                                 'price': bookie_prices}). \
                        to_dict(orient='records)')
                    d['mean_bookie_price'] = np.nanmean(bookie_prices)
                    d['median_bookie_price'] = np.nanmedian(bookie_prices)
                    d['min_bookie_price'] = np.nanmin(bookie_prices)
                    d['max_bookie_price'] = np.nanmax(bookie_prices)

                except KeyError:
                    log.info("No turf odds for selection: {}".format(
                        r.selection_id))

            if mb_market:
                d['mb_market_id'] = mb_market['id']
                runner_name = bf_selection_name_mapping[r.selection_id]
                mb_selection_id = None
                for mr in mb_market['runners']:
                    if mr['name'].lstrip('1234567890- ') == runner_name:
                        mb_selection_id = mr['id']
                        d['mb_selection_id'] = mb_selection_id
                        d['mb_volume'] = mr['volume']
                        back_index, lay_index = 0, 0
                        for mp in mr['prices']:
                            if mp['side'] == 'back':
                                d['mb_back_prices{}'.format(
                                    back_index)] = mp['decimal-odds']
                                d['mb_back_sizes{}'.format(
                                    back_index)] = mp['available-amount']
                                back_index += 1
                            else:
                                d['mb_lay_prices{}'.format(
                                    back_index)] = mp['decimal-odds']
                                d['mb_lay_sizes{}'.format(
                                    back_index)] = mp['available-amount']
                                lay_index += 1
                if not mb_selection_id:
                    log.warning(
                        "Didn't find runner information for bf selection id {}"
                        .format(r.selection_id))

            d.update(race_status)
            log.debug(d)
            m = MongoManager()
            success = m.insert_document(collection_name, d)
            log.debug(success)
예제 #10
0
    def __init__(self, use_remote=True, use_archive=False):

        # to create a local copy, run mongod locally with shell and copy over the remote with this command in mongodb
        # db.copyDatabase("horse_racing","horse_racing","dickreuter.com","rj","rj","SCRAM-SHA-1" )
        # to run it automatically as service in windows, do this with admin rights: mongod --install

        config = get_config()
        prod = config.get("Servers", "prod")
        remote_server = config.get("MongoDB", "remote_server")

        # use localhost when program runs on prod:
        localhost = config.get("MongoDB", "localhost")

        # database for price operations
        price_db = config.get("MongoDB", "price_db")
        price_login = config.get("MongoDB", "price_login")
        price_pass = config.get("MongoDB", "price_pass")
        price_login_write = config.get("MongoDB", "price_login_write")
        price_pass_write = config.get("MongoDB", "price_pass_write")

        # database for pnl operations
        pnl_db = config.get("MongoDB", "pnl_db")
        pnl_login = config.get("MongoDB", "pnl_login")
        pnl_pass = config.get("MongoDB", "pnl_pass")
        pnl_login_write = config.get("MongoDB", "pnl_login_write")
        pnl_pass_write = config.get("MongoDB", "pnl_pass_write")

        # database for archive
        archive_db = config.get("MongoDB", "archive_db")
        archive_login_write = config.get("MongoDB", "archive_login_write")
        archive_pass_write = config.get("MongoDB", "archive_pass_write")

        if use_archive:  # use archive for everything
            # database for price operations
            price_db = archive_db
            price_login = archive_login_write
            price_pass = archive_pass_write
            price_login_write = archive_login_write
            price_pass_write = archive_pass_write

            # database for pnl operations
            pnl_db = archive_db
            pnl_login = archive_login_write
            pnl_pass = archive_pass_write
            pnl_login_write = archive_login_write
            pnl_pass_write = archive_pass_write

        if use_remote:
            if hostname == prod:
                self.mongoclient_price = MongoClient(
                    'mongodb://{}:{}@{}/{}'.format(price_login_write,
                                                   price_pass_write, localhost,
                                                   price_db))
                self.mongoclient_pnl = MongoClient(
                    'mongodb://{}:{}@{}/{}'.format(pnl_login_write,
                                                   pnl_pass_write, localhost,
                                                   pnl_db))

                self.mongoclient_archive = MongoClient(
                    'mongodb://{}:{}@{}/{}'.format(archive_login_write,
                                                   archive_pass_write,
                                                   localhost, archive_db))

            else:
                self.mongoclient_price = MongoClient(
                    'mongodb://{}:{}@{}/{}'.format(price_login, price_pass,
                                                   remote_server, price_db))
                self.mongoclient_pnl = MongoClient(
                    'mongodb://{}:{}@{}/{}'.format(pnl_login, pnl_pass,
                                                   remote_server, pnl_db))
                self.mongoclient_archive = MongoClient(
                    'mongodb://{}:{}@{}/{}'.format(archive_login_write,
                                                   archive_pass_write,
                                                   remote_server, archive_db))
        else:
            self.mongoclient_price = MongoClient(
                'mongodb://localhost/horse_racing')
            self.mongoclient_pnl = MongoClient(
                'mongodb://localhost/horse_racing')
            self.mongoclient_archive = MongoClient(
                'mongodb://localhost/archive')

        self.mongodb_price = self.mongoclient_price[price_db]
        self.mongodb_pnl = self.mongoclient_pnl[pnl_db]
        self.mongodb_archive = self.mongoclient_archive[archive_db]