Autosave, more charts & layout.

This commit is contained in:
Jamie Cash
2021-03-01 17:59:25 +00:00
parent 7ca46b1be2
commit c85ff8f79e
3 changed files with 148 additions and 97 deletions
+67 -37
View File
@@ -12,7 +12,6 @@ import pytz
import pandas as pd
import logging
import logging.config
import os
matplotlib.use('WXAgg')
@@ -158,19 +157,17 @@ class MonitorFrame(wx.Frame):
self.Bind(wx.EVT_CLOSE, self.on_close, self)
def open_file(self, event):
with wx.FileDialog(self, "Open Coefficients file", wildcard="CSV (*.csv)|*.csv",
with wx.FileDialog(self, "Open Coefficients file", wildcard="cpd (*.cpd)|*.cpd",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return # the user changed their mind
# Load the file chosen by the user. Also load the corresponding data file if there is one.
# Load the file chosen by the user.
self.__opened_filename = fileDialog.GetPath()
data_filename = f"{os.path.splitext(self.__opened_filename)[0]}.price.data"
if os.path.isfile(data_filename):
self.cor.load(self.__opened_filename, price_data_filename=data_filename)
else:
self.cor.load(self.__opened_filename)
self.SetStatusText(f"Loading file {self.__opened_filename}.")
self.cor.load(self.__opened_filename)
# Refresh data in grid
self.refresh_grid()
@@ -188,7 +185,7 @@ class MonitorFrame(wx.Frame):
self.SetStatusText(f"File saved as {self.__opened_filename}")
def save_file_as(self, event):
with wx.FileDialog(self, "Save Coefficients file", wildcard="CSV (*.csv)|*.csv",
with wx.FileDialog(self, "Save Coefficients file", wildcard="cpd (*.cpd)|*.cpd",
style=wx.FD_SAVE) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return # the user changed their mind
@@ -197,8 +194,7 @@ class MonitorFrame(wx.Frame):
self.SetStatusText(f"Saving file as {self.__opened_filename}")
self.__opened_filename = fileDialog.GetPath()
data_filename = f"{os.path.splitext(self.__opened_filename)[0]}.price.data"
self.cor.save(self.__opened_filename, price_data_filename=data_filename)
self.cor.save(self.__opened_filename)
self.SetStatusText(f"File saved as {self.__opened_filename}")
@@ -278,13 +274,19 @@ class MonitorFrame(wx.Frame):
self.SetStatusText("Monitoring for changes to coefficients.")
self.timer.Start(self.config.get('monitor.interval')*1000)
# Autosave filename
filename = self.__opened_filename if self.__opened_filename is not None else 'autosave.cpd'
self.cor.start_monitor(interval=self.config.get('monitor.interval'),
from_mins=self.config.get('monitor.from.minutes'),
min_prices=self.config.get('monitor.min_prices'),
max_set_size_diff_pct=self.config.get('monitor.max_set_size_diff_pct'),
overlap_pct=self.config.get('monitor.overlap_pct'),
max_p_value=self.config.get('monitor.max_p_value'),
cache_time=self.config.get('monitor.tick_cache_time'))
cache_time=self.config.get('monitor.tick_cache_time'),
autosave=self.config.get('monitor.autosave'),
filename=filename)
else:
self.__log.info("Stopping monitoring.")
self.monitor_toggle.SetBackgroundColour(wx.RED)
@@ -389,9 +391,12 @@ class MonitorFrame(wx.Frame):
:param symbol2:
:return:
"""
# Get the data price data for the base coefficient calculation and the coefficient history data
# Get the price data for the base coefficient calculation, tick data to calculate last coefficient and and the
# coefficient history data
symbol_1_price_data = self.cor.get_price_data(symbol1)
symbol_2_price_data = self.cor.get_price_data(symbol2)
symbol_1_ticks = self.cor.get_ticks(symbol1, cache_only=True)
symbol_2_ticks = self.cor.get_ticks(symbol2, cache_only=True)
history_data = self.cor.get_coefficient_history(symbol1, symbol2)
times = history_data['UTC Date To']
coefficients = history_data['Coefficient']
@@ -399,7 +404,7 @@ class MonitorFrame(wx.Frame):
# Display if we have any data
self.__log.debug(f"Refreshing history graph {symbol1}:{symbol2}.")
self.__graph.draw(times=times, coefficients=coefficients, prices=[symbol_1_price_data, symbol_2_price_data],
symbols=[symbol1, symbol2])
ticks=[symbol_1_ticks, symbol_2_ticks], symbols=[symbol1, symbol2])
# Un-hide and layout if hidden
if not self.__graph.IsShown():
@@ -477,9 +482,10 @@ class GraphPanel(wx.Panel):
# Super
wx.Panel.__init__(self, parent)
# 3 axis, price data 1, price data 2 and coefficient data. All will have axis labels and top and right boarders
# 3 axis, 2 price data for calculate, 2 price data for last coefficient and coefficient history.
# All will have axis labels and top and right boarders
# removed
self.__fig, self.__axes = plt.subplots(nrows=3, ncols=1)
self.__fig, self.__axes = plt.subplots(nrows=5, ncols=1)
# Create the canvas
self.__canvas = FigureCanvas(self, -1, self.__fig)
@@ -500,13 +506,14 @@ class GraphPanel(wx.Panel):
self.__axes = None
self.__fig = None
def draw(self, times, coefficients, prices=None, symbols=None):
def draw(self, times, coefficients, prices=None, symbols=None, ticks=None):
"""
Plot the correlations.
:param times: Series of time values for x axis
:param coefficients: Series of coefficients values for y axis
:param times: Series of time values for x axis for coefficient history chart
:param coefficients: Series of coefficients values for y axis of coefficient history chart
:param prices: Price data used to calculate base coefficient. List [Symbol1 Price Data, Symbol 2 Price Data]
:param symbols: Symbols. List [Symbol1, Symbol2]
:param ticks: Ticks used to calculate last coefficient. List [Symbol1, Symbol2]
:return:
"""
# Clear. We will need to redraw
@@ -514,25 +521,48 @@ class GraphPanel(wx.Panel):
ax.clear()
if symbols is not None and len(symbols) == 2:
# Price history chart for both symbols
for i in range(0, 2):
if symbols[i] is not None and prices is not None and len(prices) == 2 and prices[i] is not None:
self.__axes[i].set_title(f"Base Coefficient Price Data for {symbols[i]}")
self.__axes[i].set_xlabel('Time')
self.__axes[i].set_ylabel('Price')
self.__axes[i].plot(prices[i]['time'], prices[i]['close'])
self.__axes[i].xaxis.set_major_formatter(self.__tick_fmt_date)
self.__axes[i].xaxis.set_minor_formatter(self.__tick_fmt_time)
plt.setp(self.__axes[i].xaxis.get_majorticklabels(), rotation=45)
# Axis ranges
price_chart_date_range = [min(min(prices[0]['time']), min(prices[1]['time'])),
max(max(prices[0]['time']), max(prices[1]['time']))]
tick_chart_date_range = [min(min(ticks[0]['time']), min(ticks[1]['time'])),
max(max(ticks[0]['time']), max(ticks[1]['time']))]
# Coefficient history chart
self.__axes[2].set_title(f"Coefficient History for {symbols[0]}:{symbols[1]}")
self.__axes[2].set_xlabel('Time')
self.__axes[2].set_ylabel('Coefficient')
self.__axes[2].plot(times, coefficients)
self.__axes[2].set_ylim([-1, 1])
self.__axes[2].xaxis.set_major_formatter(self.__tick_fmt_time)
plt.setp(self.__axes[2].xaxis.get_majorticklabels(), rotation=45)
# Chart config
titles = [f"Base Coefficient Price Data for {symbols[0]}", f"Base Coefficient Price Data for {symbols[1]}",
f"Coefficient Tick Data for {symbols[0]}", f"Coefficient Tick Data for {symbols[1]}",
f"Coefficient History for {symbols[0]}:{symbols[1]}"]
xlims = [price_chart_date_range, price_chart_date_range, tick_chart_date_range, tick_chart_date_range, None]
ylims = [None, None, None, None, [-1, 1]]
xlabels = [None, None, None, None, None]
ylabels = ['Price', 'Price', 'Price', 'Price', 'Coefficient']
tick_labels = [[], prices[1]['time'], [], ticks[1]['time'], times]
mtick_fmts = [None, self.__tick_fmt_date, None, self.__tick_fmt_time, self.__tick_fmt_time]
mtick_rot = [0, 45, 0, 45, 45]
xdata = [prices[0]['time'], prices[1]['time'], ticks[0]['time'], ticks[1]['time'], times]
ydata = [prices[0]['close'], prices[1]['close'], ticks[0]['ask'], ticks[1]['ask'], coefficients]
# Draw 5 charts
for index in range(0, len(self.__axes)):
# Titles and axis labels
self.__axes[index].set_title(titles[index])
self.__axes[index].set_xlabel(xlabels[index])
self.__axes[index].set_ylabel(ylabels[index])
# Limits
if xlims[index] is not None:
self.__axes[index].set_xlim(xlims[index])
if ylims[index] is not None:
self.__axes[index].set_ylim(ylims[index])
# Tick labels and formats
self.__axes[index].xaxis.set_ticklabels(tick_labels[index])
if mtick_fmts[index] is not None:
self.__axes[index].xaxis.set_major_formatter(mtick_fmts[index])
plt.setp(self.__axes[index].xaxis.get_majorticklabels(), rotation=mtick_rot[index])
# Plot
self.__axes[index].plot(xdata[index], ydata[index])
# Layout with padding between charts
self.__fig.tight_layout(pad=0.5)