Exercise: some premature optimization


In [29]:
%%file roll.py
"""
rolls a slightly biased (100-sided) die
"""

import random
import numpy as np
import numpy.random as npr

def win(x):
    '''
    a simple win/loss: where win if (100 > x > 50)
    '''
    return int(bool(100 > x > 50))


def die():
    '''     
    a simple win/loss: where win if (100 > random(1,100) > 50)
    '''         
    return win(random.randint(1,100))


_win = np.vectorize(win)


def dice(N=1):
    '''
    a simple win/loss: where win if (100 > random(1,100,N) > 50)
    '''
    return _win(npr.randint(1,100,N))


def many_die(N=1):
    '''roll simple (biased) win/loss N times'''
    rolls = []
    for i in range(N):
        rolls.append(die())
    return rolls


# EOF


Overwriting roll.py

In [2]:
%%file strategy.py
"""
betting strategies

forked from: http://pythonprogramming.net/dashboard/#tab_montecarloyo
"""

import roll
import numpy as np


def trajectory(N=1):
    """convert dice rolls True/False to +1/-1"""
    results = np.empty(N+1)
    results[0] = 0
    results[1:] = np.asarray(roll.dice(N), int)
    record = results[1:]
    record[record == 0] = -1
    return results


def clip(x):
    """clip all values to zero upon first non-positive value"""
    x[x <= 0] = 0
    x[np.logical_not(np.logical_and.accumulate(x))] = 0
    return x


def vsimple(funds, initial_wager, wager_count, *args):
    '''Simple (numpy) bettor, betting the same amount each time.'''
    wager = initial_wager
    return clip(funds + (wager * np.cumsum(trajectory(wager_count))))


def vmartingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    wager = float(initial_wager)

    history = trajectory(wager_count)
    won = history.copy()
    won[1:] = history[:-1] > -1  # also treat '0' as 'win'

    # upon losing, double the bet
    # upon winning, bet the initial
    # can't bet more than you have
    for i,w in enumerate(won[1:]):
        n = i+1
        if w:
            won[n] = 1
            continue
        scale = wscale if history[i] == 1 else lscale
        won[n] = min(scale * won[i], funds/wager + sum(history[:n] * won[:n]))
    '''# calculation looks something like this...
    history = [0, 1, 1,-1,-1, 1, 1,-1,-1,-1]
        won = [0, 1, 1, 1, 0, 0, 1, 1, 0, 0]
        bet = [0, 1, 1, 1, 2, 4, 1, 1, 2, 4]
      value = [0, 1, 1,-1,-2, 4, 1,-1,-2,-4]
    '''
    return clip(funds + (wager * np.cumsum(history * won)))


def simple(funds, initial_wager, wager_count, *args):
    '''
    Simple bettor, betting the same amount each time.
    '''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)

    currentWager = 1

    while currentWager <= wager_count:
        if roll.die():
            value += wager
            history[currentWager] = value
        else:
            value -= wager
            if value <= 0:
                break
            history[currentWager] = value
        currentWager += 1

    return history


def martingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    '''martingale bettor, "doubling-down" (actually, "*scaling-down")'''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)

    currentWager = 1

    # since we'll be betting based on previous bet outcome #
    previousWager = 'win'

    # since we'll be doubling #
    previousWagerAmount = initial_wager

    while currentWager <= wager_count:
        if previousWager == 'win':
            if roll.die():
                value += wager
                history[currentWager] = value
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager
        elif previousWager == 'loss':
            if roll.die():
                wager = previousWagerAmount * wscale
                if (value - wager) < 0:
                    wager = value
                value += wager
                history[currentWager] = value
                wager = initial_wager
                previousWager = 'win'
            else:
                wager = previousWagerAmount * lscale
                if (value - wager) < 0:
                    wager = value
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager

        currentWager += 1

    return history


