Search code examples
pythongambling

How to write a bet settling function in Python


I'm trying to write a function that takes a sports bet and returns its Net result.

While I managed to accomplish it for bets on total, I couldn't finish settling bets on handicap since it led to some enormous wall of nested if/else statements.

If you are not familiar with betting, an exhaustive test suite should help with understanding what the program is supposed to do.

The main question is how to solve this problem in a way distinct from enumerating all of the possible cases.

Any feedback is greatly appreciated.

SUPPORTED_BET_TYPES = ['total', 'handicap']
SIDES = ['home', 'away', 'over', 'under']
BET_OUTCOMES = ['Won', 'Lost', 'Cancelled', 'Half Won', 'Half Lost']


def settle_bet(bet_type, side, points, price, bet_amount, home_score, away_score):
    '''Returns a result of the bet'''

    if bet_type == 'total':
        return settle_total_bet(side, points, price, bet_amount, home_score, away_score)
    elif bet_type == 'handicap':
        return settle_handicap_bet(side, points, price, bet_amount, home_score, away_score)


def settle_total_bet(side, points, price, bet_amount, home_score, away_score):
    '''Returns Net result of the bet on total'''

    outcome = determine_total_bet_outcome(side, points, home_score, away_score)

    if outcome == 'Won':
        return bet_amount * (price - 1)
    elif outcome == 'Half Won':
        return bet_amount * ((price - 1) / 2)
    elif outcome == 'Cancelled':
        return 0
    elif outcome == 'Half Lost':
        return bet_amount * (-1 / 2)
    else:
        return bet_amount * -1


def determine_total_bet_outcome(side, points, home_score, away_score):
    '''Returns the appropriate outcome of the bet from BET_OUTCOMES'''

    total_score = home_score + away_score
    points_score_diff = points - total_score

    if points_score_diff == 0:
        return 'Cancelled'
    elif points_score_diff == 0.25:
        if side == 'over':
            return 'Half Lost'
        else:
            return 'Half Won'
    elif points_score_diff == -0.25:
        if side == 'over':
            return 'Half Won'
        else:
            return 'Half Lost'
    elif points_score_diff >= 0.5:
        if side == 'over':
            return 'Lost'
        else:
            return 'Won'
    elif points_score_diff <= -0.5:
        if side == 'over':
            return 'Won'
        else:
            return 'Lost'


