bbstrader 0.2.95__py3-none-any.whl → 0.2.97__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/models/risk.py CHANGED
@@ -68,7 +68,7 @@ class RiskModel(metaclass=ABCMeta):
68
68
  such as historical returns or volatility, used to
69
69
  assess market conditions.
70
70
  """
71
- raise NotImplementedError("Should implement which_trade_allowed()")
71
+ pass
72
72
 
73
73
  @abstractmethod
74
74
  def which_quantity_allowed(self):
@@ -76,7 +76,7 @@ class RiskModel(metaclass=ABCMeta):
76
76
  Defines the strategy for asset allocation within
77
77
  the portfolio to optimize risk-reward ratio.
78
78
  """
79
- raise NotImplementedError("Should implement which_quantity_allowed()")
79
+ pass
80
80
 
81
81
 
82
82
  class HMMRiskManager(RiskModel):
@@ -8,10 +8,9 @@ from loguru import logger as log
8
8
 
9
9
  from bbstrader.btengine.strategy import MT5Strategy, Strategy
10
10
  from bbstrader.config import BBSTRADER_DIR
11
- from bbstrader.core.utils import TradeAction
12
11
  from bbstrader.metatrader.account import Account, check_mt5_connection
13
- from bbstrader.metatrader.trade import Trade
14
- from bbstrader.trading.scripts import send_message
12
+ from bbstrader.metatrader.trade import Trade, TradeAction
13
+ from bbstrader.trading.utils import send_message
15
14
 
16
15
  try:
17
16
  import MetaTrader5 as MT5
@@ -114,6 +113,7 @@ def _mt5_execution(
114
113
  comment,
115
114
  **kwargs,
116
115
  ):
116
+ global logger
117
117
  logger = kwargs.get("logger", log)
118
118
 
119
119
  def _print_exc(dm, msg):