def dAlembert(funds, initial_wager, wager_count, *args):
    '''d'Alembert bettor'''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)

    currentWager = 1

    # since we'll be betting based on previous bet outcome #
    previousWager = 'win'

    # since we'll be doubling #
    previousWagerAmount = initial_wager

    while currentWager <= wager_count:
        if previousWager == 'win':
            if wager == initial_wager:
                pass
            else:
                wager -= initial_wager
            if roll.die():
                value += wager
                history[currentWager] = value
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager
        elif previousWager == 'loss':
            wager = previousWagerAmount + initial_wager
            if (value - wager) < 0:
                wager = value
            if roll.die():
                value += wager
                history[currentWager] = value
                previousWager = 'win'
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager

        currentWager += 1

    return history


# for vector monte carlo
''' # could be nice, but history has different lengths
v_simple = np.vectorize(simple)
v_martingale = np.vectorize(martingale)
v_dAlembert = np.vectorize(dAlembert)
'''

# EOF


Overwriting strategy.py

In [3]:
%%file trials.py
"""
monte carlo trials for betting strategies, and measures of success
"""

import numpy as np


def monte(bettor, initial_funds, initial_bet, number_bets, number_players, W,L):
    "monte carlo run for a betting strategy"
    history = []
    while len(history) < number_players:
        history.append(bettor(initial_funds, initial_bet, number_bets, W,L))
    return np.array(history)


def alive(history, number_players):
    "find the percentage of players that are not broke"
    return 100. * sum(np.asarray(history, bool).T[-1])/number_players


def gains(history, number_players, initial_funds):
    "find the percentage of players that have profited"
    return 100. * sum(history.T[-1] > initial_funds)/number_players


def profit(history, number_players, initial_funds):
    "find the total profit"
    return np.max(history.T[-1]) - initial_funds


def margin(history, number_players, initial_funds):
    "find the percentage the return on investment is over the initial funds"
    initial = number_players * initial_funds
    return 100.* (sum(history.T[-1]) - initial)/initial


# EOF


Overwriting trials.py

In [1]:
%%file use_trials2.py
"""
usage testing of trials
"""

import numpy as np
import matplotlib.pylab as mpl
import trials
import time

def plot_trajectories(bettor, initial_funds, initial_bet, number_bets, number_players, W,L):
    "plot the Monte Carlo trajectories of a 100-sided die for the selected strategy"
    history = trials.monte(bettor, initial_funds, initial_bet, number_bets, number_players, W,L)
    mpl.plot(history.T)
    mpl.plot(initial_funds * np.ones(number_bets+1), lw=2)

    print "survived: {}%".format(trials.alive(history, number_players))
    print "profited: {}%".format(trials.gains(history, number_players, initial_funds))
    funds = trials.margin(history, number_players, initial_funds)
    funds = np.mean(funds)*initial_funds
    win = funds >= 0
    print "ave profit: {}${:.2f}".format('' if win else '-', funds if win else -funds)
    funds = trials.profit(history, number_players, initial_funds)
    win = funds >= 0
    print "max profit: {}${:.2f}".format('' if win else '-', funds if win else -funds)
    return 


def use_monte():
    import strategy
    initial_funds = 10000
    initial_bet = 100
    number_bets = 1000
    number_players = 100
    bettor = strategy.martingale
    W = L = 2.0

    return trials.monte(bettor, initial_funds, initial_bet, number_bets, number_players, W,L)


def use_vmonte():
    import strategy
    initial_funds = 10000
    initial_bet = 100
    number_bets = 1000
    number_players = 100
    bettor = strategy.vmartingale
    W = L = 2.0

    return trials.monte(bettor, initial_funds, initial_bet, number_bets, number_players, W,L)


def use_trials():
    import strategy
    initial_funds = 10000
    initial_bet = 100
    number_bets = 1000
    number_players = 100
    bettor = strategy.martingale
    W = L = 2.0

    plot_trajectories(bettor, initial_funds, initial_bet, number_bets, number_players, W,L)
    mpl.show()


def use_vtrials():
    import strategy
    initial_funds = 10000
    initial_bet = 100
    number_bets = 1000
    number_players = 100
    bettor = strategy.vmartingale
    W = L = 2.0

    plot_trajectories(bettor, initial_funds, initial_bet, number_bets, number_players, W,L)
    mpl.show()
    

# EOF


Overwriting use_trials2.py

In [9]:
%matplotlib inline

