Skip to content

Commit 71630a3

Browse files
committed
save code changes
1 parent 543ebb2 commit 71630a3

File tree

9 files changed

+603
-65
lines changed

9 files changed

+603
-65
lines changed

.qt_for_python/uic/loadDataFiles.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
class Ui_Form(object):
1515
def setupUi(self, Form):
1616
Form.setObjectName("Form")
17-
Form.resize(390, 458)
17+
Form.resize(488, 458)
1818
self.gridLayout_2 = QtWidgets.QGridLayout(Form)
1919
self.gridLayout_2.setObjectName("gridLayout_2")
2020
self.dataFilesListWidget = QtWidgets.QListWidget(Form)
@@ -29,6 +29,7 @@ def setupUi(self, Form):
2929
self.label_4.setObjectName("label_4")
3030
self.gridLayout_2.addWidget(self.label_4, 2, 0, 1, 1)
3131
self.importPB = QtWidgets.QPushButton(Form)
32+
self.importPB.setMinimumSize(QtCore.QSize(0, 40))
3233
self.importPB.setObjectName("importPB")
3334
self.gridLayout_2.addWidget(self.importPB, 5, 0, 1, 2)
3435
self.verticalLayout = QtWidgets.QVBoxLayout()
@@ -38,40 +39,44 @@ def setupUi(self, Form):
3839
self.groupBox.setObjectName("groupBox")
3940
self.gridLayout = QtWidgets.QGridLayout(self.groupBox)
4041
self.gridLayout.setObjectName("gridLayout")
42+
self.semicolonRB = QtWidgets.QRadioButton(self.groupBox)
43+
self.semicolonRB.setObjectName("semicolonRB")
44+
self.gridLayout.addWidget(self.semicolonRB, 3, 3, 1, 1)
4145
self.label = QtWidgets.QLabel(self.groupBox)
4246
self.label.setObjectName("label")
4347
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
44-
self.filePathLE = QtWidgets.QLineEdit(self.groupBox)
45-
self.filePathLE.setObjectName("filePathLE")
46-
self.gridLayout.addWidget(self.filePathLE, 0, 1, 1, 2)
47-
self.openFilePB = QtWidgets.QToolButton(self.groupBox)
48-
self.openFilePB.setObjectName("openFilePB")
49-
self.gridLayout.addWidget(self.openFilePB, 0, 3, 1, 1)
5048
self.label_3 = QtWidgets.QLabel(self.groupBox)
5149
self.label_3.setObjectName("label_3")
5250
self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
53-
self.datetimeFormatLE = QtWidgets.QLineEdit(self.groupBox)
54-
self.datetimeFormatLE.setObjectName("datetimeFormatLE")
55-
self.gridLayout.addWidget(self.datetimeFormatLE, 1, 1, 1, 2)
5651
self.label_2 = QtWidgets.QLabel(self.groupBox)
5752
self.label_2.setObjectName("label_2")
58-
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
53+
self.gridLayout.addWidget(self.label_2, 3, 0, 1, 1)
5954
self.tabRB = QtWidgets.QRadioButton(self.groupBox)
6055
self.tabRB.setChecked(True)
6156
self.tabRB.setObjectName("tabRB")
62-
self.gridLayout.addWidget(self.tabRB, 2, 1, 1, 1)
57+
self.gridLayout.addWidget(self.tabRB, 3, 1, 1, 1)
6358
self.commaRB = QtWidgets.QRadioButton(self.groupBox)
6459
self.commaRB.setObjectName("commaRB")
65-
self.gridLayout.addWidget(self.commaRB, 2, 2, 1, 1)
60+
self.gridLayout.addWidget(self.commaRB, 3, 2, 1, 1)
61+
self.filePathLE = QtWidgets.QLineEdit(self.groupBox)
62+
self.filePathLE.setObjectName("filePathLE")
63+
self.gridLayout.addWidget(self.filePathLE, 0, 1, 1, 3)
64+
self.openFilePB = QtWidgets.QToolButton(self.groupBox)
65+
self.openFilePB.setObjectName("openFilePB")
66+
self.gridLayout.addWidget(self.openFilePB, 0, 4, 1, 1)
67+
self.datetimeFormatLE = QtWidgets.QLineEdit(self.groupBox)
68+
self.datetimeFormatLE.setObjectName("datetimeFormatLE")
69+
self.gridLayout.addWidget(self.datetimeFormatLE, 1, 1, 1, 4)
70+
self.loadFilePB = QtWidgets.QPushButton(self.groupBox)
71+
self.loadFilePB.setMinimumSize(QtCore.QSize(0, 40))
72+
self.loadFilePB.setObjectName("loadFilePB")
73+
self.gridLayout.addWidget(self.loadFilePB, 4, 1, 1, 4)
6674
self.errorLabel = QtWidgets.QLabel(self.groupBox)
6775
self.errorLabel.setStyleSheet("color: red")
6876
self.errorLabel.setText("")
6977
self.errorLabel.setAlignment(QtCore.Qt.AlignCenter)
7078
self.errorLabel.setObjectName("errorLabel")
71-
self.gridLayout.addWidget(self.errorLabel, 4, 0, 1, 3)
72-
self.loadFilePB = QtWidgets.QPushButton(self.groupBox)
73-
self.loadFilePB.setObjectName("loadFilePB")
74-
self.gridLayout.addWidget(self.loadFilePB, 3, 1, 1, 2)
79+
self.gridLayout.addWidget(self.errorLabel, 5, 0, 1, 5)
7580
self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 2)
7681
self.label_5 = QtWidgets.QLabel(Form)
7782
self.label_5.setStyleSheet("font-style: italic")
@@ -90,11 +95,12 @@ def retranslateUi(self, Form):
9095
self.label_4.setText(_translate("Form", "List of all files to import in cerebro"))
9196
self.importPB.setText(_translate("Form", "Import all data files"))
9297
self.groupBox.setTitle(_translate("Form", "Loading a new data file"))
98+
self.semicolonRB.setText(_translate("Form", "semicolon"))
9399
self.label.setText(_translate("Form", "Import a new data file"))
94-
self.openFilePB.setText(_translate("Form", "..."))
95100
self.label_3.setText(_translate("Form", "Date time format"))
96101
self.label_2.setText(_translate("Form", "Separator"))
97102
self.tabRB.setText(_translate("Form", "tab"))
98103
self.commaRB.setText(_translate("Form", "comma"))
104+
self.openFilePB.setText(_translate("Form", "..."))
99105
self.loadFilePB.setText(_translate("Form", "Load .CSV file"))
100106
self.label_5.setText(_translate("Form", "Files should be ordered from lower (on top) to higher timeframe (at bottom)."))

