Skip to content

Commit 7eb9f8f

Browse files
committed
Loading data : the user config file now load previous data files
1 parent 7faa0bb commit 7eb9f8f

10 files changed

+266
-122
lines changed

Diff for: Singleton.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Singleton:
2+
__instance = None
3+
4+
def __new__(cls,*args, **kwargs):
5+
if cls.__instance is None :
6+
cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
7+
return cls.__instance

Diff for: SkinokBacktraderUI.py

+44-64
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
from CerebroEnhanced import *
2424

2525
import sys, os
26+
27+
from dataManager import DataManager
2628
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/observers')
2729
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/strategies')
2830
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/../finplot')
@@ -34,6 +36,7 @@
3436

3537
from observers.SkinokObserver import SkinokObserver
3638
from wallet import Wallet
39+
from userConfig import UserConfig
3740

3841
class SkinokBacktraderUI:
3942

@@ -64,6 +67,42 @@ def __init__(self):
6467
# Timeframes
6568
self.timeFrameIndex = {"M1" : 0, "M5" : 10, "M15": 20, "M30": 30, "H1":40, "H4":50, "D":60, "W":70}
6669

70+
self.dataManager = DataManager()
71+
72+
# Restore previous session for faster tests
73+
self.loadConfig()
74+
75+
pass
76+
77+
def loadConfig(self):
78+
79+
userConfig = UserConfig()
80+
userConfig.loadConfigFile()
81+
82+
isEmpty = True
83+
84+
# Load previous data files
85+
for timeframe in self.timeFrameIndex.keys():
86+
87+
if timeframe in userConfig.data.keys():
88+
89+
filePath = userConfig.data[timeframe]['filePath']
90+
timeFormat = userConfig.data[timeframe]['timeFormat']
91+
separator = userConfig.data[timeframe]['separator']
92+
93+
fileName = os.path.basename(filePath)
94+
95+
df, errorMessage = self.dataManager.loadDataFile(filePath,timeFormat, separator)
96+
97+
if df is not None:
98+
self.dataframes[fileName] = df
99+
isEmpty = False
100+
else:
101+
print(f" Error loading user data file : {errorMessage}")
102+
103+
if not isEmpty:
104+
self.importData()
105+
67106
pass
68107

69108
def resetCerebro(self):
@@ -97,53 +136,16 @@ def resetCerebro(self):
97136

98137
pass
99138

100-
# Return True if loading is successfull & the error string if False
101-
def loadData(self, dataPath, datetimeFormat, separator):
102139

103-
# Try importing data file
104-
# We should code a widget that ask for options as : separators, date format, and so on...
105-
try:
106-
fileName = os.path.basename(dataPath)
107-
108-
# Python contains
109-
if not dataPath in self.dataframes:
110-
if pd.__version__<'2.0.0':
111-
self.dataframes[fileName] = pd.read_csv(dataPath,
112-
sep=separator,
113-
parse_dates=[0],
114-
date_parser=lambda x: pd.to_datetime(x, format=datetimeFormat),
115-
skiprows=0,
116-
header=0,
117-
names=["Time", "Open", "High", "Low", "Close", "Volume"],
118-
index_col=0)
119-
else:
120-
self.dataframes[fileName] = pd.read_csv(dataPath,
121-
sep=separator,
122-
parse_dates=[0],
123-
date_format=datetimeFormat,
124-
skiprows=0,
125-
header=0,
126-
names=["Time", "Open", "High", "Low", "Close", "Volume"],
127-
index_col=0)
128-
129-
except ValueError as err:
130-
return False, "ValueError error:" + str(err)
131-
except AttributeError as err:
132-
return False, "AttributeError error:" + str(err)
133-
except IndexError as err:
134-
return False, "IndexError error:" + str(err)
135-
except :
136-
return False, "Unexpected error:" + str(sys.exc_info()[0])
137-
138-
return True, ""
139-
140-
def importData(self, fileNames):
140+
def importData(self):
141141

142142
try:
143+
144+
fileNames = list(self.dataframes.keys())
143145

144146
# Sort data by timeframe
145147
# For cerebro, we need to add lower timeframes first
146-
fileNames.sort( key=lambda x: self.timeFrameIndex[self.findTimeFrame(self.dataframes[x])])
148+
fileNames.sort( key=lambda x: self.timeFrameIndex[self.dataManager.findTimeFrame(self.dataframes[x])] )
147149

148150
# Files should be loaded in the good order
149151
for fileName in fileNames:
@@ -160,7 +162,7 @@ def importData(self, fileNames):
160162
self.cerebro.adddata(self.data) # Add the data feed
161163

162164
# Find timeframe
163-
timeframe = self.findTimeFrame(df)
165+
timeframe = self.dataManager.findTimeFrame(df)
164166

165167
# Create the chart window for the good timeframe (if it does not already exists?)
166168
self.interface.createChartDock(timeframe)
@@ -182,29 +184,7 @@ def importData(self, fileNames):
182184
return False
183185
pass
184186