In [14]:
import numpy as np
import random
np.random.seed(123)
random.seed(123)

In [15]:
use_trials()


survived: 13.0%
profited: 13.0%
ave profit: -$243900.00
max profit: $52200.00

In [16]:
np.random.seed(123)
random.seed(123)

In [17]:
use_trials()


survived: 13.0%
profited: 13.0%
ave profit: -$243900.00
max profit: $52200.00

In [18]:
np.random.seed(123)
random.seed(123)

In [19]:
use_vtrials()


survived: 15.0%
profited: 14.0%
ave profit: -$263500.00
max profit: $54000.00

In [21]:
np.random.seed(123)
random.seed(123)
%timeit -n 10 use_monte()

np.random.seed(123)
random.seed(123)
%timeit -n 10 use_vmonte()


10 loops, best of 3: 96.6 ms per loop
10 loops, best of 3: 2.5 s per loop

In [9]:
import profiling
import roll

%timeit roll.dice(1000)
%timeit roll.many_die(1000)

profiling.profile('roll.dice(1000)')
profiling.profile('roll.many_die(1000)')


1000 loops, best of 3: 538 µs per loop
100 loops, best of 3: 2.16 ms per loop
         1018 function calls in 0.001 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.001    0.001 <string>:1(<module>)
        1    0.000    0.000    0.001    0.001 function_base.py:1672(__call__)
        1    0.000    0.000    0.000    0.000 function_base.py:1702(_get_ufunc_and_otypes)
        1    0.000    0.000    0.001    0.001 function_base.py:1758(_vectorize_call)
        2    0.000    0.000    0.000    0.000 numeric.py:394(asarray)
        1    0.000    0.000    0.001    0.001 roll.py:26(dice)
     1001    0.000    0.000    0.000    0.000 roll.py:9(win)
        1    0.000    0.000    0.000    0.000 {isinstance}
        1    0.000    0.000    0.000    0.000 {len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
        1    0.000    0.000    0.000    0.000 {method 'randint' of 'mtrand.RandomState' objects}
        4    0.000    0.000    0.000    0.000 {numpy.core.multiarray.array}
        1    0.000    0.000    0.000    0.000 {numpy.core.umath.frompyfunc}


         6004 function calls in 0.003 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.003    0.003 <string>:1(<module>)
     1000    0.001    0.000    0.001    0.000 random.py:175(randrange)
     1000    0.000    0.000    0.002    0.000 random.py:238(randint)
     1000    0.001    0.000    0.003    0.000 roll.py:16(die)
        1    0.000    0.000    0.003    0.003 roll.py:33(many_die)
     1000    0.001    0.000    0.001    0.000 roll.py:9(win)
     1000    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
     1000    0.000    0.000    0.000    0.000 {method 'random' of '_random.Random' objects}
        1    0.000    0.000    0.000    0.000 {range}



In [22]:
%%file profile_strategy.py
"""
betting strategies

forked from: http://pythonprogramming.net/dashboard/#tab_montecarloyo
"""

import roll
import numpy as np
import random


@profile
def trajectory(N=1):
    """convert dice rolls True/False to +1/-1"""
    results = np.empty(N+1)
    results[0] = 0
    results[1:] = np.asarray(roll.dice(N), int)
    record = results[1:]
    record[record == 0] = -1
    return results


@profile
def clip(x):
    """clip all values to zero upon first non-positive value"""
    x[x <= 0] = 0
    x[np.logical_not(np.logical_and.accumulate(x))] = 0
    return x


@profile
def vsimple(funds, initial_wager, wager_count, *args):
    '''Simple (numpy) bettor, betting the same amount each time.'''
    wager = initial_wager
    return clip(funds + (wager * np.cumsum(trajectory(wager_count))))


@profile
def vmartingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    wager = float(initial_wager)

    history = trajectory(wager_count)
    won = history.copy()
    won[1:] = history[:-1] > -1  # also treat '0' as 'win'

    # upon losing, double the bet
    # upon winning, bet the initial
    # can't bet more than you have
    for i,w in enumerate(won[1:]):
        n = i+1
        if w:
            won[n] = 1
            continue
        scale = wscale if history[i] == 1 else lscale
        won[n] = min(scale * won[i], funds/wager + sum(history[:n] * won[:n]))
    '''# calculation looks something like this...
    history = [0, 1, 1,-1,-1, 1, 1,-1,-1,-1]
        won = [0, 1, 1, 1, 0, 0, 1, 1, 0, 0]
        bet = [0, 1, 1, 1, 2, 4, 1, 1, 2, 4]
      value = [0, 1, 1,-1,-2, 4, 1,-1,-2,-4]
    '''
    return clip(funds + (wager * np.cumsum(history * won)))


@profile
def simple(funds, initial_wager, wager_count, *args):
    '''
    Simple bettor, betting the same amount each time.
    '''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)

    currentWager = 1

    while currentWager <= wager_count:
        if roll.die():
            value += wager
            history[currentWager] = value
        else:
            value -= wager
            if value <= 0:
                break
            history[currentWager] = value
        currentWager += 1

    return history


