jgtfx2console 0.4.27__py3-none-any.whl → 0.5.15__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. jgtfx2console/LiveChartDataExport.py +2 -2
  2. jgtfx2console/__init__.py +1 -1
  3. jgtfx2console/common_samples/BatchOrderMonitor.py +84 -0
  4. jgtfx2console/common_samples/OrderMonitor.py +171 -0
  5. jgtfx2console/common_samples/OrderMonitorNetting.py +195 -0
  6. jgtfx2console/common_samples/TableListenerContainer.py +197 -0
  7. jgtfx2console/common_samples/__init__.py +23 -0
  8. jgtfx2console/common_samples/common.py +219 -0
  9. jgtfx2console/config_generator.py +12 -5
  10. jgtfx2console/forexconnect/ForexConnect.py +7 -2
  11. jgtfx2console/forexconnect/_fix_import.sh +3 -0
  12. jgtfx2console/forexconnect/lib/windows/ForexConnect.dll +0 -0
  13. jgtfx2console/forexconnect/lib/windows/__init__.py +0 -0
  14. jgtfx2console/forexconnect/lib/windows/_depend_on.txt +11 -0
  15. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-console-l1-1-0.dll +0 -0
  16. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-datetime-l1-1-0.dll +0 -0
  17. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-debug-l1-1-0.dll +0 -0
  18. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-errorhandling-l1-1-0.dll +0 -0
  19. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-file-l1-1-0.dll +0 -0
  20. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-file-l1-2-0.dll +0 -0
  21. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-file-l2-1-0.dll +0 -0
  22. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-handle-l1-1-0.dll +0 -0
  23. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-heap-l1-1-0.dll +0 -0
  24. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-interlocked-l1-1-0.dll +0 -0
  25. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-libraryloader-l1-1-0.dll +0 -0
  26. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-localization-l1-2-0.dll +0 -0
  27. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-memory-l1-1-0.dll +0 -0
  28. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-namedpipe-l1-1-0.dll +0 -0
  29. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-processenvironment-l1-1-0.dll +0 -0
  30. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-processthreads-l1-1-0.dll +0 -0
  31. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-processthreads-l1-1-1.dll +0 -0
  32. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-profile-l1-1-0.dll +0 -0
  33. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-rtlsupport-l1-1-0.dll +0 -0
  34. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-string-l1-1-0.dll +0 -0
  35. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-synch-l1-1-0.dll +0 -0
  36. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-synch-l1-2-0.dll +0 -0
  37. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-sysinfo-l1-1-0.dll +0 -0
  38. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-timezone-l1-1-0.dll +0 -0
  39. jgtfx2console/forexconnect/lib/windows/api-ms-win-core-util-l1-1-0.dll +0 -0
  40. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-conio-l1-1-0.dll +0 -0
  41. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-convert-l1-1-0.dll +0 -0
  42. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-environment-l1-1-0.dll +0 -0
  43. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-filesystem-l1-1-0.dll +0 -0
  44. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-heap-l1-1-0.dll +0 -0
  45. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-locale-l1-1-0.dll +0 -0
  46. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-math-l1-1-0.dll +0 -0
  47. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-multibyte-l1-1-0.dll +0 -0
  48. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-private-l1-1-0.dll +0 -0
  49. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-process-l1-1-0.dll +0 -0
  50. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-runtime-l1-1-0.dll +0 -0
  51. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-stdio-l1-1-0.dll +0 -0
  52. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-string-l1-1-0.dll +0 -0
  53. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-time-l1-1-0.dll +0 -0
  54. jgtfx2console/forexconnect/lib/windows/api-ms-win-crt-utility-l1-1-0.dll +0 -0
  55. jgtfx2console/forexconnect/lib/windows/cacert.pem +3314 -0
  56. jgtfx2console/forexconnect/lib/windows/concrt140.dll +0 -0
  57. jgtfx2console/forexconnect/lib/windows/fxcorepy.pyd +0 -0
  58. jgtfx2console/forexconnect/lib/windows/fxmsg.dll +0 -0
  59. jgtfx2console/forexconnect/lib/windows/fxtp.dll +0 -0
  60. jgtfx2console/forexconnect/lib/windows/gscurl.dll +0 -0
  61. jgtfx2console/forexconnect/lib/windows/gsexpat.dll +0 -0
  62. jgtfx2console/forexconnect/lib/windows/gslibeay32.dll +0 -0
  63. jgtfx2console/forexconnect/lib/windows/gsssleay32.dll +0 -0
  64. jgtfx2console/forexconnect/lib/windows/gstool3.dll +0 -0
  65. jgtfx2console/forexconnect/lib/windows/gszlib.dll +0 -0
  66. jgtfx2console/forexconnect/lib/windows/httplib.dll +0 -0
  67. jgtfx2console/forexconnect/lib/windows/log4cplus.dll +0 -0
  68. jgtfx2console/forexconnect/lib/windows/msvcp140.dll +0 -0
  69. jgtfx2console/forexconnect/lib/windows/pdas.dll +0 -0
  70. jgtfx2console/forexconnect/lib/windows/pricehistorymgr.dll +0 -0
  71. jgtfx2console/forexconnect/lib/windows/python3.dll +0 -0
  72. jgtfx2console/forexconnect/lib/windows/quotesmgr2.dll +0 -0
  73. jgtfx2console/forexconnect/lib/windows/requirements.txt +5 -0
  74. jgtfx2console/forexconnect/lib/windows/sqlite3.8.dll +0 -0
  75. jgtfx2console/forexconnect/lib/windows/ucrtbase.dll +0 -0
  76. jgtfx2console/forexconnect/lib/windows/vccorlib140.dll +0 -0
  77. jgtfx2console/forexconnect/lib/windows/vcruntime140.dll +0 -0
  78. jgtfx2console/fxcli2console.py +12 -7
  79. {jgtfx2console-0.4.27.dist-info → jgtfx2console-0.5.15.dist-info}/METADATA +18 -21
  80. jgtfx2console-0.5.15.dist-info/RECORD +112 -0
  81. {jgtfx2console-0.4.27.dist-info → jgtfx2console-0.5.15.dist-info}/WHEEL +1 -1
  82. jgtfx2console-0.5.15.dist-info/entry_points.txt +2 -0
  83. jgtfx2console-0.4.27.dist-info/RECORD +0 -39
  84. jgtfx2console-0.4.27.dist-info/entry_points.txt +0 -4
  85. {jgtfx2console-0.4.27.dist-info → jgtfx2console-0.5.15.dist-info}/LICENSE +0 -0
  86. {jgtfx2console-0.4.27.dist-info → jgtfx2console-0.5.15.dist-info}/top_level.txt +0 -0
