bbstrader 0.2.93__py3-none-any.whl → 0.2.94__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.

Files changed (35) hide show
  1. bbstrader/__ini__.py +20 -20
  2. bbstrader/__main__.py +50 -50
  3. bbstrader/btengine/__init__.py +54 -54
  4. bbstrader/btengine/scripts.py +157 -157
  5. bbstrader/compat.py +19 -19
  6. bbstrader/config.py +137 -137
  7. bbstrader/core/data.py +22 -22
  8. bbstrader/core/utils.py +146 -146
  9. bbstrader/metatrader/__init__.py +6 -6
  10. bbstrader/metatrader/account.py +1516 -1516
  11. bbstrader/metatrader/copier.py +750 -745
  12. bbstrader/metatrader/rates.py +584 -584
  13. bbstrader/metatrader/risk.py +749 -748
  14. bbstrader/metatrader/scripts.py +81 -81
  15. bbstrader/metatrader/trade.py +1836 -1836
  16. bbstrader/metatrader/utils.py +645 -645
  17. bbstrader/models/__init__.py +10 -10
  18. bbstrader/models/factors.py +312 -312
  19. bbstrader/models/ml.py +1272 -1272
  20. bbstrader/models/optimization.py +182 -182
  21. bbstrader/models/portfolio.py +223 -223
  22. bbstrader/models/risk.py +398 -398
  23. bbstrader/trading/__init__.py +11 -11
  24. bbstrader/trading/execution.py +846 -846
  25. bbstrader/trading/script.py +155 -155
  26. bbstrader/trading/scripts.py +69 -69
  27. bbstrader/trading/strategies.py +860 -860
  28. bbstrader/tseries.py +1842 -1842
  29. {bbstrader-0.2.93.dist-info → bbstrader-0.2.94.dist-info}/LICENSE +21 -21
  30. {bbstrader-0.2.93.dist-info → bbstrader-0.2.94.dist-info}/METADATA +188 -187
  31. bbstrader-0.2.94.dist-info/RECORD +44 -0
  32. bbstrader-0.2.93.dist-info/RECORD +0 -44
  33. {bbstrader-0.2.93.dist-info → bbstrader-0.2.94.dist-info}/WHEEL +0 -0
  34. {bbstrader-0.2.93.dist-info → bbstrader-0.2.94.dist-info}/entry_points.txt +0 -0
  35. {bbstrader-0.2.93.dist-info → bbstrader-0.2.94.dist-info}/top_level.txt +0 -0
@@ -1,155 +1,155 @@
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)
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)
@@ -1,69 +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
+ 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
+