@profile
def martingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    '''martingale bettor, "doubling-down" (actually, "*scaling-down")'''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)

    currentWager = 1

    # since we'll be betting based on previous bet outcome #
    previousWager = 'win'

    # since we'll be doubling #
    previousWagerAmount = initial_wager

    while currentWager <= wager_count:
        if previousWager == 'win':
            if roll.die():
                value += wager
                history[currentWager] = value
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager
        elif previousWager == 'loss':
            if roll.die():
                wager = previousWagerAmount * wscale
                if (value - wager) < 0:
                    wager = value
                value += wager
                history[currentWager] = value
                wager = initial_wager
                previousWager = 'win'
            else:
                wager = previousWagerAmount * lscale
                if (value - wager) < 0:
                    wager = value
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager

        currentWager += 1

    return history



def run_trajectory(initial_funds, initial_bets, number_bets, *args, **kwds):
    "plot the rolls of a 100-sided die for all strategies"
    bettors = (simple, martingale, vsimple, vmartingale)
    for bettor in bettors:
        np.random.seed(123)
        random.seed(123)
        _ = bettor(initial_funds, initial_bets, number_bets, *args, **kwds)
    return


if __name__ == '__main__':
    initial_funds = 10000
    initial_bet = 100
    number_bets = 1000
    W = L = 2

    run_trajectory(initial_funds, initial_bet, number_bets, W,L)


# EOF


Overwriting profile_strategy.py

In [23]:
%%bash
kernprof -lv profile_strategy.py


Wrote profile results to profile_strategy.py.lprof
Timer unit: 1e-06 s

Total time: 0.002013 s
File: profile_strategy.py
Function: trajectory at line 12

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    12                                           @profile
    13                                           def trajectory(N=1):
    14                                               """convert dice rolls True/False to +1/-1"""
    15         2           13      6.5      0.6      results = np.empty(N+1)
    16         2            5      2.5      0.2      results[0] = 0
    17         2         1926    963.0     95.7      results[1:] = np.asarray(roll.dice(N), int)
    18         2            2      1.0      0.1      record = results[1:]
    19         2           67     33.5      3.3      record[record == 0] = -1
    20         2            0      0.0      0.0      return results

Total time: 5.8e-05 s
File: profile_strategy.py
Function: clip at line 23

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    23                                           @profile
    24                                           def clip(x):
    25                                               """clip all values to zero upon first non-positive value"""
    26         2           18      9.0     31.0      x[x <= 0] = 0
    27         2           39     19.5     67.2      x[np.logical_not(np.logical_and.accumulate(x))] = 0
    28         2            1      0.5      1.7      return x

Total time: 0.00113 s
File: profile_strategy.py
Function: vsimple at line 31

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    31                                           @profile
    32                                           def vsimple(funds, initial_wager, wager_count, *args):
    33                                               '''Simple (numpy) bettor, betting the same amount each time.'''
    34         1            0      0.0      0.0      wager = initial_wager
    35         1         1130   1130.0    100.0      return clip(funds + (wager * np.cumsum(trajectory(wager_count))))

