Skip to content

Commit

Permalink
Rework on Strategy UI + fix minor bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Skinok committed May 23, 2023
1 parent e3d1d3d commit 32e6c7f
Show file tree
Hide file tree
Showing 10 changed files with 1,043 additions and 298 deletions.
2 changes: 1 addition & 1 deletion SkinokBacktraderUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def importData(self, fileNames):
self.interface.drawChart(df, timeframe)

# Enable run button
self.interface.strategyTesterUI.runBacktestPB.setEnabled(True)
self.interface.strategyTesterUI.runBacktestBtn.setEnabled(True)

return True

Expand Down
11 changes: 6 additions & 5 deletions finplotWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(self, dockArea, dockChart, interface):

self.last_ax_data_xtick = []


pass

#########
Expand All @@ -68,6 +68,7 @@ def createPlotWidgets(self, timeframe):
# Ax Profit & Loss
self.interface.strategyResultsUI.ResultsTabWidget.widget(1).layout().addWidget(self.axPnL.ax_widget)

fplt.add_crosshair_info(self.update_crosshair_text, ax=self.ax0)
pass

def drawCandles(self):
Expand All @@ -76,7 +77,7 @@ def drawCandles(self):

#self.hover_label = fplt.add_legend('', ax=self.ax0)
#fplt.set_time_inspector(self.update_legend_text, ax=self.ax0, when='hover', data=data)
fplt.add_crosshair_info(self.update_crosshair_text, ax=self.ax0)


# Inside plot widget controls
#self.createControlPanel(self.ax0.ax_widget)
Expand Down Expand Up @@ -238,9 +239,9 @@ def update_legend_text(self, x, y, ax, data):
pass

def update_crosshair_text(self,x, y, xtext, ytext):
ytext = '%s \n open: %.4f\n close: %.4f\n high: %.4f\n low: %.4f' \
% (ytext, self.data.iloc[x].Open, self.data.iloc[x].Close, self.data.iloc[x].High, self.data.iloc[x].Low)
return xtext, ytext
ytext = '%s \n Open: %.5f\n Close: %.5f\n High: %.5f\n Low: %.5f' \
% (ytext, self.data.iloc[x].Open, self.data.iloc[x].Close, self.data.iloc[x].High, self.data.iloc[x].Low)
return xtext,ytext

def activateDarkMode(self, activated):

Expand Down
6 changes: 4 additions & 2 deletions strategyResultsUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@

class StrategyResultsUI(QtWidgets.QWidget):

def __init__(self, controller):
def __init__(self, controller, parent = None):
super(StrategyResultsUI, self).__init__()

self.controller = controller

self.parent = parent

# It does not finish by a "/"
self.current_dir_path = os.path.dirname(os.path.realpath(__file__))

uic.loadUi( self.current_dir_path + "/ui/strategyResults.ui", self)

self.SummaryGB = self.findChild(QtWidgets.QGroupBox, "SummaryGB")
self.summaryTableWidget= self.findChild(QtWidgets.QTableWidget, "summaryTableWidget")
self.TradesGB = self.findChild(QtWidgets.QGroupBox, "TradesGB")

124 changes: 117 additions & 7 deletions strategyTesterUI.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,58 @@
from PyQt6 import QtCore, QtWidgets, uic

import os
import loadDataFilesUI

class StrategyTesterUI(QtWidgets.QWidget):

def __init__(self, controller):
def __init__(self, controller, parentWindow):
super(StrategyTesterUI, self).__init__()

self.controller = controller

self.parent = parentWindow

# It does not finish by a "/"
self.current_dir_path = os.path.dirname(os.path.realpath(__file__))

uic.loadUi( self.current_dir_path + "/ui/strategyTester.ui", self)

# Data
self.importDataBtn = self.findChild(QtWidgets.QPushButton, "importDataBtn")
self.importDataBtn.clicked.connect( self.loadData )

# Strategy type PushButtons
self.strategyTypeAITensorFlowBtn = self.findChild(QtWidgets.QPushButton, "strategyTypeAITensorFlowBtn")
self.strategyTypeAiStablebaselinesBtn = self.findChild(QtWidgets.QPushButton, "strategyTypeAiStablebaselinesBtn")
self.strategyTypeAlgoBtn = self.findChild(QtWidgets.QPushButton, "strategyTypeAlgoBtn")
self.strategyTypeAiTorchBtn = self.findChild(QtWidgets.QPushButton, "strategyTypeAiTorchBtn")

self.runBacktestPB = self.findChild(QtWidgets.QPushButton, "runBacktestPB")
self.runBacktestPB.clicked.connect(self.run)
self.strategyTypeDetailsSW = self.findChild(QtWidgets.QStackedWidget, "strategyTypeDetailsSW")

self.runningStratPB = self.findChild(QtWidgets.QProgressBar, "runningStratPB")
# Ai Algo
self.AiModelPathLE = self.findChild(QtWidgets.QLineEdit, "AiModelPathLE")
self.AiModelPathBtn = self.findChild(QtWidgets.QPushButton, "AiModelPathBtn")

