Padraic Cunningham
Padraic Cunningham

Reputation: 180512

using cython to speed up a python application

I am using the following python code in a Kivy application. The code works fine and displays the correct information but is quite slow when calculating the return values and displaying to the screen. My questions are:

  1. could I write the function in C and use cython to incorporate it to my python program.

  2. if I can, would there be any noticeable speed increase or does the problem lie somewhere else?

def offset_back(initial_bet, initial_odds):

    returns = []
    new_odds = Decimal(initial_odds)
    while new_odds > 1:
        # calculate tick based on size of odds
        if 50 < new_odds <= 100:
            tick = Decimal("5.0")
        elif 30 < new_odds <= 50:
            tick = Decimal("2.0")
        elif 20 < new_odds <= 30:
            tick = Decimal("1.0")
        elif 10 < new_odds <= 20:
            tick = Decimal("0.5")
        elif 6 < new_odds <= 10:
            tick = Decimal("0.2")
        elif 4 < new_odds <= 6:
            tick = Decimal("0.1")
        elif 3 < new_odds <= 4:
            tick = Decimal(".05")
        elif 2 < new_odds <= 3:
            tick = Decimal(".02")
        elif new_odds <= 2:
            tick = Decimal(".01")
        else:
                tick = Decimal("10")

        #  calculate percentage difference between initial bet and new odds
        drop = Decimal(100 - (100 * Decimal(initial_odds) / Decimal(new_odds))) / 100
        # calculate amount needed to increase bet by to cancel liability
        increase = abs((initial_bet * drop))
        # calculate new stake
        new_bet = (initial_bet + increase)
        # calculate potential profit based on the new stake - initial invested stake
        profit = (new_bet - initial_bet)
        returns.append(" Stake: %.2f" % abs(new_bet)+ " " * spacing + "Odds: " "%.2f" % abs(new_odds)+ " " * spacing + "Profit: " "%.2f" % abs(profit))
        new_odds -= tick
    return returns

Upvotes: 0

Views: 700

Answers (2)

Lo&#239;c Faure-Lacroix
Lo&#239;c Faure-Lacroix

Reputation: 13610

First suggestion:

Here are some suggestions, try to move the Decimal declarations out of the loop, just reference to them when adding/substracting. As long as you created them once, it should be much faster.

decimals = [
 Decimal("10")
 ,Decimal("5.0")
 ,Decimal("2.0")
 ,Decimal("1.0")
 ,Decimal("0.5")
 ,Decimal("0.2")
 ,Decimal("0.1")
 ,Decimal(".05")
 ,Decimal(".02")
 ,Decimal(".01")
]

And replace the if by something like this:

if 50 < new_odds <= 100:
    tick = decimals[1]

Second suggestion:

is to remove the if else if ..., as you don't always get into the first if, you have to do at worse a lot of comparison to get the right case. Replace the if block for something like this.

thick = decimals[getThick(new_odds)]

The getThick should implement a formula that can be transformed to indexes. I guess your thick function could be expressed mathematically.

Here using bisect_left as Hugh proposed would be a good idea unless you can come up with a function that does that by calculation.

Third suggestion:

Replace that line by a format string:

returns.append(" Stake: %.2f %s Odds: %.2f %s Profit: %.2f" % 
               (abs(new_bet), spacing, abs(new_odds), spacing, abs(profit)))

Upvotes: 2

Hugh Bothwell
Hugh Bothwell

Reputation: 56694

  1. Avoid using Decimal - nothing you are doing here requires absolute precision.

  2. Convert the if..then cascade to a binary lookup with bisect

  3. I don't understand exactly what some of your math accomplishes, but I am very leery of your use of abs() here. Are you sure that's what you want?

  4. May not be a good idea, but for sake of demonstration: I have converted the function to a generator function using the yield statement; instead of returning an array of strings, it returns a string at a time.

.

from bisect import bisect_left

breakpoints = [-1.,  2.,   3.,   4.,   6.,   10.,  20.,  30.,  50.,  100.]
ticks       = [0.,   0.01, 0.02, 0.05, 0.1,  0.2,  0.5,  1.,   2.,   5.,   10.]

def offset_back(initial_bet, initial_odds, breakpoints=breakpoints, ticks=ticks):
    new_odds = initial_odds
    while new_odds > 1.:
        # calculate tick based on size of odds
        tick = ticks[bisect_left(breakpoints, new_odds)]
        # calculate percentage difference between initial bet and new odds
        drop = 1. - initial_odds / new_odds
        # calculate new stake, increased to cancel liability
        new_bet = initial_bet + abs(initial_bet * drop)   # are you sure abs() is correct here?
        # calculate potential profit based on the new stake - initial invested stake
        profit = new_bet - initial_bet

        new_odds -= tick
        yield " Stake: {stake:0.2f}    Odds: {odds:0.2f}    Profit: {profit:0.2f}".format(stake=abs(new_bet), odds=abs(new_odds), profit=abs(profit))

Upvotes: 2

Related Questions