Exemple #1
0
    def report_outcome_for_football(self, response):
        for key, orders in self.orders_by_provider.iteritems():
            for bet_info in orders:
                sport, (_, event_id), market, params, bm = parse_sticker(
                    bet_info.sticker)
                gsm_id = key[0]

                try:
                    details = response[gsm_id]['details']
                except KeyError:
                    logging.debug("Manual #Order %s" % bet_info)
                    continue

                last_score_ft = (details['team1FTG'], details['team2FTG'])
                last_score_ht = (details['team1HTG'], details['team2HTG'])

                if market in (Markets.FULL_TIME_ASIAN_HANDICAP_GOALS,
                              Markets.FULL_TIME_OVER_UNDER_GOALS,
                              Markets.FULL_TIME_CORRECT_SCORE,
                              Markets.FULL_TIME_1X2):
                    n_win, n_bet = determine_football_outcome(
                        market, params, last_score_ft)
                elif market in (Markets.HALF_TIME_ASIAN_HANDICAP_GOALS,
                                Markets.HALF_TIME_OVER_UNDER_GOALS,
                                Markets.HALF_TIME_CORRECT_SCORE,
                                Markets.HALF_TIME_1X2):
                    n_win, n_bet = determine_football_outcome(
                        market, params, last_score_ft, last_score_ht)
                else:
                    logging.error("Cannot determine market pnl #Order %s\n" %
                                  bet_info)
                    continue

                report_bet_outcome_pnl(n_win, n_bet, bet_info)
Exemple #2
0
def football_pnl_grid(orders, normalize_by_stake=False, max_evts=7, default_if_unknown=False, reshape=False):
    '''
    :param orders: can be for (e.g.) goal or corner markets
    :param max_evts: the maximum number of events (e.g. goals or corners) or a team handled by the pnl grid
    '''
    pnl_per_score = []
    aggregate_bet_notional = 1

    if normalize_by_stake:
        aggregate_bet_notional = sum(order_size(b, default_if_unknown) for b in orders)

    for team1_score, team2_score in product(range(max_evts + 1), range(max_evts + 1)):
        pnl_for_score = 0
        for order in orders:
            _, market_scope, market, params, _ = parse_sticker(order.sticker)
            n_win, n_bet = determine_football_outcome(market, params, (team1_score, team2_score))
            outcome, pnl = determine_order_outcome_pnl(order, n_win, n_bet, default_if_unknown=default_if_unknown)
            if normalize_by_stake:
                pnl /= float(aggregate_bet_notional)
            pnl_for_score += pnl
        pnl_per_score.append(pnl_for_score)

    if reshape:
        return np.array(pnl_per_score).reshape(max_evts + 1, max_evts + 1)
    return np.array(pnl_per_score)
Exemple #3
0
    def report_outcome_for_tennis(self, response):
        for key, orders in self.orders_by_provider.iteritems():
            for bet_info in orders:
                sport, (_, event_id), market, params, bm = parse_sticker(
                    bet_info.sticker)
                enp_id = key[0]

                try:
                    details = response[enp_id]['details']
                except KeyError:
                    logging.debug("Manual #Order %s" % bet_info)
                    continue

                player_a_result = details.get('playerAResult', -1)

                if market == TennisMarkets.MATCH_ODDS:
                    n_win, n_bet = determine_tennis_outcome(
                        market, params, player_a_result)
                    report_bet_outcome_pnl(n_win, n_bet, bet_info)
                elif market in [
                        TennisMarkets.SET_BETTING,
                        TennisMarkets.TOTAL_GAMES_OVER_UNDER,
                        TennisMarkets.HANDICAP_GAMES
                ]:
                    scores = response.get(enp_id, {}).get('details', {})
                    n_win, n_bet = determine_tennis_outcome_alternative_markets(
                        market, params, scores)
                    report_bet_outcome_pnl(n_win, n_bet, bet_info)
                else:
                    logging.error("Cannot determine market pnl #Order %s\n" %
                                  bet_info)
                    continue
    def market_data_stickers_figures_for_trade_id(self, trade_id, stickers_for_trade_id):
        # get all historical odds for the stickers
        # sticker is
        best_odds_figs = []
        for sticker in stickers_for_trade_id:
            sport, market_scope, market, params, _ = parse_sticker(sticker)
            stream = OddsStream(sport, market_scope[1], market, *params,
                                bookmaker=Bookmakers.BETFAIR)

            odds = get_historical_odds([stream])[stream]

            # Calculate best back and lay for a unique sticker
            back_dt = []
            lay_dt = []
            back_odds = []
            lay_odds = []
            for oddsTick in odds:
                if len(oddsTick.back) > 0:
                    back_odds.append(oddsTick.back[0].o)
                    back_dt.append(oddsTick.timestamp)

                if len(oddsTick.lay) > 0:
                    lay_odds.append(oddsTick.lay[0].o)
                    lay_dt.append(oddsTick.timestamp)

            # best odds fig
            best_odds_fig = self.construct_best_odds_figure(back_dt, back_odds, lay_dt, lay_odds, trade_id, sticker)
            best_odds_figs.append(best_odds_fig)

        return best_odds_figs