Total time: 0.027562 s
File: profile_strategy.py
Function: vmartingale at line 38

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    38                                           @profile
    39                                           def vmartingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    40         1            1      1.0      0.0      wager = float(initial_wager)
    41                                           
    42         1          977    977.0      3.5      history = trajectory(wager_count)
    43         1            2      2.0      0.0      won = history.copy()
    44         1           18     18.0      0.1      won[1:] = history[:-1] > -1  # also treat '0' as 'win'
    45                                           
    46                                               # upon losing, double the bet
    47                                               # upon winning, bet the initial
    48                                               # can't bet more than you have
    49      1001          592      0.6      2.1      for i,w in enumerate(won[1:]):
    50      1000          466      0.5      1.7          n = i+1
    51      1000          449      0.4      1.6          if w:
    52       491          278      0.6      1.0              won[n] = 1
    53       491          192      0.4      0.7              continue
    54       509          492      1.0      1.8          scale = wscale if history[i] == 1 else lscale
    55       509        24050     47.2     87.3          won[n] = min(scale * won[i], funds/wager + sum(history[:n] * won[:n]))
    56                                               '''# calculation looks something like this...
    57                                               history = [0, 1, 1,-1,-1, 1, 1,-1,-1,-1]
    58                                                   won = [0, 1, 1, 1, 0, 0, 1, 1, 0, 0]
    59                                                   bet = [0, 1, 1, 1, 2, 4, 1, 1, 2, 4]
    60                                                 value = [0, 1, 1,-1,-2, 4, 1,-1,-2,-4]
    61                                               '''
    62         1           45     45.0      0.2      return clip(funds + (wager * np.cumsum(history * won)))

Total time: 0.007904 s
File: profile_strategy.py
Function: simple at line 65

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    65                                           @profile
    66                                           def simple(funds, initial_wager, wager_count, *args):
    67                                               '''
    68                                               Simple bettor, betting the same amount each time.
    69                                               '''
    70         1            4      4.0      0.1      value = funds
    71         1            1      1.0      0.0      wager = initial_wager
    72         1            1      1.0      0.0      wager_count = int(wager_count)
    73         1            9      9.0      0.1      history = [funds] + [0]*(wager_count)
    74                                           
    75         1            0      0.0      0.0      currentWager = 1
    76                                           
    77      1001          401      0.4      5.1      while currentWager <= wager_count:
    78      1000         5832      5.8     73.8          if roll.die():
    79       468          211      0.5      2.7              value += wager
    80       468          226      0.5      2.9              history[currentWager] = value
    81                                                   else:
    82       532          262      0.5      3.3              value -= wager
    83       532          242      0.5      3.1              if value <= 0:
    84                                                           break
    85       532          262      0.5      3.3              history[currentWager] = value
    86      1000          453      0.5      5.7          currentWager += 1
    87                                           
    88         1            0      0.0      0.0      return history

Total time: 0.000205 s
File: profile_strategy.py
Function: martingale at line 91

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    91                                           @profile
    92                                           def martingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    93                                               '''martingale bettor, "doubling-down" (actually, "*scaling-down")'''
    94         1            0      0.0      0.0      value = funds
    95         1            1      1.0      0.5      wager = initial_wager
    96         1            1      1.0      0.5      wager_count = int(wager_count)
    97         1           12     12.0      5.9      history = [funds] + [0]*(wager_count)
    98                                           
    99         1            0      0.0      0.0      currentWager = 1
   100                                           
   101                                               # since we'll be betting based on previous bet outcome #
   102         1            0      0.0      0.0      previousWager = 'win'
   103                                           
   104                                               # since we'll be doubling #
   105         1            0      0.0      0.0      previousWagerAmount = initial_wager
   106                                           
   107        16            9      0.6      4.4      while currentWager <= wager_count:
   108        16           10      0.6      4.9          if previousWager == 'win':
   109         4           27      6.8     13.2              if roll.die():
   110                                                           value += wager
   111                                                           history[currentWager] = value
   112                                                       else:
   113         4            3      0.8      1.5                  value -= wager
   114         4            2      0.5      1.0                  if value <= 0:
   115                                                               break
   116         4            3      0.8      1.5                  history[currentWager] = value
   117         4            2      0.5      1.0                  previousWager = 'loss'
   118         4            3      0.8      1.5                  previousWagerAmount = wager
   119        12            7      0.6      3.4          elif previousWager == 'loss':
   120        12           75      6.2     36.6              if roll.die():
   121         3            3      1.0      1.5                  wager = previousWagerAmount * wscale
   122         3            2      0.7      1.0                  if (value - wager) < 0:
   123                                                               wager = value
   124         3            0      0.0      0.0                  value += wager
   125         3            0      0.0      0.0                  history[currentWager] = value
   126         3            0      0.0      0.0                  wager = initial_wager
   127         3            1      0.3      0.5                  previousWager = 'win'
   128                                                       else:
   129         9            6      0.7      2.9                  wager = previousWagerAmount * lscale
   130         9            4      0.4      2.0                  if (value - wager) < 0:
   131         1            0      0.0      0.0                      wager = value
   132         9            4      0.4      2.0                  value -= wager
   133         9            5      0.6      2.4                  if value <= 0:
   134         1            1      1.0      0.5                      break
   135         8            4      0.5      2.0                  history[currentWager] = value
   136         8            4      0.5      2.0                  previousWager = 'loss'
   137         8            5      0.6      2.4                  previousWagerAmount = wager
   138                                           
   139        15           10      0.7      4.9          currentWager += 1
   140                                           
   141         1            1      1.0      0.5      return history


