bbstrader 0.3.2__py3-none-any.whl → 0.3.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bbstrader might be problematic. Click here for more details.
- bbstrader/__main__.py +15 -7
- bbstrader/apps/__init__.py +0 -0
- bbstrader/apps/_copier.py +664 -0
- bbstrader/btengine/data.py +3 -3
- bbstrader/btengine/strategy.py +165 -90
- bbstrader/core/data.py +3 -1
- bbstrader/core/scripts.py +62 -19
- bbstrader/core/utils.py +5 -3
- bbstrader/metatrader/account.py +196 -42
- bbstrader/metatrader/analysis.py +7 -5
- bbstrader/metatrader/copier.py +325 -171
- bbstrader/metatrader/rates.py +2 -2
- bbstrader/metatrader/scripts.py +15 -2
- bbstrader/metatrader/trade.py +2 -2
- bbstrader/metatrader/utils.py +65 -5
- bbstrader/models/ml.py +8 -5
- bbstrader/models/nlp.py +16 -11
- bbstrader/trading/execution.py +100 -48
- bbstrader/tseries.py +0 -2
- {bbstrader-0.3.2.dist-info → bbstrader-0.3.4.dist-info}/METADATA +5 -5
- {bbstrader-0.3.2.dist-info → bbstrader-0.3.4.dist-info}/RECORD +25 -23
- {bbstrader-0.3.2.dist-info → bbstrader-0.3.4.dist-info}/WHEEL +0 -0
- {bbstrader-0.3.2.dist-info → bbstrader-0.3.4.dist-info}/entry_points.txt +0 -0
- {bbstrader-0.3.2.dist-info → bbstrader-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {bbstrader-0.3.2.dist-info → bbstrader-0.3.4.dist-info}/top_level.txt +0 -0
bbstrader/metatrader/account.py
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
3
|
import urllib.request
|
|
4
|
-
from datetime import datetime
|
|
4
|
+
from datetime import datetime
|
|
5
5
|
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
|
|
6
6
|
|
|
7
|
+
import numpy as np
|
|
7
8
|
import pandas as pd
|
|
8
9
|
from currency_converter import SINGLE_DAY_ECB_URL, CurrencyConverter
|
|
10
|
+
from numpy.typing import NDArray
|
|
9
11
|
|
|
10
12
|
from bbstrader.metatrader.utils import (
|
|
13
|
+
TIMEFRAMES,
|
|
11
14
|
AccountInfo,
|
|
12
15
|
BookInfo,
|
|
13
16
|
InvalidBroker,
|
|
14
17
|
OrderCheckResult,
|
|
15
18
|
OrderSentResult,
|
|
19
|
+
RateDtype,
|
|
20
|
+
RateInfo,
|
|
16
21
|
SymbolInfo,
|
|
17
22
|
SymbolType,
|
|
18
23
|
TerminalInfo,
|
|
24
|
+
TickDtype,
|
|
25
|
+
TickFlag,
|
|
19
26
|
TickInfo,
|
|
20
27
|
TradeDeal,
|
|
21
28
|
TradeOrder,
|
|
@@ -33,6 +40,7 @@ except ImportError:
|
|
|
33
40
|
__all__ = [
|
|
34
41
|
"Account",
|
|
35
42
|
"Broker",
|
|
43
|
+
"MetaQuotes",
|
|
36
44
|
"AdmiralMarktsGroup",
|
|
37
45
|
"JustGlobalMarkets",
|
|
38
46
|
"PepperstoneGroupLimited",
|
|
@@ -41,6 +49,7 @@ __all__ = [
|
|
|
41
49
|
]
|
|
42
50
|
|
|
43
51
|
__BROKERS__ = {
|
|
52
|
+
"MQL": "MetaQuotes Ltd.",
|
|
44
53
|
"AMG": "Admirals Group AS",
|
|
45
54
|
"JGM": "Just Global Markets Ltd.",
|
|
46
55
|
"FTMO": "FTMO S.R.O.",
|
|
@@ -67,14 +76,13 @@ _ADMIRAL_MARKETS_PRODUCTS_ = [
|
|
|
67
76
|
]
|
|
68
77
|
_JUST_MARKETS_PRODUCTS_ = ["Stocks", "Crypto", "indices", "Commodities", "Forex"]
|
|
69
78
|
|
|
70
|
-
SUPPORTED_BROKERS = [__BROKERS__[b] for b in {"AMG", "JGM", "FTMO"}]
|
|
79
|
+
SUPPORTED_BROKERS = [__BROKERS__[b] for b in {"MQL", "AMG", "JGM", "FTMO"}]
|
|
71
80
|
INIT_MSG = (
|
|
72
|
-
f"\n*
|
|
73
|
-
f"*
|
|
74
|
-
f"*
|
|
75
|
-
f"
|
|
76
|
-
f"*
|
|
77
|
-
f"* If you are looking for a prop firm, See [{_FTMO_URL_}]\n"
|
|
81
|
+
f"\n* Check your internet connection\n"
|
|
82
|
+
f"* Make sure MT5 is installed and active\n"
|
|
83
|
+
f"* Looking for a boker? See [{_ADMIRAL_MARKETS_URL_}] "
|
|
84
|
+
f"or [{_JUST_MARKETS_URL_}]\n"
|
|
85
|
+
f"* Looking for a prop firm? See [{_FTMO_URL_}]\n"
|
|
78
86
|
)
|
|
79
87
|
|
|
80
88
|
amg_url = _ADMIRAL_MARKETS_URL_
|
|
@@ -136,7 +144,16 @@ AMG_EXCHANGES = {
|
|
|
136
144
|
}
|
|
137
145
|
|
|
138
146
|
|
|
139
|
-
def check_mt5_connection(
|
|
147
|
+
def check_mt5_connection(
|
|
148
|
+
*,
|
|
149
|
+
path=None,
|
|
150
|
+
login=None,
|
|
151
|
+
password=None,
|
|
152
|
+
server=None,
|
|
153
|
+
timeout=60_000,
|
|
154
|
+
portable=False,
|
|
155
|
+
**kwargs,
|
|
156
|
+
) -> bool:
|
|
140
157
|
"""
|
|
141
158
|
Initialize the connection to the MetaTrader 5 terminal.
|
|
142
159
|
|
|
@@ -156,12 +173,11 @@ def check_mt5_connection(**kwargs) -> bool:
|
|
|
156
173
|
- Follow these instructions to lunch each terminal in portable mode first:
|
|
157
174
|
https://www.metatrader5.com/en/terminal/help/start_advanced/start#configuration_file
|
|
158
175
|
"""
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
portable = kwargs.get("portable", False)
|
|
176
|
+
if login is not None and server is not None:
|
|
177
|
+
account_info = mt5.account_info()
|
|
178
|
+
if account_info is not None:
|
|
179
|
+
if account_info.login == login and account_info.server == server:
|
|
180
|
+
return True
|
|
165
181
|
|
|
166
182
|
init = False
|
|
167
183
|
if path is None and (login or password or server):
|
|
@@ -221,6 +237,11 @@ class Broker(object):
|
|
|
221
237
|
return f"{self.__class__.__name__}({self.name})"
|
|
222
238
|
|
|
223
239
|
|
|
240
|
+
class MetaQuotes(Broker):
|
|
241
|
+
def __init__(self, **kwargs):
|
|
242
|
+
super().__init__(__BROKERS__["MQL"], **kwargs)
|
|
243
|
+
|
|
244
|
+
|
|
224
245
|
class AdmiralMarktsGroup(Broker):
|
|
225
246
|
def __init__(self, **kwargs):
|
|
226
247
|
super().__init__(__BROKERS__["AMG"], **kwargs)
|
|
@@ -262,6 +283,7 @@ class AMP(Broker): ...
|
|
|
262
283
|
|
|
263
284
|
BROKERS: Dict[str, Broker] = {
|
|
264
285
|
"FTMO": FTMO(),
|
|
286
|
+
"MQL": MetaQuotes(),
|
|
265
287
|
"AMG": AdmiralMarktsGroup(),
|
|
266
288
|
"JGM": JustGlobalMarkets(),
|
|
267
289
|
"PGL": PepperstoneGroupLimited(),
|
|
@@ -503,7 +525,7 @@ class Account(object):
|
|
|
503
525
|
"""Helper function to print account info"""
|
|
504
526
|
self._show_info(self.get_account_info, "account")
|
|
505
527
|
|
|
506
|
-
def get_terminal_info(self, show=False) ->
|
|
528
|
+
def get_terminal_info(self, show=False) -> TerminalInfo | None:
|
|
507
529
|
"""
|
|
508
530
|
Get the connected MetaTrader 5 client terminal status and settings.
|
|
509
531
|
|
|
@@ -951,7 +973,7 @@ class Account(object):
|
|
|
951
973
|
futures_types["bonds"].append(info.name)
|
|
952
974
|
return futures_types[category]
|
|
953
975
|
|
|
954
|
-
def get_symbol_info(self, symbol: str) ->
|
|
976
|
+
def get_symbol_info(self, symbol: str) -> SymbolInfo | None:
|
|
955
977
|
"""Get symbol properties
|
|
956
978
|
|
|
957
979
|
Args:
|
|
@@ -984,6 +1006,14 @@ class Account(object):
|
|
|
984
1006
|
msg = self._symbol_info_msg(symbol)
|
|
985
1007
|
raise_mt5_error(message=f"{str(e)} {msg}")
|
|
986
1008
|
|
|
1009
|
+
def _symbol_info_msg(self, symbol):
|
|
1010
|
+
return (
|
|
1011
|
+
f"No history found for {symbol} in Market Watch.\n"
|
|
1012
|
+
f"* Ensure {symbol} is selected and displayed in the Market Watch window.\n"
|
|
1013
|
+
f"* See https://www.metatrader5.com/en/terminal/help/trading/market_watch\n"
|
|
1014
|
+
f"* Ensure the symbol name is correct.\n"
|
|
1015
|
+
)
|
|
1016
|
+
|
|
987
1017
|
def show_symbol_info(self, symbol: str):
|
|
988
1018
|
"""
|
|
989
1019
|
Print symbol properties
|
|
@@ -993,15 +1023,7 @@ class Account(object):
|
|
|
993
1023
|
"""
|
|
994
1024
|
self._show_info(self.get_symbol_info, "symbol", symbol=symbol)
|
|
995
1025
|
|
|
996
|
-
def
|
|
997
|
-
return (
|
|
998
|
-
f"No history found for {symbol} in Market Watch.\n"
|
|
999
|
-
f"* Ensure {symbol} is selected and displayed in the Market Watch window.\n"
|
|
1000
|
-
f"* See https://www.metatrader5.com/en/terminal/help/trading/market_watch\n"
|
|
1001
|
-
f"* Ensure the symbol name is correct.\n"
|
|
1002
|
-
)
|
|
1003
|
-
|
|
1004
|
-
def get_tick_info(self, symbol: str) -> Union[TickInfo, None]:
|
|
1026
|
+
def get_tick_info(self, symbol: str) -> TickInfo | None:
|
|
1005
1027
|
"""Get symbol tick properties
|
|
1006
1028
|
|
|
1007
1029
|
Args:
|
|
@@ -1043,7 +1065,148 @@ class Account(object):
|
|
|
1043
1065
|
"""
|
|
1044
1066
|
self._show_info(self.get_tick_info, "tick", symbol=symbol)
|
|
1045
1067
|
|
|
1046
|
-
def
|
|
1068
|
+
def get_rate_info(self, symbol: str, timeframe: str = "1m") -> RateInfo | None:
|
|
1069
|
+
"""Get the most recent bar for a specified symbol and timeframe.
|
|
1070
|
+
|
|
1071
|
+
Args:
|
|
1072
|
+
symbol (str): The symbol for which to get the rate information.
|
|
1073
|
+
timeframe (str): The timeframe for the rate information. Default is '1m'.
|
|
1074
|
+
See ``bbstrader.metatrader.utils.TIMEFRAMES`` for supported timeframes.
|
|
1075
|
+
Returns:
|
|
1076
|
+
RateInfo: The most recent bar as a RateInfo named tuple.
|
|
1077
|
+
None: If no rates are found or an error occurs.
|
|
1078
|
+
Raises:
|
|
1079
|
+
MT5TerminalError: A specific exception based on the error code.
|
|
1080
|
+
"""
|
|
1081
|
+
rates = mt5.copy_rates_from_pos(symbol, TIMEFRAMES[timeframe], 0, 1)
|
|
1082
|
+
if rates is None or len(rates) == 0:
|
|
1083
|
+
return None
|
|
1084
|
+
rate = rates[0]
|
|
1085
|
+
return RateInfo(*rate)
|
|
1086
|
+
|
|
1087
|
+
def get_rates_from_pos(
|
|
1088
|
+
self, symbol: str, timeframe: str, start_pos: int = 0, bars: int = 1
|
|
1089
|
+
) -> NDArray[np.void]:
|
|
1090
|
+
"""
|
|
1091
|
+
Get bars from the MetaTrader 5 terminal starting from the specified index.
|
|
1092
|
+
|
|
1093
|
+
Args:
|
|
1094
|
+
symbol: Financial instrument name, for example, "EURUSD"
|
|
1095
|
+
timeframe: Timeframe the bars are requested for.
|
|
1096
|
+
start_pos: Initial index of the bar the data are requested from.
|
|
1097
|
+
bars: Number of bars to receive.
|
|
1098
|
+
|
|
1099
|
+
Returns:
|
|
1100
|
+
bars as the numpy array with the named time, open, high, low, close, tick_volume, spread and real_volume columns.
|
|
1101
|
+
Returns an empty array in case of an error.
|
|
1102
|
+
"""
|
|
1103
|
+
rates = mt5.copy_rates_from_pos(symbol, TIMEFRAMES[timeframe], start_pos, bars)
|
|
1104
|
+
if rates is None or len(rates) == 0:
|
|
1105
|
+
return np.array([], dtype=RateDtype)
|
|
1106
|
+
return rates
|
|
1107
|
+
|
|
1108
|
+
def get_rates_from_date(
|
|
1109
|
+
self,
|
|
1110
|
+
symbol: str,
|
|
1111
|
+
timeframe: str,
|
|
1112
|
+
date_from: datetime | pd.Timestamp,
|
|
1113
|
+
bars: int = 1,
|
|
1114
|
+
) -> NDArray[np.void]:
|
|
1115
|
+
"""
|
|
1116
|
+
Get bars from the MetaTrader 5 terminal starting from the specified date.
|
|
1117
|
+
|
|
1118
|
+
Args:
|
|
1119
|
+
symbol: Financial instrument name, for example, "EURUSD"
|
|
1120
|
+
timeframe: Timeframe the bars are requested for.
|
|
1121
|
+
date_from: Date of opening of the first bar from the requested sample.
|
|
1122
|
+
bars: Number of bars to receive.
|
|
1123
|
+
|
|
1124
|
+
Returns:
|
|
1125
|
+
bars as the numpy array with the named time, open, high, low, close, tick_volume, spread and real_volume columns.
|
|
1126
|
+
Returns an empty array in case of an error.
|
|
1127
|
+
|
|
1128
|
+
"""
|
|
1129
|
+
rates = mt5.copy_rates_from(symbol, TIMEFRAMES[timeframe], date_from, bars)
|
|
1130
|
+
if rates is None or len(rates) == 0:
|
|
1131
|
+
return np.array([], dtype=RateDtype)
|
|
1132
|
+
return rates
|
|
1133
|
+
|
|
1134
|
+
def get_rates_range(
|
|
1135
|
+
self,
|
|
1136
|
+
symbol: str,
|
|
1137
|
+
timeframe: str,
|
|
1138
|
+
date_from: datetime | pd.Timestamp,
|
|
1139
|
+
date_to: datetime | pd.Timestamp = datetime.now(),
|
|
1140
|
+
) -> NDArray[np.void]:
|
|
1141
|
+
"""
|
|
1142
|
+
Get bars in the specified date range from the MetaTrader 5 terminal.
|
|
1143
|
+
|
|
1144
|
+
Args:
|
|
1145
|
+
symbol: Financial instrument name, for example, "EURUSD"
|
|
1146
|
+
timeframe: Timeframe the bars are requested for.
|
|
1147
|
+
date_from: Date the bars are requested from.
|
|
1148
|
+
date_to: Date, up to which the bars are requested.
|
|
1149
|
+
|
|
1150
|
+
Returns:
|
|
1151
|
+
bars as the numpy array with the named time, open, high, low, close, tick_volume, spread and real_volume columns.
|
|
1152
|
+
Returns an empty array in case of an error.
|
|
1153
|
+
"""
|
|
1154
|
+
rates = mt5.copy_rates_range(symbol, TIMEFRAMES[timeframe], date_from, date_to)
|
|
1155
|
+
if rates is None or len(rates) == 0:
|
|
1156
|
+
return np.array([], dtype=RateDtype)
|
|
1157
|
+
return rates
|
|
1158
|
+
|
|
1159
|
+
def get_tick_from_date(
|
|
1160
|
+
self,
|
|
1161
|
+
symbol: str,
|
|
1162
|
+
date_from: datetime | pd.Timestamp,
|
|
1163
|
+
ticks: int = 1,
|
|
1164
|
+
flag: Literal["all", "info", "trade"] = "all",
|
|
1165
|
+
) -> NDArray[np.void]:
|
|
1166
|
+
"""
|
|
1167
|
+
Get ticks from the MetaTrader 5 terminal starting from the specified date.
|
|
1168
|
+
|
|
1169
|
+
Args:
|
|
1170
|
+
symbol: Financial instrument name, for example, "EURUSD"
|
|
1171
|
+
date_from: Date the ticks are requested from.
|
|
1172
|
+
ticks: Number of bars to receive.
|
|
1173
|
+
flag: A flag to define the type of the requested ticks ("all", "info", "trade").
|
|
1174
|
+
|
|
1175
|
+
Returns:
|
|
1176
|
+
Returns ticks as the numpy array with the named time, bid, ask, last and flags columns.
|
|
1177
|
+
Return an empty array in case of an error.
|
|
1178
|
+
"""
|
|
1179
|
+
ticks_data = mt5.copy_ticks_from(symbol, date_from, ticks, TickFlag[flag])
|
|
1180
|
+
if ticks_data is None or len(ticks_data) == 0:
|
|
1181
|
+
return np.array([], dtype=TickDtype)
|
|
1182
|
+
return ticks_data
|
|
1183
|
+
|
|
1184
|
+
def get_tick_range(
|
|
1185
|
+
self,
|
|
1186
|
+
symbol: str,
|
|
1187
|
+
date_from: datetime | pd.Timestamp,
|
|
1188
|
+
date_to: datetime | pd.Timestamp = datetime.now(),
|
|
1189
|
+
flag: Literal["all", "info", "trade"] = "all",
|
|
1190
|
+
) -> NDArray[np.void]:
|
|
1191
|
+
"""
|
|
1192
|
+
Get ticks for the specified date range from the MetaTrader 5 terminal.
|
|
1193
|
+
|
|
1194
|
+
Args:
|
|
1195
|
+
symbol: Financial instrument name, for example, "EURUSD"
|
|
1196
|
+
date_from: Date the ticks are requested from.
|
|
1197
|
+
date_to: Date, up to which the ticks are requested.
|
|
1198
|
+
flag: A flag to define the type of the requested ticks ("all", "info", "trade").
|
|
1199
|
+
|
|
1200
|
+
Returns:
|
|
1201
|
+
Returns ticks as the numpy array with the named time, bid, ask, last and flags columns.
|
|
1202
|
+
Return an empty array in case of an error.
|
|
1203
|
+
"""
|
|
1204
|
+
ticks_data = mt5.copy_ticks_range(symbol, date_from, date_to, TickFlag[flag])
|
|
1205
|
+
if ticks_data is None or len(ticks_data) == 0:
|
|
1206
|
+
return np.array([], dtype=TickDtype)
|
|
1207
|
+
return ticks_data
|
|
1208
|
+
|
|
1209
|
+
def get_market_book(self, symbol: str) -> Tuple[BookInfo]:
|
|
1047
1210
|
"""
|
|
1048
1211
|
Get the Market Depth content for a specific symbol.
|
|
1049
1212
|
Args:
|
|
@@ -1185,7 +1348,7 @@ class Account(object):
|
|
|
1185
1348
|
group: Optional[str] = None,
|
|
1186
1349
|
ticket: Optional[int] = None,
|
|
1187
1350
|
to_df: bool = False,
|
|
1188
|
-
) -> Union[pd.DataFrame, Tuple[TradePosition]
|
|
1351
|
+
) -> Union[pd.DataFrame, Tuple[TradePosition]]:
|
|
1189
1352
|
"""
|
|
1190
1353
|
Get open positions with the ability to filter by symbol or ticket.
|
|
1191
1354
|
There are four call options:
|
|
@@ -1215,7 +1378,6 @@ class Account(object):
|
|
|
1215
1378
|
Returns:
|
|
1216
1379
|
Union[pd.DataFrame, Tuple[TradePosition], None]:
|
|
1217
1380
|
- `TradePosition` in the form of a named tuple structure (namedtuple) or pd.DataFrame.
|
|
1218
|
-
- `None` in case of an error.
|
|
1219
1381
|
|
|
1220
1382
|
Notes:
|
|
1221
1383
|
The method allows receiving all open positions within a specified period.
|
|
@@ -1271,7 +1433,7 @@ class Account(object):
|
|
|
1271
1433
|
position: Optional[int] = None, # TradePosition.ticket
|
|
1272
1434
|
to_df: bool = True,
|
|
1273
1435
|
save: bool = False,
|
|
1274
|
-
) -> Union[pd.DataFrame, Tuple[TradeDeal]
|
|
1436
|
+
) -> Union[pd.DataFrame, Tuple[TradeDeal]]:
|
|
1275
1437
|
"""
|
|
1276
1438
|
Get deals from trading history within the specified interval
|
|
1277
1439
|
with the ability to filter by `ticket` or `position`.
|
|
@@ -1309,7 +1471,6 @@ class Account(object):
|
|
|
1309
1471
|
Returns:
|
|
1310
1472
|
Union[pd.DataFrame, Tuple[TradeDeal], None]:
|
|
1311
1473
|
- `TradeDeal` in the form of a named tuple structure (namedtuple) or pd.DataFrame().
|
|
1312
|
-
- `None` in case of an error.
|
|
1313
1474
|
|
|
1314
1475
|
Notes:
|
|
1315
1476
|
The method allows receiving all history orders within a specified period.
|
|
@@ -1372,7 +1533,7 @@ class Account(object):
|
|
|
1372
1533
|
group: Optional[str] = None,
|
|
1373
1534
|
ticket: Optional[int] = None,
|
|
1374
1535
|
to_df: bool = False,
|
|
1375
|
-
) -> Union[pd.DataFrame, Tuple[TradeOrder]
|
|
1536
|
+
) -> Union[pd.DataFrame, Tuple[TradeOrder]]:
|
|
1376
1537
|
"""
|
|
1377
1538
|
Get active orders with the ability to filter by symbol or ticket.
|
|
1378
1539
|
There are four call options:
|
|
@@ -1399,7 +1560,6 @@ class Account(object):
|
|
|
1399
1560
|
Returns:
|
|
1400
1561
|
Union[pd.DataFrame, Tuple[TradeOrder], None]:
|
|
1401
1562
|
- `TradeOrder` in the form of a named tuple structure (namedtuple) or pd.DataFrame().
|
|
1402
|
-
- `None` in case of an error.
|
|
1403
1563
|
|
|
1404
1564
|
Notes:
|
|
1405
1565
|
The method allows receiving all history orders within a specified period.
|
|
@@ -1464,7 +1624,7 @@ class Account(object):
|
|
|
1464
1624
|
position: Optional[int] = None, # position ticket
|
|
1465
1625
|
to_df: bool = True,
|
|
1466
1626
|
save: bool = False,
|
|
1467
|
-
) -> Union[pd.DataFrame, Tuple[TradeOrder]
|
|
1627
|
+
) -> Union[pd.DataFrame, Tuple[TradeOrder]]:
|
|
1468
1628
|
"""
|
|
1469
1629
|
Get orders from trading history within the specified interval
|
|
1470
1630
|
with the ability to filter by `ticket` or `position`.
|
|
@@ -1502,7 +1662,6 @@ class Account(object):
|
|
|
1502
1662
|
Returns:
|
|
1503
1663
|
Union[pd.DataFrame, Tuple[TradeOrder], None]
|
|
1504
1664
|
- `TradeOrder` in the form of a named tuple structure (namedtuple) or pd.DataFrame().
|
|
1505
|
-
- `None` in case of an error.
|
|
1506
1665
|
|
|
1507
1666
|
Notes:
|
|
1508
1667
|
The method allows receiving all history orders within a specified period.
|
|
@@ -1583,16 +1742,11 @@ class Account(object):
|
|
|
1583
1742
|
Returns:
|
|
1584
1743
|
List[TradeDeal]: List of today deals
|
|
1585
1744
|
"""
|
|
1586
|
-
|
|
1587
|
-
history = (
|
|
1588
|
-
self.get_trades_history(date_from=date_from, group=group, to_df=False) or []
|
|
1589
|
-
)
|
|
1745
|
+
history = self.get_trades_history(group=group, to_df=False) or []
|
|
1590
1746
|
positions_ids = set([deal.position_id for deal in history if deal.magic == id])
|
|
1591
1747
|
today_deals = []
|
|
1592
1748
|
for position in positions_ids:
|
|
1593
|
-
deal = self.get_trades_history(
|
|
1594
|
-
date_from=date_from, position=position, to_df=False
|
|
1595
|
-
)
|
|
1749
|
+
deal = self.get_trades_history(position=position, to_df=False) or []
|
|
1596
1750
|
if deal is not None and len(deal) == 2:
|
|
1597
1751
|
deal_time = datetime.fromtimestamp(deal[1].time)
|
|
1598
1752
|
if deal_time.date() == datetime.now().date():
|
bbstrader/metatrader/analysis.py
CHANGED
|
@@ -4,17 +4,15 @@ import numpy as np
|
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import seaborn as sns
|
|
6
6
|
|
|
7
|
-
from bbstrader.metatrader.account import check_mt5_connection
|
|
7
|
+
from bbstrader.metatrader.account import check_mt5_connection, shutdown_mt5
|
|
8
8
|
from bbstrader.metatrader.utils import TIMEFRAMES
|
|
9
9
|
|
|
10
10
|
sns.set_theme()
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def _get_data(
|
|
14
|
-
check_mt5_connection(path=path)
|
|
13
|
+
def _get_data(symbol, timeframe, bars):
|
|
15
14
|
rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, bars)
|
|
16
15
|
df = pd.DataFrame(rates)
|
|
17
|
-
df["time"] = pd.to_datetime(df["time"], unit="s")
|
|
18
16
|
return df
|
|
19
17
|
|
|
20
18
|
|
|
@@ -76,10 +74,14 @@ def display_volume_profile(
|
|
|
76
74
|
Returns:
|
|
77
75
|
None: Displays a matplotlib chart of the volume profile.
|
|
78
76
|
"""
|
|
79
|
-
|
|
77
|
+
check_mt5_connection(path=path)
|
|
78
|
+
df = _get_data(symbol, TIMEFRAMES[timeframe], bars)
|
|
79
|
+
if df.empty:
|
|
80
|
+
raise ValueError(f"No data found for {symbol} in {path}")
|
|
80
81
|
hist, bin_edges, bin_centers = volume_profile(df, bins)
|
|
81
82
|
poc, vah, val = value_area(hist, bin_centers, va_percentage)
|
|
82
83
|
current_price = mt5.symbol_info_tick(symbol).bid
|
|
84
|
+
shutdown_mt5()
|
|
83
85
|
|
|
84
86
|
plt.figure(figsize=(6, 10))
|
|
85
87
|
plt.barh(bin_centers, hist, height=bin_centers[1] - bin_centers[0], color="skyblue")
|