# Custom Algo
self.runningStratBtn = self.findChild(QtWidgets.QProgressBar, "runningStratBtn")
self.strategyNameCB = self.findChild(QtWidgets.QComboBox, "strategyNameCB")

# Run button
self.runBacktestBtn = self.findChild(QtWidgets.QPushButton, "runBacktestBtn")

# Connect ui buttons
self.strategyTypeAITensorFlowBtn.clicked.connect(self.strategyTypeAITensorFlowActivated)
self.strategyTypeAiStablebaselinesBtn.clicked.connect(self.strategyTypeAiStablebaselinesActivated)
self.strategyTypeAiTorchBtn.clicked.connect(self.strategyTypeAiTorchActivated)
self.strategyTypeAlgoBtn.clicked.connect(self.strategyTypeAlgoActivated)

self.AiModelPathBtn.clicked.connect(self.openAiFileDialog)

self.strategyNameCB.currentIndexChanged.connect(self.strategyNameActivated)
self.runBacktestBtn.clicked.connect(self.run)

self.runBacktestPB.setEnabled(False)
# Init Run button to false waiting for user inputs
self.runBacktestBtn.setEnabled(False)

def initialize(self):

Expand All @@ -33,16 +63,96 @@ def initialize(self):
self.strategyBaseName = []
for stratName in self.strategyNames:
# here remove file extension
self.strategyBaseName.append(QtCore.QFileInfo(stratName).baseName())
if not stratName.startswith('Ai'):
self.strategyBaseName.append(QtCore.QFileInfo(stratName).baseName())

self.strategyNameCB.addItems(self.strategyBaseName)
self.strategyNameCB.setCurrentIndex(self.strategyNameCB.count()-1)

#
self.loadDataFileUI = loadDataFilesUI.LoadDataFilesUI(self.controller, self.parent)
self.loadDataFileUI.hide()
pass

def loadData(self):
self.loadDataFileUI.show()
pass

def run(self):
self.controller.run()
pass

def strategyNameActivated(self):
stratBaseName = self.strategyNameCB.currentText()
self.controller.addStrategy(stratBaseName)

pass

def strategyTypeAITensorFlowActivated(self):
if self.strategyTypeAITensorFlowBtn.isChecked():
self.strategyTypeDetailsSW.setCurrentIndex(1)
self.AiModelChecked = "AiTensorFlowModel"
pass

def strategyTypeAiStablebaselinesActivated(self):
if self.strategyTypeAiStablebaselinesBtn.isChecked():
self.strategyTypeDetailsSW.setCurrentIndex(1)
self.AiModelChecked = "AiStableBaselinesModel"
pass

def strategyTypeAiTorchActivated(self):
if self.strategyTypeAiTorchBtn.isChecked():
self.strategyTypeDetailsSW.setCurrentIndex(1)
self.AiModelChecked = "AiTorchModel"
pass

def strategyTypeAlgoActivated(self):
if self.strategyTypeAlgoBtn.isChecked():
self.strategyTypeDetailsSW.setCurrentIndex(0)
pass

def openAiFileDialog(self):

if self.AiModelChecked == "AiTensorFlowModel":
self.loadTFModel()
elif self.AiModelChecked == "AiStableBaselinesModel":
self.loadStableBaselinesModel()
elif self.AiModelChecked == "AiTorchModel":
self.loadTorchModel()

pass

# Load an AI Model from Tensor Flow framework
def loadTFModel(self):

ai_model_dir = QtWidgets.QFileDialog.getExistingDirectory(self.parent,"Open Tensorflow Model", self.current_dir_path)

self.controller.addStrategy(self.AiModelChecked)

self.AiModelPathLE.setText(ai_model_dir)
self.controller.strategyParametersSave("model", ai_model_dir)

pass

# Load an AI Model from Stable Baselines framework
def loadStableBaselinesModel(self):

ai_model_zip_file = QtWidgets.QFileDialog.getOpenFileName(self.parent,"Open Torch Model", self.current_dir_path, "*.zip")[0]

self.controller.addStrategy(self.AiModelChecked)

self.AiModelPathLE.setText(ai_model_zip_file)
self.controller.strategyParametersSave("model", ai_model_zip_file)

pass

# Load an AI Model from Py Torch framework
def loadTorchModel(self):

ai_model_zip_file = QtWidgets.QFileDialog.getOpenFileName(self.parent,"Open Torch Model", self.current_dir_path, "*.zip")[0]

self.controller.addStrategy(self.AiModelChecked)

self.AiModelPathLE.setText(ai_model_zip_file)
self.controller.strategyParametersSave("model", ai_model_zip_file)

pass
104 changes: 104 additions & 0 deletions ui/loadDataFiles_ui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Form implementation generated from reading ui file 'c:\perso\trading\anaconda3\backtrader-ichimoku\ui\loadDataFiles.ui'
#
# Created by: PyQt6 UI code generator 6.5.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.