Exemple #5
0
    def run(self):
        for trading_user_id in TRADING_USERS.values():
            for strategy_name in self.strategy_names:
                orders = get_settled_orders(trading_user_id, self.start_dt,
                                            self.end_dt, strategy_name)

                for order in orders:
                    try:
                        bet_info = json_to_bet_info(order)
                    except KeyError:
                        logging.error("Missing Sticker #Order %s\n" % order)
                        continue
                    sport, (scope,
                            event_id), market, params, bm = parse_sticker(
                                bet_info.sticker)
                    exec_details = bet_info.execution_details
                    provider = exec_details['provider']
                    if provider in self.providers:
                        bookmaker = exec_details['bookmaker']
                        sticker = bet_info.sticker
                        if len(sticker) == 0:
                            logging.error("Missing Sticker #Order %s\n" %
                                          order)
                            continue

                        if scope == MarketScopes.EVENT:
                            # just event scopes for now
                            current_orders = self.orders_by_provider[event_id,
                                                                     provider,
                                                                     bookmaker]
                            current_orders.append(bet_info)

                            if len(self.orders_by_provider
                                   ) >= _FLUSH_NUM_ORDERS:
                                # Calculate outcomes for all event_ids
                                event_ids = self._get_event_ids()
                                response = data_api.get_event_outcome(
                                    sport, event_ids)
                                self.report_outcome_for_events(response)
                                self.report_missing_fx_rate()
                                # flush dictionary
                                self.orders_by_provider.clear()
                                self.flushed = True

        if self.orders_by_provider:
            # Calculate outcomes for all event_ids
            event_ids = self._get_event_ids()
            response = data_api.get_event_outcome(
                extract_sport(bet_info.sticker), event_ids)
            self.report_outcome_for_events(response)
            self.report_missing_fx_rate()
        elif not self.flushed:
            logging.info("No orders found")
Exemple #6
0
def tennis_pnl_grid_match_winner(orders):
    """
    Returns a 1d array containing the pnl in case player A or player B wins the match. Only works with MATCH ODDS
    market
    """
    pnl_per_result = np.zeros(2)
    for idx, player_a_res in enumerate(['winner', 'loser']):
        for order in orders:
            _, _, _, params, _ = parse_sticker(order.sticker)
            nwin, n_bet = determine_tennis_outcome(
                TennisMarkets.MATCH_ODDS, params, player_a_res)
            outcome, pnl = determine_order_outcome_pnl(
                order, nwin, n_bet, default_if_unknown=False)
            pnl_per_result[idx] += pnl

    return pnl_per_result
Exemple #7
0
    def get_per_event_vol(self, stats, instructions, orders):
        per_event_vol = {}

        for order in orders:
            pnl = StrategyRunStatsHelper.get_order_matched_vol(order)
            if pnl == 0.:
                continue
            sport, (scope,
                    event_id), mkt, params, _ = parse_sticker(order['sticker'])
            if event_id not in per_event_vol:
                per_event_vol[event_id] = 0.
            per_event_vol[event_id] += pnl

        for key in per_event_vol.keys():
            per_event_vol[key] = round(per_event_vol[key], 2)
        return per_event_vol