In [24]:
%%file profile_strategy2.py
"""
betting strategies

forked from: http://pythonprogramming.net/dashboard/#tab_montecarloyo
"""

import roll
import numpy as np
import random


#@profile
def trajectory(N=1):
    """convert dice rolls True/False to +1/-1"""
    results = np.empty(N+1)
    results[0] = 0
    results[1:] = np.asarray(roll.dice(N), int)
    record = results[1:]
    record[record == 0] = -1
    return results


#@profile
def clip(x):
    """clip all values to zero upon first non-positive value"""
    x[x <= 0] = 0
    x[np.logical_not(np.logical_and.accumulate(x))] = 0
    return x


#@profile
def vsimple(funds, initial_wager, wager_count, *args):
    '''Simple (numpy) bettor, betting the same amount each time.'''
    wager = initial_wager
    return clip(funds + (wager * np.cumsum(trajectory(wager_count))))


#@profile
def vmartingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    wager = float(initial_wager)

    history = trajectory(wager_count)
    won = history.copy()
    won[1:] = history[:-1] > -1  # also treat '0' as 'win'

    # upon losing, double the bet
    # upon winning, bet the initial
    # can't bet more than you have
    for i,w in enumerate(won[1:]):
        n = i+1
        if w:
            won[n] = 1
            continue
        scale = wscale if history[i] == 1 else lscale
        won[n] = min(scale * won[i], funds/wager + sum(history[:n] * won[:n]))
    '''# calculation looks something like this...
    history = [0, 1, 1,-1,-1, 1, 1,-1,-1,-1]
        won = [0, 1, 1, 1, 0, 0, 1, 1, 0, 0]
        bet = [0, 1, 1, 1, 2, 4, 1, 1, 2, 4]
      value = [0, 1, 1,-1,-2, 4, 1,-1,-2,-4]
    '''
    return clip(funds + (wager * np.cumsum(history * won)))


@profile
def simple(funds, initial_wager, wager_count, *args):
    '''
    Simple bettor, betting the same amount each time.
    '''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)
    roll_die = roll.dice(wager_count+1)


    currentWager = 1

    while currentWager <= wager_count:
        if roll_die[currentWager]:
            value += wager
            history[currentWager] = value
        else:
            value -= wager
            if value <= 0:
                break
            history[currentWager] = value
        currentWager += 1

    return history


@profile
def martingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    '''martingale bettor, "doubling-down" (actually, "*scaling-down")'''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)
    roll_die = roll.dice(wager_count+1)


    currentWager = 1

    # since we'll be betting based on previous bet outcome #
    previousWager = 'win'

    # since we'll be doubling #
    previousWagerAmount = initial_wager

    while currentWager <= wager_count:
        if previousWager == 'win':
            if roll_die[currentWager]:
                value += wager
                history[currentWager] = value
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager
        elif previousWager == 'loss':
            if roll_die[currentWager]:
                wager = previousWagerAmount * wscale
                if (value - wager) < 0:
                    wager = value
                value += wager
                history[currentWager] = value
                wager = initial_wager
                previousWager = 'win'
            else:
                wager = previousWagerAmount * lscale
                if (value - wager) < 0:
                    wager = value
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager

        currentWager += 1

    return history



