In sports trading, we face a great deal of risk and uncertainty that we often express initially as a series of questions.
- What is my target bankroll?
- How much am I willing to lose?
- What are my chances of success?
- Over how many events (session length) should I set this goal?
- How much should I risk per event?
First, it is essential to clarify what we mean by "Win-Goal" and "Loss-Limit":
- Win-Goal: Predefined profit target that we aim to achieve within a specific session or over a certain number of events.
- Loss-Limit: Maximum amount of capital that we are prepared to lose during the same period.
Setting these parameters helps us to manage our bankrolls effectively.
Second, using historical data on win probabilities and win odds, we will run a series of Monte Carlo simulations of thousands of trading sessions.
- Win-Goal Probability: We calculate the likelihood of achieving various win goals before reaching the loss limit over a predetermined number of events (trading opportunities).
- Sensitivity Analysis: We assess how different settings of loss limits and stakes affect the probability of achieving the win goal before reaching the loss limit.
Third, let us consider a simple example. We will set the following parameters (Not meant to be either realistic or recommended):
- Bankroll: 1000
- Loss-Limit: 25% (bankroll)
- Win Odds: 2.50
- Win Probability: 42%
- Number of Events: 20
We want to know the probability of reaching win goals of 125 and 175 over these 20 events. Using the simulated scenario, we get these results:
- Probability of reaching a win goal of 125 over 20 events: 30.57%
- Probability of reaching a win goal of 175 over 20 events: 30.57%
It might seem odd that the probabilities of reaching different win goals (125 and 175) are identical at 30.57%. This could occur due to several reasons:
- Statistical Anomaly: In some simulation runs, due to the randomness inherent in Monte Carlo methods, outcomes might align by chance.
- Dominant Loss-Limit Effect: If the loss limit is highly restrictive, it might prevent the bankroll from fluctuating significantly. In such cases, once a certain profit level is achievable, higher profits might also become equally probable if losses are tightly controlled.
- Stake Size and Market Limits: The fixed stake size and the limited number of events might create scenarios where reaching any profit above a certain threshold (like 125) doesn't significantly change the odds of achieving even higher profits within the constraints of the model.
The Python script below allows us to evaluate trading sessions based on realistic statistical simulations. By adjusting win goals and loss limits according to the simulation results, we can better manage our risk and potentially increase our profitability.
This approach to risk management not only enhances our understanding of the strategy's robustness but also encourages a disciplined approach to trading, essential for long-term success.
# -*- coding: latin-1 -*-
import random
from datetime import date
from functools import reduce
from scipy.stats import beta
from tabulate import tabulate
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
__date__ = str(date.today())
__query__ = ''
__title__ = 'Win-Goal Less Than Loss-Limit'
__author__ = 'matekus'
__version__ = 'v1.02'
__copyright__ = '(c) 2024, ' + __author__ + ', All Rights Reserved.'
__address__ = '[ https://vendire-ludorum.blogspot.com/ ]'
def monte_carlo_simulation(bankroll, win_prob, win_odds, loss_limit, win_goals, stake, markets, trials) -> list:
wins = [0] * len(win_goals)
for _ in range(trials):
current_bankroll = bankroll
for _ in range(markets):
current_bankroll += stake * (win_odds - 1) if random.random() < win_prob else -stake
if current_bankroll <= bankroll - loss_limit:
break
wins = [wins[i] + 1 if current_bankroll >= bankroll + goal else wins[i] for i, goal in enumerate(win_goals)]
probabilities = [win / trials for win in wins]
return probabilities
def print_monte_carlo_results(state) -> dict:
new_state = state.copy()
bankroll = new_state['bankroll']
win_prob = new_state['win_prob']
win_odds = new_state['win_odds']
win_goals = new_state['win_goals']
stakes_percentages = new_state['stakes_percentages']
loss_limit_percentages = new_state['loss_limit_percentages']
markets = new_state['markets']
trials = new_state['trials']
# Calculate loss limits for each percentage
loss_limits = [bankroll * llp for llp in loss_limit_percentages]
print('')
print(f'Bankroll: {bankroll:.0f}')
for loss_limit in loss_limits:
print(f'Drawdown Limit for {loss_limit/bankroll*100:.0f}%: {bankroll - loss_limit:.0f}')
print('')
# Run the Monte-Carlo simulation for each stake and loss limit
for stake_percentage in stakes_percentages:
stake = stake_percentage * bankroll
for loss_limit in loss_limits:
probabilities = monte_carlo_simulation(bankroll, win_prob, win_odds, loss_limit, win_goals, stake, markets, trials)
print(f'Stake: {stake_percentage*100:.0f}% of bankroll - {stake:.0f}')
print(f'Loss-Limit: {loss_limit:.0f}')
for i, goal in enumerate(win_goals):
print(f' Probability of reaching a win goal of {goal} over {markets} events: {probabilities[i]:.2%}')
print('')
return new_state
def main() -> None:
print('')
print(__title__)
print(__copyright__)
print(__address__)
print('')
print('[', __date__, ']')
print('')
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument("-b", "--bankroll", default=1000.0, type=float, help="Initial bankroll.")
parser.add_argument("-llp", "--loss_limit_percentages", nargs='+', type=float, default=[0.25], help="Loss limit percentages.")
parser.add_argument("-wo", "--win_odds", default=2.50, type=float, help="Win odds (historic).")
parser.add_argument("-wp", "--win_prob", default=0.42, type=float, help="Win probability (historic).")
parser.add_argument("-wg", "--win_goals", default=[125, 175], type=list, help="Win goals.")
parser.add_argument("-sp", "--stakes_percentages", default=[0.01, 0.02, 0.03], type=list, help="Stakes percentages.")
parser.add_argument("-m", "--markets", default=20, type=int, help="Number of markets.")
args = vars(parser.parse_args())
# Define pipeline with updated steps
pipeline = [
print_monte_carlo_results
]
# Define initial state.
initial_state = {
'bankroll': args["bankroll"],
'loss_limit_percentages': args["loss_limit_percentages"],
'win_odds': args["win_odds"],
'win_prob': args["win_prob"],
'win_goals': args["win_goals"],
'stakes_percentages': args["stakes_percentages"],
'markets': args["markets"],
'trials': 10000,
}
# Run pipeline.
_ = reduce(lambda v, f: f(v), pipeline, initial_state)
print('')
print('Fini!')
print('')
if __name__ == '__main__':
main()
"""
> python Win-Goal_Less-Than_Loss-Limit.py -b 1500
Win-Goal Less Than Loss-Limit
(c) 2024, matekus, All Rights Reserved.
[ https://vendire-ludorum.blogspot.com/ ]
[ 2024-04-29 ]
Bankroll: 1500
Drawdown Limit for 25%: 1125
Stake: 1% of bankroll - 15
Loss-Limit: 375
Probability of reaching a win goal of 125 over 20 events: 8.28%
Probability of reaching a win goal of 175 over 20 events: 2.95%
Stake: 2% of bankroll - 30
Loss-Limit: 375
Probability of reaching a win goal of 125 over 20 events: 31.15%
Probability of reaching a win goal of 175 over 20 events: 16.88%
Stake: 3% of bankroll - 45
Loss-Limit: 375
Probability of reaching a win goal of 125 over 20 events: 30.74%
Probability of reaching a win goal of 175 over 20 events: 30.74%
Fini!
"""
# EOF.
As ever, the script has little or no "errr0r" handling and is only a starting point for your own explorations. Enjoy!