bbstrader 0.1.5__py3-none-any.whl → 0.1.7__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/__ini__.py +0 -1
- bbstrader/btengine/__init__.py +12 -9
- bbstrader/btengine/backtest.py +100 -702
- bbstrader/btengine/data.py +25 -12
- bbstrader/btengine/event.py +18 -11
- bbstrader/btengine/execution.py +67 -7
- bbstrader/btengine/performance.py +34 -1
- bbstrader/btengine/portfolio.py +24 -14
- bbstrader/btengine/strategy.py +4 -3
- bbstrader/metatrader/account.py +18 -6
- bbstrader/metatrader/rates.py +35 -12
- bbstrader/metatrader/trade.py +54 -38
- bbstrader/metatrader/utils.py +3 -2
- bbstrader/models/risk.py +39 -2
- bbstrader/trading/__init__.py +8 -1
- bbstrader/trading/execution.py +344 -923
- bbstrader/trading/strategies.py +838 -0
- bbstrader/tseries.py +603 -19
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.7.dist-info}/METADATA +15 -7
- bbstrader-0.1.7.dist-info/RECORD +26 -0
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.7.dist-info}/WHEEL +1 -1
- bbstrader/strategies.py +0 -681
- bbstrader/trading/run.py +0 -131
- bbstrader/trading/utils.py +0 -153
- bbstrader-0.1.5.dist-info/RECORD +0 -28
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.7.dist-info}/LICENSE +0 -0
- {bbstrader-0.1.5.dist-info → bbstrader-0.1.7.dist-info}/top_level.txt +0 -0
bbstrader/metatrader/trade.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import csv
|
|
3
3
|
import time
|
|
4
|
-
import logging
|
|
5
4
|
import numpy as np
|
|
6
5
|
from datetime import datetime
|
|
7
6
|
import MetaTrader5 as Mt5
|
|
7
|
+
from logging import Logger
|
|
8
8
|
from typing import List, Tuple, Dict, Any, Optional, Literal
|
|
9
9
|
from bbstrader.metatrader.risk import RiskManagement
|
|
10
10
|
from bbstrader.metatrader.account import INIT_MSG
|
|
@@ -13,9 +13,6 @@ from bbstrader.metatrader.utils import (
|
|
|
13
13
|
raise_mt5_error, trade_retcode_message, config_logger
|
|
14
14
|
)
|
|
15
15
|
|
|
16
|
-
# Configure the logger
|
|
17
|
-
logger = config_logger('trade.log', console_log=True)
|
|
18
|
-
|
|
19
16
|
class Trade(RiskManagement):
|
|
20
17
|
"""
|
|
21
18
|
Extends the `RiskManagement` class to include specific trading operations,
|
|
@@ -81,6 +78,8 @@ class Trade(RiskManagement):
|
|
|
81
78
|
finishing_time: str = "23:00",
|
|
82
79
|
ending_time: str = "23:30",
|
|
83
80
|
verbose: Optional[bool] = None,
|
|
81
|
+
console_log: Optional[bool] = False,
|
|
82
|
+
logger: Logger | str = 'bbstrader.log',
|
|
84
83
|
**kwargs,
|
|
85
84
|
):
|
|
86
85
|
"""
|
|
@@ -98,6 +97,8 @@ class Trade(RiskManagement):
|
|
|
98
97
|
ending_time (str): The time after which any open position will be closed.
|
|
99
98
|
verbose (bool | None): If set to None (default), account summary and risk managment
|
|
100
99
|
parameters are printed in the terminal.
|
|
100
|
+
console_log (bool): If set to True, log messages are displayed in the console.
|
|
101
|
+
logger (Logger | str): The logger object to use for logging messages could be a string or a logger object.
|
|
101
102
|
|
|
102
103
|
Inherits:
|
|
103
104
|
- max_risk
|
|
@@ -131,6 +132,8 @@ class Trade(RiskManagement):
|
|
|
131
132
|
self.start = start_time
|
|
132
133
|
self.end = ending_time
|
|
133
134
|
self.finishing = finishing_time
|
|
135
|
+
self.console_log = console_log
|
|
136
|
+
self.logger = self._get_logger(logger, console_log)
|
|
134
137
|
self.tf = kwargs.get("time_frame", 'D1')
|
|
135
138
|
|
|
136
139
|
self.lot = self.get_lot()
|
|
@@ -160,8 +163,14 @@ class Trade(RiskManagement):
|
|
|
160
163
|
print()
|
|
161
164
|
self.risk_managment()
|
|
162
165
|
print(
|
|
163
|
-
f">>> Everything is OK, @{self.expert_name} is Running
|
|
166
|
+
f">>> Everything is OK, @{self.expert_name} is Running ...>>>\n")
|
|
164
167
|
|
|
168
|
+
def _get_logger(self, logger: str | Logger, consol_log: bool) -> Logger:
|
|
169
|
+
"""Get the logger object"""
|
|
170
|
+
if isinstance(logger, str):
|
|
171
|
+
return config_logger(logger, consol_log)
|
|
172
|
+
return logger
|
|
173
|
+
|
|
165
174
|
def initialize(self):
|
|
166
175
|
"""
|
|
167
176
|
Initializes the MetaTrader 5 (MT5) terminal for trading operations.
|
|
@@ -183,7 +192,7 @@ class Trade(RiskManagement):
|
|
|
183
192
|
f" Version @{self.version}, on {self.symbol}."
|
|
184
193
|
)
|
|
185
194
|
except Exception as e:
|
|
186
|
-
logger.error(f"During initialization: {e}")
|
|
195
|
+
self.logger.error(f"During initialization: {e}")
|
|
187
196
|
|
|
188
197
|
def select_symbol(self):
|
|
189
198
|
"""
|
|
@@ -200,7 +209,7 @@ class Trade(RiskManagement):
|
|
|
200
209
|
if not Mt5.symbol_select(self.symbol, True):
|
|
201
210
|
raise_mt5_error(message=INIT_MSG)
|
|
202
211
|
except Exception as e:
|
|
203
|
-
logger.error(f"Selecting symbol '{self.symbol}': {e}")
|
|
212
|
+
self.logger.error(f"Selecting symbol '{self.symbol}': {e}")
|
|
204
213
|
|
|
205
214
|
def prepare_symbol(self):
|
|
206
215
|
"""
|
|
@@ -222,7 +231,7 @@ class Trade(RiskManagement):
|
|
|
222
231
|
if self.verbose:
|
|
223
232
|
print("Initialization successfully completed.")
|
|
224
233
|
except Exception as e:
|
|
225
|
-
logger.error(f"Preparing symbol '{self.symbol}': {e}")
|
|
234
|
+
self.logger.error(f"Preparing symbol '{self.symbol}': {e}")
|
|
226
235
|
|
|
227
236
|
def summary(self):
|
|
228
237
|
"""Show a brief description about the trading program"""
|
|
@@ -327,7 +336,7 @@ class Trade(RiskManagement):
|
|
|
327
336
|
|
|
328
337
|
# Save to CSV if specified
|
|
329
338
|
if save:
|
|
330
|
-
today_date = datetime.now().strftime(
|
|
339
|
+
today_date = datetime.now().strftime('%Y%m%d%H%M%S')
|
|
331
340
|
# Create a dictionary with the statistics
|
|
332
341
|
statistics_dict = {
|
|
333
342
|
"Total Trades": deals,
|
|
@@ -351,7 +360,7 @@ class Trade(RiskManagement):
|
|
|
351
360
|
else:
|
|
352
361
|
symbol = self.symbol
|
|
353
362
|
|
|
354
|
-
filename = f"{symbol}_{today_date}_session.csv"
|
|
363
|
+
filename = f"{symbol}_{today_date}@{self.expert_id}_session.csv"
|
|
355
364
|
filepath = os.path.join(dir, filename)
|
|
356
365
|
|
|
357
366
|
# Updated code to write to CSV
|
|
@@ -362,7 +371,7 @@ class Trade(RiskManagement):
|
|
|
362
371
|
writer.writerow(["Statistic", "Value"])
|
|
363
372
|
for stat, value in statistics_dict.items():
|
|
364
373
|
writer.writerow([stat, value])
|
|
365
|
-
logger.info(f"Session statistics saved to {filepath}")
|
|
374
|
+
self.logger.info(f"Session statistics saved to {filepath}")
|
|
366
375
|
|
|
367
376
|
def open_buy_position(
|
|
368
377
|
self,
|
|
@@ -416,7 +425,7 @@ class Trade(RiskManagement):
|
|
|
416
425
|
request["action"] = Mt5.TRADE_ACTION_PENDING
|
|
417
426
|
request["type"] = self._order_type()[action][0]
|
|
418
427
|
|
|
419
|
-
self.break_even(
|
|
428
|
+
self.break_even(mm=mm)
|
|
420
429
|
if self.check(comment):
|
|
421
430
|
self.request_result(_price, request, action),
|
|
422
431
|
|
|
@@ -508,14 +517,14 @@ class Trade(RiskManagement):
|
|
|
508
517
|
if self.days_end():
|
|
509
518
|
return False
|
|
510
519
|
elif not self.trading_time():
|
|
511
|
-
logger.info(f"Not Trading time, SYMBOL={self.symbol}")
|
|
520
|
+
self.logger.info(f"Not Trading time, SYMBOL={self.symbol}")
|
|
512
521
|
return False
|
|
513
522
|
elif not self.is_risk_ok():
|
|
514
|
-
logger.error(f"Risk not allowed, SYMBOL={self.symbol}")
|
|
523
|
+
self.logger.error(f"Risk not allowed, SYMBOL={self.symbol}")
|
|
515
524
|
self._check(comment)
|
|
516
525
|
return False
|
|
517
526
|
elif not self._risk_free():
|
|
518
|
-
logger.error(f"Maximum trades Reached, SYMBOL={self.symbol}")
|
|
527
|
+
self.logger.error(f"Maximum trades Reached, SYMBOL={self.symbol}")
|
|
519
528
|
self._check(comment)
|
|
520
529
|
return False
|
|
521
530
|
elif self.profit_target():
|
|
@@ -525,7 +534,7 @@ class Trade(RiskManagement):
|
|
|
525
534
|
def _check(self, txt: str = ""):
|
|
526
535
|
if self.positive_profit() or self.get_current_open_positions() is None:
|
|
527
536
|
self.close_positions(position_type='all')
|
|
528
|
-
logger.info(txt)
|
|
537
|
+
self.logger.info(txt)
|
|
529
538
|
time.sleep(5)
|
|
530
539
|
self.statistics(save=True)
|
|
531
540
|
|
|
@@ -560,7 +569,7 @@ class Trade(RiskManagement):
|
|
|
560
569
|
result.retcode, display=True, add_msg=f"{e}{addtionnal}")
|
|
561
570
|
if result.retcode != Mt5.TRADE_RETCODE_DONE:
|
|
562
571
|
msg = trade_retcode_message(result.retcode)
|
|
563
|
-
logger.error(
|
|
572
|
+
self.logger.error(
|
|
564
573
|
f"Trade Order Request, RETCODE={result.retcode}: {msg}{addtionnal}")
|
|
565
574
|
if result.retcode in [
|
|
566
575
|
Mt5.TRADE_RETCODE_CONNECTION, Mt5.TRADE_RETCODE_TIMEOUT]:
|
|
@@ -580,7 +589,7 @@ class Trade(RiskManagement):
|
|
|
580
589
|
# Print the result
|
|
581
590
|
if result.retcode == Mt5.TRADE_RETCODE_DONE:
|
|
582
591
|
msg = trade_retcode_message(result.retcode)
|
|
583
|
-
logger.info(f"Trade Order {msg}{addtionnal}")
|
|
592
|
+
self.logger.info(f"Trade Order {msg}{addtionnal}")
|
|
584
593
|
if type != "BMKT" or type != "SMKT":
|
|
585
594
|
self.opened_orders.append(result.order)
|
|
586
595
|
long_msg = (
|
|
@@ -588,7 +597,7 @@ class Trade(RiskManagement):
|
|
|
588
597
|
f"Lot(s): {result.volume}, Sl: {self.get_stop_loss()}, "
|
|
589
598
|
f"Tp: {self.get_take_profit()}"
|
|
590
599
|
)
|
|
591
|
-
logger.info(long_msg)
|
|
600
|
+
self.logger.info(long_msg)
|
|
592
601
|
time.sleep(0.1)
|
|
593
602
|
if type == "BMKT" or type == "SMKT":
|
|
594
603
|
self.opened_positions.append(result.order)
|
|
@@ -606,12 +615,12 @@ class Trade(RiskManagement):
|
|
|
606
615
|
f"2. {order_type} Position Opened, Symbol: {self.symbol}, Price: @{round(position.price_open,5)}, "
|
|
607
616
|
f"Sl: @{position.sl} Tp: @{position.tp}"
|
|
608
617
|
)
|
|
609
|
-
logger.info(order_info)
|
|
618
|
+
self.logger.info(order_info)
|
|
610
619
|
pos_info = (
|
|
611
620
|
f"3. [OPEN POSITIONS ON {self.symbol} = {len(positions)}, ACCOUNT OPEN PnL = {profit} "
|
|
612
621
|
f"{self.get_account_info().currency}]\n"
|
|
613
622
|
)
|
|
614
|
-
logger.info(pos_info)
|
|
623
|
+
self.logger.info(pos_info)
|
|
615
624
|
|
|
616
625
|
def open_position(
|
|
617
626
|
self,
|
|
@@ -767,7 +776,7 @@ class Trade(RiskManagement):
|
|
|
767
776
|
return True
|
|
768
777
|
return False
|
|
769
778
|
|
|
770
|
-
def break_even(self, id: Optional[int] = None):
|
|
779
|
+
def break_even(self, mm=True, id: Optional[int] = None):
|
|
771
780
|
"""
|
|
772
781
|
Checks if it's time to put the break even,
|
|
773
782
|
if so , it will sets the break even ,and if the break even was already set,
|
|
@@ -776,8 +785,11 @@ class Trade(RiskManagement):
|
|
|
776
785
|
|
|
777
786
|
Args:
|
|
778
787
|
id (int): The strategy Id or Expert Id
|
|
788
|
+
mm (bool): Weither to manage the position or not
|
|
779
789
|
"""
|
|
780
790
|
time.sleep(0.1)
|
|
791
|
+
if not mm:
|
|
792
|
+
return
|
|
781
793
|
Id = id if id is not None else self.expert_id
|
|
782
794
|
positions = self.get_positions(symbol=self.symbol)
|
|
783
795
|
be = self.get_break_even()
|
|
@@ -905,7 +917,7 @@ class Trade(RiskManagement):
|
|
|
905
917
|
result.retcode, display=True, add_msg=f"{e}{addtionnal}")
|
|
906
918
|
if result.retcode != Mt5.TRADE_RETCODE_DONE:
|
|
907
919
|
msg = trade_retcode_message(result.retcode)
|
|
908
|
-
logger.error(
|
|
920
|
+
self.logger.error(
|
|
909
921
|
f"Break-Even Order Request, Position: #{tiket}, RETCODE={result.retcode}: {msg}{addtionnal}")
|
|
910
922
|
tries = 0
|
|
911
923
|
while result.retcode != Mt5.TRADE_RETCODE_DONE and tries < 10:
|
|
@@ -925,11 +937,11 @@ class Trade(RiskManagement):
|
|
|
925
937
|
tries += 1
|
|
926
938
|
if result.retcode == Mt5.TRADE_RETCODE_DONE:
|
|
927
939
|
msg = trade_retcode_message(result.retcode)
|
|
928
|
-
logger.info(f"Break-Even Order {msg}{addtionnal}")
|
|
940
|
+
self.logger.info(f"Break-Even Order {msg}{addtionnal}")
|
|
929
941
|
info = (
|
|
930
942
|
f"Stop loss set to Break-even, Position: #{tiket}, Symbol: {self.symbol}, Price: @{price}"
|
|
931
943
|
)
|
|
932
|
-
logger.info(info)
|
|
944
|
+
self.logger.info(info)
|
|
933
945
|
self.break_even_status.append(tiket)
|
|
934
946
|
|
|
935
947
|
def win_trade(self,
|
|
@@ -1046,7 +1058,7 @@ class Trade(RiskManagement):
|
|
|
1046
1058
|
result.retcode, display=True, add_msg=f"{e}{addtionnal}")
|
|
1047
1059
|
if result.retcode != Mt5.TRADE_RETCODE_DONE:
|
|
1048
1060
|
msg = trade_retcode_message(result.retcode)
|
|
1049
|
-
logger.error(
|
|
1061
|
+
self.logger.error(
|
|
1050
1062
|
f"Closing Order Request, Position: #{ticket}, RETCODE={result.retcode}: {msg}{addtionnal}")
|
|
1051
1063
|
tries = 0
|
|
1052
1064
|
while result.retcode != Mt5.TRADE_RETCODE_DONE and tries < 5:
|
|
@@ -1063,11 +1075,11 @@ class Trade(RiskManagement):
|
|
|
1063
1075
|
tries += 1
|
|
1064
1076
|
if result.retcode == Mt5.TRADE_RETCODE_DONE:
|
|
1065
1077
|
msg = trade_retcode_message(result.retcode)
|
|
1066
|
-
logger.info(
|
|
1078
|
+
self.logger.info(
|
|
1067
1079
|
f"Closing Order {msg}{addtionnal}")
|
|
1068
1080
|
info = (
|
|
1069
1081
|
f"Position #{ticket} closed, Symbol: {self.symbol}, Price: @{request['price']}")
|
|
1070
|
-
logger.info(info)
|
|
1082
|
+
self.logger.info(info)
|
|
1071
1083
|
return True
|
|
1072
1084
|
else:
|
|
1073
1085
|
return False
|
|
@@ -1095,13 +1107,16 @@ class Trade(RiskManagement):
|
|
|
1095
1107
|
|
|
1096
1108
|
if positions is not None:
|
|
1097
1109
|
if position_type == 'all':
|
|
1098
|
-
pos_type = ""
|
|
1099
1110
|
tickets = [position.ticket for position in positions]
|
|
1100
1111
|
else:
|
|
1101
1112
|
tickets = positions
|
|
1102
|
-
pos_type = position_type
|
|
1103
1113
|
else:
|
|
1104
1114
|
tickets = []
|
|
1115
|
+
|
|
1116
|
+
if position_type == 'all':
|
|
1117
|
+
pos_type = ''
|
|
1118
|
+
else:
|
|
1119
|
+
pos_type = position_type
|
|
1105
1120
|
|
|
1106
1121
|
if len(tickets) != 0:
|
|
1107
1122
|
for ticket in tickets.copy():
|
|
@@ -1110,14 +1125,14 @@ class Trade(RiskManagement):
|
|
|
1110
1125
|
time.sleep(1)
|
|
1111
1126
|
|
|
1112
1127
|
if len(tickets) == 0:
|
|
1113
|
-
logger.info(
|
|
1114
|
-
f"ALL {
|
|
1128
|
+
self.logger.info(
|
|
1129
|
+
f"ALL {pos_type.upper()} Positions closed, SYMBOL={self.symbol}.")
|
|
1115
1130
|
else:
|
|
1116
|
-
logger.info(
|
|
1117
|
-
f"{len(tickets)} {
|
|
1131
|
+
self.logger.info(
|
|
1132
|
+
f"{len(tickets)} {pos_type.upper()} Positions not closed, SYMBOL={self.symbol}")
|
|
1118
1133
|
else:
|
|
1119
|
-
logger.info(
|
|
1120
|
-
f"No {
|
|
1134
|
+
self.logger.info(
|
|
1135
|
+
f"No {pos_type.upper()} Positions to close, SYMBOL={self.symbol}.")
|
|
1121
1136
|
|
|
1122
1137
|
def get_stats(self) -> Tuple[Dict[str, Any]]:
|
|
1123
1138
|
"""
|
|
@@ -1274,7 +1289,8 @@ class Trade(RiskManagement):
|
|
|
1274
1289
|
|
|
1275
1290
|
def create_trade_instance(
|
|
1276
1291
|
symbols: List[str],
|
|
1277
|
-
params: Dict[str, Any]
|
|
1292
|
+
params: Dict[str, Any],
|
|
1293
|
+
logger: Logger = ...) -> Dict[str, Trade]:
|
|
1278
1294
|
"""
|
|
1279
1295
|
Creates Trade instances for each symbol provided.
|
|
1280
1296
|
|
|
@@ -1289,7 +1305,6 @@ def create_trade_instance(
|
|
|
1289
1305
|
ValueError: If the 'symbols' list is empty or the 'params' dictionary is missing required keys.
|
|
1290
1306
|
"""
|
|
1291
1307
|
instances = {}
|
|
1292
|
-
|
|
1293
1308
|
if not symbols:
|
|
1294
1309
|
raise ValueError("The 'symbols' list cannot be empty.")
|
|
1295
1310
|
for symbol in symbols:
|
|
@@ -1297,4 +1312,5 @@ def create_trade_instance(
|
|
|
1297
1312
|
instances[symbol] = Trade(**params, symbol=symbol)
|
|
1298
1313
|
except Exception as e:
|
|
1299
1314
|
logger.error(f"Creating Trade instance, SYMBOL={symbol} {e}")
|
|
1315
|
+
assert len(instances) == len(symbols), "Failed to create Trade instances for all symbols."
|
|
1300
1316
|
return instances
|
bbstrader/metatrader/utils.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
import MetaTrader5 as MT5
|
|
2
3
|
import logging
|
|
3
4
|
from typing import List, NamedTuple, Optional
|
|
@@ -216,7 +217,7 @@ class SymbolInfo(NamedTuple):
|
|
|
216
217
|
volume: int
|
|
217
218
|
volumehigh: int
|
|
218
219
|
volumelow: int
|
|
219
|
-
time:
|
|
220
|
+
time: datetime
|
|
220
221
|
digits: int
|
|
221
222
|
spread: int
|
|
222
223
|
spread_float: bool
|
|
@@ -316,7 +317,7 @@ class TickInfo(NamedTuple):
|
|
|
316
317
|
* flags: Tick flags
|
|
317
318
|
* volume_real: Volume for the current Last price with greater accuracy
|
|
318
319
|
"""
|
|
319
|
-
time:
|
|
320
|
+
time: datetime
|
|
320
321
|
bid: float
|
|
321
322
|
ask: float
|
|
322
323
|
last: float
|
bbstrader/models/risk.py
CHANGED
|
@@ -7,12 +7,14 @@ from hmmlearn.hmm import GaussianHMM
|
|
|
7
7
|
from abc import ABCMeta, abstractmethod
|
|
8
8
|
from matplotlib import cm, pyplot as plt
|
|
9
9
|
from matplotlib.dates import YearLocator, MonthLocator
|
|
10
|
-
from typing import Optional
|
|
10
|
+
from typing import Optional, Dict
|
|
11
|
+
from bbstrader.metatrader.rates import Rates
|
|
11
12
|
sns.set_theme()
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
14
15
|
"RiskModel",
|
|
15
|
-
"HMMRiskManager"
|
|
16
|
+
"HMMRiskManager",
|
|
17
|
+
"build_hmm_models"
|
|
16
18
|
]
|
|
17
19
|
|
|
18
20
|
|
|
@@ -347,3 +349,38 @@ class HMMRiskManager(RiskModel):
|
|
|
347
349
|
ax.xaxis.set_minor_locator(MonthLocator())
|
|
348
350
|
ax.grid(True)
|
|
349
351
|
plt.show()
|
|
352
|
+
|
|
353
|
+
def build_hmm_models(symbol_list=None, **kwargs
|
|
354
|
+
) -> Dict[str, HMMRiskManager]:
|
|
355
|
+
mt5_data = kwargs.get("use_mt5_data", False)
|
|
356
|
+
data = kwargs.get("hmm_data")
|
|
357
|
+
tf = kwargs.get("time_frame", 'D1')
|
|
358
|
+
hmm_end = kwargs.get("hmm_end", 0)
|
|
359
|
+
sd = kwargs.get("session_duration", 23.0)
|
|
360
|
+
hmm_tickers = kwargs.get("hmm_tickers")
|
|
361
|
+
if hmm_tickers is not None:
|
|
362
|
+
symbols = hmm_tickers
|
|
363
|
+
else:
|
|
364
|
+
symbols = symbol_list
|
|
365
|
+
hmm_models = {symbol: None for symbol in symbols}
|
|
366
|
+
if data is not None:
|
|
367
|
+
if isinstance(data, pd.DataFrame):
|
|
368
|
+
hmm_data = data
|
|
369
|
+
hmm = HMMRiskManager(
|
|
370
|
+
data=hmm_data, verbose=True, iterations=1000, **kwargs)
|
|
371
|
+
for symbol in symbols:
|
|
372
|
+
hmm_models[symbol] = hmm
|
|
373
|
+
elif isinstance(data, dict):
|
|
374
|
+
for symbol, data in data.items():
|
|
375
|
+
hmm = HMMRiskManager(
|
|
376
|
+
data=data, verbose=True, iterations=1000, **kwargs)
|
|
377
|
+
hmm_models[symbol] = hmm
|
|
378
|
+
if mt5_data:
|
|
379
|
+
for symbol in symbols:
|
|
380
|
+
rates = Rates(symbol, tf, start_pos=hmm_end, session_duration=sd)
|
|
381
|
+
data = rates.get_rates_from_pos()
|
|
382
|
+
assert data is not None, f"No data for {symbol}"
|
|
383
|
+
hmm = HMMRiskManager(
|
|
384
|
+
data=data, verbose=True, iterations=1000, **kwargs)
|
|
385
|
+
hmm_models[symbol] = hmm
|
|
386
|
+
return hmm_models
|
bbstrader/trading/__init__.py
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Trading strategies execution module
|
|
3
|
+
|
|
4
|
+
This module is responsible for executing trading strategies.
|
|
5
|
+
It provides a framework for executing trading strategies and managing the trading process.
|
|
6
|
+
The module is designed to be flexible and extensible, allowing users to define their own trading
|
|
7
|
+
strategies and customize the trading process.
|
|
8
|
+
|
|
3
9
|
"""
|
|
4
|
-
from bbstrader.trading.
|
|
10
|
+
from bbstrader.trading.execution import ExecutionEngine
|
|
11
|
+
from bbstrader.trading.strategies import *
|