SkinokBacktraderUI.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ def loadData(self, dataPath, datetimeFormat, separator):
125125
return False, "ValueError error:" + str(err)
126126
except AttributeError as err:
127127
return False, "AttributeError error:" + str(err)
128+
except IndexError as err:
129+
return False, "IndexError error:" + str(err)
128130
except :
129131
return False, "Unexpected error:" + str(sys.exc_info()[0])
130132

@@ -225,7 +227,7 @@ def strategyParametersChanged(self, lineEdit, parameterName, parameterOldValue):
225227
if isinstance(param, int):
226228
self.strategyParameters[parameterName] = int(lineEdit.text())
227229
elif isinstance(param, float):
228-
self.strategyParameters[parameterName] = int(lineEdit.text())
230+
self.strategyParameters[parameterName] = float(lineEdit.text())
229231
else:
230232
self.strategyParameters[parameterName] = lineEdit.text()
231233

@@ -246,8 +248,8 @@ def run(self):
246248
self.interface.resetChart()
247249

248250
# Add strategy here to get modified parameters
249-
test = self.strategyParameters
250-
self.strategyIndex = self.cerebro.addstrategy(self.strategyClass, test)
251+
params = self.strategyParameters
252+
self.strategyIndex = self.cerebro.addstrategy(self.strategyClass, params)
251253

252254
# Wallet Management : reset between each run
253255
self.cerebro.broker.setcash(self.startingcash)

indicators/ichimoku.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414

1515
class Ichimoku():
1616

17+
'''
18+
THIS CLASS TAKE A PANDA DATAFRAME AS INPUT, AND NOT A BACKTRADER DATA FEED (Use bt.Ind.Ichimoku instead)
19+
'''
20+
21+
1722
'''
1823
Developed and published in his book in 1969 by journalist Goichi Hosoda
1924
@@ -37,6 +42,10 @@ class Ichimoku():
3742
3843
'''
3944

45+
46+
'''
47+
THIS METHOD TAKE A PANDA DATAFRAME AS INPUT, AND NOT A BACKTRADER DATA FEED (Use bt.Ind.Ichimoku instead)
48+
'''
4049
def __init__(self, dataFrames, tenkan = 9, kijun = 26, senkou = 52, senkou_lead = 26, chikou = 26):
4150

4251
# Tenkan-sen (Conversion Line): (9-period high + 9-period low)/2))

loadDataFilesUI.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def __init__(self, controller, parent = None):
2323

2424
self.tabRB = self.findChild(QtWidgets.QRadioButton, "tabRB")
2525
self.commaRB = self.findChild(QtWidgets.QRadioButton, "commaRB")
26+
self.semicolonRB = self.findChild(QtWidgets.QRadioButton, "semicolonRB")
2627

