jgtfx2console 0.4.24__tar.gz → 0.4.26__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {jgtfx2console-0.4.24/jgtfx2console.egg-info → jgtfx2console-0.4.26}/PKG-INFO +1 -1
- jgtfx2console-0.4.26/jgtfx2console/LiveChartDataExport.py +431 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/__init__.py +1 -1
- jgtfx2console-0.4.26/jgtfx2console/config_generator.py +74 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26/jgtfx2console.egg-info}/PKG-INFO +1 -1
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console.egg-info/SOURCES.txt +2 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/pyproject.toml +1 -1
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/LICENSE +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/README.md +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/README.rst +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/EachRowListener.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/ForexConnect.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/LiveHistory.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/ResponseListener.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/SessionStatusListener.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/TableListener.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/TableManagerListener.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/__init__.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/common.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/errors.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/x-pyd.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/fxcli2console.py +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console.egg-info/dependency_links.txt +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console.egg-info/entry_points.txt +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console.egg-info/requires.txt +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console.egg-info/top_level.txt +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/setup.cfg +0 -0
- {jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/setup.py +0 -0
@@ -0,0 +1,431 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import time
|
3
|
+
import argparse
|
4
|
+
import os
|
5
|
+
import sys
|
6
|
+
|
7
|
+
from jgtutils import jgtcommon
|
8
|
+
|
9
|
+
|
10
|
+
path_from_where_we_call = os.getcwd()
|
11
|
+
|
12
|
+
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
|
13
|
+
|
14
|
+
c_script_dir_name = os.path.dirname(__file__)
|
15
|
+
abs_path_of_this_file = os.path.abspath(c_script_dir_name)
|
16
|
+
print("abs_path_of_this_file: "+abs_path_of_this_file)
|
17
|
+
print("c_script_dir_name: "+c_script_dir_name)
|
18
|
+
path1 = os.path.join(c_script_dir_name, '.')
|
19
|
+
print("path1: "+path1)
|
20
|
+
abs_path1 = os.path.abspath(path1)
|
21
|
+
print("abs_path1: "+abs_path1)
|
22
|
+
sys.path.append(abs_path1)
|
23
|
+
#cd to : abs_path_of_this_file #@STCIssue Wont go further that CONNECTED if we are not in that directory.
|
24
|
+
os.chdir(abs_path_of_this_file)
|
25
|
+
|
26
|
+
from forexconnect import fxcorepy, ForexConnect
|
27
|
+
from forexconnect import Common, LiveHistoryCreator
|
28
|
+
|
29
|
+
from dateutil import parser
|
30
|
+
|
31
|
+
import xml.etree.ElementTree as ET
|
32
|
+
|
33
|
+
import common_samples
|
34
|
+
import csv
|
35
|
+
import pytz
|
36
|
+
from datetime import timedelta, datetime
|
37
|
+
|
38
|
+
delimiter = None
|
39
|
+
datetime_separator = None
|
40
|
+
format_decimal_places = None
|
41
|
+
timezone = None
|
42
|
+
|
43
|
+
|
44
|
+
def parse_args():
|
45
|
+
arg_parser = argparse.ArgumentParser(description='Process command parameters.')
|
46
|
+
arg_parser.add_argument('-p',
|
47
|
+
metavar="PASSWORD",
|
48
|
+
required=False,
|
49
|
+
help='Your password.')
|
50
|
+
arg_parser.add_argument('-config', metavar="CONFIG_FILE", default='jgtfxliveconfig.xml',
|
51
|
+
help='Config file')
|
52
|
+
|
53
|
+
args = arg_parser.parse_args()
|
54
|
+
return args
|
55
|
+
|
56
|
+
|
57
|
+
verbose = 0
|
58
|
+
order_request_id = ""
|
59
|
+
|
60
|
+
|
61
|
+
class SaveNewBar:
|
62
|
+
def __init__(self, symbol, bars):
|
63
|
+
self.symbol = symbol
|
64
|
+
self.bars = bars
|
65
|
+
|
66
|
+
def save_bar(self, instrument, history, filename):
|
67
|
+
global delimiter
|
68
|
+
global datetime_separator
|
69
|
+
global format_decimal_places
|
70
|
+
global timezone
|
71
|
+
|
72
|
+
if timezone == 'Local':
|
73
|
+
time_difference = -time.timezone
|
74
|
+
else:
|
75
|
+
tz = pytz.timezone(timezone)
|
76
|
+
time_difference = tz.utcoffset(datetime.now).total_seconds()
|
77
|
+
|
78
|
+
hist = history[:-1].tail(1)
|
79
|
+
with open(filename, "a", newline="") as file:
|
80
|
+
writer = csv.writer(file, delimiter=delimiter)
|
81
|
+
last_complete_data_frame = hist
|
82
|
+
dtime = str(last_complete_data_frame.index.values[0])
|
83
|
+
|
84
|
+
dtime = dtime.replace('T', ' ')
|
85
|
+
dt = parser.parse(dtime)
|
86
|
+
dt = dt+timedelta(0, time_difference)
|
87
|
+
dt = str(dt)
|
88
|
+
dtime = dt.replace(' ', datetime_separator)
|
89
|
+
out = [dtime]
|
90
|
+
str_prices = dtime + ", "
|
91
|
+
for price_name in last_complete_data_frame:
|
92
|
+
price_entry = last_complete_data_frame.get(price_name)
|
93
|
+
price_value = price_entry.values[0]
|
94
|
+
str_prices += price_name + "=" + str(price_value) + ", "
|
95
|
+
price = price_entry.values[0]
|
96
|
+
if format_decimal_places and price_name != "Volume":
|
97
|
+
if instrument.find("JPY") >= 0:
|
98
|
+
out.append("%.3f" % price)
|
99
|
+
else:
|
100
|
+
out.append("%.5f" % price)
|
101
|
+
else:
|
102
|
+
out.append(price)
|
103
|
+
writer.writerow(out)
|
104
|
+
file.close()
|
105
|
+
print("New bar saved to "+filename+": "+str_prices[0: -2])
|
106
|
+
|
107
|
+
return
|
108
|
+
|
109
|
+
|
110
|
+
order_created_count = 0
|
111
|
+
|
112
|
+
|
113
|
+
def find_in_tree(tree, node):
|
114
|
+
found = tree.find(node)
|
115
|
+
if found is None:
|
116
|
+
found = []
|
117
|
+
return found
|
118
|
+
|
119
|
+
|
120
|
+
def on_request_completed(request_id, response):
|
121
|
+
del request_id, response
|
122
|
+
global order_created_count
|
123
|
+
order_created_count += 1
|
124
|
+
return True
|
125
|
+
|
126
|
+
|
127
|
+
def on_changed(live_history, instrument):
|
128
|
+
def _on_changed(table_listener, row_id, row):
|
129
|
+
del table_listener, row_id
|
130
|
+
try:
|
131
|
+
if row.table_type == fxcorepy.O2GTableType.OFFERS and row.instrument == instrument:
|
132
|
+
live_history.add_or_update(row)
|
133
|
+
except Exception as e:
|
134
|
+
common_samples.print_exception(e)
|
135
|
+
return
|
136
|
+
|
137
|
+
return _on_changed
|
138
|
+
|
139
|
+
|
140
|
+
def on_bar_added(instrument, filename):
|
141
|
+
def _on_bar_added(history):
|
142
|
+
snb = SaveNewBar(instrument, history[:-1])
|
143
|
+
snb.save_bar(instrument, history, filename)
|
144
|
+
|
145
|
+
return _on_bar_added
|
146
|
+
|
147
|
+
|
148
|
+
def session_status_changed(fx, live_history, instrument, str_user_id, str_password, str_url, str_connection,
|
149
|
+
reconnect_on_disconnected):
|
150
|
+
offers_listener = None
|
151
|
+
first_call = reconnect_on_disconnected
|
152
|
+
orders_listener = None
|
153
|
+
|
154
|
+
def _session_status_changed(session, status):
|
155
|
+
nonlocal offers_listener
|
156
|
+
nonlocal first_call
|
157
|
+
nonlocal orders_listener
|
158
|
+
if not first_call:
|
159
|
+
common_samples.session_status_changed(session.trading_session_descriptors, status)
|
160
|
+
else:
|
161
|
+
first_call = False
|
162
|
+
if status == fxcorepy.AO2GSessionStatus.O2GSessionStatus.CONNECTED:
|
163
|
+
offers = fx.get_table(ForexConnect.OFFERS)
|
164
|
+
if live_history is not None:
|
165
|
+
on_changed_callback = on_changed(live_history, instrument)
|
166
|
+
offers_listener = Common.subscribe_table_updates(offers, on_change_callback=on_changed_callback)
|
167
|
+
elif status == fxcorepy.AO2GSessionStatus.O2GSessionStatus.DISCONNECTING or \
|
168
|
+
status == fxcorepy.AO2GSessionStatus.O2GSessionStatus.RECONNECTING or \
|
169
|
+
status == fxcorepy.AO2GSessionStatus.O2GSessionStatus.SESSION_LOST:
|
170
|
+
if orders_listener is not None:
|
171
|
+
orders_listener.unsubscribe()
|
172
|
+
orders_listener = None
|
173
|
+
if offers_listener is not None:
|
174
|
+
offers_listener.unsubscribe()
|
175
|
+
offers_listener = None
|
176
|
+
elif status == fxcorepy.AO2GSessionStatus.O2GSessionStatus.DISCONNECTED and reconnect_on_disconnected:
|
177
|
+
fx.session.login(str_user_id, str_password, str_url, str_connection)
|
178
|
+
|
179
|
+
return _session_status_changed
|
180
|
+
|
181
|
+
|
182
|
+
def check_params(instr, tf, offer):
|
183
|
+
if not instr:
|
184
|
+
raise Exception(
|
185
|
+
"The instrument is empty")
|
186
|
+
|
187
|
+
if not tf:
|
188
|
+
raise Exception(
|
189
|
+
"The timeframe is empty")
|
190
|
+
|
191
|
+
if not offer:
|
192
|
+
raise Exception(
|
193
|
+
"The instrument '{0}' is not valid".format(instr))
|
194
|
+
|
195
|
+
|
196
|
+
def parse_xml(config_file):
|
197
|
+
try:
|
198
|
+
jgtconf=jgtcommon.readconfig()
|
199
|
+
#print(jgtconf)
|
200
|
+
except:
|
201
|
+
raise Exception(
|
202
|
+
"The JGT configuration file '$HOME/config.json' does not exist")
|
203
|
+
try:
|
204
|
+
os.stat(config_file)
|
205
|
+
except OSError:
|
206
|
+
raise Exception(
|
207
|
+
"The configuration file '{0}' does not exist".format(config_file))
|
208
|
+
|
209
|
+
xmlfile = open(config_file, "r")
|
210
|
+
conf = ET.parse(xmlfile)
|
211
|
+
root = conf.getroot()
|
212
|
+
|
213
|
+
settings = find_in_tree(root, "Settings")
|
214
|
+
|
215
|
+
|
216
|
+
str_user_id = find_in_tree(settings, "Login").text
|
217
|
+
if str_user_id == '0' or str_user_id == '' or str_user_id is None:
|
218
|
+
str_user_id =jgtconf.get('user_id')
|
219
|
+
|
220
|
+
str_url = find_in_tree(settings, "Url").text
|
221
|
+
str_connection = find_in_tree(settings, "Connection").text
|
222
|
+
if str_connection == '' or str_connection is None or str_connection=='0':
|
223
|
+
str_connection = os.getenv('connection') or jgtconf.get('connection')
|
224
|
+
str_session_id = find_in_tree(settings, "SessionID").text
|
225
|
+
str_pin = find_in_tree(settings, "Pin").text
|
226
|
+
delim = find_in_tree(settings, "Delimiter").text
|
227
|
+
output_dir = find_in_tree(settings, "OutputDir").text
|
228
|
+
#test if our path is relative
|
229
|
+
if output_dir and output_dir[0] != '/':
|
230
|
+
output_dir = os.path.join(path_from_where_we_call, output_dir)
|
231
|
+
#print("relative output_dir modified: "+output_dir)
|
232
|
+
if output_dir == '' or output_dir is None or output_dir=='0':
|
233
|
+
output_dir = os.getenv('JGTPY_DATA') or jgtconf.get('JGTPY_DATA')
|
234
|
+
dt_separator = find_in_tree(settings, "DateTimeSeparator").text
|
235
|
+
|
236
|
+
if dt_separator == '' or dt_separator is None:
|
237
|
+
dt_separator = ' '
|
238
|
+
fdp = find_in_tree(settings, "FormatDecimalPlaces").text
|
239
|
+
tzone = find_in_tree(settings, "Timezone").text
|
240
|
+
|
241
|
+
if tzone != 'EST' and tzone != 'UTC' and tzone != 'Local':
|
242
|
+
print('Timezone is not recognized, using EST')
|
243
|
+
tzone = 'UTC' #Default timezone
|
244
|
+
|
245
|
+
print("=============================")
|
246
|
+
print("User ID: " + str_user_id)
|
247
|
+
print("URL: " + str_url)
|
248
|
+
print("Connection: " + str_connection)
|
249
|
+
#print("Session ID: " + str_session_id)
|
250
|
+
#print("Pin: " + str_pin)
|
251
|
+
#print("Delimiter: " + delim)
|
252
|
+
print("Output Directory: " + output_dir)
|
253
|
+
print("DateTime Separator: " + dt_separator)
|
254
|
+
print("Format Decimal Places: " + fdp)
|
255
|
+
print("Timezone: " + tzone)
|
256
|
+
|
257
|
+
print("=============================")
|
258
|
+
|
259
|
+
if output_dir:
|
260
|
+
if not os.path.exists(output_dir):
|
261
|
+
raise Exception(
|
262
|
+
"The output directory '{0}' does not exist. (try writting an absolute path in the config or use 0 so it will read the JGTPY_DATA environment variable)".format(output_dir))
|
263
|
+
|
264
|
+
if fdp == "Y" or fdp == "y":
|
265
|
+
fdp = True
|
266
|
+
else:
|
267
|
+
fdp = False
|
268
|
+
|
269
|
+
data = []
|
270
|
+
|
271
|
+
for elem in settings.findall("History"):
|
272
|
+
data2 = [find_in_tree(elem, "Instrument").text]
|
273
|
+
data2.append(find_in_tree(elem, "Timeframe").text)
|
274
|
+
if output_dir:
|
275
|
+
ifn = find_in_tree(elem, "Filename").text
|
276
|
+
data2.append(os.path.join(output_dir, ifn))
|
277
|
+
else:
|
278
|
+
data2.append(find_in_tree(elem, "Filename").text)
|
279
|
+
data2.append(find_in_tree(elem, "NumBars").text)
|
280
|
+
data2.append(find_in_tree(elem, "Headers").text)
|
281
|
+
data.append(data2)
|
282
|
+
|
283
|
+
if len(data) == 0:
|
284
|
+
raise Exception(
|
285
|
+
"No instruments in the config file are present")
|
286
|
+
|
287
|
+
return str_user_id, str_url, str_connection, str_session_id, str_pin, \
|
288
|
+
delim, output_dir, dt_separator, fdp, tzone, data
|
289
|
+
|
290
|
+
|
291
|
+
def set_init_history(fx, lhc, instr, tf, filename, numbars, str_user_id, str_password, str_url, str_connection):
|
292
|
+
lhc.append(LiveHistoryCreator(tf))
|
293
|
+
last_index = len(lhc)-1
|
294
|
+
on_bar_added_callback = on_bar_added(instr, filename)
|
295
|
+
lhc[last_index].subscribe(on_bar_added_callback)
|
296
|
+
session_status_changed_callback = session_status_changed(fx, lhc[last_index], instr, str_user_id,
|
297
|
+
str_password, str_url, str_connection, True)
|
298
|
+
session_status_changed_callback(fx.session, fx.session.session_status)
|
299
|
+
fx.set_session_status_listener(session_status_changed_callback)
|
300
|
+
|
301
|
+
nd_array_history = fx.get_history(instr, tf, None, None, int(numbars)+2)
|
302
|
+
|
303
|
+
lhc[last_index].history = nd_array_history
|
304
|
+
|
305
|
+
return lhc, nd_array_history
|
306
|
+
|
307
|
+
|
308
|
+
def get_time_difference(tzone):
|
309
|
+
if tzone == 'Local':
|
310
|
+
time_difference = -time.timezone
|
311
|
+
else:
|
312
|
+
tz = pytz.timezone(tzone)
|
313
|
+
time_difference = tz.utcoffset(datetime.now).total_seconds()
|
314
|
+
return time_difference
|
315
|
+
|
316
|
+
|
317
|
+
def save_old_history(instr, filename, headers, nd_array_history, time_difference, dt_separator):
|
318
|
+
header = ['DateTime', 'Bid Open', 'Bid High', 'Bid Low', 'Bid Close', 'Ask Open', 'Ask High',
|
319
|
+
'Ask Low', 'Ask Close', 'Volume']
|
320
|
+
with open(filename, "w", newline="") as file:
|
321
|
+
writer = csv.writer(file, delimiter=delimiter)
|
322
|
+
if headers:
|
323
|
+
head = [headers]
|
324
|
+
writer.writerow(head)
|
325
|
+
else:
|
326
|
+
writer.writerow(header)
|
327
|
+
for i in range(1, len(nd_array_history)-1):
|
328
|
+
last_complete_data_frame = nd_array_history[i:i+1]
|
329
|
+
str2 = str(last_complete_data_frame[0])
|
330
|
+
str2 = str2.replace('(', '')
|
331
|
+
str2 = str2.replace(')', '')
|
332
|
+
str2 = str2.replace("'", '')
|
333
|
+
str2 = str2.replace(' ', '')
|
334
|
+
str2 = str2.split(',')
|
335
|
+
array = np.array(str2)
|
336
|
+
array[0] = array[0].replace('T', ' ')
|
337
|
+
dt = parser.parse(array[0])
|
338
|
+
dt = dt+timedelta(0, time_difference)
|
339
|
+
dt = str(dt)
|
340
|
+
array[0] = dt.replace(' ', dt_separator)
|
341
|
+
out = [array[0]]
|
342
|
+
for i2 in range(1, len(array)-1):
|
343
|
+
price = float(array[i2])
|
344
|
+
if format_decimal_places:
|
345
|
+
if instr.find("JPY") >= 0:
|
346
|
+
out.append("%.3f" % price)
|
347
|
+
else:
|
348
|
+
out.append("%.5f" % price)
|
349
|
+
else:
|
350
|
+
out.append(price)
|
351
|
+
out.append(array[len(array)-1])
|
352
|
+
writer.writerow(out)
|
353
|
+
|
354
|
+
def main():
|
355
|
+
global delimiter
|
356
|
+
global datetime_separator
|
357
|
+
global format_decimal_places
|
358
|
+
global timezone
|
359
|
+
|
360
|
+
args = parse_args()
|
361
|
+
config_file = args.config
|
362
|
+
if not os.path.exists(config_file):
|
363
|
+
config_file=os.path.join(path_from_where_we_call,config_file)
|
364
|
+
|
365
|
+
jgtconf=jgtcommon.readconfig()
|
366
|
+
|
367
|
+
if args.p:
|
368
|
+
str_password = args.p
|
369
|
+
else:
|
370
|
+
str_password = jgtconf.get('password') or os.getenv('password')
|
371
|
+
|
372
|
+
if str_password is None:
|
373
|
+
raise Exception("Password is required. Use -p option or export password=mypasswd")
|
374
|
+
sys.exit("Password is required. Use -p option or export password=mypasswd")
|
375
|
+
|
376
|
+
str_user_id, str_url, str_connection, str_session_id, str_pin, delimiter, output_dir, \
|
377
|
+
datetime_separator, format_decimal_places, timezone, data = parse_xml(config_file)
|
378
|
+
|
379
|
+
# print("cwd: "+os.getcwd())
|
380
|
+
# os.chdir(abs_path_of_this_file)
|
381
|
+
# print("cwd: "+os.getcwd())
|
382
|
+
with ForexConnect() as fx:
|
383
|
+
try:
|
384
|
+
print("Connecting to: user id:"+str_user_id+", url:"+str_url+", Connection:"+str_connection)
|
385
|
+
try:
|
386
|
+
fx.login(str_user_id, str_password, str_url,
|
387
|
+
str_connection, str_session_id, str_pin,
|
388
|
+
common_samples.session_status_changed)
|
389
|
+
except Exception as e:
|
390
|
+
print("Exception: " + str(e))
|
391
|
+
raise Exception(
|
392
|
+
"Login failed. Invalid parameters")
|
393
|
+
|
394
|
+
lhc = []
|
395
|
+
for param in data:
|
396
|
+
offer = Common.get_offer(fx, param[0])
|
397
|
+
|
398
|
+
check_params(param[0], param[1], offer)
|
399
|
+
|
400
|
+
tf = ForexConnect.get_timeframe(fx, param[1])
|
401
|
+
if not tf:
|
402
|
+
raise Exception(
|
403
|
+
"The timeframe '{0}' is not valid".format(param[1]))
|
404
|
+
|
405
|
+
lhc, nd_array_history = set_init_history(fx, lhc, param[0], param[1], param[2], param[3],
|
406
|
+
str_user_id, str_password, str_url, str_connection)
|
407
|
+
|
408
|
+
time_difference = get_time_difference(timezone)
|
409
|
+
|
410
|
+
save_old_history(param[0], param[2], param[4], nd_array_history, time_difference, datetime_separator)
|
411
|
+
|
412
|
+
print("Old history saved to "+param[2])
|
413
|
+
|
414
|
+
while True:
|
415
|
+
time.sleep(60)
|
416
|
+
|
417
|
+
except Exception as e:
|
418
|
+
common_samples.print_exception(e)
|
419
|
+
try:
|
420
|
+
fx.set_session_status_listener(session_status_changed(fx, None, None, str_user_id, str_password,
|
421
|
+
str_url, str_connection, False))
|
422
|
+
fx.logout()
|
423
|
+
except Exception as e:
|
424
|
+
common_samples.print_exception(e)
|
425
|
+
|
426
|
+
|
427
|
+
if __name__ == "__main__":
|
428
|
+
main()
|
429
|
+
print("")
|
430
|
+
input("Done! Press enter key to exit\n")
|
431
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import argparse
|
2
|
+
|
3
|
+
|
4
|
+
import os
|
5
|
+
import xml.etree.ElementTree as ET
|
6
|
+
|
7
|
+
def generate_config(instruments, timeframes, nb_bar=500, default_headers="DateTime,Bid Open,Bid Close,Ask High,Ask Low,Volume", data_dir=None):
|
8
|
+
# Split the CSV strings into lists
|
9
|
+
instruments = instruments.split(',')
|
10
|
+
timeframes = timeframes.split(',')
|
11
|
+
|
12
|
+
# Create the root element
|
13
|
+
config = ET.Element('configuration')
|
14
|
+
|
15
|
+
# Create the Settings element
|
16
|
+
settings = ET.SubElement(config, 'Settings')
|
17
|
+
|
18
|
+
# Add the Login, OutputDir, and Url elements
|
19
|
+
ET.SubElement(settings, 'Login').text = '0'#os.getenv('user_id','0')
|
20
|
+
ET.SubElement(settings, 'OutputDir').text = data_dir or os.getenv('JGTPY_DATA')
|
21
|
+
ET.SubElement(settings, 'Url').text = os.getenv('url','https://www.fxcorporate.com/Hosts.jsp')
|
22
|
+
|
23
|
+
# Add the other elements
|
24
|
+
ET.SubElement(settings, 'Connection').text = os.getenv('connection','Real')
|
25
|
+
ET.SubElement(settings, 'SessionID').text = ''
|
26
|
+
ET.SubElement(settings, 'Pin').text = ''
|
27
|
+
ET.SubElement(settings, 'Delimiter').text = ','
|
28
|
+
ET.SubElement(settings, 'DateTimeSeparator').text = ' '
|
29
|
+
ET.SubElement(settings, 'FormatDecimalPlaces').text = 'Y'
|
30
|
+
ET.SubElement(settings, 'Timezone').text = 'UTC'
|
31
|
+
|
32
|
+
# Add the History elements
|
33
|
+
for instrument in instruments:
|
34
|
+
for timeframe in timeframes:
|
35
|
+
history = ET.SubElement(settings, 'History')
|
36
|
+
ET.SubElement(history, 'Instrument').text = instrument
|
37
|
+
ET.SubElement(history, 'Timeframe').text = timeframe
|
38
|
+
ifn = instrument.replace("/","-")
|
39
|
+
ET.SubElement(history, 'Filename').text = f'{ifn}_{timeframe}.csv'
|
40
|
+
ET.SubElement(history, 'NumBars').text = str(nb_bar)
|
41
|
+
ET.SubElement(history, 'Headers').text = default_headers
|
42
|
+
|
43
|
+
# Return the XML as a string
|
44
|
+
return ET.tostring(config, encoding='utf8', method='xml').decode()
|
45
|
+
|
46
|
+
def main():
|
47
|
+
import argparse
|
48
|
+
parser = argparse.ArgumentParser(description='Generate a configuration file for the ptoLiveChartDataExport')
|
49
|
+
parser.add_argument('--instruments', help='The list of instruments to export (comma-separated)')
|
50
|
+
parser.add_argument('--timeframes', help='The list of timeframes to export (comma-separated)')
|
51
|
+
parser.add_argument('--outxml', type=str,default="jgtfxliveconfig.xml", help='Output XML file')
|
52
|
+
|
53
|
+
#data_dir = os.getenv('JGTPY_DATA') or if --data_dir
|
54
|
+
parser.add_argument('--data_dir', help='The directory where the data will be saved')
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
args = parser.parse_args()
|
59
|
+
instruments = args.instruments
|
60
|
+
timeframes = args.timeframes
|
61
|
+
data_dir = args.data_dir or os.getenv('JGTPY_DATA')
|
62
|
+
outxml = args.outxml
|
63
|
+
|
64
|
+
# Generate the configuration
|
65
|
+
config = generate_config(instruments, timeframes, data_dir=data_dir)
|
66
|
+
|
67
|
+
# Print the configuration
|
68
|
+
print(config)
|
69
|
+
with open(outxml, 'w') as f:
|
70
|
+
f.write(config)
|
71
|
+
print("Configuration file written to:", outxml)
|
72
|
+
|
73
|
+
if __name__ == '__main__':
|
74
|
+
main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/ResponseListener.py
RENAMED
File without changes
|
{jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/SessionStatusListener.py
RENAMED
File without changes
|
File without changes
|
{jgtfx2console-0.4.24 → jgtfx2console-0.4.26}/jgtfx2console/forexconnect/TableManagerListener.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|