Exemple #8
0
def f_instruction_to_row(sport, instr, extra_info=None):
    '''
    :param extra_info: (dict) extra information to take from raw instructions,
        e.g. {'timestamp': 'details.signals.0.timestamp'}
    '''
    _, (_, event_id), mkt_id, params, _ = parse_sticker(instr['sticker'])
    sel_id = params[0]
    hc = np.nan if len(params) == 1 else params[1]

    instr_dict = {
        'fixture_id': int(event_id[3:]),
        'average_price_matched': instr['average_price_matched'],
        'capital_received': instr['details'].get('capital_received', -1),
        'sticker': instr['sticker'],
        'market': MARKET_ABBR[sport][mkt_id],
        'selection': Selections.to_str(sel_id),
        'hc': hc,
        'is_back': (instr['bet_side'] == 'back'),
        'instruction_id': instr['id'],
        'selection_id': sel_id,
        'market_id': mkt_id,
        'handicap': hc,
        'placed_time': parse_date_if_necessary(instr['placed_time'],
                                               to_utc=True),
        'size_wanted': instr['size'],
        'size_matched': instr['size_matched'],
        'strategy': instr['strategy'],
        'strategy_descr': instr['strategy_descr'],
        'trade_id': instr['trade_id'],
    }

    if extra_info is not None:
        # get specified additional information from instruction
        info_dict = {}  # initialise
        for label, i in extra_info.iteritems():
            i_keys = i.split('.')
            info = instr.copy()  # initialise
            for i_key in i_keys:
                try:
                    i_key = int(i_key)  # convert to int if possible
                except:
                    pass
                info = info[i_key]  # update
            info_dict[label] = info

        instr_dict.update(info_dict)
    return instr_dict
Exemple #9
0
 def _add_sticker_info(self, sticker, order, info):
     sport, (market_scope,
             gsm_id), market_id, params, bm = parse_sticker(sticker)
     if sport != self._sport:
         raise Exception('Received a sticker which is not from the correct'
                         ' sport {} ! {}'.format(self._sport, order))
     sticker_info = {
         'sticker': sticker,
         'event_id': gsm_id,
         'fixture_id': int(gsm_id[3:]),
         'handicap': None if len(params) == 1 else params[1],
         'selection_id': params[0],
         'selection': SELECTION_ABBR[self._sport][params[0]],
         'market': MARKET_ABBR[self._sport][market_id],
         'market_id': market_id
     }
     info.update(sticker_info)
Exemple #10
0
    def report_outcome_for_basketball(self):
        for key, orders in self.orders_by_provider.iteritems():
            for bet_info in orders:
                sport, (_, event_id), market, params, bm = parse_sticker(
                    bet_info.sticker)
                enp_id = key[0]

                if market in (BasketballMarkets.FULL_TIME_POINT_SPREAD,
                              BasketballMarkets.FULL_TIME_MONEYLINE,
                              BasketballMarkets.FULL_TIME_TOTAL_POINTS):

                    n_win, n_bet = determine_basketball_outcome_from_api(
                        market, params, enp_id)

                    report_bet_outcome_pnl(n_win, n_bet, bet_info)
                else:
                    logging.error("Cannot determine market pnl #Order %s\n" %
                                  bet_info)
                    continue
Exemple #11
0
def convert_bet_states_to_array(order_states):
    """
    Convert bet_states DataFrame to array of bets containing only last known bet state
    :param order_states: DataFrame of bet states
    :return: array of bet objects
    """
    orders = dict()
    for timestamp, order in order_states.iteritems():
        _, market_scope, market, params, _ = parse_sticker(order.sticker)
        orders[order.id] = {
            'event': market_scope[1],
            'pnl': order.pnl,
            'market': market,
            'commission': order.commission,
            'stake': order.size,
            'is_back': order.is_back,
            'odds': order.price if order.matched_odds == 0 else order.matched_odds,
            'date': timestamp,
        }
    return orders.values()
