-
Notifications
You must be signed in to change notification settings - Fork 5
/
backtesting.py
166 lines (127 loc) · 6.85 KB
/
backtesting.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# The idea of this script is to test how much money we would have made or lost
# by using the 2017-2018 season and betting to make £2 whenever we find value
from collections import namedtuple
import os
import numpy as np
import matplotlib.pyplot as plt
import fifa_ratings_predictor.constants as constants
from fifa_ratings_predictor.data_methods import read_match_data, read_player_data, normalise_features, \
assign_odds_to_match, read_all_football_data
from fifa_ratings_predictor.matching import match_lineups_to_fifa_players, create_feature_vector_from_players
from fifa_ratings_predictor.model import NeuralNet
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
Bet = namedtuple('Bet', ['true_odds', 'predicted_odds', 'stake', 'type', 'profit', 'match'])
class BetTracker:
def __init__(self):
self.invested = 0
self.pending_bet = None
self.completed_bets = []
self.profit = 0
self.bankroll = 100
def make_bet(self, bet):
self.pending_bet = bet
self.invested += bet.stake
self.bankroll -= bet.stake
def bet_won(self):
self.profit += self.pending_bet.profit
self.bankroll += self.pending_bet.stake + self.pending_bet.profit
self.completed_bets.append((self.pending_bet, 'W'))
self.pending_bet = None
def bet_lost(self):
self.profit -= self.pending_bet.stake
self.completed_bets.append((self.pending_bet, 'L'))
self.pending_bet = None
@property
def roi(self):
return self.profit / self.invested
def calculate_profit(bet):
return bet.stake * bet.odds - bet.stake
def calculate_stake(odds, method='constant profit', constant_profit=2, probability=None):
assert method in ['constant_profit', 'kelly']
if method == 'constant_profit':
stake = constant_profit / (odds - 1)
elif method == 'kelly':
stake = ((odds * probability) - 1) / (odds - 1)
return stake
def main():
bet_tracker = BetTracker()
match_data = read_match_data(season='2017-2018', league='E0')
match_data = assign_odds_to_match(match_data, read_all_football_data(league='E0'))
player_data = read_player_data(season='2017-2018')
net = NeuralNet()
bank =[100]
all_odds = []
errors = 0
for match in match_data:
print(match['info']['date'], match['info']['home team'], match['info']['away team'])
try:
home_players_matched = match_lineups_to_fifa_players(match['info']['home lineup names'],
match['info']['home lineup numbers'],
match['info']['home lineup nationalities'],
constants.LINEUP_TO_PLAYER_TEAM_MAPPINGS['ALL'][
match['info']['home team']], match['info']['season'],
player_data)
away_players_matched = match_lineups_to_fifa_players(match['info']['away lineup names'],
match['info']['away lineup numbers'],
match['info']['away lineup nationalities'],
constants.LINEUP_TO_PLAYER_TEAM_MAPPINGS['ALL'][
match['info']['away team']], match['info']['season'],
player_data)
home_feature_vector = create_feature_vector_from_players(home_players_matched)
away_feature_vector = create_feature_vector_from_players(away_players_matched)
feature_vector = np.array(home_feature_vector + away_feature_vector).reshape(-1, 36)
feature_vector = normalise_features(feature_vector)
probabilities = net.predict(feature_vector, model_name='./models/E0/deep')
pred_home_odds, pred_draw_odds, pred_away_odds = [1 / x for x in probabilities[0]]
home_odds, draw_odds, away_odds = match['info']['home odds'], match['info']['draw odds'], match['info'][
'away odds']
all_odds.append((pred_home_odds, home_odds))
all_odds.append((pred_away_odds, away_odds))
if pred_home_odds < home_odds < 3.2 and 0.02 <= probabilities[0][0] - 1/home_odds:
stake = calculate_stake(home_odds, probability=1 / pred_home_odds, method='constant_profit')
profit = stake * home_odds - stake
bet = Bet(true_odds=home_odds, predicted_odds=pred_home_odds, stake=stake, profit=profit, match=match,
type='home')
bet_tracker.make_bet(bet)
if match['info']['home goals'] > match['info']['away goals']:
bet_tracker.bet_won()
else:
bet_tracker.bet_lost()
bank.append(bet_tracker.bankroll)
elif pred_away_odds < away_odds < 3.2 and 0.02 <= probabilities[0][2] - 1/away_odds:
stake = calculate_stake(away_odds, probability=1 / pred_away_odds, method='constant_profit')
profit = stake * away_odds - stake
bet = Bet(true_odds=away_odds, predicted_odds=pred_away_odds, stake=stake, profit=profit, match=match,
type='away')
bet_tracker.make_bet(bet)
if match['info']['home goals'] < match['info']['away goals']:
bet_tracker.bet_won()
else:
bet_tracker.bet_lost()
bank.append(bet_tracker.bankroll)
except Exception as exception:
print(exception)
errors += 1
return bet_tracker, bank, all_odds
def plot_backtest(bankroll, roi, plot_title, name='graph.png'):
import matplotlib.font_manager
flist = matplotlib.font_manager.get_fontconfig_fonts()
for fname in flist:
try:
s = matplotlib.font_manager.FontProperties(fname=fname).get_name()
if 'bank' in s:
props = matplotlib.font_manager.FontProperties(fname=fname)
except RuntimeError:
pass
propies = dict(boxstyle='round', facecolor='#225599')
fig = plt.figure()
ax = plt.axes()
plt.plot(np.arange(len(bankroll)), bankroll, c='#113355')
ax.text(0.05, 0.95, 'ROI: %{}'.format(roi), transform=ax.transAxes, fontsize=6,
verticalalignment='top', bbox=propies, fontproperties=props)
fig.set_facecolor('#aabbcc')
ax.set_facecolor('#aabbcc')
ax.set_title(plot_title, fontproperties=props, color="#223355")
plt.savefig(name, dpi=300, bbox_inches='tight', facecolor=fig.get_facecolor())
if __name__ == '__main__':
tracker, bankroll, odds = main()