def test():
    # Bets on Total

    # Won or Lost
    assert settle_bet('total', 'over', 2.5, 1.90, 100, 3, 2) == 100 * (1.90 - 1)
    assert settle_bet('total', 'over', 3.5, 1.85, 100, 0, 1) == 100 * -1
    assert settle_bet('total', 'under', 2.5, 1.94, 100, 0, 0) == 100 * (1.94 - 1)
    assert settle_bet('total', 'under', 3.5, 1.75, 100, 1, 3) == 100 * -1

    # Won or Lost Or Cancelled
    assert settle_bet('total', 'over', 3.0, 1.82, 100, 2, 2) == 100 * (1.82 - 1)
    assert settle_bet('total', 'over', 3.0, 1.82, 100, 1, 2) == 100 * 0
    assert settle_bet('total', 'over', 3.0, 1.82, 100, 0, 0) == 100 * -1

    assert settle_bet('total', 'under', 3.0, 1.82, 100, 2, 2) == 100 * -1
    assert settle_bet('total', 'under', 3.0, 1.82, 100, 1, 2) == 100 * 0
    assert settle_bet('total', 'under', 3.0, 1.82, 100, 0, 0) == 100 * (1.82 - 1)

    # Won or Lost or Half Won or Half Lost
    assert settle_bet('total', 'over', 2.25, 1.95, 100, 2, 1) == 100 * (1.95 - 1)
    assert settle_bet('total', 'over', 2.25, 1.90, 100, 0, 0) == 100 * -1
    assert settle_bet('total', 'over', 2.25, 1.80, 100, 1, 1) == 100 * (-1 / 2)

    assert settle_bet('total', 'under', 2.25, 1.95, 100, 2, 1) == 100 * -1
    assert settle_bet('total', 'under', 2.25, 1.90, 100, 0, 0) == 100 * (1.90 - 1)
    assert settle_bet('total', 'under', 2.25, 1.80, 100, 1, 1) == 100 * ((1.80 - 1) / 2)

    assert settle_bet('total', 'over', 2.75, 1.90, 100, 3, 3) == 100 * (1.90 - 1)
    assert settle_bet('total', 'over', 2.75, 1.88, 100, 1, 2) == 100 * ((1.88 - 1) / 2)
    assert settle_bet('total', 'over', 2.75, 1.90, 100, 1, 0) == 100 * -1

    assert settle_bet('total', 'under', 2.75, 1.90, 100, 3, 3) == 100 * -1
    assert settle_bet('total', 'under', 2.75, 1.88, 100, 1, 2) == 100 * (-1 / 2)
    assert settle_bet('total', 'under', 2.75, 1.90, 100, 1, 0) == 100 * (1.90 - 1)

    # Bets on Handicap

    # Won or Lost

    # assert settle_bet('handicap', 'home', -0.5, 1.88, 100, 4, 0) == 100 * (1.88 - 1)
    # assert settle_bet('handicap', 'home', -0.5, 1.88, 100, 0, 0) == 100 * -1
    # assert settle_bet('handicap', 'home', -0.5, 1.88, 100, 1, 2) == 100 * -1
    #
    # assert settle_bet('handicap', 'away', -0.5, 1.88, 100, 4, 0) == 100 * -1
    # assert settle_bet('handicap', 'away', -0.5, 1.88, 100, 0, 0) == 100 * -1
    # assert settle_bet('handicap', 'away', -0.5, 1.88, 100, 1, 2) == 100 * (1.88 - 1)
    #
    # # Won or Lost Or Cancelled
    # assert settle_bet('handicap', 'home', 0.0, 1.90, 100, 1, 0) == 100 * (1.90 - 1)
    # assert settle_bet('handicap', 'home', 0.0, 1.85, 100, 2, 2) == 100 * 0
    # assert settle_bet('handicap', 'home', 0.0, 1.97, 100, 1, 3) == 100 * -1
    #
    # assert settle_bet('handicap', 'away', 0.0, 1.90, 100, 1, 0) == 100 * -1
    # assert settle_bet('handicap', 'away', 0.0, 1.85, 100, 2, 2) == 100 * 0
    # assert settle_bet('handicap', 'away', 0.0, 1.97, 100, 1, 3) == 100 * (1.97 - 1)
    #
    # # Won or Lost or Half Won or Half Lost
    #
    # assert settle_bet('handicap', 'home', -0.25, 1.84, 100, 1, 0) == 100 * (1.84 - 1)
    # assert settle_bet('handicap', 'home', -0.25, 1.84, 100, 2, 2) == 100 * (-1 / 2)
    # assert settle_bet('handicap', 'home', -0.25, 1.84, 100, 1, 3) == 100 * -1
    #
    # assert settle_bet('handicap', 'home', 1.25, 1.96, 100, 3, 2) == 100 * (1.96 - 1)
    # assert settle_bet('handicap', 'home', 1.25, 1.96, 100, 1, 1) == 100 * (1.96 - 1)
    # assert settle_bet('handicap', 'home', 1.25, 1.96, 100, 1, 2) == 100 * ((1.96 - 1) / 2)
    # assert settle_bet('handicap', 'home', 1.25, 1.96, 100, 0, 2) == 100 * -1
    #
    # assert settle_bet('handicap', 'away', -1.25, 1.86, 100, 0, 2) == 100 * (1.86 - 1)
    # assert settle_bet('handicap', 'away', -1.25, 1.86, 100, 1, 2) == 100 * (-1 / 2)
    # assert settle_bet('handicap', 'away', -1.25, 1.86, 100, 0, 0) == 100 * -1
    # assert settle_bet('handicap', 'away', -1.25, 1.86, 100, 3, 0) == 100 * -1
    #
    # assert settle_bet('handicap', 'away', 0.25, 1.97, 100, 1, 0) == 100 * -1
    # assert settle_bet('handicap', 'away', 0.25, 1.97, 100, 2, 2) == 100 * ((1.97 - 1) / 2)
    # assert settle_bet('handicap', 'away', 0.25, 1.97, 100, 1, 4) == 100 * (1.97 - 1)
    #
    # assert settle_bet('handicap', 'home', -0.75, 1.90, 100, 4, 0) == 100 * (1.90 - 1)
    # assert settle_bet('handicap', 'home', -0.75, 1.90, 100, 3, 2) == 100 * ((1.90 - 1) / 2)
    # assert settle_bet('handicap', 'home', -0.75, 1.90, 100, 1, 1) == 100 * -1
    # assert settle_bet('handicap', 'home', -0.75, 1.90, 100, 0, 2) == 100 * -1
    #
    # assert settle_bet('handicap', 'home', 1.75, 1.88, 100, 0, 3) == 100 * (1.88 - 1)
    # assert settle_bet('handicap', 'home', 1.75, 1.88, 100, 2, 4) == 100 * (-1 / 2)
    # assert settle_bet('handicap', 'home', 1.75, 1.88, 100, 1, 1) == 100 * (1.88 - 1)
    # assert settle_bet('handicap', 'home', 1.75, 1.88, 100, 1, 0) == 100 * (1.88 - 1)
    #
    # assert settle_bet('handicap', 'away', -2.75, 1.92, 100, 0, 4) == 100 * (1.92 - 1)
    # assert settle_bet('handicap', 'away', -2.75, 1.92, 100, 1, 4) == 100 * ((1.92 - 1) / 2)
    # assert settle_bet('handicap', 'away', -2.75, 1.92, 100, 2, 3) == 100 * -1
    # assert settle_bet('handicap', 'away', -2.75, 1.92, 100, 1, 1) == 100 * -1
    # assert settle_bet('handicap', 'away', -2.75, 1.92, 100, 1, 0) == 100 * -1
    #
    # assert settle_bet('handicap', 'away', 0.75, 1.91, 100, 1, 2) == 100 * (1.91 - 1)
    # assert settle_bet('handicap', 'away', 0.75, 1.91, 100, 0, 0) == 100 * ((1.91 - 1) / 2)
    # assert settle_bet('handicap', 'away', 0.75, 1.91, 100, 3, 2) == 100 * -1

    print("All tests passed.")