def run_trajectory(initial_funds, initial_bets, number_bets, *args, **kwds):
    "plot the rolls of a 100-sided die for all strategies"
    bettors = (simple, martingale, vsimple, vmartingale)
    for bettor in bettors:
        np.random.seed(123)
        random.seed(123)
        _ = bettor(initial_funds, initial_bets, number_bets, *args, **kwds)
    return


if __name__ == '__main__':
    initial_funds = 10000
    initial_bet = 100
    number_bets = 1000
    W = L = 2

    run_trajectory(initial_funds, initial_bet, number_bets, W,L)


# EOF


Overwriting profile_strategy2.py

In [25]:
%%bash
kernprof -lv profile_strategy2.py


Wrote profile results to profile_strategy2.py.lprof
Timer unit: 1e-06 s

Total time: 0.003621 s
File: profile_strategy2.py
Function: simple at line 65

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    65                                           @profile
    66                                           def simple(funds, initial_wager, wager_count, *args):
    67                                               '''
    68                                               Simple bettor, betting the same amount each time.
    69                                               '''
    70         1            3      3.0      0.1      value = funds
    71         1            0      0.0      0.0      wager = initial_wager
    72         1            1      1.0      0.0      wager_count = int(wager_count)
    73         1           10     10.0      0.3      history = [funds] + [0]*(wager_count)
    74         1          989    989.0     27.3      roll_die = roll.dice(wager_count+1)
    75                                           
    76                                           
    77         1            0      0.0      0.0      currentWager = 1
    78                                           
    79      1001          428      0.4     11.8      while currentWager <= wager_count:
    80      1000          531      0.5     14.7          if roll_die[currentWager]:
    81       490          227      0.5      6.3              value += wager
    82       490          231      0.5      6.4              history[currentWager] = value
    83                                                   else:
    84       510          229      0.4      6.3              value -= wager
    85       510          257      0.5      7.1              if value <= 0:
    86                                                           break
    87       510          247      0.5      6.8              history[currentWager] = value
    88      1000          467      0.5     12.9          currentWager += 1
    89                                           
    90         1            1      1.0      0.0      return history

Total time: 0.001582 s
File: profile_strategy2.py
Function: martingale at line 93

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    93                                           @profile
    94                                           def martingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    95                                               '''martingale bettor, "doubling-down" (actually, "*scaling-down")'''
    96         1            0      0.0      0.0      value = funds
    97         1            1      1.0      0.1      wager = initial_wager
    98         1            1      1.0      0.1      wager_count = int(wager_count)
    99         1            9      9.0      0.6      history = [funds] + [0]*(wager_count)
   100         1          918    918.0     58.0      roll_die = roll.dice(wager_count+1)
   101                                           
   102                                           
   103         1            1      1.0      0.1      currentWager = 1
   104                                           
   105                                               # since we'll be betting based on previous bet outcome #
   106         1            1      1.0      0.1      previousWager = 'win'
   107                                           
   108                                               # since we'll be doubling #
   109         1            1      1.0      0.1      previousWagerAmount = initial_wager
   110                                           
   111       123           57      0.5      3.6      while currentWager <= wager_count:
   112       123           66      0.5      4.2          if previousWager == 'win':
   113        62           41      0.7      2.6              if roll_die[currentWager]:
   114        29           16      0.6      1.0                  value += wager
   115        29           20      0.7      1.3                  history[currentWager] = value
   116                                                       else:
   117        33           17      0.5      1.1                  value -= wager
   118        33           22      0.7      1.4                  if value <= 0:
   119                                                               break
   120        33           18      0.5      1.1                  history[currentWager] = value
   121        33           16      0.5      1.0                  previousWager = 'loss'
   122        33           17      0.5      1.1                  previousWagerAmount = wager
   123        61           29      0.5      1.8          elif previousWager == 'loss':
   124        61           36      0.6      2.3              if roll_die[currentWager]:
   125        32           21      0.7      1.3                  wager = previousWagerAmount * wscale
   126        32           22      0.7      1.4                  if (value - wager) < 0:
   127                                                               wager = value
   128        32           17      0.5      1.1                  value += wager
   129        32           18      0.6      1.1                  history[currentWager] = value
   130        32           16      0.5      1.0                  wager = initial_wager
   131        32           14      0.4      0.9                  previousWager = 'win'
   132                                                       else:
   133        29           18      0.6      1.1                  wager = previousWagerAmount * lscale
   134        29           16      0.6      1.0                  if (value - wager) < 0:
   135         1            1      1.0      0.1                      wager = value
   136        29           14      0.5      0.9                  value -= wager
   137        29           15      0.5      0.9                  if value <= 0:
   138         1            1      1.0      0.1                      break
   139        28           18      0.6      1.1                  history[currentWager] = value
   140        28           15      0.5      0.9                  previousWager = 'loss'
   141        28           17      0.6      1.1                  previousWagerAmount = wager
   142                                           
   143       122           71      0.6      4.5          currentWager += 1
   144                                           
   145         1            1      1.0      0.1      return history