185-
def findTimeFrame(self, df):
186-
187-
if len(df.index) > 2:
188-
dtDiff = df.index[1] - df.index[0]
189-
190-
if dtDiff.total_seconds() == 60:
191-
return "M1"
192-
elif dtDiff.total_seconds() == 300:
193-
return "M5"
194-
elif dtDiff.total_seconds() == 900:
195-
return "M15"
196-
elif dtDiff.total_seconds() == 1800:
197-
return "M30"
198-
elif dtDiff.total_seconds() == 3600:
199-
return "H1"
200-
elif dtDiff.total_seconds() == 14400:
201-
return "H4"
202-
elif dtDiff.total_seconds() == 86400:
203-
return "D"
204-
elif dtDiff.total_seconds() == 604800:
205-
return "W"
206187

207-
pass
208188

209189
def addStrategy(self, strategyName):
210190

Diff for: connectors/OandaV20Connector.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
3+
# Après avoir importé les librairies nécessaires
4+
class OandaV20Connector(OandaV20Store):
5+
# Le constructeur de la classe
6+
def __init__(self, token, account, practice=True):
7+
# Appelle le constructeur de la classe parente
8+
super().__init__(token=token, account=account, practice=practice)
9+
# Crée un broker à partir du store
10+
self.broker = self.getbroker()
11+
# Crée un data feed à partir du store
12+
self.data = self.getdata(dataname="EUR_USD", timeframe=bt.TimeFrame.Minutes, compression=1)
13+
14+
# Une méthode pour ajouter le data feed au Cerebro
15+
def add_data(self, cerebro):
16+
cerebro.adddata(self.data)
17+
18+
# Une méthode pour ajouter le broker au Cerebro
19+
def add_broker(self, cerebro):
20+
cerebro.setbroker(self.broker)

Diff for: dataManager.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
2+
import os,sys
3+
import Singleton
4+
import pandas as pd
5+
6+
from Singleton import Singleton
7+
8+
class DataManager(Singleton):
9+
10+
def DatetimeFormat(self, dataFilePath):
11+
fileparts = os.path.split(dataFilePath)
12+
datafile = fileparts[1]
13+
# print(datafile[-4:])
14+
if datafile[-4:]=='.csv':
15+
df = pd.read_csv(dataFilePath, nrows=1)
16+
17+
timestring = df.iloc[0,0]
18+
ncolon = timestring.count(':')
19+
if ncolon==2:
20+
return "%Y-%m-%d %H:%M:%S"
21+
elif ncolon==1:
22+
return "%Y-%m-%d %H:%M"
23+
else:
24+
nspace = timestring.count(' ')
25+
if nspace==1:
26+
return "%Y-%m-%d %H"
27+
else:
28+
return "%Y-%m-%d"
29+
30+
return ""
31+
32+
33+
# Return True if loading is successfull & the error string if False
34+
# dataPath is the full file path
35+
def loadDataFile(self, dataPath, datetimeFormat, separator):
36+
37+
# Try importing data file
38+
# We should code a widget that ask for options as : separators, date format, and so on...
39+
try:
40+
41+
# Python contains
42+
if pd.__version__<'2.0.0':
43+
df = pd.read_csv(dataPath,
44+
sep=separator,
45+
parse_dates=[0],
46+
date_parser=lambda x: pd.to_datetime(x, format=datetimeFormat),
47+
skiprows=0,
48+
header=0,
49+
names=["Time", "Open", "High", "Low", "Close", "Volume"],
50+
index_col=0)
51+
else:
52+
df = pd.read_csv(dataPath,
53+
sep=separator,
54+
parse_dates=[0],
55+
date_format=datetimeFormat,
56+
skiprows=0,
57+
header=0,
58+
names=["Time", "Open", "High", "Low", "Close", "Volume"],
59+
index_col=0)
60+
61+
return df, ""
62+
63+
except ValueError as err:
64+
return None, "ValueError error:" + str(err)
65+
except AttributeError as err:
66+
return None, "AttributeError error:" + str(err)
67+
except IndexError as err:
68+
return None, "IndexError error:" + str(err)
69+
except :
70+
return None, "Unexpected error:" + str(sys.exc_info()[0])
71+
72+
73+
def findTimeFrame(self, df):
74+
75+
if len(df.index) > 2:
76+
dtDiff = df.index[1] - df.index[0]
77+
78+
if dtDiff.total_seconds() == 60:
79+
return "M1"
80+
elif dtDiff.total_seconds() == 300:
81+
return "M5"
82+
elif dtDiff.total_seconds() == 900:
83+
return "M15"
84+
elif dtDiff.total_seconds() == 1800:
85+
return "M30"
86+
elif dtDiff.total_seconds() == 3600:
87+
return "H1"
88+
elif dtDiff.total_seconds() == 14400:
89+
return "H4"
90+
elif dtDiff.total_seconds() == 86400:
91+
return "D"
92+
elif dtDiff.total_seconds() == 604800:
93+
return "W"
94+
95+
pass

0 commit comments

Comments
 (0)