Exemple #12
0
 def get_order_bm(order):
     sport, (scope,
             event_id), mkt, params, bm = parse_sticker(order['sticker'])
     if bm is not None:
         return BOOKMAKER_ABBR[bm]
     return order['execution_details']['bookmaker']
    def _update_max_loss(self, updated_instructions, _updated_orders):
        closed_trades = set()

        for instruction in updated_instructions:
            sport, (_, event_id), market, params, bm = parse_sticker(
                instruction.sticker)

            trade_id = instruction.trade_id

            if sport == Sports.FOOTBALL:
                # if not already present, initialise pnl grids
                # (accounting for the possibility of a corner market, which affects the size of the grids)
                # note: this effectively replaces the default grid of the defaultdict
                max_evts = _get_football_max_evts(instruction)

                if event_id not in self._current_pnl_grid_by_trade_by_event:
                    self._current_pnl_grid_by_trade_by_event[event_id] = {}
                if trade_id not in self._current_pnl_grid_by_trade_by_event[
                        event_id]:
                    self._current_pnl_grid_by_trade_by_event[event_id][
                        trade_id] = empty_pnl_grid(grid_size=max_evts + 1)

                if event_id not in self._active_pnl_grid_by_trade_by_event:
                    self._active_pnl_grid_by_trade_by_event[event_id] = {}
                if trade_id not in self._active_pnl_grid_by_trade_by_event[
                        event_id]:
                    self._active_pnl_grid_by_trade_by_event[event_id][
                        trade_id] = empty_pnl_grid(grid_size=max_evts + 1)
            else:
                err_msg = ('WARN: risk not implemented for sport {}'.format(
                    instruction.sticker))
                warnings.warn(err_msg)

            if instruction in self._instructions_by_trade_by_event[event_id][
                    trade_id]:
                self._current_pnl_grid_by_trade_by_event[event_id][
                    trade_id] -= self._current_pnl_grid_by_instruction_id[
                        instruction.id]
                self._active_pnl_grid_by_trade_by_event[event_id][
                    trade_id] -= self._active_pnl_grid_by_instruction_id[
                        instruction.id]

            self._instructions_by_trade_by_event[event_id][trade_id].add(
                instruction)

            # create an instruction for the total matchable amount
            instruction_copy = deepcopy(instruction)
            if instruction.status in (InstructionStatus.IDLE,
                                      InstructionStatus.PROCESSING,
                                      InstructionStatus.WATCHING):
                instruction_copy.matched_amount = instruction.size
            else:
                instruction_copy.matched_amount = instruction.matched_amount

            sport = extract_sport(instruction.sticker)

            if sport == Sports.FOOTBALL:
                max_evts = _get_football_max_evts(instruction)
                self._current_pnl_grid_by_instruction_id[
                    instruction.id] = football_pnl_grid([instruction],
                                                        max_evts=max_evts,
                                                        reshape=True)
                self._active_pnl_grid_by_instruction_id[
                    instruction.id] = football_pnl_grid([instruction_copy],
                                                        max_evts=max_evts,
                                                        reshape=True)
            else:
                # TODO more sports
                self._current_pnl_grid_by_instruction_id[
                    instruction.id] = empty_pnl_grid()
                self._active_pnl_grid_by_instruction_id[
                    instruction.id] = empty_pnl_grid()

            self._current_pnl_grid_by_trade_by_event[event_id][
                trade_id] += self._current_pnl_grid_by_instruction_id[
                    instruction.id]
            self._active_pnl_grid_by_trade_by_event[event_id][
                trade_id] += self._active_pnl_grid_by_instruction_id[
                    instruction.id]

            # check if a trade has opened, the open dt will be that provided by the strategy,
            # this is for RINA style calculations - this is now the only way
            # to calculate time in market, there is no fancy attempts to automatically calculate it
            if trade_id not in self._trade_open_dt and 'trade_open_dt' in instruction.details:
                trade_open_dt = instruction.details['trade_open_dt']
                self._trade_open_dt[trade_id] = trade_open_dt

            # check if a trade has been labelled closed by the strategy
            if trade_id in self._trade_open_dt and trade_id not in self._trade_close_dt and 'trade_close_dt' in instruction.details:
                trade_closed_dt = instruction.details['trade_close_dt']
                self._trade_close_dt[trade_id] = trade_closed_dt
                closed_trades.add(trade_id)

        # TODO consider reducing max loss as orders settle?
        max_loss = 0

        # calculate the max loss from the active pnl grids, ie the total matchable amounts
        for event_id, pnl_grid_by_trade in self._active_pnl_grid_by_trade_by_event.items(
        ):
            max_loss_for_event = 0

            for trade_id, pnl_grid_for_trade in pnl_grid_by_trade.items():
                min_pnl_for_trade = np.min(pnl_grid_for_trade)
                max_loss_for_trade = min(0, min_pnl_for_trade)
                self._max_loss_by_trade_by_event[event_id][
                    trade_id] = max_loss_for_trade
                max_loss_for_event += max_loss_for_trade

            max_loss += max_loss_for_event

        self._max_loss = max_loss

        for closed_trade_id in closed_trades:
            if closed_trade_id not in self._time_in_market_by_trade:
                time_in_market_sec = (
                    self._trade_close_dt[closed_trade_id] -
                    self._trade_open_dt[closed_trade_id]).total_seconds()
                time_in_market = min(1., time_in_market_sec / (111. * 60.))
                self._time_in_market_by_trade[closed_trade_id] = time_in_market

                new_mean_time_in_market = get_new_mean(
                    self._mean_time_in_market, time_in_market,
                    len(self._time_in_market_by_trade))
                self._mean_time_in_market = new_mean_time_in_market
def _get_football_max_evts(instruction):
    _, _, market, _, _ = parse_sticker(instruction.sticker)
    return (25 if Markets.is_corner_mkt(market) else
            _get_default_args(football_pnl_grid)['max_evts'])