@@ -168,6 +168,7 @@ def _mt5_execution(
168
168
  if symbol not in weights:
169
169
  continue
170
170
  trade = trades_instances[symbol]
171
+ assert daily_risk is not None
171
172
  dailydd = round(weights[symbol] * daily_risk, 5)
172
173
  trade.dailydd = dailydd
173
174
 
@@ -212,7 +213,9 @@ def _mt5_execution(
212
213
  f"Running {STRATEGY} Strategy in {time_frame} Interval ..., ACCOUNT={ACCOUNT}"
213
214
  )
214
215
 
215
- def run_trade_algorithm(signal, symbol, id, trade: Trade, price, stoplimit):
216
+ def run_trade_algorithm(
217
+ signal, symbol, id, trade: Trade, price, stoplimit, comment
218
+ ):
216
219
  signal = "BMKT" if signal == "LONG" or signal == "BUY" else signal
217
220
  signal = "SMKT" if signal == "SHORT" or signal == "SELL" else signal
218
221
  info = f"SIGNAL = {signal}, SYMBOL={symbol}, STRATEGY={STRATEGY}, TIMEFRAME={time_frame} , ACCOUNT={ACCOUNT}"
@@ -242,9 +245,13 @@ def _mt5_execution(
242
245
  if notify:
243
246
  _send_notification(sigmsg, symbol)
244
247
  if position_type in POSITIONS_TYPES:
245
- trade.close_positions(position_type=order_type, id=id)
248
+ trade.close_positions(
249
+ position_type=order_type, id=id, comment=comment
250
+ )
246
251
  else:
247
- trade.close_orders(order_type=order_type, id=id)
252
+ trade.close_orders(
253
+ order_type=order_type, id=id, comment=comment
254
+ )
248
255
  elif signal in BUYS and not long_market[symbol]:
249
256
  if use_trade_time:
250
257
  if time_intervals % trade_time == 0 or buys[symbol] is None:
@@ -412,6 +419,7 @@ def _mt5_execution(
412
419
  trade,
413
420
  signal.price,
414
421
  signal.stoplimit,
422
+ signal.comment or comment,
415
423
  )
416
424
  else:
417
425
  if len(symbols) >= 10:
@@ -592,6 +600,9 @@ def _mt5_execution(
592
600
  )
593
601
  _print_exc(debug_mode, msg)
594
602
  continue
603
+ except KeyboardInterrupt:
604
+ logger.info("Stopping the Execution Engine ...")
605
+ break
595
606
 
596
607
 
597
608
  def _tws_execution(*args, **kwargs):
@@ -819,7 +830,7 @@ def mt5_engine(account_id: str, **kwargs):
819
830
 
820
831
  def RunMt5Engines(accounts: Dict[str, Dict], start_delay: float = 1.0):
821
832
  """Runs multiple MT5 execution engines in parallel using multiprocessing.
822
-
833
+
823
834
  Args:
824
835
  accounts: Dictionary of accounts to run the execution engines on.
825
836
  Keys are the account names or IDs and values are the parameters for the execution engine.
@@ -1,69 +1,155 @@
1
- import asyncio
1
+ import argparse
2
+ import json
3
+ import multiprocessing as mp
4
+ import os
5
+ import sys
2
6
 
3
- from notifypy import Notify
4
- from telegram import Bot
5
- from telegram.error import TelegramError
7
+ from bbstrader.btengine import MT5Strategy, Strategy
8
+ from bbstrader.core.utils import load_class, load_module
9
+ from bbstrader.metatrader.trade import create_trade_instance
10
+ from bbstrader.trading.execution import mt5_engine
6
11
 
12
+ EXECUTION_PATH = os.path.expanduser("~/.bbstrader/execution/execution.py")
13
+ CONFIG_PATH = os.path.expanduser("~/.bbstrader/execution/execution.json")
7
14
 
8
- __all__ = ["send_telegram_message", "send_notification", "send_message"]
9
15
 
16
+ def load_config(config_path, strategy_name, account=None):
17
+ if not os.path.exists(config_path):
18
+ raise FileNotFoundError(f"Configuration file not found at {config_path}")
19
+ with open(config_path, "r") as f:
20
+ config = json.load(f)
21
+ try:
22
+ config = config[strategy_name]
23
+ except KeyError:
24
+ raise ValueError(
25
+ f"Strategy {strategy_name} not found in the configuration file."
26
+ )
27
+ if account is not None:
28
+ try:
29
+ config = config[account]
30
+ except KeyError:
31
+ raise ValueError(f"Account {account} not found in the configuration file.")
32
+ if config.get("symbol_list") is None:
33
+ raise ValueError("symbol_list is required in the configuration file.")
34
+ if config.get("trades_kwargs") is None:
35
+ raise ValueError("trades_kwargs is required in the configuration file.")
36
+ return config
10
37
 
11
- async def send_telegram_message(token, chat_id, text=""):
12
- """
13
- Send a message to a telegram chat
14
38
 
15
- Args:
16
- token: str: Telegram bot token
17
- chat_id: int or str or list: Chat id or list of chat ids
18
- text: str: Message to send
19
- """
20
- try:
21
- bot = Bot(token=token)
22
- if isinstance(chat_id, (int, str)):
23
- chat_id = [chat_id]
24
- for id in chat_id:
25
- await bot.send_message(chat_id=id, text=text)
26
- except TelegramError as e:
27
- print(f"Error sending message: {e}")
39
+ def worker_function(account, args):
40
+ strategy_module = load_module(args.path)
41
+ strategy_class = load_class(strategy_module, args.strategy, (MT5Strategy, Strategy))
28
42
 
43
+ config = load_config(args.config, args.strategy, account)
44
+ symbol_list = config.pop("symbol_list")
45
+ trades_kwargs = config.pop("trades_kwargs")
46
+ trades = create_trade_instance(symbol_list, trades_kwargs)
29
47
 
30
- def send_notification(title, message=""):
31
- """
32
- Send a desktop notification
48
+ kwargs = {
49
+ "symbol_list": symbol_list,
50
+ "trades_instances": trades,
51
+ "strategy_cls": strategy_class,
52
+ "account": account,
53
+ **config,
54
+ }
55
+ mt5_engine(account, **kwargs)
33
56
 
34
- Args:
35
- title: str: Title of the notification
36
- message: str: Message of the notification
37
- """
38
- notification = Notify(default_notification_application_name="bbstrading")
39
- notification.title = title
40
- notification.message = message
41
- notification.send()
42
-
43
-
44
- def send_message(
45
- title="SIGNAL",
46
- message="New signal",
47
- notify_me=False,
48
- telegram=False,
49
- token=None,
50
- chat_id=None,
51
- ):
52
- """
53
- Send a message to the user
54
-
55
- Args:
56
- title: str: Title of the message
57
- message: str: Message of the message
58
- notify_me: bool: Send a desktop notification
59
- telegram: bool: Send a telegram message
60
- token: str: Telegram bot token
61
- chat_id: int or str or list: Chat id or list of chat ids
57
+
58
+ def mt5_terminal(args):
59
+ if args.parallel:
60
+ if len(args.account) == 0:
61
+ raise ValueError(
62
+ "account or accounts are required when running in parallel"
63
+ )
64
+
65
+ processes = []
66
+ try:
67
+ for account in args.account:
68
+ p = mp.Process(target=worker_function, args=(account, args))
69
+ p.start()
70
+ processes.append(p)
71
+
72
+ for p in processes:
73
+ p.join()
74
+ except Exception as e:
75
+ print(f"Error in parallel execution: {e}")
76
+ raise e
77
+ except KeyboardInterrupt:
78
+ print("\nTerminating Execution...")
79
+ for p in processes:
80
+ p.terminate()
81
+ for p in processes:
82
+ p.join()
83
+ print("Execution terminated")
84
+ else:
85
+ worker_function(None, args)
86
+
87
+
88
+ def tws_terminal(args):
89
+ raise NotImplementedError("TWS terminal is not implemented yet")
90
+
91
+
92
+ def execute_strategy(unknown):
93
+ HELP_MSG = """
94
+ Execute a strategy on one or multiple MT5 accounts.
95
+
96
+ Usage:
97
+ python -m bbstrader --run execution [options]
98
+
99
+ Options:
100
+ -s, --strategy: Strategy class name to run
101
+ -a, --account: Account(s) name(s) or ID(s) to run the strategy on (must be the same as in the configuration file)
102
+ -p, --path: Path to the execution file (default: ~/.bbstrader/execution/execution.py)
103
+ -c, --config: Path to the configuration file (default: ~/.bbstrader/execution/execution.json)
104
+ -l, --parallel: Run the strategy in parallel (default: False)
105
+ -t, --terminal: Terminal to use (default: MT5)
106
+ -h, --help: Show this help message and exit
107
+
108
+ Note:
109
+ The configuration file must contain all the required parameters
110
+ to create trade instances for each account and strategy.
111
+ The configuration file must be a dictionary with the following structure:
112
+ If parallel is True:
113
+ {
114
+ "strategy_name": {
115
+ "account_name": {
116
+ "symbol_list": ["symbol1", "symbol2"],
117
+ "trades_kwargs": {"param1": "value1", "param2": "value2"}
118
+ **other_parameters (for the strategy and the execution engine)
119
+ }
120
+ }
121
+ }
122
+ If parallel is False:
123
+ {
124
+ "strategy_name": {
125
+ "symbol_list": ["symbol1", "symbol2"],
126
+ "trades_kwargs": {"param1": "value1", "param2": "value2"}
127
+ **other_parameters (for the strategy and the execution engine)
128
+ }
129
+ }
130
+ See bbstrader.metatrader.trade.create_trade_instance for more details on the trades_kwargs.
131
+ See bbstrader.trading.execution.MT5ExecutionEngine for more details on the other parameters.
132
+
133
+ All other paramaters must be python built-in types.
134
+ If you have custom type you must set them in your strategy class
135
+ or run the MT5ExecutionEngine directly, don't run on CLI.
62
136
  """
63
- if notify_me:
64
- send_notification(title, message=message)
65
- if telegram:
66
- if token is None or chat_id is None:
67
- raise ValueError("Token and chat_id must be provided")
68
- asyncio.run(send_telegram_message(token, chat_id, text=message))
137
+ if "-h" in unknown or "--help" in unknown:
138
+ print(HELP_MSG)
139
+ sys.exit(0)
140
+
141
+ parser = argparse.ArgumentParser()
142
+ parser.add_argument("-s", "--strategy", type=str, required=True)
143
+ parser.add_argument("-a", "--account", type=str, nargs="*", default=[])
144
+ parser.add_argument("-p", "--path", type=str, default=EXECUTION_PATH)
145
+ parser.add_argument("-c", "--config", type=str, default=CONFIG_PATH)
146
+ parser.add_argument("-l", "--parallel", action="store_true")
147
+ parser.add_argument(
148
+ "-t", "--terminal", type=str, default="MT5", choices=["MT5", "TWS"]
149
+ )
150
+ args = parser.parse_args(unknown)
69
151
 
152
+ if args.terminal == "MT5":
153
+ mt5_terminal(args)
154
+ elif args.terminal == "TWS":
155
+ tws_terminal(args)
@@ -1,5 +1,11 @@
1
1
  """
2
2
  Strategies module for trading strategies backtesting and execution.
3
+
4
+ DISCLAIMER:
5
+ This module is for educational purposes only and should not be
6
+ considered as financial advice. Always consult with a qualified financial advisor before making any investment decisions.
7
+ The authors and contributors of this module are not responsible for any financial losses or damages incurred as a result of using
8
+ this module or the information contained herein.
3
9
  """
4
10
 
5
11
  from datetime import datetime
@@ -0,0 +1,69 @@
1
+ import asyncio
2
+
3
+ from notifypy import Notify
4
+ from telegram import Bot
5
+ from telegram.error import TelegramError
6
+
7
+
8
+ __all__ = ["send_telegram_message", "send_notification", "send_message"]
9
+
10
+
11
+ async def send_telegram_message(token, chat_id, text=""):
12
+ """
13
+ Send a message to a telegram chat
14
+
15
+ Args:
16
+ token: str: Telegram bot token
17
+ chat_id: int or str or list: Chat id or list of chat ids
18
+ text: str: Message to send
19
+ """
20
+ try:
21
+ bot = Bot(token=token)
22
+ if isinstance(chat_id, (int, str)):
23
+ chat_id = [chat_id]
24
+ for id in chat_id:
25
+ await bot.send_message(chat_id=id, text=text)
26
+ except TelegramError as e:
27
+ print(f"Error sending message: {e}")
28
+
29
+
30
+ def send_notification(title, message=""):
31
+ """
32
+ Send a desktop notification
33
+
34
+ Args:
35
+ title: str: Title of the notification
36
+ message: str: Message of the notification
37
+ """
38
+ notification = Notify(default_notification_application_name="bbstrading")
39
+ notification.title = title
40
+ notification.message = message
41
+ notification.send()
42
+
43
+
44
+ def send_message(
45
+ title="SIGNAL",
46
+ message="New signal",
47
+ notify_me=False,
48
+ telegram=False,
49
+ token=None,
50
+ chat_id=None,
51
+ ):
52
+ """
53
+ Send a message to the user
54
+
55
+ Args:
56
+ title: str: Title of the message
57
+ message: str: Message of the message
58
+ notify_me: bool: Send a desktop notification
59
+ telegram: bool: Send a telegram message
60
+ token: str: Telegram bot token
61
+ chat_id: int or str or list: Chat id or list of chat ids
62
+ """
63
+ if notify_me:
64
+ send_notification(title, message=message)
65
+ if telegram:
66
+ if token is None or chat_id is None:
67
+ raise ValueError("Token and chat_id must be provided")
68
+ asyncio.run(send_telegram_message(token, chat_id, text=message))
69
+
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: bbstrader
3
- Version: 0.2.95
3
+ Version: 0.2.97
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/
@@ -58,6 +58,14 @@ Requires-Dist: lightgbm
58
58
  Requires-Dist: alphalens-reloaded
59
59
  Requires-Dist: pyfiglet
60
60
  Requires-Dist: colorama
61
+ Requires-Dist: praw
62
+ Requires-Dist: tweepy
63
+ Requires-Dist: beautifulsoup4
64
+ Requires-Dist: dash
65
+ Requires-Dist: nltk
66
+ Requires-Dist: spacy
67
+ Requires-Dist: textblob
68
+ Requires-Dist: vaderSentiment
61
69
  Provides-Extra: mt5
62
70
  Requires-Dist: MetaTrader5; extra == "mt5"
63
71
  Dynamic: author
@@ -69,6 +77,7 @@ Dynamic: download-url
69
77
  Dynamic: home-page
70
78
  Dynamic: keywords
71
79
  Dynamic: license
80
+ Dynamic: license-file
72
81
  Dynamic: maintainer
73
82
  Dynamic: project-url
74
83
  Dynamic: provides-extra
@@ -1,44 +1,45 @@
1
1
  bbstrader/__ini__.py,sha256=v6zyJHj5FMRL-_P7AwnTGbCF-riMqhqlTvDgfulj7go,621
2
- bbstrader/__main__.py,sha256=Fg-Ft1EXKbAn1FzZ94ak6kbVHarhrCEmm0dH9lDPMlA,1484
2
+ bbstrader/__main__.py,sha256=EtfD-TrAphboYxwfe7-WeD-1d4bJceeBputFrV-W-qQ,1525
3
3
  bbstrader/compat.py,sha256=djbHMvTvy0HYm1zyZ6Ttp_LMwP2PqTSVw1r7pqbz7So,487
4
4
  bbstrader/config.py,sha256=c2nCUw-bYWf5kkyFls5Nqld8HdMczexSilTni7rYUBw,3973
5
5
  bbstrader/tseries.py,sha256=H4D_A966HdN8YjBfuCcF8QBQdhjOrTcidR98wP2KN_I,68339
6
6
  bbstrader/btengine/__init__.py,sha256=y1btjaEfhWsH8vuE7mBRpP9Tu-Azt9REhuVYsPCAfBU,2955
7
7
  bbstrader/btengine/backtest.py,sha256=ZzGhoN-_g0cF-OCyk173imze2OXEhykHTUiJ9MowDO8,14582
8
- bbstrader/btengine/data.py,sha256=UpHW27o7cb9ibQJ6JYovfG_zyxA9SCwR0-Zv7zUQxSM,27296
8
+ bbstrader/btengine/data.py,sha256=Tuc6M8itbGpPjsfRpZBB8v0FJpPt7-hUkP6I5meP0Sg,26927
9
9
  bbstrader/btengine/event.py,sha256=38mhZH9d53C4x7bZER2B0O6M18txzS4u7zveKyxeP5Y,8603
10
- bbstrader/btengine/execution.py,sha256=Ij5dLc9mGgtWp2dKAH5oURplA3RS_ZtwTwSrp9IYfpk,10644
10
+ bbstrader/btengine/execution.py,sha256=mXY0tyFv6G1XF48R5Kx2-pDnwu1mUyOc0ZeeysQG62A,10587
11
11
  bbstrader/btengine/performance.py,sha256=1ecWrTzHBQbk4ORvbTEKxwCzlL1brcXOEUwgbnjAwx4,12470
12
12
  bbstrader/btengine/portfolio.py,sha256=mh2_zNJDmKzb0lo55PXhbXYxXMmXRA4YLkgzwxRMuZE,16110
13
13
  bbstrader/btengine/scripts.py,sha256=8o66dq4Ex4DsH4s8xvJqUOFjLzZJSnbBvvNBzohtzoE,4837
14
- bbstrader/btengine/strategy.py,sha256=c-wvotJdhHu5FWAlPkv33LfjoW-7ID2G0Di_hc7CYMM,33217
15
- bbstrader/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- bbstrader/core/data.py,sha256=0EhB-bI3QRjFRyfDfebrNAAmViXtXFPHbEsGpJKI5oM,430
17
- bbstrader/core/utils.py,sha256=dpP2qPFxo-gEvlzHvhoTH89UkftqiAqUJ6Lz04UDfRs,4079
14
+ bbstrader/btengine/strategy.py,sha256=PFIb9gUWahaXpzCFL-RchpBumlEJsz5Elbz_A2qZ8Jc,31285
15
+ bbstrader/core/__init__.py,sha256=GIFzFSStPfE0XM2j7mDeZZQeMTh_AwPsDOQXwMVJLgw,97
16
+ bbstrader/core/data.py,sha256=VPuynoT0uFYduh7la8gZSnEv_Gq8Xu2vJZJ7TfQMll8,18797
17
+ bbstrader/core/utils.py,sha256=WjuabzBjhY65ku2KL-f7CMalE2x-wrX-6mCA_qhhFPE,2728
18
18
  bbstrader/ibkr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  bbstrader/ibkr/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  bbstrader/metatrader/__init__.py,sha256=A5Ye9tpc2sp9Xk5qjKw-EfYsoRcZtAt8nqvC3tCtZs8,333
21
21
  bbstrader/metatrader/account.py,sha256=qAFqCPmoUjiqjY5M9sjbSvh-STjQUGdFCHOEcB7uoDI,56493
22
- bbstrader/metatrader/copier.py,sha256=AOuoNWafNiQiZ4IIjWBG5b7UhdyYMXK6-myEPDl1O9g,31761
22
+ bbstrader/metatrader/copier.py,sha256=-cFroX4M1q9rlupU4xLP0N6lR8ZbP_izUOQ2sBe_lFc,31797
23
23
  bbstrader/metatrader/rates.py,sha256=0bKyjGnafZ19DwC0-IxXUBJzOdAo-cNmhabwhKLxcos,20585
24
24
  bbstrader/metatrader/risk.py,sha256=pwG4q1_uPGgPlokDGVNtd04O6p28yIbgT-evvHuo-Qc,27029
25
25
  bbstrader/metatrader/scripts.py,sha256=Yjp7Un-wDTInptHS_rPFpXNKWbVM871VEkaHxsO2MPQ,2115
26
- bbstrader/metatrader/trade.py,sha256=6FbFywRPu0_TlB31lTMb3VjACw1GPQsi7RjQNtJnh6w,76780
26
+ bbstrader/metatrader/trade.py,sha256=Q1cArcpMnovRTED0kwMybcpwPB28rQKXLcJV4jldF0w,81202
27
27
  bbstrader/metatrader/utils.py,sha256=lYIvAeiL_ceACmkVNo4-QRopias08KyBUI7THfdj3c0,17103
28
- bbstrader/models/__init__.py,sha256=du7qdXH0RYF_GHmYGcD78QAOlAHYwhEBc2HPkVdv0IY,498
28
+ bbstrader/models/__init__.py,sha256=s2mJrtKePXQaw_PvcrtPCD2mPCdVXP4Myzg0MlLVipo,547
29
29
  bbstrader/models/factors.py,sha256=5kSAOS1MHvTZ-Ti03TtjOxl_EvC-V_9e389xeR_82ak,13020
30
- bbstrader/models/ml.py,sha256=3jPDSQm_XZda6yClGqm6SrTczvWWdmHIU-UKsMohu5g,47519
30
+ bbstrader/models/ml.py,sha256=tCr7YyODl0CDoOUpYqJ1q12ls86Sc-_Fu3b2Y0Z7TJ8,47551
31
+ bbstrader/models/nlp.py,sha256=P7SYaTIqEBldjwYfS6IrO66Y6-ioDXUrCSf3bZxQrDE,28073
31
32
  bbstrader/models/optimization.py,sha256=vnks6uxFZdqXgxaZJNxq8z0IH45KZ8yaXo38JhIVKGc,6399
32
33
  bbstrader/models/portfolio.py,sha256=r-47Zrn2r7iKCHm5YVtwkbBJXAZGM3QYy-rXCWY9-Bg,8079
33
- bbstrader/models/risk.py,sha256=Efr7dKcr37n75TXv5rcgSYNDPu2Plzcn65AOOIh9x_8,15007
34
+ bbstrader/models/risk.py,sha256=JQOXPshMOru6Eb0AMU6oKCNzg6mlGfL6_tN90lWcVBE,14878
34
35
  bbstrader/trading/__init__.py,sha256=ycLyuuxN5SujqtzR9X0Q74UQfK93q2va-GGAXdr-KS8,457
35
- bbstrader/trading/execution.py,sha256=UOdXdQ1IYgCTG1GHwjhyLRIJnBDHuhVMyK_qjzdPlYY,34649
36
- bbstrader/trading/script.py,sha256=wR5TUrHn-Cd2kzfURXn14VTCEZ-QA8ydwYHayMPK0oI,5720
37
- bbstrader/trading/scripts.py,sha256=57dKF9dcRu04oU2VRqydRrzW39dCW2wlDWhVt-sZdRw,1857
38
- bbstrader/trading/strategies.py,sha256=yibrXPa8yw8KCNkJEmNaygjfleCNgA_T58vizGS584I,36159
39
- bbstrader-0.2.95.dist-info/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
40
- bbstrader-0.2.95.dist-info/METADATA,sha256=NhjLD936Qj-MskepQdXccTqs1M8v1z_K2aT5ylo1MF8,11381
41
- bbstrader-0.2.95.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
42
- bbstrader-0.2.95.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
43
- bbstrader-0.2.95.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
44
- bbstrader-0.2.95.dist-info/RECORD,,
36
+ bbstrader/trading/execution.py,sha256=4-XyRll1x8gfF68cTZXjtRF79csDx_oKNI0F71cv1Bw,35028
37
+ bbstrader/trading/scripts.py,sha256=wR5TUrHn-Cd2kzfURXn14VTCEZ-QA8ydwYHayMPK0oI,5720
38
+ bbstrader/trading/strategies.py,sha256=D_M91UwRiFwZKvKFKmz427TPd-dNyWWbhehaP8RI17c,36539
39
+ bbstrader/trading/utils.py,sha256=57dKF9dcRu04oU2VRqydRrzW39dCW2wlDWhVt-sZdRw,1857
40
+ bbstrader-0.2.97.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
41
+ bbstrader-0.2.97.dist-info/METADATA,sha256=mBnvqbUXVjE-dl5A5tkdYRuGd_fh2oKU55K-Ryfm9po,11590
42
+ bbstrader-0.2.97.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
43
+ bbstrader-0.2.97.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
44
+ bbstrader-0.2.97.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
45
+ bbstrader-0.2.97.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (76.0.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,155 +0,0 @@
1
- import argparse
2
- import json
3
- import multiprocessing as mp
4
- import os
5
- import sys
6
-
7
- from bbstrader.btengine import MT5Strategy, Strategy
8
- from bbstrader.core.utils import load_class, load_module
9
- from bbstrader.metatrader.trade import create_trade_instance
10
- from bbstrader.trading.execution import mt5_engine
11
-
12
- EXECUTION_PATH = os.path.expanduser("~/.bbstrader/execution/execution.py")
13
- CONFIG_PATH = os.path.expanduser("~/.bbstrader/execution/execution.json")
14
-
15
-
16
- def load_config(config_path, strategy_name, account=None):
17
- if not os.path.exists(config_path):
18
- raise FileNotFoundError(f"Configuration file not found at {config_path}")
19
- with open(config_path, "r") as f:
20
- config = json.load(f)
21
- try:
22
- config = config[strategy_name]
23
- except KeyError:
24
- raise ValueError(
25
- f"Strategy {strategy_name} not found in the configuration file."
26
- )
27
- if account is not None:
28
- try:
29
- config = config[account]
30
- except KeyError:
31
- raise ValueError(f"Account {account} not found in the configuration file.")
32
- if config.get("symbol_list") is None:
33
- raise ValueError("symbol_list is required in the configuration file.")
34
- if config.get("trades_kwargs") is None:
35
- raise ValueError("trades_kwargs is required in the configuration file.")
36
- return config
37
-
38
-
39
- def worker_function(account, args):
40
- strategy_module = load_module(args.path)
41
- strategy_class = load_class(strategy_module, args.strategy, (MT5Strategy, Strategy))
42
-
43
- config = load_config(args.config, args.strategy, account)
44
- symbol_list = config.pop("symbol_list")
45
- trades_kwargs = config.pop("trades_kwargs")
46
- trades = create_trade_instance(symbol_list, trades_kwargs)
47
-
48
- kwargs = {
49
- "symbol_list": symbol_list,
50
- "trades_instances": trades,
51
- "strategy_cls": strategy_class,
52
- "account": account,
53
- **config,
54
- }
55
- mt5_engine(account, **kwargs)
56
-
57
-
58
- def mt5_terminal(args):
59
- if args.parallel:
60
- if len(args.account) == 0:
61
- raise ValueError(
62
- "account or accounts are required when running in parallel"
63
- )
64
-
65
- processes = []
66
- try:
67
- for account in args.account:
68
- p = mp.Process(target=worker_function, args=(account, args))
69
- p.start()
70
- processes.append(p)
71
-
72
- for p in processes:
73
- p.join()
74
- except Exception as e:
75
- print(f"Error in parallel execution: {e}")
76
- raise e
77
- except KeyboardInterrupt:
78
- print("\nTerminating Execution...")
79
- for p in processes:
80
- p.terminate()
81
- for p in processes:
82
- p.join()
83
- print("Execution terminated")
84
- else:
85
- worker_function(None, args)
86
-
87
-
88
- def tws_terminal(args):
89
- raise NotImplementedError("TWS terminal is not implemented yet")
90
-
91
-
92
- def execute_strategy(unknown):
93
- HELP_MSG = """
94
- Execute a strategy on one or multiple MT5 accounts.
95
-
96
- Usage:
97
- python -m bbstrader --run execution [options]
98
-
99
- Options:
100
- -s, --strategy: Strategy class name to run
101
- -a, --account: Account(s) name(s) or ID(s) to run the strategy on (must be the same as in the configuration file)
102
- -p, --path: Path to the execution file (default: ~/.bbstrader/execution/execution.py)
103
- -c, --config: Path to the configuration file (default: ~/.bbstrader/execution/execution.json)
104
- -l, --parallel: Run the strategy in parallel (default: False)
105
- -t, --terminal: Terminal to use (default: MT5)
106
- -h, --help: Show this help message and exit
107
-
108
- Note:
109
- The configuration file must contain all the required parameters
110
- to create trade instances for each account and strategy.
111
- The configuration file must be a dictionary with the following structure:
112
- If parallel is True:
113
- {
114
- "strategy_name": {
115
- "account_name": {
116
- "symbol_list": ["symbol1", "symbol2"],
117
- "trades_kwargs": {"param1": "value1", "param2": "value2"}
118
- **other_parameters (for the strategy and the execution engine)
119
- }
120
- }
121
- }
122
- If parallel is False:
123
- {
124
- "strategy_name": {
125
- "symbol_list": ["symbol1", "symbol2"],
126
- "trades_kwargs": {"param1": "value1", "param2": "value2"}
127
- **other_parameters (for the strategy and the execution engine)
128
- }
129
- }
130
- See bbstrader.metatrader.trade.create_trade_instance for more details on the trades_kwargs.
131
- See bbstrader.trading.execution.MT5ExecutionEngine for more details on the other parameters.
132
-
133
- All other paramaters must be python built-in types.
134
- If you have custom type you must set them in your strategy class
135
- or run the MT5ExecutionEngine directly, don't run on CLI.
136
- """
137
- if "-h" in unknown or "--help" in unknown:
138
- print(HELP_MSG)
139
- sys.exit(0)
140
-
141
- parser = argparse.ArgumentParser()
142
- parser.add_argument("-s", "--strategy", type=str, required=True)
143
- parser.add_argument("-a", "--account", type=str, nargs="*", default=[])
144
- parser.add_argument("-p", "--path", type=str, default=EXECUTION_PATH)
145
- parser.add_argument("-c", "--config", type=str, default=CONFIG_PATH)
146
- parser.add_argument("-l", "--parallel", action="store_true")
147
- parser.add_argument(
148
- "-t", "--terminal", type=str, default="MT5", choices=["MT5", "TWS"]
149
- )
150
- args = parser.parse_args(unknown)
151
-
152
- if args.terminal == "MT5":
153
- mt5_terminal(args)
154
- elif args.terminal == "TWS":
155
- tws_terminal(args)