2728
self.openFilePB = self.findChild(QtWidgets.QToolButton, "openFilePB")
2829
self.loadFilePB = self.findChild(QtWidgets.QPushButton, "loadFilePB")
@@ -51,7 +52,7 @@ def openFile(self):
5152
def loadFile(self):
5253

5354
# try loading file by controller
54-
separator = '\t' if self.tabRB.isChecked() else ','
55+
separator = '\t' if self.tabRB.isChecked() else ',' if self.commaRB.isChecked() else ';'
5556
success, errorMessage = self.controller.loadData(self.dataFileName, self.datetimeFormatLE.text(), separator)
5657

5758
if success:

strategies/AiStableBaselinesModel.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
###############################################################################
2+
#
3+
# Copyright (C) 2021 - Skinok
4+
#
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License as published by
7+
# the Free Software Foundation, either version 3 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
#
18+
###############################################################################
19+
import backtrader as bt
20+
21+
import metaStrategy as mt
22+
23+
from stable_baselines3 import PPO
24+
25+
import numpy as np
26+
from enum import Enum
27+
28+
# action list
29+
class Action(Enum):
30+
HOLD=0
31+
BUY=1
32+
SELL=2
33+
34+
# Create a subclass of Strategy to define the indicators and logic
35+
class AiStableBaselinesModel(mt.MetaStrategy):
36+
37+
params = (
38+
('model', ""), # Model name
39+
('tradeSize', 5000),
40+
('atrperiod', 14), # ATR Period (standard)
41+
('atrdist_SL', 3), # ATR distance for stop price
42+
('atrdist_TP', 5), # ATR distance for take profit price
43+
)
44+
45+
def notify_order(self, order):
46+
if order.status == order.Completed:
47+
#print("Order completed")
48+
pass
49+
50+
if not order.alive():
51+
self.order = None # indicate no order is pending
52+
53+
def __init__(self, *argv):
54+
55+
# used to modify parameters
56+
super().__init__(argv[0])
57+
58+
# Ichi indicator
59+
self.ichimoku = bt.ind.Ichimoku()
60+
61+
# To set the stop price
62+
self.atr = bt.indicators.ATR(self.data, period=self.p.atrperiod)
63+
64+
self.stochastic = bt.ind.stochastic.Stochastic(self.data)
65+
66+
pass
67+
68+
def start(self):
69+
self.order = None # sentinel to avoid operrations on pending order
70+
71+
# Load the model
72+
self.model = PPO.load(self.p.model)
73+
pass
74+
75+
def next(self):
76+
77+
self.obseravation = self.next_observation()
78+
79+
# Prepare data for Model
80+
action, _states = self.model.predict(self.obseravation) # deterministic=True
81+
82+
if not self.position: # not in the market
83+
84+
if action == Action.SELL.value:
85+
self.order = self.sell(size=self.p.tradeSize)
86+
ldist = self.atr[0] * self.p.atrdist_SL
87+
self.lstop = self.data.close[0] + ldist
88+
pdist = self.atr[0] * self.p.atrdist_TP
89+
self.take_profit = self.data.close[0] - pdist
90+
91+
elif action == Action.BUY.value:
92+
self.order = self.buy(size=self.p.tradeSize)
93+
ldist = self.atr[0] * self.p.atrdist_SL
94+
self.lstop = self.data.close[0] - ldist
95+
pdist = self.atr[0] * self.p.atrdist_TP
96+
self.take_profit = self.data.close[0] + pdist
97+
98+
else: # in the market
99+
pclose = self.data.close[0]
100+
pstop = self.lstop # seems to be the bug
101+
102+
if (not ((pstop<pclose<self.take_profit)|(pstop>pclose>self.take_profit))):
103+
self.close() # Close position
104+
105+
pass
106+
107+
# Here you have to transform self object price and indicators into a np.array input for AI Model
108+
# How you do it depend on your AI Model inputs
109+
# Strategy is in the data preparation for AI :D
110+
def next_observation(self):
111+
112+
# https://stackoverflow.com/questions/53979199/tensorflow-keras-returning-multiple-predictions-while-expecting-one
113+
114+
# Ichimoku
115+
inputs = [ self.ichimoku.tenkan[0], self.ichimoku.kijun[0], self.ichimoku.senkou[0], self.ichimoku.senkou_lead[0], self.ichimoku.chikou[0] ]
116+
117+
# Stochastic
118+
inputs = inputs + [self.stochastic.percK[0] / 100.0, self.stochastic.percD[0] / 100.0]
119+
120+
return np.array(inputs)
121+
122+
pass

0 commit comments

Comments
 (0)