@@ -47,7 +47,7 @@ def parse_args():
47
47
  metavar="PASSWORD",
48
48
  required=False,
49
49
  help='Your password.')
50
- arg_parser.add_argument('-config', metavar="CONFIG_FILE", default='jgtfxliveconfig.xml',
50
+ arg_parser.add_argument('-config', metavar="CONFIG_FILE", default='fxliveconfig.xml',
51
51
  help='Config file')
52
52
 
53
53
  args = arg_parser.parse_args()
@@ -233,7 +233,7 @@ def parse_xml(config_file):
233
233
  output_dir = os.getenv('JGTPY_DATA') or jgtconf.get('JGTPY_DATA')
234
234
  dt_separator = find_in_tree(settings, "DateTimeSeparator").text
235
235
 
236
- if dt_separator == '' or dt_separator is None:
236
+ if dt_separator == '' or dt_separator is None or dt_separator=='0' or dt_separator=='space' or dt_separator=='\n' :
237
237
  dt_separator = ' '
238
238
  fdp = find_in_tree(settings, "FormatDecimalPlaces").text
239
239
  tzone = find_in_tree(settings, "Timezone").text
jgtfx2console/__init__.py CHANGED
@@ -42,6 +42,6 @@ with warnings.catch_warnings():
42
42
  # your code here
43
43
 
44
44
 
45
- __version__ = "0.4.27"
45
+ __version__ = "0.5.15"
46
46
 
47
47
 
@@ -0,0 +1,84 @@
1
+ # Copyright 2019 Gehtsoft USA LLC
2
+
3
+ # Licensed under the license derived from the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+
6
+ # You may obtain a copy of the License at
7
+
8
+ # http://fxcodebase.com/licenses/open-source/license.html
9
+
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from typing import List
17
+
18
+ from forexconnect import fxcorepy
19
+
20
+ from common_samples.OrderMonitor import OrderMonitor
21
+
22
+
23
+ class BatchOrderMonitor:
24
+ __request_ids = None
25
+ __monitors = []
26
+
27
+ def __init__(self) -> None:
28
+ pass
29
+
30
+ @property
31
+ def monitors(self) -> List[OrderMonitor]:
32
+ return self.__monitors
33
+
34
+ @property
35
+ def is_batch_executed(self) -> bool:
36
+ all_completed = True
37
+ for monitor in self.__monitors:
38
+ if monitor.is_order_completed:
39
+ self.remove_request_id(monitor.order.request_id)
40
+ else:
41
+ all_completed = False
42
+ return len(self.__request_ids) == 0 and all_completed
43
+
44
+ def set_request_ids(self, request_ids: List[str]) -> None:
45
+ self.__request_ids = request_ids
46
+
47
+ def on_request_completed(self, request_id: str, response: fxcorepy.O2GResponse) -> None:
48
+ pass
49
+
50
+ def remove_request_id(self, request_id: str) -> None:
51
+ if self.is_own_request(request_id):
52
+ self.__request_ids.remove(request_id)
53
+
54
+ def on_request_failed(self, request_id: str) -> None:
55
+ self.remove_request_id(request_id)
56
+
57
+ def on_trade_added(self, trade_row: fxcorepy.O2GTradeRow) -> None:
58
+ for monitor in self.__monitors:
59
+ monitor.on_trade_added(trade_row)
60
+
61
+ def on_order_added(self, order: fxcorepy.O2GOrderRow) -> None:
62
+ request_id = order.request_id
63
+ print("Order Added " + order.order_id)
64
+ if self.is_own_request(request_id):
65
+ if OrderMonitor.is_closing_order(order) or OrderMonitor.is_opening_order(order):
66
+ self._add_to_monitoring(order)
67
+
68
+ def on_order_deleted(self, order: fxcorepy.O2GOrderRow) -> None:
69
+ for monitor in self.__monitors:
70
+ monitor.on_order_deleted(order)
71
+
72
+ def on_message_added(self, message: fxcorepy.O2GMessageRow) -> None:
73
+ for monitor in self.__monitors:
74
+ monitor.on_message_added(message)
75
+
76
+ def on_closed_trade_added(self, close_trade_row: fxcorepy.O2GClosedTradeRow) -> None:
77
+ for monitor in self.__monitors:
78
+ monitor.on_closed_trade_added(close_trade_row)
79
+
80
+ def is_own_request(self, request_id: str) -> bool:
81
+ return request_id in self.__request_ids
82
+
83
+ def _add_to_monitoring(self, order: fxcorepy.O2GOrderRow) -> None:
84
+ self.__monitors.append(OrderMonitor(order))
@@ -0,0 +1,171 @@
1
+ # Copyright 2019 Gehtsoft USA LLC
2
+
3
+ # Licensed under the license derived from the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+
6
+ # You may obtain a copy of the License at
7
+
8
+ # http://fxcodebase.com/licenses/open-source/license.html
9
+
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from typing import List
17
+ from enum import Enum
18
+
19
+ from forexconnect import fxcorepy
20
+
21
+
22
+ class OrderMonitor:
23
+ class ExecutionResult(Enum):
24
+ EXECUTING = 1
25
+ EXECUTED = 2
26
+ PARTIAL_REJECTED = 3
27
+ FULLY_REJECTED = 4
28
+ CANCELED = 5
29
+
30
+ class OrderState(Enum):
31
+ ORDER_EXECUTING = 1
32
+ ORDER_EXECUTED = 2
33
+ ORDER_CANCELED = 3
34
+ ORDER_REJECTED = 4
35
+
36
+ __market_condition = "5"
37
+
38
+ def __init__(self, order: fxcorepy.O2GOrderRow) -> None:
39
+ self.__order = order
40
+ self.__trades = []
41
+ self.__closed_trades = []
42
+ self.__state = OrderMonitor.OrderState.ORDER_EXECUTING
43
+ self.__result = OrderMonitor.ExecutionResult.EXECUTING
44
+ self.__total_amount = 0
45
+ self.__reject_amount = 0
46
+ self.__reject_message = ""
47
+
48
+ @staticmethod
49
+ def is_opening_order(order: fxcorepy.O2GOrderRow) -> bool:
50
+ return order.type.startswith("O")
51
+
52
+ @staticmethod
53
+ def is_closing_order(order: fxcorepy.O2GOrderRow) -> bool:
54
+ return order.type.startswith("C")
55
+
56
+ @property
57
+ def order_row(self) -> fxcorepy.O2GOrderRow:
58
+ return self.__order
59
+
60
+ @property
61
+ def trade_rows(self) -> List[fxcorepy.O2GTradeRow]:
62
+ return self.__trades
63
+
64
+ @property
65
+ def closed_trade_rows(self) -> List[fxcorepy.O2GClosedTradeRow]:
66
+ return self.__closed_trades
67
+
68
+ @property
69
+ def reject_amount(self) -> int:
70
+ return self.__reject_amount
71
+
72
+ @property
73
+ def reject_message(self) -> str:
74
+ return self.__reject_message
75
+
76
+ @property
77
+ def result(self) -> ExecutionResult:
78
+ return self.__result
79
+
80
+ @property
81
+ def is_order_completed(self) -> bool:
82
+ print(self.__result)
83
+ return self.__result != OrderMonitor.ExecutionResult.EXECUTING
84
+
85
+ @property
86
+ def is_all_trades_received(self) -> bool:
87
+ if self.__state == OrderMonitor.OrderState.ORDER_EXECUTING:
88
+ return False
89
+ i_current_total_amount = 0
90
+ for trade in self.__trades:
91
+ i_current_total_amount += trade.amount
92
+
93
+ for trade in self.__closed_trades:
94
+ i_current_total_amount += trade.amount
95
+
96
+ return i_current_total_amount == self.__total_amount
97
+
98
+ def on_trade_added(self, trade: fxcorepy.O2GTradeRow) -> None:
99
+ trade_order_id = trade.open_order_id
100
+ order_id = self.__order.order_id
101
+ if trade_order_id == order_id:
102
+ self.__trades.append(trade)
103
+ if self.__state == OrderMonitor.OrderState.ORDER_EXECUTED or \
104
+ self.__state == OrderMonitor.OrderState.ORDER_REJECTED or \
105
+ self.__state == OrderMonitor.OrderState.ORDER_CANCELED:
106
+ if self.is_all_trades_received:
107
+ self.set_result(True)
108
+
109
+ def on_closed_trade_added(self, closed_trade: fxcorepy.O2GClosedTradeRow) -> None:
110
+ order_id = self.__order.order_id
111
+ closed_trade_order_id = closed_trade.close_order_id
112
+ print(closed_trade_order_id, order_id)
113
+ if order_id == closed_trade_order_id:
114
+ self.__closed_trades.append(closed_trade)
115
+ if self.__state == OrderMonitor.OrderState.ORDER_EXECUTED or \
116
+ self.__state == OrderMonitor.OrderState.ORDER_REJECTED or \
117
+ self.__state == OrderMonitor.OrderState.ORDER_CANCELED:
118
+ if self.is_all_trades_received:
119
+ self.set_result(True)
120
+
121
+ def on_order_deleted(self, order: fxcorepy.O2GOrderRow) -> None:
122
+ deleted_order_id = order.order_id
123
+ order_id = self.__order.order_id
124
+ if deleted_order_id == order_id:
125
+ # Store Reject amount
126
+ if order.status.startswith("R"):
127
+ self.__state = OrderMonitor.OrderState.ORDER_REJECTED
128
+ self.__reject_amount = order.amount
129
+ self.__total_amount = order.origin_amount - self.__reject_amount
130
+ if self.__reject_message != "" and self.is_all_trades_received:
131
+ self.set_result(True)
132
+ elif order.status.startswith("C"):
133
+ self.__state = OrderMonitor.OrderState.ORDER_CANCELED
134
+ self.__reject_amount = order.amount
135
+ self.__total_amount = order.origin_amount - self.__reject_amount
136
+ if self.is_all_trades_received:
137
+ self.set_result(False)
138
+ else:
139
+ self.__reject_amount = 0
140
+ self.__total_amount = order.origin_amount
141
+ self.__state = OrderMonitor.OrderState.ORDER_EXECUTED
142
+ if self.is_all_trades_received:
143
+ self.set_result(True)
144
+
145
+ def on_message_added(self, message: fxcorepy.O2GMessageRow) -> None:
146
+ if self.__state == OrderMonitor.OrderState.ORDER_REJECTED or \
147
+ self.__state == OrderMonitor.OrderState.ORDER_EXECUTING:
148
+ is_reject_message = self.check_and_store_message(message)
149
+ if self.__state == OrderMonitor.OrderState.ORDER_REJECTED and is_reject_message:
150
+ self.set_result(True)
151
+
152
+ def set_result(self, success: bool) -> None:
153
+ if success:
154
+ if self.__reject_amount == 0:
155
+ self.__result = OrderMonitor.ExecutionResult.EXECUTED
156
+ else:
157
+ self.__result = OrderMonitor.ExecutionResult.FULLY_REJECTED \
158
+ if (len(self.__trades) == 0 and len(self.__closed_trades) == 0) \
159
+ else OrderMonitor.ExecutionResult.PARTIAL_REJECTED
160
+
161
+ else:
162
+ self.__result = OrderMonitor.ExecutionResult.CANCELED
163
+
164
+ def check_and_store_message(self, message: fxcorepy.O2GMessageRow) -> bool:
165
+ feature = message.feature
166
+ if feature == self.__market_condition:
167
+ text = message.text
168
+ if self.__order.order_id in text:
169
+ self.__reject_message = message.text
170
+ return True
171
+ return False
@@ -0,0 +1,195 @@
1
+ # Copyright 2019 Gehtsoft USA LLC
2
+
3
+ # Licensed under the license derived from the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+
6
+ # You may obtain a copy of the License at
7
+
8
+ # http://fxcodebase.com/licenses/open-source/license.html
9
+
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from typing import List
17
+ from enum import Enum
18
+
19
+ from forexconnect import fxcorepy
20
+
21
+
22
+ class OrderMonitorNetting:
23
+
24
+ class ExecutionResult(Enum):
25
+ EXECUTING = 1
26
+ EXECUTED = 2
27
+ PARTIAL_REJECTED = 3
28
+ FULLY_REJECTED = 4
29
+ CANCELED = 5
30
+
31
+ class OrderState(Enum):
32
+ ORDER_EXECUTING = 1
33
+ ORDER_EXECUTED = 2
34
+ ORDER_CANCELED = 3
35
+ ORDER_REJECTED = 4
36
+
37
+ __market_condition = "5"
38
+
39
+ def __init__(self, order: fxcorepy.O2GOrderRow, i_net_position_amount: int = 0) -> None:
40
+ self.__order = order
41
+ self.__trades = []
42
+ self.__updated_trades = []
43
+ self.__closed_trades = []
44
+ self.__state = OrderMonitorNetting.OrderState.ORDER_EXECUTING
45
+ self.__result = OrderMonitorNetting.ExecutionResult.EXECUTING
46
+ self.__total_amount = 0
47
+ self.__reject_amount = 0
48
+ self.__reject_message = ""
49
+ self.__initial_amount = i_net_position_amount
50
+
51
+ @staticmethod
52
+ def is_opening_order(order: fxcorepy.O2GOrderRow) -> bool:
53
+ return order.type.startswith("O")
54
+
55
+ @staticmethod
56
+ def is_closing_order(order: fxcorepy.O2GOrderRow) -> bool:
57
+ return order.type.startswith("C")
58
+
59
+ # Process trade adding during order execution
60
+ def on_trade_added(self, trade: fxcorepy.O2GTradeRow) -> None:
61
+ trade_order_id = trade.open_order_id
62
+ order_id = self.__order.order_id
63
+ if trade_order_id == order_id:
64
+ self.__trades.append(trade)
65
+ if self.__state == OrderMonitorNetting.OrderState.ORDER_EXECUTED or \
66
+ self.__state == OrderMonitorNetting.OrderState.ORDER_REJECTED or \
67
+ self.__state == OrderMonitorNetting.OrderState.ORDER_CANCELED:
68
+ if self.is_all_trades_received:
69
+ self.set_result(True)
70
+
71
+ # Process trade updating during order execution
72
+ def on_trade_updated(self, trade_row: fxcorepy.O2GTradeRow) -> None:
73
+ s_trade_order_id = trade_row.open_order_id
74
+ s_order_id = self.__order.order_id
75
+ if s_trade_order_id == s_order_id:
76
+ self.__updated_trades.append(trade_row)
77
+ if self.__state == OrderMonitorNetting.OrderState.ORDER_EXECUTED or \
78
+ self.__state == OrderMonitorNetting.OrderState.ORDER_REJECTED or \
79
+ self.__state == OrderMonitorNetting.OrderState.ORDER_CANCELED:
80
+ if self.is_all_trades_received:
81
+ self.set_result(True)
82
+
83
+ # Process trade closing during order execution
84
+ def on_closed_trade_added(self, closed_trade: fxcorepy.O2GClosedTradeRow) -> None:
85
+ order_id = self.__order.order_id
86
+ closed_trade_order_id = closed_trade.close_order_id
87
+ if order_id == closed_trade_order_id:
88
+ self.__closed_trades.append(closed_trade)
89
+ if self.__state == OrderMonitorNetting.OrderState.ORDER_EXECUTED or \
90
+ self.__state == OrderMonitorNetting.OrderState.ORDER_REJECTED or \
91
+ self.__state == OrderMonitorNetting.OrderState.ORDER_CANCELED:
92
+ if self.is_all_trades_received:
93
+ self.set_result(True)
94
+
95
+ # Process order deletion as result of execution
96
+ def on_order_deleted(self, order: fxcorepy.O2GOrderRow) -> None:
97
+ deleted_order_id = order.order_id
98
+ order_id = self.__order.order_id
99
+ if deleted_order_id == order_id:
100
+ # Store Reject amount
101
+ if order.Status.startswith("R"):
102
+ self.__state = OrderMonitorNetting.OrderState.ORDER_REJECTED
103
+ self.__reject_amount = order.amount
104
+ self.__total_amount = order.origin_amount - self.__reject_amount
105
+ if self.__reject_message != "" and self.is_all_trades_received:
106
+ self.set_result(True)
107
+ else:
108
+ if order.Status.startswith("C"):
109
+ self.__state = OrderMonitorNetting.OrderState.ORDER_CANCELED
110
+ self.__reject_amount = order.amount
111
+ self.__total_amount = order.origin_amount - self.__reject_amount
112
+ if self.is_all_trades_received:
113
+ self.set_result(False)
114
+ else:
115
+ self.__reject_amount = 0
116
+ self.__total_amount = order.OriginAmount
117
+ self.__state = OrderMonitorNetting.OrderState.ORDER_EXECUTED
118
+ if self.is_all_trades_received:
119
+ self.set_result(True)
120
+
121
+ def on_message_added(self, message: fxcorepy.O2GMessageRow) -> None:
122
+ if self.__state == OrderMonitorNetting.OrderState.ORDER_REJECTED or \
123
+ self.__state == OrderMonitorNetting.OrderState.ORDER_EXECUTING:
124
+ is_reject_message = self.check_and_store_message(message)
125
+ if self.__state == OrderMonitorNetting.OrderState.ORDER_REJECTED and is_reject_message:
126
+ self.set_result(True)
127
+
128
+ @property
129
+ def order_row(self) -> fxcorepy.O2GOrderRow:
130
+ return self.__order
131
+
132
+ @property
133
+ def trade_rows(self) -> List[fxcorepy.O2GTradeRow]:
134
+ return self.__trades
135
+
136
+ @property
137
+ def updated_trade_rows(self) -> List[fxcorepy.O2GTradeRow]:
138
+ return self.__updated_trades
139
+
140
+ @property
141
+ def closed_trade_rows(self) -> List[fxcorepy.O2GClosedTradeRow]:
142
+ return self.__closed_trades
143
+
144
+ @property
145
+ def reject_amount(self) -> int:
146
+ return self.__reject_amount
147
+
148
+ @property
149
+ def reject_message(self) -> str:
150
+ return self.__reject_message
151
+
152
+ @property
153
+ def result(self) -> ExecutionResult:
154
+ return self.__result
155
+
156
+ @property
157
+ def is_order_completed(self) -> bool:
158
+ return self.__result != OrderMonitorNetting.ExecutionResult.EXECUTING
159
+
160
+ def check_and_store_message(self, message: fxcorepy.O2GMessageRow) -> bool:
161
+ feature = message.feature
162
+ if feature == self.__market_condition:
163
+ text = message.text
164
+ if self.__order.order_id in text:
165
+ self.__reject_message = message.text
166
+ return True
167
+ return False
168
+
169
+ @property
170
+ def is_all_trades_received(self) -> bool:
171
+ if self.__state == OrderMonitorNetting.OrderState.ORDER_EXECUTING:
172
+ return False
173
+ i_current_total_amount = 0
174
+ for trade in self.__trades:
175
+ i_current_total_amount += trade.amount
176
+
177
+ for trade in self.__updated_trades:
178
+ i_current_total_amount += trade.amount
179
+
180
+ for trade in self.__closed_trades:
181
+ i_current_total_amount += trade.amount
182
+
183
+ return abs(i_current_total_amount - self.__initial_amount) == self.__total_amount
184
+
185
+ def set_result(self, success: bool) -> None:
186
+ if success:
187
+ if self.__reject_amount == 0:
188
+ self.__result = OrderMonitorNetting.ExecutionResult.EXECUTED
189
+ else:
190
+ self.__result = OrderMonitorNetting.ExecutionResult.FULLY_REJECTED \
191
+ if (len(self.__trades) == 0 and len(self.__closed_trades) == 0) \
192
+ else OrderMonitorNetting.ExecutionResult.PARTIAL_REJECTED
193
+
194
+ else:
195
+ self.__result = OrderMonitorNetting.ExecutionResult.CANCELED
@@ -0,0 +1,197 @@
1
+ # Copyright 2019 Gehtsoft USA LLC
2
+
3
+ # Licensed under the license derived from the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+
6
+ # You may obtain a copy of the License at
7
+
8
+ # http://fxcodebase.com/licenses/open-source/license.html
9
+
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import traceback
17
+
18
+ from forexconnect import ForexConnect, Common
19
+
20
+ from common_samples import OrderMonitor
21
+
22
+
23
+ class TableListenerContainer:
24
+ __response_listener = None
25
+ __request_id = ""
26
+ __order_monitor = None
27
+
28
+ def __init__(self, response_listener, fx):
29
+ self.__response_listener = response_listener
30
+ self._fx = fx
31
+ self._listeners = []
32
+
33
+ def set_request_id(self, request_id):
34
+ self.__request_id = request_id
35
+
36
+ def _on_added_orders(self, listener, row_id, order_row):
37
+ del listener, row_id
38
+ if self.__request_id == order_row.request_id:
39
+ if OrderMonitor.is_closing_order(
40
+ order_row) or OrderMonitor.is_opening_order(
41
+ order_row) and self.__order_monitor is None:
42
+ print(
43
+ "The order has been added. Order ID: {0:s}, Rate: {1:.5f}, Time In Force: {2:s}".format(
44
+ order_row.order_id, order_row.rate,
45
+ order_row.time_in_force))
46
+ self.__order_monitor = OrderMonitor(order_row)
47
+
48
+ def _on_added_trades(self, listener, row_id, trade_row):
49
+ del listener, row_id
50
+ if self.__order_monitor is not None:
51
+ self.__order_monitor.on_trade_added(trade_row)
52
+ if self.__order_monitor.is_order_completed:
53
+ self._print_result()
54
+ self.__response_listener.stop_waiting()
55
+
56
+ def _on_added_closed_trades(self, listener, row_id, closed_trade_row):
57
+ del listener, row_id
58
+ if self.__order_monitor is not None:
59
+ self.__order_monitor.on_closed_trade_added(closed_trade_row)
60
+ if self.__order_monitor.is_order_completed:
61
+ self._print_result()
62
+ self.__response_listener.stop_waiting()
63
+
64
+ def _on_added_messages(self, listener, row_id, message_row):
65
+ del listener, row_id
66
+ if self.__order_monitor is not None:
67
+ self.__order_monitor.on_message_added(message_row)
68
+ if self.__order_monitor.is_order_completed:
69
+ self._print_result()
70
+ self.__response_listener.stop_waiting()
71
+
72
+ def _on_deleted_orders(self, listener, row_id, row_data):
73
+ del listener, row_id
74
+ order_row = row_data
75
+ if self.__request_id == order_row.request_id:
76
+ if self.__order_monitor is not None:
77
+ print("The order has been deleted. Order ID: {0}".format(
78
+ order_row.order_id))
79
+ self.__order_monitor.on_order_deleted(order_row)
80
+ if self.__order_monitor.is_order_completed:
81
+ self._print_result()
82
+ self.__response_listener.stop_waiting()
83
+
84
+ def _print_result_canceled(self, order_id, trades, closed_trades):
85
+ if len(trades) > 0:
86
+ self._print_trades(trades, order_id)
87
+ self._print_closed_trades(closed_trades, order_id)
88
+ print("A part of the order has been canceled. Amount = {0}".format(
89
+ self.__order_monitor.reject_amount))
90
+ else:
91
+ print("The order: OrderID = {0} has been canceled".format(
92
+ order_id))
93
+ print("The cancel amount = {0}".format(
94
+ self.__order_monitor.reject_amount))
95
+
96
+ def _print_result_fully_rejected(self, order_id, trades, closed_trades):
97
+ del trades, closed_trades
98
+ print("The order has been rejected. OrderID = {0}".format(
99
+ order_id))
100
+ print("The rejected amount = {0}".format(
101
+ self.__order_monitor.reject_amount))
102
+ print("Rejection cause: {0}".format(
103
+ self.__order_monitor.reject_message))
104
+
105
+ def _print_result_partial_rejected(self, order_id, trades, closed_trades):
106
+ self._print_trades(trades, order_id)
107
+ self._print_closed_trades(closed_trades, order_id)
108
+ print("A part of the order has been rejected. Amount = {0}".format(
109
+ self.__order_monitor.reject_amount))
110
+ print("Rejection cause: {0} ".format(
111
+ self.__order_monitor.reject_message))
112
+
113
+ def _print_result_executed(self, order_id, trades, closed_trades):
114
+ self._print_trades(trades, order_id)
115
+ self._print_closed_trades(closed_trades, order_id)
116
+
117
+ def _print_result(self):
118
+ if self.__order_monitor is not None:
119
+ result = self.__order_monitor.result
120
+ order = self.__order_monitor.order_row
121
+ order_id = order.order_id
122
+ trades = self.__order_monitor.trade_rows
123
+ closed_trades = self.__order_monitor.closed_trade_rows
124
+
125
+ print_result_func = {
126
+ OrderMonitor.ExecutionResult.CANCELED: self._print_result_canceled,
127
+ OrderMonitor.ExecutionResult.FULLY_REJECTED: self._print_result_fully_rejected,
128
+ OrderMonitor.ExecutionResult.PARTIAL_REJECTED: self._print_result_partial_rejected,
129
+ OrderMonitor.ExecutionResult.EXECUTED: self._print_result_executed
130
+ }
131
+ try:
132
+ print_result_func[result](order_id, trades, closed_trades)
133
+ except KeyError:
134
+ pass
135
+ except Exception as e:
136
+ print("Exception: {0}\n".format(e))
137
+ print(traceback.format_exc())
138
+
139
+ @staticmethod
140
+ def _print_trades(trades, order_id):
141
+ if len(trades) == 0:
142
+ return
143
+ print(
144
+ "For the order: OrderID = {0} the following positions have been opened:".format(
145
+ order_id))
146
+
147
+ for trade in trades:
148
+ trade_id = trade.trade_id
149
+ amount = trade.amount
150
+ rate = trade.open_rate
151
+ print(
152
+ "Trade ID: {0:s}; Amount: {1:d}; Rate: {2:.5f}".format(trade_id,
153
+ amount,
154
+ rate))
155
+
156
+ @staticmethod
157
+ def _print_closed_trades(closed_trades, order_id):
158
+ if len(closed_trades) == 0:
159
+ return
160
+ print(
161
+ "For the order: OrderID = {0} the following positions have been closed: ".format(
162
+ order_id))
163
+
164
+ for closed_trade in closed_trades:
165
+ trade_id = closed_trade.trade_id
166
+ amount = closed_trade.amount
167
+ rate = closed_trade.close_rate
168
+ print(
169
+ "Closed Trade ID: {0:s}; Amount: {1:d}; Closed Rate: {2:.5f}".format(
170
+ trade_id, amount, rate))
171
+
172
+ def subscribe_events(self):
173
+ orders_table = self._fx.get_table(ForexConnect.ORDERS)
174
+ orders_table_listener = Common.subscribe_table_updates(orders_table,
175
+ on_add_callback=self._on_added_orders,
176
+ on_delete_callback=self._on_deleted_orders)
177
+ self._listeners.append(orders_table_listener)
178
+
179
+ trades_table = self._fx.get_table(ForexConnect.TRADES)
180
+ trades_table_listener = Common.subscribe_table_updates(trades_table,
181
+ on_add_callback=self._on_added_trades)
182
+ self._listeners.append(trades_table_listener)
183
+
184
+ messages_table = self._fx.get_table(ForexConnect.MESSAGES)
185
+ messages_table_listener = Common.subscribe_table_updates(messages_table,
186
+ on_add_callback=self._on_added_messages)
187
+ self._listeners.append(messages_table_listener)
188
+
189
+ closed_trades_table = self._fx.get_table(ForexConnect.CLOSED_TRADES)
190
+ closed_trades_table_listener = Common.subscribe_table_updates(closed_trades_table,
191
+ on_add_callback=self._on_added_closed_trades)
192
+ self._listeners.append(closed_trades_table_listener)
193
+
194
+ def unsubscribe_events(self):
195
+ for listener in self._listeners:
196
+ listener.unsubscribe()
197
+ self._listeners = []