As promised; here's the code you need, Thanks to Birchy on the Slack Group
import os
from random import random
from matplotlib import pyplot
from tkinter import *
from tkinter import filedialog
from time import time
gui = Tk()
home_path = os.path.expanduser('~')
init_dir = os.path.join(home_path, 'Downloads')
init_path = os.path.join(init_dir, 'BetHistory.csv')
csv_path = StringVar(gui, value=init_path)
mc_iters = IntVar(gui, value=10) # initial number of MC iterations
csv_bets = []
def update_file_path():
hist_path = filedialog.askopenfilename(
parent=gui,
initialdir=init_dir,
title='Choose BetHistory file',
filetypes=[('csv', '*.csv')]
)
if hist_path:
# update label
csv_path.set(hist_path)
def load_csv():
global csv_bets
csv_bets = []
with open(csv_path.get(), 'r') as f:
for row in reversed(f.readlines()[1:]):
cols = list(row.split(','))
if len(cols) != 12:
continue # corrupted csv data
# convert csv strings to floats
for i, v in enumerate(cols):
if i < 7: continue
try:
if '(' in cols:
cols = cols.replace('(', '-').partition(')')[0]
cols = float(cols)
except:
pass
cols[2] = cols[2].upper() # bet side
# add extra info for Monte Carlo lookups
side = cols[2] # 'BACK', 'LAY'
stake = cols[8] # bet stake
price = cols[10] # avg price matched
payout = round(stake * (price - 1), 2) # back win or lay payout
mc_lookup = {
'p_win': 1 / price, # implied probability
True: 0.0, # return if runner wins
False: 0.0, # return if runner loses
}
if side == 'BACK':
mc_lookup[True] = payout # return if runner wins
mc_lookup[False] = -stake # return if runner loses
elif side == 'LAY':
mc_lookup[True] = -payout # return if runner wins
mc_lookup[False] = stake # return if runner loses
cols.append(mc_lookup)
# update cache
csv_bets.append(cols)
def calc_actual_pnl():
"""returns (P&L, ROI, PLOT) tuple"""
load_csv()
total_pnl = 0.0
total_risk = 0.0
roi = 0.0
pnl_plots = []
for bet in csv_bets:
if bet[2] == 'BACK': bet[9] = bet[8] # liability = stake
total_risk = round(total_risk + bet[9], 2)
total_pnl = round(total_pnl + bet[11], 2)
pnl_plots.append(total_pnl)
if total_risk > 0:
roi = round(100 * (total_pnl / total_risk), 2)
return total_pnl, roi, pnl_plots
def plot_graph():
total_pnl, roi, pnl_plots = calc_actual_pnl()
if total_pnl:
# maximise plot window
mngr = pyplot.get_current_fig_manager()
try:
mngr.window.state('zoomed') # OS = WINDOWS
except:
# not tested on OSX/Linux!
pass
pyplot.plot(pnl_plots)
pyplot.xlabel('BETS')
pyplot.ylabel('P&L')
title = 'P&L: %.2f ROI: %.2f%%' % (total_pnl, roi)
pyplot.title(title)
pyplot.show()
def run_monte_carlo():
# calc actual P&L
total_pnl, roi, pnl_plots = calc_actual_pnl()
# run MC
label_mc_result['text'] = ''
button_path['state'] = 'disabled'
button_mc_start['state'] = 'disabled'
button_plot['state'] = 'disabled'
mc_better_count = 0
mc_run_count = int(mc_iters.get() * 1000)
iupdate = 0
start_time = time()
max_drawdown = 0.0
dd_mean_sum, dd_mean_count = 0.0, 0
for i in range(mc_run_count):
mc_pnl, max_pnl = 0.0, 0.0
iupdate += 1
if iupdate > 50:
# update gui
prog = 'Running: %d/%d' % (i, mc_run_count)
label_mc_result['text'] = prog
gui.update()
iupdate = 0
sample_dd = 0.0
for bet in csv_bets:
mc_lookup = bet[12]
runner_wins = random() <= mc_lookup['p_win'] # MC random result
mc_pnl += mc_lookup[runner_wins]
if mc_pnl > max_pnl: max_pnl = mc_pnl
dd = max_pnl - mc_pnl
if dd > sample_dd: sample_dd = dd
if sample_dd > max_drawdown: max_drawdown = sample_dd
dd_mean_sum += sample_dd
dd_mean_count += 1
# did MC P&L beat our actual P&L?
if mc_pnl > total_pnl:
mc_better_count += 1
# outputs
run_time = time() - start_time
eval_count = mc_run_count * len(csv_bets) # total evaluations
mc_better_percentage = 100 * (mc_better_count / mc_run_count)
msg = 'Statistics:\n'
msg += '* Completed %.1fM evaluations in %.2fs\n' % (eval_count / 1e6, run_time)
msg += '* Analysed %d strategy bets\n' % len(csv_bets)
msg += '* Monte Carlo beats strategy: '
msg += '%d times in %d runs (%.2f%%)\n' % (mc_better_count, mc_run_count, mc_better_percentage)
msg += '* Drawdown: max = %.2f, mean = %.2f' % (max_drawdown, dd_mean_sum / dd_mean_count)
label_mc_result['text'] = msg
button_path['state'] = 'normal'
button_plot['state'] = 'normal'
button_mc_start['state'] = 'normal'
gui.update()
# set main window size & header font
gui.geometry('450x300') # main window size
gui.title('BetHistory.csv Analysis')
# file path gui
button_path = Button(gui, text='Change', command=update_file_path)
button_path.place(x=20, y=16)
label_file = Label(gui, text='FILE:')
label_file.place(x=85, y=20)
label_path = Label(gui, textvariable=csv_path)
label_path.place(x=120, y=20)
# plotting gui
button_plot = Button(gui, text='Plot P&L Graph', command=plot_graph)
button_plot.place(x=20, y=80)
# Monte Carlo gui
input_mc_iters = Entry(gui, textvariable=mc_iters, justify='center')
input_mc_iters.place(x=140, y=141, width=40, height=24)
button_mc_start = Button(gui, text='Run Monte Carlo', command=run_monte_carlo)
button_mc_start.place(x=20, y=140)
label_mc = Label(gui, text='x1000 iterations')
label_mc.place(x=180, y=142)
label_mc_result = Label(gui, justify=LEFT)
label_mc_result.place(x=20, y=170)
gui.mainloop()
Automation Strategies
It is essentially just replaying your bets in random "buckets" in random "orders" so you can assess drawdown and such... not sure it can truly help you know how "fitted" your strategy is?
I actually think the random exit idea is a possible way of helping understand how "fitted" your strategy might be see ref here: https://www.seeitmarket.com/3-of-many-u ... ing-18266/
I actually think the random exit idea is a possible way of helping understand how "fitted" your strategy might be see ref here: https://www.seeitmarket.com/3-of-many-u ... ing-18266/
- Realrocknrolla
- Posts: 1903
- Joined: Fri Jun 05, 2020 7:15 pm
Yes, i'm good at "shit" stuff, rubbish at "trading"Realrocknrolla wrote: ↑Wed May 12, 2021 6:16 pmI like colours.
But i cant do shit like that. My skills are not up there yet.
- Realrocknrolla
- Posts: 1903
- Joined: Fri Jun 05, 2020 7:15 pm
Lolgoat68 wrote: ↑Wed May 12, 2021 6:20 pmYes, i'm good at "shit" stuff, rubbish at "trading"Realrocknrolla wrote: ↑Wed May 12, 2021 6:16 pmI like colours.
But i cant do shit like that. My skills are not up there yet.
I can manual trade fine. Automation and programming im dump at.