15 changed files with 1092 additions and 85 deletions
@ -0,0 +1,155 @@
@@ -0,0 +1,155 @@
|
||||
|
||||
|
||||
import sys |
||||
import importlib |
||||
from importlib.machinery import SourceFileLoader |
||||
import inspect |
||||
|
||||
from naiback.strategy import Strategy |
||||
|
||||
import numpy as np |
||||
import math |
||||
|
||||
def render_float(a): |
||||
return "{:.3f}".format(a) |
||||
|
||||
|
||||
def render_ratio(a, b): |
||||
if b != 0: |
||||
return a / b |
||||
else: |
||||
return 0 |
||||
|
||||
class PortfolioExecutor: |
||||
|
||||
def __init__(self): |
||||
pass |
||||
|
||||
def execute_from_file(self, path, feeds, extents=None): |
||||
if "execution._current_strategy" in sys.modules: |
||||
del sys.modules["execution._current_strategy"] |
||||
loader = SourceFileLoader('execution._current_strategy', path) |
||||
mod = loader.load_module() |
||||
for item in inspect.getmembers(mod, inspect.isclass): |
||||
klass = item[1] |
||||
if klass is not Strategy and issubclass(klass, Strategy): |
||||
all_trades = [] |
||||
for feed in feeds: |
||||
strategy = klass() |
||||
strategy.add_feed(feed) |
||||
|
||||
if extents is None: |
||||
strategy.run() |
||||
else: |
||||
strategy.run(from_time=extents[0], to_time=extents[1]) |
||||
|
||||
trades = strategy.get_analyzer('tradeslist').get_result() |
||||
all_trades = self.merge_trades(all_trades, trades) |
||||
|
||||
results = self.calc_stats(all_trades) |
||||
equity = self.calc_equity(all_trades) |
||||
return (results, all_trades, equity) |
||||
|
||||
def merge_trades(self, trades1, trades2): |
||||
all_trades = list(sorted(trades1 + trades2, key=lambda x: x['entry_time'])) |
||||
result = [] |
||||
current_trades = [] |
||||
max_trades = 3 |
||||
for trade in all_trades: |
||||
if len(current_trades) < max_trades: |
||||
current_trades.append(trade) |
||||
result.append(trade) |
||||
new_current_trades = [] |
||||
for ct in current_trades: |
||||
if ct['exit_time'] < trade['entry_time']: |
||||
new_current_trades.append(ct) |
||||
else: |
||||
# possibly adjust the balance |
||||
pass |
||||
current_trades = new_current_trades |
||||
return result |
||||
|
||||
def calc_stats(self, trades): |
||||
longs = list(filter(lambda x: x['is_long'], trades)) |
||||
shorts = list(filter(lambda x: not x['is_long'], trades)) |
||||
|
||||
result = { 'all' : {}, 'long' : {}, 'short' : {} } |
||||
result['all']['net_profit'] = sum([t['pnl'] for t in trades]) |
||||
result['long']['net_profit'] = sum([t['pnl'] for t in longs]) |
||||
result['short']['net_profit'] = sum([t['pnl'] for t in shorts]) |
||||
|
||||
result['all']['bars_in_trade'] = 0 # TODO? |
||||
result['long']['bars_in_trade'] = 0 |
||||
result['short']['bars_in_trade'] = 0 |
||||
|
||||
result['all']['profit_per_bar'] = 0 |
||||
result['long']['profit_per_bar'] = 0 |
||||
result['short']['profit_per_bar'] = 0 |
||||
|
||||
result['all']['number_of_trades'] = len(trades) |
||||
result['long']['number_of_trades'] = len(longs) |
||||
result['short']['number_of_trades'] = len(shorts) |
||||
|
||||
result['all']['avg'] = render_ratio(result['all']['net_profit'], result['all']['number_of_trades']) |
||||
result['long']['avg'] = render_ratio(result['long']['net_profit'], result['long']['number_of_trades']) |
||||
result['short']['avg'] = render_ratio(result['short']['net_profit'], result['short']['number_of_trades']) |
||||
|
||||
result['all']['avg_percentage'] = render_ratio(sum([t['profit_percentage'] for t in trades]), result['all']['number_of_trades']) |
||||
result['long']['avg_percentage'] = render_ratio(sum([t['profit_percentage'] for t in longs]), result['long']['number_of_trades']) |
||||
result['short']['avg_percentage'] = render_ratio(sum([t['profit_percentage'] for t in shorts]), result['short']['number_of_trades']) |
||||
|
||||
result['all']['avg_bars'] = render_ratio(result['all']['bars_in_trade'], result['all']['number_of_trades']) |
||||
result['long']['avg_bars'] = render_ratio(result['long']['bars_in_trade'], result['long']['number_of_trades']) |
||||
result['short']['avg_bars'] = render_ratio(result['short']['bars_in_trade'], result['short']['number_of_trades']) |
||||
|
||||
result['all']['won'] = len(list(filter(lambda t: t['pnl'] > 0, trades))) |
||||
result['long']['won'] = len(list(filter(lambda t: t['pnl'] > 0, longs))) |
||||
result['short']['won'] = len(list(filter(lambda t: t['pnl'] > 0, shorts))) |
||||
|
||||
result['all']['lost'] = len(list(filter(lambda t: t['pnl'] <= 0, trades))) |
||||
result['long']['lost'] = len(list(filter(lambda t: t['pnl'] <= 0, longs))) |
||||
result['short']['lost'] = len(list(filter(lambda t: t['pnl'] <= 0, shorts))) |
||||
|
||||
result['all']['total_won'] = sum(map(lambda t: t['pnl'], filter(lambda t: t['pnl'] > 0, trades))) |
||||
result['long']['total_won'] = sum(map(lambda t: t['pnl'], filter(lambda t: t['pnl'] > 0, longs))) |
||||
result['short']['total_won'] = sum(map(lambda t: t['pnl'], filter(lambda t: t['pnl'] > 0, shorts))) |
||||
|
||||
result['all']['total_lost'] = sum(map(lambda t: t['pnl'], filter(lambda t: t['pnl'] <= 0, trades))) |
||||
result['long']['total_lost'] = sum(map(lambda t: t['pnl'], filter(lambda t: t['pnl'] <= 0, longs))) |
||||
result['short']['total_lost'] = sum(map(lambda t: t['pnl'], filter(lambda t: t['pnl'] <= 0, shorts))) |
||||
|
||||
result['all']['profit_factor'] = render_ratio(result['all']['total_won'], -result['all']['total_lost']) |
||||
result['long']['profit_factor'] = render_ratio(result['long']['total_won'], -result['long']['total_lost']) |
||||
result['short']['profit_factor'] = render_ratio(result['short']['total_won'], -result['short']['total_lost']) |
||||
|
||||
mean = np.mean(list(map(lambda x: x['pnl'], trades))) |
||||
stddev = np.std(list(map(lambda x: x['pnl'], trades))) |
||||
sharpe = mean / stddev |
||||
tstat = sharpe * math.sqrt(len(trades)) |
||||
result['all']['sharpe_ratio'] = sharpe |
||||
result['all']['t_stat'] = tstat |
||||
|
||||
mean = np.mean(list(map(lambda x: x['pnl'], longs))) |
||||
stddev = np.std(list(map(lambda x: x['pnl'], longs))) |
||||
sharpe = mean / stddev |
||||
tstat = sharpe * math.sqrt(len(longs)) |
||||
result['long']['sharpe_ratio'] = sharpe |
||||
result['long']['t_stat'] = tstat |
||||
|
||||
mean = np.mean(list(map(lambda x: x['pnl'], shorts))) |
||||
stddev = np.std(list(map(lambda x: x['pnl'], shorts))) |
||||
sharpe = mean / stddev |
||||
tstat = sharpe * math.sqrt(len(shorts)) |
||||
result['short']['sharpe_ratio'] = sharpe |
||||
result['short']['t_stat'] = tstat |
||||
|
||||
return result |
||||
|
||||
def calc_equity(self, trades): |
||||
sorted_trades = sorted(trades, key=lambda x: x['exit_time']) |
||||
equity = [] |
||||
current = 0 |
||||
for t in sorted_trades: |
||||
current += t['pnl'] |
||||
equity.append(current) |
||||
|
||||
@ -0,0 +1,138 @@
@@ -0,0 +1,138 @@
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets |
||||
from PyQt5.Qsci import * |
||||
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas |
||||
from matplotlib.figure import Figure |
||||
import matplotlib.pyplot as plt |
||||
import matplotlib |
||||
|
||||
import numpy as np |
||||
|
||||
|
||||
class CorrelationChartCanvas(FigureCanvas): |
||||
def __init__(self, parent=None, width=6, height=6, dpi=100): |
||||
self.fig = Figure(figsize=(width, height), dpi=dpi) |
||||
|
||||
FigureCanvas.__init__(self, self.fig) |
||||
self.setParent(parent) |
||||
|
||||
self.trades_series = {} |
||||
self.mode = "daily" |
||||
|
||||
def setMode(self, mode): |
||||
if mode not in ["daily", "monthly"]: |
||||
return |
||||
|
||||
self.mode = mode |
||||
self._refresh() |
||||
|
||||
def add_trades_series(self, name, trades): |
||||
self.trades_series[name] = trades |
||||
self._refresh() |
||||
|
||||
def add_trades_series_batched(self, trades_list): |
||||
for series in trades_list: |
||||
self.trades_series[series["name"]] = series["trades"] |
||||
self._refresh() |
||||
|
||||
def remove_trades_series(self, name): |
||||
del self.trades_series[name] |
||||
self._refresh() |
||||
|
||||
def _refresh(self): |
||||
self.fig.clear() |
||||
|
||||
if len(self.trades_series) == 0: |
||||
return |
||||
|
||||
corr_matrix = np.zeros((len(self.trades_series), len(self.trades_series))) |
||||
x = 0 |
||||
y = 0 |
||||
names = [] |
||||
for n1, trades1 in self.trades_series.items(): |
||||
names.append(n1) |
||||
for n2, trades2 in self.trades_series.items(): |
||||
corr_matrix[x][y] = self._calc_correlation(trades1, trades2) |
||||
y += 1 |
||||
x += 1 |
||||
y = 0 |
||||
|
||||
ax1 = self.figure.add_subplot(111) |
||||
ax1.imshow(corr_matrix, cmap="BrBG", norm=matplotlib.colors.Normalize(vmin=-1.0, vmax=1.0)) |
||||
ax1.set_title("Returns correlation") |
||||
ax1.set_xticks(np.arange(len(names))) |
||||
ax1.set_yticks(np.arange(len(names))) |
||||
ax1.set_xticklabels(names) |
||||
ax1.set_yticklabels(names) |
||||
for i in range(len(self.trades_series)): |
||||
for j in range(len(self.trades_series)): |
||||
col = 'k' |
||||
if corr_matrix[i, j] > 0.7: |
||||
col = 'w' |
||||
text = ax1.text(j, i, "{:.2f}".format(corr_matrix[i, j]), ha="center", va="center", color=col, fontsize="x-small") |
||||
|
||||
plt.setp(ax1.get_xticklabels(), rotation=45, ha="right", rotation_mode="anchor") |
||||
|
||||
self.draw() |
||||
|
||||
def _calc_correlation(self, trades1, trades2): |
||||
t1 = {} |
||||
all_dates = set() |
||||
for trade in trades1: |
||||
all_dates.add(self._trade_date(trade)) |
||||
try: |
||||
t1[self._trade_date(trade)] += trade["percentage"] |
||||
except KeyError: |
||||
t1[self._trade_date(trade)] = trade["percentage"] |
||||
|
||||
t2 = {} |
||||
for trade in trades2: |
||||
all_dates.add(self._trade_date(trade)) |
||||
try: |
||||
t2[self._trade_date(trade)] += trade["percentage"] |
||||
except KeyError: |
||||
t2[self._trade_date(trade)] = trade["percentage"] |
||||
|
||||
|
||||
ret1 = [] |
||||
for d in all_dates: |
||||
try: |
||||
ret1.append(t1[d]) |
||||
except KeyError: |
||||
ret1.append(0) |
||||
|
||||
ret2 = [] |
||||
for d in all_dates: |
||||
try: |
||||
ret2.append(t2[d]) |
||||
except KeyError: |
||||
ret2.append(0) |
||||
|
||||
mean1 = np.mean(ret1) |
||||
mean2 = np.mean(ret2) |
||||
sigma1 = np.std(ret1) |
||||
sigma2 = np.std(ret2) |
||||
|
||||
s = 0 |
||||
for i in range(len(all_dates)): |
||||
x1 = ret1[i] - mean1 |
||||
x2 = ret2[i] - mean2 |
||||
s += x1 * x2 |
||||
s /= len(all_dates) |
||||
s /= (sigma1 * sigma2) |
||||
|
||||
return s |
||||
|
||||
|
||||
def _trade_date(self, trade): |
||||
if self.mode == "daily": |
||||
return trade["exit_time"].date() |
||||
else: |
||||
return trade["exit_time"].date().replace(day=1) |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,92 @@
@@ -0,0 +1,92 @@
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets |
||||
from PyQt5.Qsci import * |
||||
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas |
||||
from matplotlib.figure import Figure |
||||
import matplotlib.pyplot as plt |
||||
|
||||
import numpy as np |
||||
|
||||
|
||||
class PerformanceCanvas(FigureCanvas): |
||||
def __init__(self, parent=None, width=5, height=4, dpi=100): |
||||
self.fig = Figure(figsize=(width, height), dpi=dpi) |
||||
|
||||
FigureCanvas.__init__(self, self.fig) |
||||
self.setParent(parent) |
||||
|
||||
self.trades_series = {} |
||||
|
||||
|
||||
def add_trades_series(self, name, trades): |
||||
self.trades_series[name] = trades |
||||
self._refresh() |
||||
|
||||
def add_trades_series_batched(self, trades_list): |
||||
for series in trades_list: |
||||
self.trades_series[series["name"]] = series["trades"] |
||||
self._refresh() |
||||
|
||||
def remove_trades_series(self, name): |
||||
del self.trades_series[name] |
||||
self._refresh() |
||||
|
||||
def _refresh(self): |
||||
self.fig.clear() |
||||
|
||||
if len(self.trades_series) == 0: |
||||
return |
||||
|
||||
all_trades = [] |
||||
for k, v in self.trades_series.items(): |
||||
for trade in v: |
||||
all_trades.append(trade) |
||||
|
||||
all_trades = sorted(all_trades, key=lambda x: x["exit_time"]) |
||||
|
||||
cumpnl = np.cumsum(list(map(lambda x: x["percentage"], all_trades))) |
||||
|
||||
max_equity = 0 |
||||
drawdown = [] |
||||
for x in cumpnl: |
||||
if x > max_equity: |
||||
max_equity = x |
||||
drawdown.append(0) |
||||
else: |
||||
drawdown.append(x - max_equity) |
||||
|
||||
monthly_returns = {} |
||||
cur_month = None |
||||
cur_pnl = 0 |
||||
|
||||
for trade in all_trades: |
||||
trade_month = trade["exit_time"].strftime("%Y-%m") |
||||
if trade_month != cur_month and cur_month is not None: |
||||
monthly_returns[cur_month] = cur_pnl |
||||
cur_pnl = 0 |
||||
cur_month = trade_month |
||||
if cur_month is None: |
||||
cur_month = trade_month |
||||
cur_pnl += trade["percentage"] |
||||
|
||||
monthly_returns[cur_month] = cur_pnl |
||||
monthly_returns_raw = [] |
||||
for k, v in monthly_returns.items(): |
||||
monthly_returns_raw.append((k, v)) |
||||
|
||||
monthly_returns_raw = sorted(monthly_returns_raw, key=lambda x: x[0]) |
||||
self.monthly_returns_x = list(map(lambda x: x[0], monthly_returns_raw)) |
||||
self.monthly_returns_y = list(map(lambda x: x[1], monthly_returns_raw)) |
||||
|
||||
ax1 = self.figure.add_subplot(211) |
||||
ax1.plot(cumpnl, "b-") |
||||
ax1.set_title("Cumulative PnL") |
||||
ax1_2 = ax1.twinx() |
||||
ax1_2.plot(drawdown, "r-") |
||||
|
||||
ax2 = self.figure.add_subplot(212) |
||||
ax2.bar(self.monthly_returns_x, self.monthly_returns_y) |
||||
ax2.set_title("Monthly PnL") |
||||
plt.setp(ax2.get_xticklabels(), rotation=90, ha="right", rotation_mode="anchor") |
||||
self.draw() |
||||
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets |
||||
from PyQt5.Qsci import * |
||||
|
||||
from ui_gen.performancewidget import Ui_PerformanceWidget |
||||
|
||||
from pathlib import PurePath |
||||
|
||||
import datetime |
||||
import json |
||||
import numpy as np |
||||
|
||||
class PerformanceWidget(QtWidgets.QWidget): |
||||
def __init__(self, parent=None): |
||||
super().__init__(parent) |
||||
|
||||
self.ui = Ui_PerformanceWidget() |
||||
self.ui.setupUi(self) |
||||
self.trades_series = {} |
||||
|
||||
def widget_type(self): |
||||
return "performance" |
||||
|
||||
def dailyToggled(self, v): |
||||
if v: |
||||
self.ui.correlationCanvas.setMode("daily") |
||||
|
||||
def monthlyToggled(self, v): |
||||
if v: |
||||
self.ui.correlationCanvas.setMode("monthly") |
||||
|
||||
def addResults(self): |
||||
filenames, _ = QtWidgets.QFileDialog.getOpenFileNames(self, self.tr("Select file to open"), "", self.tr("JSON files (*.json);;All Files (*)")) |
||||
results = [] |
||||
for filename in filenames: |
||||
with open(filename, "rt") as f: |
||||
name = PurePath(filename).name |
||||
QtWidgets.QListWidgetItem(name, self.ui.lw_strategies) |
||||
trades = json.loads(f.read()) |
||||
for trade in trades: |
||||
trade["entry_time"] = datetime.datetime.strptime(trade["entry_time"], "%Y-%m-%d %H:%M:%S") |
||||
trade["exit_time"] = datetime.datetime.strptime(trade["exit_time"], "%Y-%m-%d %H:%M:%S") |
||||
|
||||
self.trades_series[name] = trades |
||||
results.append({"name" : name, "trades" : trades}) |
||||
|
||||
self.ui.canvas.add_trades_series_batched(results) |
||||
self.ui.correlationCanvas.add_trades_series_batched(results) |
||||
self.update_stats() |
||||
|
||||
|
||||
def removeResults(self): |
||||
selected_rows = sorted(map(lambda x: self.ui.lw_strategies.row(x), self.ui.lw_strategies.selectedItems())) |
||||
for row in reversed(selected_rows): |
||||
item = self.ui.lw_strategies.takeItem(row) |
||||
self.ui.canvas.remove_trades_series(item.text()) |
||||
self.ui.correlationCanvas.remove_trades_series(item.text()) |
||||
|
||||
self.update_stats() |
||||
|
||||
def update_stats(self): |
||||
self.ui.tw_stats.clear() |
||||
monmean = np.mean(self.ui.canvas.monthly_returns_y) |
||||
monstd = np.std(self.ui.canvas.monthly_returns_y) |
||||
if monstd == 0: |
||||
monz = 0 |
||||
else: |
||||
monz = monmean / monstd |
||||
self.add_stat("Monthly mean", monmean) |
||||
self.add_stat("Monthly std. dev.", monstd) |
||||
self.add_stat("Z-Score", monz) |
||||
|
||||
self.ui.tw_stats.resizeColumnToContents(0) |
||||
self.ui.tw_stats.resizeColumnToContents(1) |
||||
|
||||
|
||||
def add_stat(self, name, value): |
||||
item = QtWidgets.QTreeWidgetItem(self.ui.tw_stats) |
||||
item.setText(0, name) |
||||
if isinstance(value, str): |
||||
item.setText(1, str) |
||||
elif isinstance(value, float): |
||||
item.setText(1, "{:.3f}".format(value)) |
||||
else: |
||||
item.setText(1, str(value)) |
||||
|
||||
@ -0,0 +1,100 @@
@@ -0,0 +1,100 @@
|
||||
# -*- coding: utf-8 -*- |
||||
|
||||
# Form implementation generated from reading ui file 'ui/performancewidget.ui' |
||||
# |
||||
# Created by: PyQt5 UI code generator 5.5.1 |
||||
# |
||||
# WARNING! All changes made in this file will be lost! |
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets |
||||
|
||||
class Ui_PerformanceWidget(object): |
||||
def setupUi(self, PerformanceWidget): |
||||
PerformanceWidget.setObjectName("PerformanceWidget") |
||||
PerformanceWidget.resize(780, 556) |
||||
self.gridLayout = QtWidgets.QGridLayout(PerformanceWidget) |
||||
self.gridLayout.setContentsMargins(2, 2, 2, 2) |
||||
self.gridLayout.setObjectName("gridLayout") |
||||
self.tab1 = QtWidgets.QTabWidget(PerformanceWidget) |
||||
self.tab1.setObjectName("tab1") |
||||
self.tab = QtWidgets.QWidget() |
||||
self.tab.setObjectName("tab") |
||||
self.gridLayout_2 = QtWidgets.QGridLayout(self.tab) |
||||
self.gridLayout_2.setContentsMargins(1, 1, 1, 1) |
||||
self.gridLayout_2.setObjectName("gridLayout_2") |
||||
self.verticalLayout = QtWidgets.QVBoxLayout() |
||||
self.verticalLayout.setContentsMargins(4, 4, 4, 4) |
||||
self.verticalLayout.setObjectName("verticalLayout") |
||||
self.canvas = PerformanceCanvas(self.tab) |
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) |
||||
sizePolicy.setHorizontalStretch(0) |
||||
sizePolicy.setVerticalStretch(0) |
||||
sizePolicy.setHeightForWidth(self.canvas.sizePolicy().hasHeightForWidth()) |
||||
self.canvas.setSizePolicy(sizePolicy) |
||||
self.canvas.setObjectName("canvas") |
||||
self.verticalLayout.addWidget(self.canvas) |
||||
self.tw_stats = QtWidgets.QTreeWidget(self.tab) |
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum) |
||||
sizePolicy.setHorizontalStretch(0) |
||||
sizePolicy.setVerticalStretch(0) |
||||
sizePolicy.setHeightForWidth(self.tw_stats.sizePolicy().hasHeightForWidth()) |
||||
self.tw_stats.setSizePolicy(sizePolicy) |
||||
self.tw_stats.setObjectName("tw_stats") |
||||
self.tw_stats.header().setVisible(False) |
||||
self.verticalLayout.addWidget(self.tw_stats) |
||||
self.gridLayout_2.addLayout(self.verticalLayout, 0, 0, 1, 1) |
||||
self.tab1.addTab(self.tab, "") |
||||
self.tab_2 = QtWidgets.QWidget() |
||||
self.tab_2.setObjectName("tab_2") |
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_2) |
||||
self.gridLayout_3.setObjectName("gridLayout_3") |
||||
self.rb_daily = QtWidgets.QRadioButton(self.tab_2) |
||||
self.rb_daily.setChecked(True) |
||||
self.rb_daily.setObjectName("rb_daily") |
||||
self.gridLayout_3.addWidget(self.rb_daily, 0, 0, 1, 1) |
||||
self.rb_monthly = QtWidgets.QRadioButton(self.tab_2) |
||||
self.rb_monthly.setObjectName("rb_monthly") |
||||
self.gridLayout_3.addWidget(self.rb_monthly, 0, 1, 1, 1) |
||||
self.correlationCanvas = CorrelationChartCanvas(self.tab_2) |
||||
self.correlationCanvas.setObjectName("correlationCanvas") |
||||
self.gridLayout_3.addWidget(self.correlationCanvas, 1, 0, 1, 2) |
||||
self.tab1.addTab(self.tab_2, "") |
||||
self.gridLayout.addWidget(self.tab1, 0, 2, 1, 1) |
||||
self.b_add = QtWidgets.QPushButton(PerformanceWidget) |
||||
self.b_add.setObjectName("b_add") |
||||
self.gridLayout.addWidget(self.b_add, 1, 0, 1, 1) |
||||
self.b_remove = QtWidgets.QPushButton(PerformanceWidget) |
||||
self.b_remove.setObjectName("b_remove") |
||||
self.gridLayout.addWidget(self.b_remove, 1, 1, 1, 1) |
||||
self.lw_strategies = QtWidgets.QListWidget(PerformanceWidget) |
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Expanding) |
||||
sizePolicy.setHorizontalStretch(0) |
||||
sizePolicy.setVerticalStretch(0) |
||||
sizePolicy.setHeightForWidth(self.lw_strategies.sizePolicy().hasHeightForWidth()) |
||||
self.lw_strategies.setSizePolicy(sizePolicy) |
||||
self.lw_strategies.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) |
||||
self.lw_strategies.setObjectName("lw_strategies") |
||||
self.gridLayout.addWidget(self.lw_strategies, 0, 0, 1, 2) |
||||
|
||||
self.retranslateUi(PerformanceWidget) |
||||
self.tab1.setCurrentIndex(1) |
||||
self.b_add.clicked.connect(PerformanceWidget.addResults) |
||||
self.b_remove.clicked.connect(PerformanceWidget.removeResults) |
||||
self.rb_daily.toggled['bool'].connect(PerformanceWidget.dailyToggled) |
||||
self.rb_monthly.toggled['bool'].connect(PerformanceWidget.monthlyToggled) |
||||
QtCore.QMetaObject.connectSlotsByName(PerformanceWidget) |
||||
|
||||
def retranslateUi(self, PerformanceWidget): |
||||
_translate = QtCore.QCoreApplication.translate |
||||
PerformanceWidget.setWindowTitle(_translate("PerformanceWidget", "Form")) |
||||
self.tw_stats.headerItem().setText(0, _translate("PerformanceWidget", "1")) |
||||
self.tw_stats.headerItem().setText(1, _translate("PerformanceWidget", "2")) |
||||
self.tab1.setTabText(self.tab1.indexOf(self.tab), _translate("PerformanceWidget", "Returns and Drawdowns")) |
||||
self.rb_daily.setText(_translate("PerformanceWidget", "Daily")) |
||||
self.rb_monthly.setText(_translate("PerformanceWidget", "Monthly")) |
||||
self.tab1.setTabText(self.tab1.indexOf(self.tab_2), _translate("PerformanceWidget", "Correlations")) |
||||
self.b_add.setText(_translate("PerformanceWidget", "Add...")) |
||||
self.b_remove.setText(_translate("PerformanceWidget", "Remove")) |
||||
|
||||
from ui.correlationchartcanvas import CorrelationChartCanvas |
||||
from ui.performancecanvas import PerformanceCanvas |
||||
@ -0,0 +1,247 @@
@@ -0,0 +1,247 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<ui version="4.0"> |
||||
<class>PerformanceWidget</class> |
||||
<widget class="QWidget" name="PerformanceWidget"> |
||||
<property name="geometry"> |
||||
<rect> |
||||
<x>0</x> |
||||
<y>0</y> |
||||
<width>780</width> |
||||
<height>556</height> |
||||
</rect> |
||||
</property> |
||||
<property name="windowTitle"> |
||||
<string>Form</string> |
||||
</property> |
||||
<layout class="QGridLayout" name="gridLayout"> |
||||
<property name="leftMargin"> |
||||
<number>2</number> |
||||
</property> |
||||
<property name="topMargin"> |
||||
<number>2</number> |
||||
</property> |
||||
<property name="rightMargin"> |
||||
<number>2</number> |
||||
</property> |
||||
<property name="bottomMargin"> |
||||
<number>2</number> |
||||
</property> |
||||
<item row="0" column="2"> |
||||
<widget class="QTabWidget" name="tab1"> |
||||
<property name="currentIndex"> |
||||
<number>1</number> |
||||
</property> |
||||
<widget class="QWidget" name="tab"> |
||||
<attribute name="title"> |
||||
<string>Returns and Drawdowns</string> |
||||
</attribute> |
||||
<layout class="QGridLayout" name="gridLayout_2"> |
||||
<property name="leftMargin"> |
||||
<number>1</number> |
||||
</property> |
||||
<property name="topMargin"> |
||||
<number>1</number> |
||||
</property> |
||||
<property name="rightMargin"> |
||||
<number>1</number> |
||||
</property> |
||||
<property name="bottomMargin"> |
||||
<number>1</number> |
||||
</property> |
||||
<item row="0" column="0"> |
||||
<layout class="QVBoxLayout" name="verticalLayout"> |
||||
<property name="leftMargin"> |
||||
<number>4</number> |
||||
</property> |
||||
<property name="topMargin"> |
||||
<number>4</number> |
||||
</property> |
||||
<property name="rightMargin"> |
||||
<number>4</number> |
||||
</property> |
||||
<property name="bottomMargin"> |
||||
<number>4</number> |
||||
</property> |
||||
<item> |
||||
<widget class="PerformanceCanvas" name="canvas" native="true"> |
||||
<property name="sizePolicy"> |
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred"> |
||||
<horstretch>0</horstretch> |
||||
<verstretch>0</verstretch> |
||||
</sizepolicy> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item> |
||||
<widget class="QTreeWidget" name="tw_stats"> |
||||
<property name="sizePolicy"> |
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum"> |
||||
<horstretch>0</horstretch> |
||||
<verstretch>0</verstretch> |
||||
</sizepolicy> |
||||
</property> |
||||
<attribute name="headerVisible"> |
||||
<bool>false</bool> |
||||
</attribute> |
||||
<column> |
||||
<property name="text"> |
||||
<string>1</string> |
||||
</property> |
||||
</column> |
||||
<column> |
||||
<property name="text"> |
||||
<string>2</string> |
||||
</property> |
||||
</column> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</item> |
||||
</layout> |
||||
</widget> |
||||
<widget class="QWidget" name="tab_2"> |
||||
<attribute name="title"> |
||||
<string>Correlations</string> |
||||
</attribute> |
||||
<layout class="QGridLayout" name="gridLayout_3"> |
||||
<item row="0" column="0"> |
||||
<widget class="QRadioButton" name="rb_daily"> |
||||
<property name="text"> |
||||
<string>Daily</string> |
||||
</property> |
||||
<property name="checked"> |
||||
<bool>true</bool> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="0" column="1"> |
||||
<widget class="QRadioButton" name="rb_monthly"> |
||||
<property name="text"> |
||||
<string>Monthly</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="1" column="0" colspan="2"> |
||||
<widget class="CorrelationChartCanvas" name="correlationCanvas" native="true"/> |
||||
</item> |
||||
</layout> |
||||
</widget> |
||||
</widget> |
||||
</item> |
||||
<item row="1" column="0"> |
||||
<widget class="QPushButton" name="b_add"> |
||||
<property name="text"> |
||||
<string>Add...</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="1" column="1"> |
||||
<widget class="QPushButton" name="b_remove"> |
||||
<property name="text"> |
||||
<string>Remove</string> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
<item row="0" column="0" colspan="2"> |
||||
<widget class="QListWidget" name="lw_strategies"> |
||||
<property name="sizePolicy"> |
||||
<sizepolicy hsizetype="Maximum" vsizetype="Expanding"> |
||||
<horstretch>0</horstretch> |
||||
<verstretch>0</verstretch> |
||||
</sizepolicy> |
||||
</property> |
||||
<property name="selectionMode"> |
||||
<enum>QAbstractItemView::ExtendedSelection</enum> |
||||
</property> |
||||
</widget> |
||||
</item> |
||||
</layout> |
||||
</widget> |
||||
<customwidgets> |
||||
<customwidget> |
||||
<class>PerformanceCanvas</class> |
||||
<extends>QWidget</extends> |
||||
<header>ui/performancecanvas.h</header> |
||||
<container>1</container> |
||||
</customwidget> |
||||
<customwidget> |
||||
<class>CorrelationChartCanvas</class> |
||||
<extends>QWidget</extends> |
||||
<header>ui/correlationchartcanvas.h</header> |
||||
<container>1</container> |
||||
</customwidget> |
||||
</customwidgets> |
||||
<resources/> |
||||
<connections> |
||||
<connection> |
||||
<sender>b_add</sender> |
||||
<signal>clicked()</signal> |
||||
<receiver>PerformanceWidget</receiver> |
||||
<slot>addResults()</slot> |
||||
<hints> |
||||
<hint type="sourcelabel"> |
||||
<x>127</x> |
||||
<y>539</y> |
||||
</hint> |
||||
<hint type="destinationlabel"> |
||||
<x>262</x> |
||||
<y>543</y> |
||||
</hint> |
||||
</hints> |
||||
</connection> |
||||
<connection> |
||||
<sender>b_remove</sender> |
||||
<signal>clicked()</signal> |
||||
<receiver>PerformanceWidget</receiver> |
||||
<slot>removeResults()</slot> |
||||
<hints> |
||||
<hint type="sourcelabel"> |
||||
<x>239</x> |
||||
<y>539</y> |
||||
</hint> |
||||
<hint type="destinationlabel"> |
||||
<x>372</x> |
||||
<y>542</y> |
||||
</hint> |
||||
</hints> |
||||
</connection> |
||||
<connection> |
||||
<sender>rb_daily</sender> |
||||
<signal>toggled(bool)</signal> |
||||
<receiver>PerformanceWidget</receiver> |
||||
<slot>dailyToggled(bool)</slot> |
||||
<hints> |
||||
<hint type="sourcelabel"> |
||||
<x>314</x> |
||||
<y>44</y> |
||||
</hint> |
||||
<hint type="destinationlabel"> |
||||
<x>508</x> |
||||
<y>537</y> |
||||
</hint> |
||||
</hints> |
||||
</connection> |
||||
<connection> |
||||
<sender>rb_monthly</sender> |
||||
<signal>toggled(bool)</signal> |
||||
<receiver>PerformanceWidget</receiver> |
||||
<slot>monthlyToggled(bool)</slot> |
||||
<hints> |
||||
<hint type="sourcelabel"> |
||||
<x>572</x> |
||||
<y>47</y> |
||||
</hint> |
||||
<hint type="destinationlabel"> |
||||
<x>647</x> |
||||
<y>546</y> |
||||
</hint> |
||||
</hints> |
||||
</connection> |
||||
</connections> |
||||
<slots> |
||||
<slot>addResults()</slot> |
||||
<slot>removeResults()</slot> |
||||
<slot>dailyToggled(bool)</slot> |
||||
<slot>monthlyToggled(bool)</slot> |
||||
</slots> |
||||
</ui> |
||||
Loading…
Reference in new issue