In [26]:
%%file strategy.py
"""
betting strategies

forked from: http://pythonprogramming.net/dashboard/#tab_montecarloyo
"""

import roll


def simple(funds, initial_wager, wager_count, *args):
    '''
    Simple bettor, betting the same amount each time.
    '''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)
    roll_die = roll.dice(wager_count+1)


    currentWager = 1

    while currentWager <= wager_count:
        if roll_die[currentWager]:
            value += wager
            history[currentWager] = value
        else:
            value -= wager
            if value <= 0:
                break
            history[currentWager] = value
        currentWager += 1

    return history


def martingale(funds, initial_wager, wager_count, wscale=1, lscale=1):
    '''martingale bettor, "doubling-down" (actually, "*scaling-down")'''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)
    roll_die = roll.dice(wager_count+1)


    currentWager = 1

    # since we'll be betting based on previous bet outcome #
    previousWager = 'win'

    # since we'll be doubling #
    previousWagerAmount = initial_wager

    while currentWager <= wager_count:
        if previousWager == 'win':
            if roll_die[currentWager]:
                value += wager
                history[currentWager] = value
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager
        elif previousWager == 'loss':
            if roll_die[currentWager]:
                wager = previousWagerAmount * wscale
                if (value - wager) < 0:
                    wager = value
                value += wager
                history[currentWager] = value
                wager = initial_wager
                previousWager = 'win'
            else:
                wager = previousWagerAmount * lscale
                if (value - wager) < 0:
                    wager = value
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager

        currentWager += 1

    return history


def dAlembert(funds, initial_wager, wager_count, *args):
    '''d'Alembert bettor'''
    value = funds
    wager = initial_wager
    wager_count = int(wager_count)
    history = [funds] + [0]*(wager_count)
    roll_die = roll.dice(wager_count+1)


    currentWager = 1

    # since we'll be betting based on previous bet outcome #
    previousWager = 'win'

    # since we'll be doubling #
    previousWagerAmount = initial_wager

    while currentWager <= wager_count:
        if previousWager == 'win':
            if wager == initial_wager:
                pass
            else:
                wager -= initial_wager
            if roll_die[currentWager]:
                value += wager
                history[currentWager] = value
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager
        elif previousWager == 'loss':
            wager = previousWagerAmount + initial_wager
            if (value - wager) < 0:
                wager = value
            if roll_die[currentWager]:
                value += wager
                history[currentWager] = value
                previousWager = 'win'
            else:
                value -= wager
                if value <= 0:
                    break
                history[currentWager] = value
                previousWager = 'loss'
                previousWagerAmount = wager

        currentWager += 1

    return history


# EOF


Overwriting strategy.py

In [28]:
np.random.seed(123)
random.seed(123)
import use_trials2
%timeit -n 10 use_trials2.use_monte()


10 loops, best of 3: 95.8 ms per loop