bbstrader 0.3.1__py3-none-any.whl → 0.3.3__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/__init__.py +1 -1
- bbstrader/__main__.py +7 -5
- bbstrader/btengine/backtest.py +7 -8
- bbstrader/btengine/data.py +3 -3
- bbstrader/btengine/execution.py +2 -2
- bbstrader/btengine/strategy.py +70 -17
- bbstrader/config.py +2 -2
- bbstrader/core/data.py +3 -1
- bbstrader/core/scripts.py +62 -19
- bbstrader/metatrader/account.py +108 -23
- bbstrader/metatrader/copier.py +753 -280
- bbstrader/metatrader/rates.py +2 -2
- bbstrader/metatrader/risk.py +1 -0
- bbstrader/metatrader/scripts.py +35 -9
- bbstrader/metatrader/trade.py +60 -43
- bbstrader/metatrader/utils.py +3 -5
- bbstrader/models/__init__.py +0 -1
- bbstrader/models/ml.py +55 -26
- bbstrader/models/nlp.py +159 -89
- bbstrader/models/optimization.py +1 -1
- bbstrader/models/risk.py +16 -386
- bbstrader/trading/execution.py +109 -50
- bbstrader/trading/strategies.py +9 -592
- bbstrader/tseries.py +39 -711
- {bbstrader-0.3.1.dist-info → bbstrader-0.3.3.dist-info}/METADATA +36 -41
- bbstrader-0.3.3.dist-info/RECORD +47 -0
- bbstrader-0.3.1.dist-info/RECORD +0 -47
- {bbstrader-0.3.1.dist-info → bbstrader-0.3.3.dist-info}/WHEEL +0 -0
- {bbstrader-0.3.1.dist-info → bbstrader-0.3.3.dist-info}/entry_points.txt +0 -0
- {bbstrader-0.3.1.dist-info → bbstrader-0.3.3.dist-info}/licenses/LICENSE +0 -0
- {bbstrader-0.3.1.dist-info → bbstrader-0.3.3.dist-info}/top_level.txt +0 -0
bbstrader/metatrader/account.py
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import re
|
|
3
3
|
import urllib.request
|
|
4
|
-
from datetime import datetime
|
|
4
|
+
from datetime import datetime, timedelta
|
|
5
5
|
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
|
|
6
6
|
|
|
7
7
|
import pandas as pd
|
|
8
|
-
from currency_converter import SINGLE_DAY_ECB_URL, CurrencyConverter
|
|
9
|
-
|
|
10
8
|
from bbstrader.metatrader.utils import (
|
|
11
9
|
AccountInfo,
|
|
12
10
|
BookInfo,
|
|
@@ -23,6 +21,7 @@ from bbstrader.metatrader.utils import (
|
|
|
23
21
|
TradeRequest,
|
|
24
22
|
raise_mt5_error,
|
|
25
23
|
)
|
|
24
|
+
from currency_converter import SINGLE_DAY_ECB_URL, CurrencyConverter
|
|
26
25
|
|
|
27
26
|
try:
|
|
28
27
|
import MetaTrader5 as mt5
|
|
@@ -33,6 +32,7 @@ except ImportError:
|
|
|
33
32
|
__all__ = [
|
|
34
33
|
"Account",
|
|
35
34
|
"Broker",
|
|
35
|
+
"MetaQuotes",
|
|
36
36
|
"AdmiralMarktsGroup",
|
|
37
37
|
"JustGlobalMarkets",
|
|
38
38
|
"PepperstoneGroupLimited",
|
|
@@ -41,6 +41,7 @@ __all__ = [
|
|
|
41
41
|
]
|
|
42
42
|
|
|
43
43
|
__BROKERS__ = {
|
|
44
|
+
"MQL": "MetaQuotes Ltd.",
|
|
44
45
|
"AMG": "Admirals Group AS",
|
|
45
46
|
"JGM": "Just Global Markets Ltd.",
|
|
46
47
|
"FTMO": "FTMO S.R.O.",
|
|
@@ -54,9 +55,7 @@ BROKERS_TIMEZONES = {
|
|
|
54
55
|
"PGL": "Europe/Helsinki",
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
_ADMIRAL_MARKETS_URL_ =
|
|
58
|
-
"https://cabinet.a-partnership.com/visit/?bta=35537&brand=admiralmarkets"
|
|
59
|
-
)
|
|
58
|
+
_ADMIRAL_MARKETS_URL_ = "https://one.justmarkets.link/a/tufvj0xugm/registration/trader"
|
|
60
59
|
_JUST_MARKETS_URL_ = "https://one.justmarkets.link/a/tufvj0xugm/registration/trader"
|
|
61
60
|
_FTMO_URL_ = "https://trader.ftmo.com/?affiliates=JGmeuQqepAZLMcdOEQRp"
|
|
62
61
|
_ADMIRAL_MARKETS_PRODUCTS_ = [
|
|
@@ -69,14 +68,13 @@ _ADMIRAL_MARKETS_PRODUCTS_ = [
|
|
|
69
68
|
]
|
|
70
69
|
_JUST_MARKETS_PRODUCTS_ = ["Stocks", "Crypto", "indices", "Commodities", "Forex"]
|
|
71
70
|
|
|
72
|
-
SUPPORTED_BROKERS = [__BROKERS__[b] for b in {"AMG", "JGM", "FTMO"}]
|
|
71
|
+
SUPPORTED_BROKERS = [__BROKERS__[b] for b in {"MQL", "AMG", "JGM", "FTMO"}]
|
|
73
72
|
INIT_MSG = (
|
|
74
|
-
f"\n*
|
|
75
|
-
f"*
|
|
76
|
-
f"*
|
|
77
|
-
f"
|
|
78
|
-
f"*
|
|
79
|
-
f"* If you are looking for a prop firm, See [{_FTMO_URL_}]\n"
|
|
73
|
+
f"\n* Check your internet connection\n"
|
|
74
|
+
f"* Make sure MT5 is installed and active\n"
|
|
75
|
+
f"* Looking for a boker? See [{_ADMIRAL_MARKETS_URL_}] "
|
|
76
|
+
f"or [{_JUST_MARKETS_URL_}]\n"
|
|
77
|
+
f"* Looking for a prop firm? See [{_FTMO_URL_}]\n"
|
|
80
78
|
)
|
|
81
79
|
|
|
82
80
|
amg_url = _ADMIRAL_MARKETS_URL_
|
|
@@ -138,13 +136,22 @@ AMG_EXCHANGES = {
|
|
|
138
136
|
}
|
|
139
137
|
|
|
140
138
|
|
|
141
|
-
def check_mt5_connection(
|
|
139
|
+
def check_mt5_connection(
|
|
140
|
+
*,
|
|
141
|
+
path=None,
|
|
142
|
+
login=None,
|
|
143
|
+
password=None,
|
|
144
|
+
server=None,
|
|
145
|
+
timeout=60_000,
|
|
146
|
+
portable=False,
|
|
147
|
+
**kwargs,
|
|
148
|
+
) -> bool:
|
|
142
149
|
"""
|
|
143
150
|
Initialize the connection to the MetaTrader 5 terminal.
|
|
144
151
|
|
|
145
152
|
Args:
|
|
146
153
|
path (str, optional): The path to the MetaTrader 5 terminal executable file.
|
|
147
|
-
Defaults to None (e.g., "C
|
|
154
|
+
Defaults to None (e.g., "C:/Program Files/MetaTrader 5/terminal64.exe").
|
|
148
155
|
login (int, optional): The login ID of the trading account. Defaults to None.
|
|
149
156
|
password (str, optional): The password of the trading account. Defaults to None.
|
|
150
157
|
server (str, optional): The name of the trade server to which the client terminal is connected.
|
|
@@ -158,13 +165,13 @@ def check_mt5_connection(**kwargs):
|
|
|
158
165
|
- Follow these instructions to lunch each terminal in portable mode first:
|
|
159
166
|
https://www.metatrader5.com/en/terminal/help/start_advanced/start#configuration_file
|
|
160
167
|
"""
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
+
if login is not None and server is not None:
|
|
169
|
+
account_info = mt5.account_info()
|
|
170
|
+
if account_info is not None:
|
|
171
|
+
if account_info.login == login and account_info.server == server:
|
|
172
|
+
return True
|
|
173
|
+
|
|
174
|
+
init = False
|
|
168
175
|
if path is None and (login or password or server):
|
|
169
176
|
raise ValueError(
|
|
170
177
|
"You must provide a path to the terminal executable file"
|
|
@@ -189,6 +196,7 @@ def check_mt5_connection(**kwargs):
|
|
|
189
196
|
raise_mt5_error(INIT_MSG)
|
|
190
197
|
except Exception:
|
|
191
198
|
raise_mt5_error(INIT_MSG)
|
|
199
|
+
return init
|
|
192
200
|
|
|
193
201
|
|
|
194
202
|
def shutdown_mt5():
|
|
@@ -221,6 +229,11 @@ class Broker(object):
|
|
|
221
229
|
return f"{self.__class__.__name__}({self.name})"
|
|
222
230
|
|
|
223
231
|
|
|
232
|
+
class MetaQuotes(Broker):
|
|
233
|
+
def __init__(self, **kwargs):
|
|
234
|
+
super().__init__(__BROKERS__["MQL"], **kwargs)
|
|
235
|
+
|
|
236
|
+
|
|
224
237
|
class AdmiralMarktsGroup(Broker):
|
|
225
238
|
def __init__(self, **kwargs):
|
|
226
239
|
super().__init__(__BROKERS__["AMG"], **kwargs)
|
|
@@ -262,6 +275,7 @@ class AMP(Broker): ...
|
|
|
262
275
|
|
|
263
276
|
BROKERS: Dict[str, Broker] = {
|
|
264
277
|
"FTMO": FTMO(),
|
|
278
|
+
"MQL": MetaQuotes(),
|
|
265
279
|
"AMG": AdmiralMarktsGroup(),
|
|
266
280
|
"JGM": JustGlobalMarkets(),
|
|
267
281
|
"PGL": PepperstoneGroupLimited(),
|
|
@@ -391,6 +405,7 @@ class Account(object):
|
|
|
391
405
|
password: Optional[str] = None,
|
|
392
406
|
server: Optional[str] = None,
|
|
393
407
|
timeout: Optional[int] = 60_000,
|
|
408
|
+
path: Optional[str] = None,
|
|
394
409
|
) -> Union[AccountInfo, None]:
|
|
395
410
|
"""
|
|
396
411
|
Get info on the current trading account or a specific account .
|
|
@@ -408,6 +423,8 @@ class Account(object):
|
|
|
408
423
|
If not specified, the value of 60 000 (60 seconds) is applied.
|
|
409
424
|
If the connection is not established within the specified time,
|
|
410
425
|
the call is forcibly terminated and the exception is generated.
|
|
426
|
+
path (str, optional): The path to the MetaTrader 5 terminal executable file.
|
|
427
|
+
Defaults to None (e.g., "C:/Program Files/MetaTrader 5/terminal64.exe").
|
|
411
428
|
|
|
412
429
|
Returns:
|
|
413
430
|
- AccountInfo in the form of a Namedtuple structure.
|
|
@@ -419,6 +436,15 @@ class Account(object):
|
|
|
419
436
|
# connect to the trade account specifying a password and a server
|
|
420
437
|
if account is not None and password is not None and server is not None:
|
|
421
438
|
try:
|
|
439
|
+
# If a path is provided, initialize the MT5 terminal with it
|
|
440
|
+
if path is not None:
|
|
441
|
+
check_mt5_connection(
|
|
442
|
+
path=path,
|
|
443
|
+
login=account,
|
|
444
|
+
password=password,
|
|
445
|
+
server=server,
|
|
446
|
+
timeout=timeout,
|
|
447
|
+
)
|
|
422
448
|
authorized = mt5.login(
|
|
423
449
|
account, password=password, server=server, timeout=timeout
|
|
424
450
|
)
|
|
@@ -1079,6 +1105,39 @@ class Account(object):
|
|
|
1079
1105
|
except Exception as e:
|
|
1080
1106
|
raise_mt5_error(e)
|
|
1081
1107
|
|
|
1108
|
+
def calculate_profit(
|
|
1109
|
+
self,
|
|
1110
|
+
action: Literal["buy", "sell"],
|
|
1111
|
+
symbol: str,
|
|
1112
|
+
lot: float,
|
|
1113
|
+
price_open: float,
|
|
1114
|
+
price_close: float,
|
|
1115
|
+
) -> float:
|
|
1116
|
+
"""
|
|
1117
|
+
Calculate profit in the account currency for a specified trading operation.
|
|
1118
|
+
|
|
1119
|
+
Args:
|
|
1120
|
+
action (str): The trading action, either 'buy' or 'sell'.
|
|
1121
|
+
symbol (str): The symbol of the financial instrument.
|
|
1122
|
+
lot (float): The lot size of the order.
|
|
1123
|
+
price_open (float): The price at which to position was opened.
|
|
1124
|
+
price_close (float): The price at which to position was closed.
|
|
1125
|
+
|
|
1126
|
+
Returns:
|
|
1127
|
+
float: The profit value
|
|
1128
|
+
|
|
1129
|
+
Raises:
|
|
1130
|
+
MT5TerminalError: A specific exception based on the error code.
|
|
1131
|
+
|
|
1132
|
+
"""
|
|
1133
|
+
actions = {"buy": mt5.ORDER_TYPE_BUY, "sell": mt5.ORDER_TYPE_SELL}
|
|
1134
|
+
try:
|
|
1135
|
+
return mt5.order_calc_profit(
|
|
1136
|
+
actions[action], symbol, lot, price_open, price_close
|
|
1137
|
+
)
|
|
1138
|
+
except Exception as e:
|
|
1139
|
+
raise_mt5_error(e)
|
|
1140
|
+
|
|
1082
1141
|
def check_order(self, request: Dict[str, Any]) -> OrderCheckResult:
|
|
1083
1142
|
"""
|
|
1084
1143
|
Check funds sufficiency for performing a required trading operation.
|
|
@@ -1327,7 +1386,7 @@ class Account(object):
|
|
|
1327
1386
|
group: Optional[str] = None,
|
|
1328
1387
|
ticket: Optional[int] = None,
|
|
1329
1388
|
to_df: bool = False,
|
|
1330
|
-
) -> Union[pd.DataFrame, Tuple[TradeOrder]
|
|
1389
|
+
) -> Union[pd.DataFrame, Tuple[TradeOrder]]:
|
|
1331
1390
|
"""
|
|
1332
1391
|
Get active orders with the ability to filter by symbol or ticket.
|
|
1333
1392
|
There are four call options:
|
|
@@ -1527,3 +1586,29 @@ class Account(object):
|
|
|
1527
1586
|
else:
|
|
1528
1587
|
history_orders = [TradeOrder(**td._asdict()) for td in history_orders]
|
|
1529
1588
|
return tuple(history_orders)
|
|
1589
|
+
|
|
1590
|
+
def get_today_deals(self, id, group=None) -> List[TradeDeal]:
|
|
1591
|
+
"""
|
|
1592
|
+
Get all today deals for a specific symbol or group of symbols
|
|
1593
|
+
|
|
1594
|
+
Args:
|
|
1595
|
+
id (int): strategy or expert id
|
|
1596
|
+
group (str): Symbol or group or symbol
|
|
1597
|
+
Returns:
|
|
1598
|
+
List[TradeDeal]: List of today deals
|
|
1599
|
+
"""
|
|
1600
|
+
date_from = datetime.now() - timedelta(days=2)
|
|
1601
|
+
history = (
|
|
1602
|
+
self.get_trades_history(date_from=date_from, group=group, to_df=False) or []
|
|
1603
|
+
)
|
|
1604
|
+
positions_ids = set([deal.position_id for deal in history if deal.magic == id])
|
|
1605
|
+
today_deals = []
|
|
1606
|
+
for position in positions_ids:
|
|
1607
|
+
deal = self.get_trades_history(
|
|
1608
|
+
date_from=date_from, position=position, to_df=False
|
|
1609
|
+
)
|
|
1610
|
+
if deal is not None and len(deal) == 2:
|
|
1611
|
+
deal_time = datetime.fromtimestamp(deal[1].time)
|
|
1612
|
+
if deal_time.date() == datetime.now().date():
|
|
1613
|
+
today_deals.append(deal[1])
|
|
1614
|
+
return today_deals
|