Exemple #15
0
def execution_data_tennis_sip(trading_user_id,
                              start_dt,
                              end_dt,
                              strategy_id,
                              strategy_run_id=None):

    cache = HistoricalOddsCache()
    mysql_enet = MySQLClient.init_from_config(auto_connect=True)

    orders = get_settled_orders(trading_user_id, start_dt, end_dt, strategy_id,
                                strategy_run_id)

    instruction_ids = {
        order['instruction_id']
        for order in orders if 'instruction_id' in order
    }
    instructions = get_instructions_by_id(trading_user_id,
                                          list(instruction_ids))

    stickers = {
        order['sticker']
        for order in orders if len(order['sticker']) > 0
    }
    enp_ids = set()

    for sticker in stickers:
        sport, (_, event_id), market, params, _ = parse_sticker(sticker)
        enp_ids.add(event_id[3:])

    if len(enp_ids) == 0:
        return []

    results_query = _SQL_QUERY % ', '.join(enp_ids)
    results_tz = pytz.timezone('Europe/London')

    try:
        event_action_data = mysql_enet.select(results_query, as_list=True)
    except:
        print results_query
        raise

    set_end_times = get_set_end_times(event_action_data)
    rows = []

    for order in orders:
        sticker = order['sticker']
        rate = order['exchange_rate']

        if len(sticker) == 0:
            continue

        sport, (_, event_id), market, params, _ = parse_sticker(sticker)

        start_dt_end_set1 = results_tz.localize(
            set_end_times[event_id]['set1'])
        start_dt_end_set2 = results_tz.localize(
            set_end_times[event_id]['set2'])

        placed_dt = ciso8601.parse_datetime(order['placed_time'])
        if start_dt_end_set1 - timedelta(
                minutes=5) < placed_dt < start_dt_end_set2:
            bf_vwap = exchange_vwap(sticker,
                                    Bookmakers.BETFAIR,
                                    start_dt_end_set1,
                                    start_dt_end_set2,
                                    odds_cache=cache,
                                    return_nan=True)
            suffix = 'set2'
        else:
            if 'set3' not in set_end_times[event_id]:
                bf_vwap = float('nan')
                suffix = 'unknown'
            else:
                start_dt_end_set3 = results_tz.localize(
                    set_end_times[event_id]['set3'])
                if start_dt_end_set2 - timedelta(
                        minutes=5) < placed_dt < start_dt_end_set3:
                    bf_vwap = exchange_vwap(sticker,
                                            Bookmakers.BETFAIR,
                                            start_dt_end_set2,
                                            start_dt_end_set3,
                                            odds_cache=cache,
                                            return_nan=True)
                    suffix = 'set3'
                else:
                    bf_vwap = float('nan')
                    suffix = 'unknown'

        try:
            rows.append({
                'order_id':
                order['id'],
                'order_source':
                order['source'],
                'instruction_id':
                order.get('instruction_id', ''),
                'strategy_descr':
                order['strategy_descr'],
                'sticker':
                sticker,
                'order_size':
                order['size'] / rate,
                'source':
                order['source'],
                'matched_size':
                order['size_matched'] / rate,
                'pnl':
                order['outcome']['net'] / rate,
                'limit_price':
                order['price'],
                'average_price':
                order['average_price_matched'],
                'side':
                order['bet_side'],
                'bf_vwap_%s' % suffix:
                bf_vwap,
                'bookmaker':
                order['execution_details'].get('bookmaker', ''),
                'benchmark_price':
                bf_vwap,
            })
        except:
            print order
            raise

    return rows
Exemple #16
0
    instructions = data_api.get_closed_instructions(trading_user_id,
                                                    strategy_id)

    filtered_instructions = []

    for instr_json in instructions:
        if start_dt <= parser.parse(instr_json['placed_time']) <= end_dt:
            filtered_instructions.append(instr_json)

    for instr_json in filtered_instructions:
        sticker = instr_json['sticker']

        if instr_json['size_matched'] < instr_json['size']:
            remaining = instr_json['size'] - instr_json['size_matched']

            sport, market_scope, market, params, _ = parse_sticker(sticker)
            outcome, n_bet = determine_tennis_outcome_from_api(
                market, params, market_scope[1])

            placed_dt = parser.parse(instr_json['placed_time'])

            vwap = exchange_vwap(sticker,
                                 Bookmakers.BETFAIR,
                                 placed_dt,
                                 placed_dt + timedelta(seconds=50),
                                 odds_cache=cache,
                                 return_nan=True)

            instr = json_to_instruction(instr_json)
            instr.size = remaining
            instr.matched_amount = 0