if __name__ == '__main__':
    test()

Solution

  • A few ideas:

    1. Instead of returning a string that represents the bet result, return a number that represents the multiplier for the bet result.

    2. Instead of separately checking whether the bet was on 'over' or 'under' vs each score difference, use the bet type to normalize the score difference into the amount by which the difference was in the bettor's favour.

    3. Make use of conditional expressions.

    Thus:

    def settle_total_bet(side, points, price, bet_amount, home_score, away_score):
        '''Returns Net result of the bet on total'''
        outcome = determine_total_bet_outcome(side, points, home_score, away_score)
        bet_size = (price - 1) if outcome > 0 else 1
        return bet_amount * bet_size * outcome
    
    
    def determine_total_bet_outcome(side, line, home_score, away_score):
        '''Returns the appropriate outcome of the bet from BET_OUTCOMES'''
        amount_over = home_score + away_score - line
        amount_successful = amount_over if side == 'over' else -amount_over
    
        if amount_successful >= 0.5:
            return 1
        elif amount_successful <= -0.5:
            return -1
        elif amount_successful > 0: # == 0.25
            return 0.5
        elif amount_successful < 0: # == -0.25
            return -0.5
        else:
            return 0
    

    As an aside: the lists at the top of your program are not really doing anything right now. But if you want to take a more rigorous approach to this idea - using one of a finite set of values to represent some data - use the standard library enum module.