from PyQt6 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(488, 458)
self.gridLayout_2 = QtWidgets.QGridLayout(Form)
self.gridLayout_2.setObjectName("gridLayout_2")
self.dataFilesListWidget = QtWidgets.QListWidget(parent=Form)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.dataFilesListWidget.sizePolicy().hasHeightForWidth())
self.dataFilesListWidget.setSizePolicy(sizePolicy)
self.dataFilesListWidget.setObjectName("dataFilesListWidget")
self.gridLayout_2.addWidget(self.dataFilesListWidget, 3, 0, 1, 1)
self.label_4 = QtWidgets.QLabel(parent=Form)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 2, 0, 1, 1)
self.importPB = QtWidgets.QPushButton(parent=Form)
self.importPB.setMinimumSize(QtCore.QSize(0, 40))
self.importPB.setObjectName("importPB")
self.gridLayout_2.addWidget(self.importPB, 5, 0, 1, 2)
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.gridLayout_2.addLayout(self.verticalLayout, 3, 1, 1, 1)
self.groupBox = QtWidgets.QGroupBox(parent=Form)
self.groupBox.setObjectName("groupBox")
self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
self.gridLayout.setObjectName("gridLayout")
self.semicolonRB = QtWidgets.QRadioButton(parent=self.groupBox)
self.semicolonRB.setObjectName("semicolonRB")
self.gridLayout.addWidget(self.semicolonRB, 3, 3, 1, 1)
self.label = QtWidgets.QLabel(parent=self.groupBox)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.label_3 = QtWidgets.QLabel(parent=self.groupBox)
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
self.label_2 = QtWidgets.QLabel(parent=self.groupBox)
self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 3, 0, 1, 1)
self.tabRB = QtWidgets.QRadioButton(parent=self.groupBox)
self.tabRB.setChecked(True)
self.tabRB.setObjectName("tabRB")
self.gridLayout.addWidget(self.tabRB, 3, 1, 1, 1)
self.commaRB = QtWidgets.QRadioButton(parent=self.groupBox)
self.commaRB.setObjectName("commaRB")
self.gridLayout.addWidget(self.commaRB, 3, 2, 1, 1)
self.filePathLE = QtWidgets.QLineEdit(parent=self.groupBox)
self.filePathLE.setObjectName("filePathLE")
self.gridLayout.addWidget(self.filePathLE, 0, 1, 1, 3)
self.openFilePB = QtWidgets.QToolButton(parent=self.groupBox)
self.openFilePB.setObjectName("openFilePB")
self.gridLayout.addWidget(self.openFilePB, 0, 4, 1, 1)
self.datetimeFormatLE = QtWidgets.QComboBox(parent=self.groupBox)
self.datetimeFormatLE.setObjectName("datetimeFormatLE")
self.gridLayout.addWidget(self.datetimeFormatLE, 1, 1, 1, 4)
self.loadFilePB = QtWidgets.QPushButton(parent=self.groupBox)
self.loadFilePB.setMinimumSize(QtCore.QSize(0, 40))
self.loadFilePB.setObjectName("loadFilePB")
self.gridLayout.addWidget(self.loadFilePB, 4, 1, 1, 4)
self.errorLabel = QtWidgets.QLabel(parent=self.groupBox)
self.errorLabel.setStyleSheet("color: red")
self.errorLabel.setText("")
self.errorLabel.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.errorLabel.setObjectName("errorLabel")
self.gridLayout.addWidget(self.errorLabel, 5, 0, 1, 5)
self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 2)
self.label_5 = QtWidgets.QLabel(parent=Form)
self.label_5.setStyleSheet("font-style: italic")
self.label_5.setScaledContents(False)
self.label_5.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label_5.setWordWrap(True)
self.label_5.setObjectName("label_5")
self.gridLayout_2.addWidget(self.label_5, 4, 0, 1, 1)

self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)

def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Import one or multiple data files"))
self.label_4.setText(_translate("Form", "List of all files to import in cerebro"))
self.importPB.setText(_translate("Form", "Import all data files"))
self.groupBox.setTitle(_translate("Form", "Loading a new data file"))
self.semicolonRB.setText(_translate("Form", "semicolon"))
self.label.setText(_translate("Form", "Import a new data file"))
self.label_3.setText(_translate("Form", "Date time format"))
self.label_2.setText(_translate("Form", "Separator"))
self.tabRB.setText(_translate("Form", "tab"))
self.commaRB.setText(_translate("Form", "comma"))
self.openFilePB.setText(_translate("Form", "..."))
self.loadFilePB.setText(_translate("Form", "Load .CSV file"))
self.label_5.setText(_translate("Form", "Files should be ordered from lower (on top) to higher timeframe (at bottom)."))
Loading

0 comments on commit 32e6c7f

Please sign in to comment.