bbstrader 0.2.97__tar.gz → 0.2.98__tar.gz
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-0.2.97/bbstrader.egg-info → bbstrader-0.2.98}/PKG-INFO +12 -16
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/__main__.py +1 -1
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/strategy.py +4 -3
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/account.py +30 -6
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/copier.py +6 -11
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/trade.py +36 -64
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/utils.py +16 -0
- bbstrader-0.2.98/bbstrader/trading/execution.py +990 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/trading/scripts.py +10 -11
- {bbstrader-0.2.97 → bbstrader-0.2.98/bbstrader.egg-info}/PKG-INFO +12 -16
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader.egg-info/requires.txt +11 -15
- {bbstrader-0.2.97 → bbstrader-0.2.98}/requirements.txt +11 -16
- {bbstrader-0.2.97 → bbstrader-0.2.98}/setup.py +1 -1
- bbstrader-0.2.97/bbstrader/trading/execution.py +0 -857
- {bbstrader-0.2.97 → bbstrader-0.2.98}/LICENSE +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/MANIFEST.in +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/README.md +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/__ini__.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/__init__.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/backtest.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/data.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/event.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/execution.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/performance.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/portfolio.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/btengine/scripts.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/compat.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/config.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/core/__init__.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/core/data.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/core/utils.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/ibkr/__init__.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/ibkr/utils.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/__init__.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/rates.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/risk.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/metatrader/scripts.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/models/__init__.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/models/factors.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/models/ml.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/models/nlp.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/models/optimization.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/models/portfolio.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/models/risk.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/trading/__init__.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/trading/strategies.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/trading/utils.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader/tseries.py +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader.egg-info/SOURCES.txt +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader.egg-info/dependency_links.txt +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader.egg-info/entry_points.txt +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/bbstrader.egg-info/top_level.txt +0 -0
- {bbstrader-0.2.97 → bbstrader-0.2.98}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bbstrader
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.98
|
|
4
4
|
Summary: Simplified Investment & Trading Toolkit
|
|
5
5
|
Home-page: https://github.com/bbalouki/bbstrader
|
|
6
6
|
Download-URL: https://pypi.org/project/bbstrader/
|
|
@@ -24,21 +24,24 @@ Classifier: Operating System :: MacOS
|
|
|
24
24
|
Classifier: License :: OSI Approved :: MIT License
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
License-File: LICENSE
|
|
27
|
-
Requires-Dist:
|
|
27
|
+
Requires-Dist: numpy<2.0.0,>=1.26.0
|
|
28
|
+
Requires-Dist: scikit-learn
|
|
29
|
+
Requires-Dist: statsmodels
|
|
30
|
+
Requires-Dist: seaborn
|
|
31
|
+
Requires-Dist: lightgbm
|
|
32
|
+
Requires-Dist: dash
|
|
33
|
+
Requires-Dist: nltk
|
|
34
|
+
Requires-Dist: spacy
|
|
35
|
+
Requires-Dist: pmdarima
|
|
36
|
+
Requires-Dist: pyportfolioopt
|
|
37
|
+
Requires-Dist: alphalens-reloaded
|
|
28
38
|
Requires-Dist: pandas_ta
|
|
29
|
-
Requires-Dist: numpy<2.0.0
|
|
30
39
|
Requires-Dist: yfinance
|
|
31
|
-
Requires-Dist: scipy
|
|
32
40
|
Requires-Dist: hmmlearn
|
|
33
|
-
Requires-Dist: pmdarima
|
|
34
41
|
Requires-Dist: arch
|
|
35
42
|
Requires-Dist: hurst
|
|
36
|
-
Requires-Dist: seaborn
|
|
37
|
-
Requires-Dist: statsmodels
|
|
38
|
-
Requires-Dist: matplotlib
|
|
39
43
|
Requires-Dist: filterpy
|
|
40
44
|
Requires-Dist: pykalman
|
|
41
|
-
Requires-Dist: pytest
|
|
42
45
|
Requires-Dist: CurrencyConverter
|
|
43
46
|
Requires-Dist: tabulate
|
|
44
47
|
Requires-Dist: python-dotenv
|
|
@@ -46,24 +49,17 @@ Requires-Dist: ipython
|
|
|
46
49
|
Requires-Dist: QuantStats
|
|
47
50
|
Requires-Dist: exchange-calendars
|
|
48
51
|
Requires-Dist: tqdm
|
|
49
|
-
Requires-Dist: scikit-learn
|
|
50
52
|
Requires-Dist: notify-py
|
|
51
53
|
Requires-Dist: python-telegram-bot
|
|
52
|
-
Requires-Dist: pyportfolioopt
|
|
53
54
|
Requires-Dist: eodhd
|
|
54
55
|
Requires-Dist: financetoolkit
|
|
55
56
|
Requires-Dist: PyYAML
|
|
56
57
|
Requires-Dist: tables
|
|
57
|
-
Requires-Dist: lightgbm
|
|
58
|
-
Requires-Dist: alphalens-reloaded
|
|
59
58
|
Requires-Dist: pyfiglet
|
|
60
59
|
Requires-Dist: colorama
|
|
61
60
|
Requires-Dist: praw
|
|
62
61
|
Requires-Dist: tweepy
|
|
63
62
|
Requires-Dist: beautifulsoup4
|
|
64
|
-
Requires-Dist: dash
|
|
65
|
-
Requires-Dist: nltk
|
|
66
|
-
Requires-Dist: spacy
|
|
67
63
|
Requires-Dist: textblob
|
|
68
64
|
Requires-Dist: vaderSentiment
|
|
69
65
|
Provides-Extra: mt5
|
|
@@ -16,7 +16,7 @@ USAGE_TEXT = """
|
|
|
16
16
|
Modules:
|
|
17
17
|
copier: Copy trades from one MetaTrader account to another or multiple accounts
|
|
18
18
|
backtest: Backtest a strategy, see bbstrader.btengine.backtest.run_backtest
|
|
19
|
-
execution: Execute a strategy, see bbstrader.trading.execution.
|
|
19
|
+
execution: Execute a strategy, see bbstrader.trading.execution.Mt5ExecutionEngine
|
|
20
20
|
|
|
21
21
|
python -m bbstrader --run <module> --help for more information on the module
|
|
22
22
|
"""
|
|
@@ -12,13 +12,13 @@ from loguru import logger
|
|
|
12
12
|
from bbstrader.btengine.data import DataHandler
|
|
13
13
|
from bbstrader.btengine.event import FillEvent, SignalEvent
|
|
14
14
|
from bbstrader.config import BBSTRADER_DIR
|
|
15
|
-
from bbstrader.metatrader.trade import TradeSignal
|
|
16
15
|
from bbstrader.metatrader.account import (
|
|
17
16
|
Account,
|
|
18
17
|
AdmiralMarktsGroup,
|
|
19
18
|
PepperstoneGroupLimited,
|
|
20
19
|
)
|
|
21
20
|
from bbstrader.metatrader.rates import Rates
|
|
21
|
+
from bbstrader.metatrader.trade import TradeSignal
|
|
22
22
|
from bbstrader.models.optimization import optimized_weights
|
|
23
23
|
|
|
24
24
|
__all__ = ["Strategy", "MT5Strategy"]
|
|
@@ -67,7 +67,7 @@ class MT5Strategy(Strategy):
|
|
|
67
67
|
"""
|
|
68
68
|
A `MT5Strategy()` object is a subclass of `Strategy` that is used to
|
|
69
69
|
calculate signals for the MetaTrader 5 trading platform. The signals
|
|
70
|
-
are generated by the `MT5Strategy` object and sent to the the `
|
|
70
|
+
are generated by the `MT5Strategy` object and sent to the the `Mt5ExecutionEngine`
|
|
71
71
|
for live trading and `MT5BacktestEngine` objects for backtesting.
|
|
72
72
|
"""
|
|
73
73
|
|
|
@@ -146,9 +146,9 @@ class MT5Strategy(Strategy):
|
|
|
146
146
|
def _initialize_portfolio(self):
|
|
147
147
|
positions = ["LONG", "SHORT"]
|
|
148
148
|
orders = ["BLMT", "BSTP", "BSTPLMT", "SLMT", "SSTP", "SSTPLMT"]
|
|
149
|
+
self._orders: Dict[str, Dict[str, List[SignalEvent]]] = {}
|
|
149
150
|
self._positions: Dict[str, Dict[str, int | float]] = {}
|
|
150
151
|
self._trades: Dict[str, Dict[str, int]] = {}
|
|
151
|
-
self._orders: Dict[str, Dict[str, List[SignalEvent]]] = {}
|
|
152
152
|
for symbol in self.symbols:
|
|
153
153
|
self._positions[symbol] = {}
|
|
154
154
|
self._orders[symbol] = {}
|
|
@@ -206,6 +206,7 @@ class MT5Strategy(Strategy):
|
|
|
206
206
|
- ``price``: The price at which to execute the action, used for pending orders.
|
|
207
207
|
- ``stoplimit``: The stop-limit price for STOP-LIMIT orders, used for pending stop limit orders.
|
|
208
208
|
- ``id``: The unique identifier for the strategy or order.
|
|
209
|
+
- ``comment``: An optional comment or description related to the trade signal.
|
|
209
210
|
"""
|
|
210
211
|
pass
|
|
211
212
|
|
|
@@ -9,6 +9,7 @@ from currency_converter import SINGLE_DAY_ECB_URL, CurrencyConverter
|
|
|
9
9
|
|
|
10
10
|
from bbstrader.metatrader.utils import (
|
|
11
11
|
AccountInfo,
|
|
12
|
+
BookInfo,
|
|
12
13
|
InvalidBroker,
|
|
13
14
|
OrderCheckResult,
|
|
14
15
|
OrderSentResult,
|
|
@@ -188,10 +189,12 @@ def check_mt5_connection(**kwargs):
|
|
|
188
189
|
except Exception:
|
|
189
190
|
raise_mt5_error(INIT_MSG)
|
|
190
191
|
|
|
192
|
+
|
|
191
193
|
def shutdown_mt5():
|
|
192
194
|
"""Close the connection to the MetaTrader 5 terminal."""
|
|
193
195
|
mt5.shutdown()
|
|
194
|
-
|
|
196
|
+
|
|
197
|
+
|
|
195
198
|
class Broker(object):
|
|
196
199
|
def __init__(self, name: str = None, **kwargs):
|
|
197
200
|
if name is None:
|
|
@@ -323,7 +326,7 @@ class Account(object):
|
|
|
323
326
|
f"For {supported['FTMO'].name}, See [{ftmo_url}]\n"
|
|
324
327
|
)
|
|
325
328
|
raise InvalidBroker(message=msg)
|
|
326
|
-
|
|
329
|
+
|
|
327
330
|
def shutdown(self):
|
|
328
331
|
"""Close the connection to the MetaTrader 5 terminal."""
|
|
329
332
|
shutdown_mt5()
|
|
@@ -1037,6 +1040,29 @@ class Account(object):
|
|
|
1037
1040
|
"""
|
|
1038
1041
|
self._show_info(self.get_tick_info, "tick", symbol=symbol)
|
|
1039
1042
|
|
|
1043
|
+
def get_market_book(self, symbol: str) -> Union[Tuple[BookInfo], None]:
|
|
1044
|
+
"""
|
|
1045
|
+
Get the Market Depth content for a specific symbol.
|
|
1046
|
+
Args:
|
|
1047
|
+
symbol (str): Financial instrument name. Required unnamed parameter.
|
|
1048
|
+
The symbol name should be specified in the same format as in the Market Watch window.
|
|
1049
|
+
|
|
1050
|
+
Returns:
|
|
1051
|
+
The Market Depth content as a tuple from BookInfo entries featuring order type, price and volume in lots.
|
|
1052
|
+
Return None in case of an error.
|
|
1053
|
+
|
|
1054
|
+
Raises:
|
|
1055
|
+
MT5TerminalError: A specific exception based on the error code.
|
|
1056
|
+
"""
|
|
1057
|
+
try:
|
|
1058
|
+
book = mt5.market_book_get(symbol)
|
|
1059
|
+
if book is None:
|
|
1060
|
+
return None
|
|
1061
|
+
else:
|
|
1062
|
+
return Tuple([BookInfo(**entry._asdict()) for entry in book])
|
|
1063
|
+
except Exception as e:
|
|
1064
|
+
raise_mt5_error(e)
|
|
1065
|
+
|
|
1040
1066
|
def calculate_margin(
|
|
1041
1067
|
self, action: Literal["buy", "sell"], symbol: str, lot: float, price: float
|
|
1042
1068
|
) -> float:
|
|
@@ -1299,8 +1325,7 @@ class Account(object):
|
|
|
1299
1325
|
df.drop(["time_msc", "external_id"], axis=1, inplace=True)
|
|
1300
1326
|
df.set_index("time", inplace=True)
|
|
1301
1327
|
if save:
|
|
1302
|
-
|
|
1303
|
-
df.to_csv(file)
|
|
1328
|
+
df.to_csv("trades_history.csv")
|
|
1304
1329
|
if to_df:
|
|
1305
1330
|
return df
|
|
1306
1331
|
else:
|
|
@@ -1507,8 +1532,7 @@ class Account(object):
|
|
|
1507
1532
|
df["time_done"] = pd.to_datetime(df["time_done"], unit="s")
|
|
1508
1533
|
|
|
1509
1534
|
if save:
|
|
1510
|
-
|
|
1511
|
-
df.to_csv(file)
|
|
1535
|
+
df.to_csv("orders_history.csv")
|
|
1512
1536
|
if to_df:
|
|
1513
1537
|
return df
|
|
1514
1538
|
else:
|
|
@@ -302,16 +302,11 @@ class TradeCopier(object):
|
|
|
302
302
|
if self.start_time is None or self.end_time is None:
|
|
303
303
|
return True
|
|
304
304
|
else:
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
305
|
+
now = datetime.now()
|
|
306
|
+
start_time = datetime.strptime(self.start_time, "%H:%M").time()
|
|
307
|
+
end_time = datetime.strptime(self.end_time, "%H:%M").time()
|
|
308
|
+
if start_time <= now.time() <= end_time:
|
|
308
309
|
return True
|
|
309
|
-
elif datetime.now().hour == int(start_hour):
|
|
310
|
-
if datetime.now().minute >= int(start_minutes):
|
|
311
|
-
return True
|
|
312
|
-
elif datetime.now().hour == int(end_hour):
|
|
313
|
-
if datetime.now().minute < int(end_minutes):
|
|
314
|
-
return True
|
|
315
310
|
return False
|
|
316
311
|
|
|
317
312
|
def copy_new_trade(
|
|
@@ -608,10 +603,10 @@ class TradeCopier(object):
|
|
|
608
603
|
self.copy_orders(destination)
|
|
609
604
|
self.copy_positions(destination)
|
|
610
605
|
time.sleep(0.1)
|
|
611
|
-
except Exception as e:
|
|
612
|
-
self.log_error(e)
|
|
613
606
|
except KeyboardInterrupt:
|
|
614
607
|
break
|
|
608
|
+
except Exception as e:
|
|
609
|
+
self.log_error(e)
|
|
615
610
|
time.sleep(self.sleeptime)
|
|
616
611
|
|
|
617
612
|
|
|
@@ -137,6 +137,20 @@ class TradeSignal:
|
|
|
137
137
|
)
|
|
138
138
|
|
|
139
139
|
|
|
140
|
+
Buys = Literal["BMKT", "BLMT", "BSTP", "BSTPLMT"]
|
|
141
|
+
Sells = Literal["SMKT", "SLMT", "SSTP", "SSTPLMT"]
|
|
142
|
+
Positions = Literal["all", "buy", "sell", "profitable", "losing"]
|
|
143
|
+
Orders = Literal[
|
|
144
|
+
"all",
|
|
145
|
+
"buy_stops",
|
|
146
|
+
"sell_stops",
|
|
147
|
+
"buy_limits",
|
|
148
|
+
"sell_limits",
|
|
149
|
+
"buy_stop_limits",
|
|
150
|
+
"sell_stop_limits",
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
|
|
140
154
|
class Trade(RiskManagement):
|
|
141
155
|
"""
|
|
142
156
|
Extends the `RiskManagement` class to include specific trading operations,
|
|
@@ -239,15 +253,12 @@ class Trade(RiskManagement):
|
|
|
239
253
|
See the ``bbstrader.metatrader.risk.RiskManagement`` class for more details on these parameters.
|
|
240
254
|
See `bbstrader.metatrader.account.check_mt5_connection()` for more details on how to connect to MT5 terminal.
|
|
241
255
|
"""
|
|
242
|
-
# Call the parent class constructor first
|
|
243
256
|
super().__init__(
|
|
244
257
|
symbol=symbol,
|
|
245
258
|
start_time=start_time,
|
|
246
259
|
finishing_time=finishing_time,
|
|
247
|
-
**kwargs,
|
|
260
|
+
**kwargs,
|
|
248
261
|
)
|
|
249
|
-
|
|
250
|
-
# Initialize Trade-specific attributes
|
|
251
262
|
self.symbol = symbol
|
|
252
263
|
self.expert_name = expert_name
|
|
253
264
|
self.expert_id = expert_id
|
|
@@ -261,12 +272,6 @@ class Trade(RiskManagement):
|
|
|
261
272
|
self.tf = kwargs.get("time_frame", "D1")
|
|
262
273
|
self.kwargs = kwargs
|
|
263
274
|
|
|
264
|
-
self.start_time_hour, self.start_time_minutes = self.start.split(":")
|
|
265
|
-
self.finishing_time_hour, self.finishing_time_minutes = self.finishing.split(
|
|
266
|
-
":"
|
|
267
|
-
)
|
|
268
|
-
self.ending_time_hour, self.ending_time_minutes = self.end.split(":")
|
|
269
|
-
|
|
270
275
|
self.buy_positions = []
|
|
271
276
|
self.sell_positions = []
|
|
272
277
|
self.opened_positions = []
|
|
@@ -480,18 +485,14 @@ class Trade(RiskManagement):
|
|
|
480
485
|
session_data, headers=["Statistics", "Values"], tablefmt="outline"
|
|
481
486
|
)
|
|
482
487
|
|
|
483
|
-
# Print the formatted statistics
|
|
484
488
|
if self.verbose:
|
|
485
489
|
print("\n[======= Trading Session Statistics =======]")
|
|
486
490
|
print(session_table)
|
|
487
491
|
|
|
488
|
-
|
|
489
|
-
if save:
|
|
492
|
+
if save and stats["deals"] > 0:
|
|
490
493
|
today_date = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
491
|
-
# Create a dictionary with the statistics
|
|
492
494
|
statistics_dict = {item[0]: item[1] for item in session_data}
|
|
493
495
|
stats_df = pd.DataFrame(statistics_dict, index=[0])
|
|
494
|
-
# Create the directory if it doesn't exist
|
|
495
496
|
dir = dir or ".sessions"
|
|
496
497
|
os.makedirs(dir, exist_ok=True)
|
|
497
498
|
if "." in self.symbol:
|
|
@@ -504,8 +505,6 @@ class Trade(RiskManagement):
|
|
|
504
505
|
stats_df.to_csv(filepath, index=False)
|
|
505
506
|
LOGGER.info(f"Session statistics saved to {filepath}")
|
|
506
507
|
|
|
507
|
-
Buys = Literal["BMKT", "BLMT", "BSTP", "BSTPLMT"]
|
|
508
|
-
|
|
509
508
|
def open_buy_position(
|
|
510
509
|
self,
|
|
511
510
|
action: Buys = "BMKT",
|
|
@@ -595,8 +594,6 @@ class Trade(RiskManagement):
|
|
|
595
594
|
}
|
|
596
595
|
return type
|
|
597
596
|
|
|
598
|
-
Sells = Literal["SMKT", "SLMT", "SSTP", "SSTPLMT"]
|
|
599
|
-
|
|
600
597
|
def open_sell_position(
|
|
601
598
|
self,
|
|
602
599
|
action: Sells = "SMKT",
|
|
@@ -1370,13 +1367,16 @@ class Trade(RiskManagement):
|
|
|
1370
1367
|
profit = 0.0
|
|
1371
1368
|
balance = self.get_account_info().balance
|
|
1372
1369
|
target = round((balance * self.target) / 100, 2)
|
|
1373
|
-
|
|
1374
|
-
|
|
1370
|
+
opened_positions = self.get_today_deals(group=self.symbol)
|
|
1371
|
+
if len(opened_positions) != 0:
|
|
1372
|
+
for position in opened_positions:
|
|
1375
1373
|
time.sleep(0.1)
|
|
1376
1374
|
# This return two TradeDeal Object,
|
|
1377
1375
|
# The first one is the opening order
|
|
1378
1376
|
# The second is the closing order
|
|
1379
|
-
history = self.get_trades_history(
|
|
1377
|
+
history = self.get_trades_history(
|
|
1378
|
+
position=position.position_id, to_df=False
|
|
1379
|
+
)
|
|
1380
1380
|
if history is not None and len(history) == 2:
|
|
1381
1381
|
profit += history[1].profit
|
|
1382
1382
|
commission += history[0].commission
|
|
@@ -1598,16 +1598,6 @@ class Trade(RiskManagement):
|
|
|
1598
1598
|
f"No {order_type.upper()} {tikets_type.upper()} to close, SYMBOL={self.symbol}."
|
|
1599
1599
|
)
|
|
1600
1600
|
|
|
1601
|
-
Orders = Literal[
|
|
1602
|
-
"all",
|
|
1603
|
-
"buy_stops",
|
|
1604
|
-
"sell_stops",
|
|
1605
|
-
"buy_limits",
|
|
1606
|
-
"sell_limits",
|
|
1607
|
-
"buy_stop_limits",
|
|
1608
|
-
"sell_stop_limits",
|
|
1609
|
-
]
|
|
1610
|
-
|
|
1611
1601
|
def close_orders(
|
|
1612
1602
|
self,
|
|
1613
1603
|
order_type: Orders,
|
|
@@ -1642,8 +1632,6 @@ class Trade(RiskManagement):
|
|
|
1642
1632
|
orders, "orders", self.close_order, order_type, id=id, comment=comment
|
|
1643
1633
|
)
|
|
1644
1634
|
|
|
1645
|
-
Positions = Literal["all", "buy", "sell", "profitable", "losing"]
|
|
1646
|
-
|
|
1647
1635
|
def close_positions(
|
|
1648
1636
|
self,
|
|
1649
1637
|
position_type: Positions,
|
|
@@ -1689,13 +1677,11 @@ class Trade(RiskManagement):
|
|
|
1689
1677
|
List[TradeDeal]: List of today deals
|
|
1690
1678
|
"""
|
|
1691
1679
|
date_from = datetime.now() - timedelta(days=2)
|
|
1692
|
-
history =
|
|
1680
|
+
history = (
|
|
1681
|
+
self.get_trades_history(date_from=date_from, group=group, to_df=False) or []
|
|
1682
|
+
)
|
|
1693
1683
|
positions_ids = set(
|
|
1694
|
-
[
|
|
1695
|
-
deal.position_id
|
|
1696
|
-
for deal in history
|
|
1697
|
-
if history is not None and deal.magic == self.expert_id
|
|
1698
|
-
]
|
|
1684
|
+
[deal.position_id for deal in history if deal.magic == self.expert_id]
|
|
1699
1685
|
)
|
|
1700
1686
|
today_deals = []
|
|
1701
1687
|
for position in positions_ids:
|
|
@@ -1715,11 +1701,12 @@ class Trade(RiskManagement):
|
|
|
1715
1701
|
:return: bool
|
|
1716
1702
|
"""
|
|
1717
1703
|
negative_deals = 0
|
|
1704
|
+
max_trades = self.max_trade()
|
|
1718
1705
|
today_deals = self.get_today_deals(group=self.symbol)
|
|
1719
1706
|
for deal in today_deals:
|
|
1720
1707
|
if deal.profit < 0:
|
|
1721
1708
|
negative_deals += 1
|
|
1722
|
-
if negative_deals >=
|
|
1709
|
+
if negative_deals >= max_trades:
|
|
1723
1710
|
return True
|
|
1724
1711
|
return False
|
|
1725
1712
|
|
|
@@ -1800,7 +1787,6 @@ class Trade(RiskManagement):
|
|
|
1800
1787
|
The function assumes that the returns are the excess of
|
|
1801
1788
|
those compared to a benchmark.
|
|
1802
1789
|
"""
|
|
1803
|
-
# Get total history
|
|
1804
1790
|
import warnings
|
|
1805
1791
|
|
|
1806
1792
|
warnings.filterwarnings("ignore")
|
|
@@ -1817,33 +1803,19 @@ class Trade(RiskManagement):
|
|
|
1817
1803
|
|
|
1818
1804
|
def days_end(self) -> bool:
|
|
1819
1805
|
"""Check if it is the end of the trading day."""
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
ending_hour = int(self.ending_time_hour)
|
|
1824
|
-
ending_minute = int(self.ending_time_minutes)
|
|
1825
|
-
|
|
1826
|
-
if current_hour > ending_hour or (
|
|
1827
|
-
current_hour == ending_hour and current_minute >= ending_minute
|
|
1828
|
-
):
|
|
1806
|
+
now = datetime.now()
|
|
1807
|
+
end = datetime.strptime(self.end, "%H:%M").time()
|
|
1808
|
+
if now.time() >= end:
|
|
1829
1809
|
return True
|
|
1830
|
-
|
|
1831
|
-
return False
|
|
1810
|
+
return False
|
|
1832
1811
|
|
|
1833
1812
|
def trading_time(self):
|
|
1834
1813
|
"""Check if it is time to trade."""
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
):
|
|
1814
|
+
now = datetime.now()
|
|
1815
|
+
start = datetime.strptime(self.start, "%H:%M").time()
|
|
1816
|
+
end = datetime.strptime(self.finishing, "%H:%M").time()
|
|
1817
|
+
if start <= now.time() <= end:
|
|
1840
1818
|
return True
|
|
1841
|
-
elif datetime.now().hour == int(self.start_time_hour):
|
|
1842
|
-
if datetime.now().minute >= int(self.start_time_minutes):
|
|
1843
|
-
return True
|
|
1844
|
-
elif datetime.now().hour == int(self.finishing_time_hour):
|
|
1845
|
-
if datetime.now().minute < int(self.finishing_time_minutes):
|
|
1846
|
-
return True
|
|
1847
1819
|
return False
|
|
1848
1820
|
|
|
1849
1821
|
def sleep_time(self, weekend=False):
|
|
@@ -286,6 +286,22 @@ class TickInfo(NamedTuple):
|
|
|
286
286
|
volume_real: float
|
|
287
287
|
|
|
288
288
|
|
|
289
|
+
class BookInfo(NamedTuple):
|
|
290
|
+
"""
|
|
291
|
+
Represents the structure of a book.
|
|
292
|
+
* type: Type of the order (buy/sell)
|
|
293
|
+
* price: Price of the order
|
|
294
|
+
* volume: Volume of the order in lots
|
|
295
|
+
* volume_dbl: Volume with greater accuracy
|
|
296
|
+
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
type: int
|
|
300
|
+
price: float
|
|
301
|
+
volume: float
|
|
302
|
+
volume_dbl: float
|
|
303
|
+
|
|
304
|
+
|
|
289
305
|
class TradeRequest(NamedTuple):
|
|
290
306
|
"""
|
|
291
307
|
Represents a Trade Request Structure
|