bbstrader 0.2.92__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.
- bbstrader/__ini__.py +20 -20
- bbstrader/__main__.py +50 -50
- bbstrader/btengine/__init__.py +54 -54
- bbstrader/btengine/data.py +11 -9
- bbstrader/btengine/scripts.py +157 -157
- bbstrader/compat.py +19 -19
- bbstrader/config.py +137 -137
- bbstrader/core/data.py +22 -22
- bbstrader/core/utils.py +146 -146
- bbstrader/metatrader/__init__.py +6 -6
- bbstrader/metatrader/account.py +1516 -1516
- bbstrader/metatrader/copier.py +750 -735
- bbstrader/metatrader/rates.py +584 -584
- bbstrader/metatrader/risk.py +749 -748
- bbstrader/metatrader/scripts.py +81 -81
- bbstrader/metatrader/trade.py +1836 -1826
- bbstrader/metatrader/utils.py +645 -645
- bbstrader/models/__init__.py +10 -10
- bbstrader/models/factors.py +312 -312
- bbstrader/models/ml.py +1272 -1265
- bbstrader/models/optimization.py +182 -182
- bbstrader/models/portfolio.py +223 -223
- bbstrader/models/risk.py +398 -398
- bbstrader/trading/__init__.py +11 -11
- bbstrader/trading/execution.py +846 -842
- bbstrader/trading/script.py +155 -155
- bbstrader/trading/scripts.py +69 -69
- bbstrader/trading/strategies.py +860 -860
- bbstrader/tseries.py +1842 -1842
- {bbstrader-0.2.92.dist-info → bbstrader-0.2.94.dist-info}/LICENSE +21 -21
- {bbstrader-0.2.92.dist-info → bbstrader-0.2.94.dist-info}/METADATA +188 -187
- bbstrader-0.2.94.dist-info/RECORD +44 -0
- {bbstrader-0.2.92.dist-info → bbstrader-0.2.94.dist-info}/WHEEL +1 -1
- bbstrader-0.2.92.dist-info/RECORD +0 -44
- {bbstrader-0.2.92.dist-info → bbstrader-0.2.94.dist-info}/entry_points.txt +0 -0
- {bbstrader-0.2.92.dist-info → bbstrader-0.2.94.dist-info}/top_level.txt +0 -0
bbstrader/__ini__.py
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Simplified Investment & Trading Toolkit
|
|
3
|
-
=======================================
|
|
4
|
-
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
__author__ = "Bertin Balouki SIMYELI"
|
|
8
|
-
__copyright__ = "2023-2025 Bertin Balouki SIMYELI"
|
|
9
|
-
__email__ = "bertin@bbstrader.com"
|
|
10
|
-
__license__ = "MIT"
|
|
11
|
-
__version__ = "0.2.0"
|
|
12
|
-
|
|
13
|
-
from bbstrader import compat # noqa: F401
|
|
14
|
-
from bbstrader import core # noqa: F401
|
|
15
|
-
from bbstrader import btengine # noqa: F401
|
|
16
|
-
from bbstrader import metatrader # noqa: F401
|
|
17
|
-
from bbstrader import models # noqa: F401
|
|
18
|
-
from bbstrader import trading # noqa: F401
|
|
19
|
-
from bbstrader import tseries # noqa: F401
|
|
20
|
-
from bbstrader.config import config_logger # noqa: F401
|
|
1
|
+
"""
|
|
2
|
+
Simplified Investment & Trading Toolkit
|
|
3
|
+
=======================================
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__author__ = "Bertin Balouki SIMYELI"
|
|
8
|
+
__copyright__ = "2023-2025 Bertin Balouki SIMYELI"
|
|
9
|
+
__email__ = "bertin@bbstrader.com"
|
|
10
|
+
__license__ = "MIT"
|
|
11
|
+
__version__ = "0.2.0"
|
|
12
|
+
|
|
13
|
+
from bbstrader import compat # noqa: F401
|
|
14
|
+
from bbstrader import core # noqa: F401
|
|
15
|
+
from bbstrader import btengine # noqa: F401
|
|
16
|
+
from bbstrader import metatrader # noqa: F401
|
|
17
|
+
from bbstrader import models # noqa: F401
|
|
18
|
+
from bbstrader import trading # noqa: F401
|
|
19
|
+
from bbstrader import tseries # noqa: F401
|
|
20
|
+
from bbstrader.config import config_logger # noqa: F401
|
bbstrader/__main__.py
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import sys
|
|
3
|
-
|
|
4
|
-
import pyfiglet
|
|
5
|
-
from colorama import Fore
|
|
6
|
-
|
|
7
|
-
from bbstrader.btengine.scripts import backtest
|
|
8
|
-
from bbstrader.metatrader.scripts import copy_trades
|
|
9
|
-
from bbstrader.trading.script import execute_strategy
|
|
10
|
-
|
|
11
|
-
DESCRIPTION = "BBSTRADER"
|
|
12
|
-
USAGE_TEXT = """
|
|
13
|
-
Usage:
|
|
14
|
-
python -m bbstrader --run <module> [options]
|
|
15
|
-
|
|
16
|
-
Modules:
|
|
17
|
-
copier: Copy trades from one MetaTrader account to another or multiple accounts
|
|
18
|
-
backtest: Backtest a strategy, see bbstrader.btengine.backtest.run_backtest
|
|
19
|
-
execution: Execute a strategy, see bbstrader.trading.execution.MT5ExecutionEngine
|
|
20
|
-
|
|
21
|
-
run <module> --help for more information on the module
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
FONT = pyfiglet.figlet_format("BBSTRADER", font="big")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def main():
|
|
28
|
-
print(Fore.BLUE + FONT)
|
|
29
|
-
parser = argparse.ArgumentParser(
|
|
30
|
-
prog="BBSTRADER",
|
|
31
|
-
usage=USAGE_TEXT,
|
|
32
|
-
description=DESCRIPTION,
|
|
33
|
-
formatter_class=argparse.RawTextHelpFormatter,
|
|
34
|
-
add_help=False,
|
|
35
|
-
)
|
|
36
|
-
parser.add_argument("--run", type=str, nargs="?", default=None, help="Run a module")
|
|
37
|
-
args, unknown = parser.parse_known_args()
|
|
38
|
-
if ("-h" in sys.argv or "--help" in sys.argv) and args.run is None:
|
|
39
|
-
print(USAGE_TEXT)
|
|
40
|
-
sys.exit(0)
|
|
41
|
-
if args.run == "copier":
|
|
42
|
-
copy_trades(unknown)
|
|
43
|
-
elif args.run == "backtest":
|
|
44
|
-
backtest(unknown)
|
|
45
|
-
elif args.run == "execution":
|
|
46
|
-
execute_strategy(unknown)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if __name__ == "__main__":
|
|
50
|
-
main()
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import pyfiglet
|
|
5
|
+
from colorama import Fore
|
|
6
|
+
|
|
7
|
+
from bbstrader.btengine.scripts import backtest
|
|
8
|
+
from bbstrader.metatrader.scripts import copy_trades
|
|
9
|
+
from bbstrader.trading.script import execute_strategy
|
|
10
|
+
|
|
11
|
+
DESCRIPTION = "BBSTRADER"
|
|
12
|
+
USAGE_TEXT = """
|
|
13
|
+
Usage:
|
|
14
|
+
python -m bbstrader --run <module> [options]
|
|
15
|
+
|
|
16
|
+
Modules:
|
|
17
|
+
copier: Copy trades from one MetaTrader account to another or multiple accounts
|
|
18
|
+
backtest: Backtest a strategy, see bbstrader.btengine.backtest.run_backtest
|
|
19
|
+
execution: Execute a strategy, see bbstrader.trading.execution.MT5ExecutionEngine
|
|
20
|
+
|
|
21
|
+
python -m bbstrader --run <module> --help for more information on the module
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
FONT = pyfiglet.figlet_format("BBSTRADER", font="big")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main():
|
|
28
|
+
print(Fore.BLUE + FONT)
|
|
29
|
+
parser = argparse.ArgumentParser(
|
|
30
|
+
prog="BBSTRADER",
|
|
31
|
+
usage=USAGE_TEXT,
|
|
32
|
+
description=DESCRIPTION,
|
|
33
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
34
|
+
add_help=False,
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument("--run", type=str, nargs="?", default=None, help="Run a module")
|
|
37
|
+
args, unknown = parser.parse_known_args()
|
|
38
|
+
if ("-h" in sys.argv or "--help" in sys.argv) and args.run is None:
|
|
39
|
+
print(USAGE_TEXT)
|
|
40
|
+
sys.exit(0)
|
|
41
|
+
if args.run == "copier":
|
|
42
|
+
copy_trades(unknown)
|
|
43
|
+
elif args.run == "backtest":
|
|
44
|
+
backtest(unknown)
|
|
45
|
+
elif args.run == "execution":
|
|
46
|
+
execute_strategy(unknown)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
main()
|
bbstrader/btengine/__init__.py
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Overview
|
|
3
|
-
========
|
|
4
|
-
|
|
5
|
-
This Backtesting Module provides a comprehensive suite of tools to test trading strategies in an event-driven system.
|
|
6
|
-
It simulates the execution of trades in historical market conditions to evaluate the performance of trading strategies
|
|
7
|
-
before applying them in live trading environments. Designed with modularity and extensibility in mind, it caters to
|
|
8
|
-
both novices and experts in algorithmic trading.
|
|
9
|
-
|
|
10
|
-
Features
|
|
11
|
-
========
|
|
12
|
-
|
|
13
|
-
- **Event-Driven Architecture**: Processes market data, generates signals, executes orders, and manages portfolio updates in response to events, closely mimicking live trading environments.
|
|
14
|
-
- **Historical Market Data Support**: Utilizes historical OHLCV data from CSV files, Yahoo finance and MT5 terminal allowing for the testing of strategies over various market conditions and time frames.
|
|
15
|
-
- **Performance Metrics Calculation**: Includes tools for calculating key performance indicators, such as `Sharpe Ratio`, `Sortino Ratio`, and `drawdowns`, to evaluate the effectiveness of trading strategies.
|
|
16
|
-
- **Visualization**: Generates plots of the `equity curve`, `returns`, `drawdowns`, and other metrics for comprehensive strategy `performance analysis`.
|
|
17
|
-
|
|
18
|
-
Components
|
|
19
|
-
==========
|
|
20
|
-
|
|
21
|
-
- **BacktestEgine**: Orchestrates the backtesting process, managing events and invoking components.
|
|
22
|
-
- **Event**: Abstract class for events, with implementations for market data, signals, fill and order events.
|
|
23
|
-
- **DataHandler**: Abstract class for market data handling, with an implementation for `CSVDataHandler`, `MT5DataHandler`, `YFDataHandler`. We will add another data handling in the future such as MacroEconomic Data, Fundamental Data, TICK Data and Real-time Data.
|
|
24
|
-
- **Portfolio**: Manages positions and calculates performance metrics, responding to market data and signals.
|
|
25
|
-
- **ExecutionHandler**: Abstract class for order execution, with a simulated execution handler provided with an implementation for `SimExecutionHandler`.
|
|
26
|
-
- **Performance**: Utility functions for calculating performance metrics and visualizing strategy performance.
|
|
27
|
-
|
|
28
|
-
Examples
|
|
29
|
-
========
|
|
30
|
-
|
|
31
|
-
>>> from bbstrader.btengine import run_backtest
|
|
32
|
-
>>> from datetime import datetime
|
|
33
|
-
>>> run_backtest(
|
|
34
|
-
... symbol_list=['AAPL', 'GOOG'],
|
|
35
|
-
... start_date=datetime(2020, 1, 1),
|
|
36
|
-
... data_handler=DataHandler,
|
|
37
|
-
... strategy=Strategy,
|
|
38
|
-
... exc_handler=ExecutionHandler,
|
|
39
|
-
... initial_capital=500000.0,
|
|
40
|
-
... heartbeat=1.0
|
|
41
|
-
... )
|
|
42
|
-
|
|
43
|
-
Notes
|
|
44
|
-
=====
|
|
45
|
-
|
|
46
|
-
See `bbstrader.btengine.backtest.run_backtest` for more details on the backtesting process and its parameters.
|
|
47
|
-
"""
|
|
48
|
-
from bbstrader.btengine.backtest import * # noqa: F403
|
|
49
|
-
from bbstrader.btengine.data import * # noqa: F403
|
|
50
|
-
from bbstrader.btengine.event import * # noqa: F403
|
|
51
|
-
from bbstrader.btengine.execution import * # noqa: F403
|
|
52
|
-
from bbstrader.btengine.performance import * # noqa: F403
|
|
53
|
-
from bbstrader.btengine.portfolio import * # noqa: F403
|
|
54
|
-
from bbstrader.btengine.strategy import * # noqa: F403
|
|
1
|
+
"""
|
|
2
|
+
Overview
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
This Backtesting Module provides a comprehensive suite of tools to test trading strategies in an event-driven system.
|
|
6
|
+
It simulates the execution of trades in historical market conditions to evaluate the performance of trading strategies
|
|
7
|
+
before applying them in live trading environments. Designed with modularity and extensibility in mind, it caters to
|
|
8
|
+
both novices and experts in algorithmic trading.
|
|
9
|
+
|
|
10
|
+
Features
|
|
11
|
+
========
|
|
12
|
+
|
|
13
|
+
- **Event-Driven Architecture**: Processes market data, generates signals, executes orders, and manages portfolio updates in response to events, closely mimicking live trading environments.
|
|
14
|
+
- **Historical Market Data Support**: Utilizes historical OHLCV data from CSV files, Yahoo finance and MT5 terminal allowing for the testing of strategies over various market conditions and time frames.
|
|
15
|
+
- **Performance Metrics Calculation**: Includes tools for calculating key performance indicators, such as `Sharpe Ratio`, `Sortino Ratio`, and `drawdowns`, to evaluate the effectiveness of trading strategies.
|
|
16
|
+
- **Visualization**: Generates plots of the `equity curve`, `returns`, `drawdowns`, and other metrics for comprehensive strategy `performance analysis`.
|
|
17
|
+
|
|
18
|
+
Components
|
|
19
|
+
==========
|
|
20
|
+
|
|
21
|
+
- **BacktestEgine**: Orchestrates the backtesting process, managing events and invoking components.
|
|
22
|
+
- **Event**: Abstract class for events, with implementations for market data, signals, fill and order events.
|
|
23
|
+
- **DataHandler**: Abstract class for market data handling, with an implementation for `CSVDataHandler`, `MT5DataHandler`, `YFDataHandler`. We will add another data handling in the future such as MacroEconomic Data, Fundamental Data, TICK Data and Real-time Data.
|
|
24
|
+
- **Portfolio**: Manages positions and calculates performance metrics, responding to market data and signals.
|
|
25
|
+
- **ExecutionHandler**: Abstract class for order execution, with a simulated execution handler provided with an implementation for `SimExecutionHandler`.
|
|
26
|
+
- **Performance**: Utility functions for calculating performance metrics and visualizing strategy performance.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
========
|
|
30
|
+
|
|
31
|
+
>>> from bbstrader.btengine import run_backtest
|
|
32
|
+
>>> from datetime import datetime
|
|
33
|
+
>>> run_backtest(
|
|
34
|
+
... symbol_list=['AAPL', 'GOOG'],
|
|
35
|
+
... start_date=datetime(2020, 1, 1),
|
|
36
|
+
... data_handler=DataHandler,
|
|
37
|
+
... strategy=Strategy,
|
|
38
|
+
... exc_handler=ExecutionHandler,
|
|
39
|
+
... initial_capital=500000.0,
|
|
40
|
+
... heartbeat=1.0
|
|
41
|
+
... )
|
|
42
|
+
|
|
43
|
+
Notes
|
|
44
|
+
=====
|
|
45
|
+
|
|
46
|
+
See `bbstrader.btengine.backtest.run_backtest` for more details on the backtesting process and its parameters.
|
|
47
|
+
"""
|
|
48
|
+
from bbstrader.btengine.backtest import * # noqa: F403
|
|
49
|
+
from bbstrader.btengine.data import * # noqa: F403
|
|
50
|
+
from bbstrader.btengine.event import * # noqa: F403
|
|
51
|
+
from bbstrader.btengine.execution import * # noqa: F403
|
|
52
|
+
from bbstrader.btengine.performance import * # noqa: F403
|
|
53
|
+
from bbstrader.btengine.portfolio import * # noqa: F403
|
|
54
|
+
from bbstrader.btengine.strategy import * # noqa: F403
|
bbstrader/btengine/data.py
CHANGED
|
@@ -175,9 +175,9 @@ class BaseCSVDataHandler(DataHandler):
|
|
|
175
175
|
new_names = self.columns or default_names
|
|
176
176
|
new_names = [name.strip().lower().replace(" ", "_") for name in new_names]
|
|
177
177
|
self.columns = new_names
|
|
178
|
-
assert (
|
|
179
|
-
"
|
|
180
|
-
)
|
|
178
|
+
assert "adj_close" in new_names or "close" in new_names, (
|
|
179
|
+
"Column names must contain 'Adj Close' and 'Close' or adj_close and close"
|
|
180
|
+
)
|
|
181
181
|
comb_index = None
|
|
182
182
|
for s in self.symbol_list:
|
|
183
183
|
# Load the CSV file with no header information,
|
|
@@ -207,7 +207,9 @@ class BaseCSVDataHandler(DataHandler):
|
|
|
207
207
|
self.columns.append("adj_close")
|
|
208
208
|
self.symbol_data[s]["adj_close"] = self.symbol_data[s]["close"]
|
|
209
209
|
self.symbol_data[s]["returns"] = (
|
|
210
|
-
self.symbol_data[s][
|
|
210
|
+
self.symbol_data[s][
|
|
211
|
+
"adj_close" if "adj_close" in new_names else "close"
|
|
212
|
+
]
|
|
211
213
|
.pct_change()
|
|
212
214
|
.dropna()
|
|
213
215
|
)
|
|
@@ -362,7 +364,7 @@ class CSVDataHandler(BaseCSVDataHandler):
|
|
|
362
364
|
|
|
363
365
|
"""
|
|
364
366
|
csv_dir = kwargs.get("csv_dir")
|
|
365
|
-
csv_dir = csv_dir or BBSTRADER_DIR / "csv_data"
|
|
367
|
+
csv_dir = csv_dir or BBSTRADER_DIR / "data" / "csv_data"
|
|
366
368
|
super().__init__(
|
|
367
369
|
events,
|
|
368
370
|
symbol_list,
|
|
@@ -422,7 +424,7 @@ class MT5DataHandler(BaseCSVDataHandler):
|
|
|
422
424
|
)
|
|
423
425
|
|
|
424
426
|
def _download_and_cache_data(self, cache_dir: str):
|
|
425
|
-
data_dir = cache_dir or BBSTRADER_DIR / "mt5" / self.tf
|
|
427
|
+
data_dir = cache_dir or BBSTRADER_DIR / "data" / "mt5" / self.tf
|
|
426
428
|
data_dir.mkdir(parents=True, exist_ok=True)
|
|
427
429
|
for symbol in self.symbol_list:
|
|
428
430
|
try:
|
|
@@ -486,7 +488,7 @@ class YFDataHandler(BaseCSVDataHandler):
|
|
|
486
488
|
|
|
487
489
|
def _download_and_cache_data(self, cache_dir: str):
|
|
488
490
|
"""Downloads and caches historical data as CSV files."""
|
|
489
|
-
cache_dir = cache_dir or BBSTRADER_DIR / "yfinance" / "daily"
|
|
491
|
+
cache_dir = cache_dir or BBSTRADER_DIR / "data" / "yfinance" / "daily"
|
|
490
492
|
os.makedirs(cache_dir, exist_ok=True)
|
|
491
493
|
for symbol in self.symbol_list:
|
|
492
494
|
filepath = os.path.join(cache_dir, f"{symbol}.csv")
|
|
@@ -598,7 +600,7 @@ class EODHDataHandler(BaseCSVDataHandler):
|
|
|
598
600
|
|
|
599
601
|
def _download_and_cache_data(self, cache_dir: str):
|
|
600
602
|
"""Downloads and caches historical data as CSV files."""
|
|
601
|
-
cache_dir = cache_dir or BBSTRADER_DIR / "eodhd" / self.period
|
|
603
|
+
cache_dir = cache_dir or BBSTRADER_DIR / "data" / "eodhd" / self.period
|
|
602
604
|
os.makedirs(cache_dir, exist_ok=True)
|
|
603
605
|
for symbol in self.symbol_list:
|
|
604
606
|
filepath = os.path.join(cache_dir, f"{symbol}.csv")
|
|
@@ -699,7 +701,7 @@ class FMPDataHandler(BaseCSVDataHandler):
|
|
|
699
701
|
|
|
700
702
|
def _download_and_cache_data(self, cache_dir: str):
|
|
701
703
|
"""Downloads and caches historical data as CSV files."""
|
|
702
|
-
cache_dir = cache_dir or BBSTRADER_DIR / "fmp" / self.period
|
|
704
|
+
cache_dir = cache_dir or BBSTRADER_DIR / "data" / "fmp" / self.period
|
|
703
705
|
os.makedirs(cache_dir, exist_ok=True)
|
|
704
706
|
for symbol in self.symbol_list:
|
|
705
707
|
filepath = os.path.join(cache_dir, f"{symbol}.csv")
|
bbstrader/btengine/scripts.py
CHANGED
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
import argparse
|
|
2
|
-
import json
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
|
|
7
|
-
from bbstrader.btengine.backtest import run_backtest
|
|
8
|
-
from bbstrader.btengine.data import (
|
|
9
|
-
CSVDataHandler,
|
|
10
|
-
DataHandler,
|
|
11
|
-
EODHDataHandler,
|
|
12
|
-
FMPDataHandler,
|
|
13
|
-
MT5DataHandler,
|
|
14
|
-
YFDataHandler,
|
|
15
|
-
)
|
|
16
|
-
from bbstrader.btengine.execution import (
|
|
17
|
-
ExecutionHandler,
|
|
18
|
-
MT5ExecutionHandler,
|
|
19
|
-
SimExecutionHandler,
|
|
20
|
-
)
|
|
21
|
-
from bbstrader.core.utils import load_class, load_module
|
|
22
|
-
|
|
23
|
-
BACKTEST_PATH = os.path.expanduser("~/.bbstrader/backtest/backtest.py")
|
|
24
|
-
CONFIG_PATH = os.path.expanduser("~/.bbstrader/backtest/backtest.json")
|
|
25
|
-
|
|
26
|
-
DATA_HANDLER_MAP = {
|
|
27
|
-
"csv": CSVDataHandler,
|
|
28
|
-
"mt5": MT5DataHandler,
|
|
29
|
-
"yf": YFDataHandler,
|
|
30
|
-
"eodh": EODHDataHandler,
|
|
31
|
-
"fmp": FMPDataHandler,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
EXECUTION_HANDLER_MAP = {
|
|
35
|
-
"sim": SimExecutionHandler,
|
|
36
|
-
"mt5": MT5ExecutionHandler,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def load_exc_handler(module, handler_name):
|
|
41
|
-
return load_class(module, handler_name, ExecutionHandler)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def load_data_handler(module, handler_name):
|
|
45
|
-
return load_class(module, handler_name, DataHandler)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def load_strategy(module, strategy_name):
|
|
49
|
-
from bbstrader.btengine.strategy import MT5Strategy, Strategy
|
|
50
|
-
|
|
51
|
-
return load_class(module, strategy_name, (Strategy, MT5Strategy))
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def load_config(config_path, strategy_name):
|
|
55
|
-
if not os.path.exists(config_path):
|
|
56
|
-
raise FileNotFoundError(
|
|
57
|
-
f"Configuration file {config_path} not found. Please create it."
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
with open(config_path, "r") as f:
|
|
61
|
-
config = json.load(f)
|
|
62
|
-
try:
|
|
63
|
-
config = config[strategy_name]
|
|
64
|
-
except KeyError:
|
|
65
|
-
raise ValueError(
|
|
66
|
-
f"Strategy {strategy_name} not found in the configuration file."
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
required_fields = ["symbol_list", "start_date", "data_handler", "execution_handler"]
|
|
70
|
-
for field in required_fields:
|
|
71
|
-
if not config.get(field):
|
|
72
|
-
raise ValueError(f"{field} is required in the configuration file.")
|
|
73
|
-
|
|
74
|
-
config["start_date"] = datetime.strptime(config["start_date"], "%Y-%m-%d")
|
|
75
|
-
|
|
76
|
-
if config.get("execution_handler") not in EXECUTION_HANDLER_MAP:
|
|
77
|
-
try:
|
|
78
|
-
backtest_module = load_module(BACKTEST_PATH)
|
|
79
|
-
exc_handler_class = load_exc_handler(
|
|
80
|
-
backtest_module, config["execution_handler"]
|
|
81
|
-
)
|
|
82
|
-
except Exception as e:
|
|
83
|
-
raise ValueError(f"Invalid execution handler: {e}")
|
|
84
|
-
else:
|
|
85
|
-
exc_handler_class = EXECUTION_HANDLER_MAP[config["execution_handler"]]
|
|
86
|
-
|
|
87
|
-
if config.get("data_handler") not in DATA_HANDLER_MAP:
|
|
88
|
-
try:
|
|
89
|
-
backtest_module = load_module(BACKTEST_PATH)
|
|
90
|
-
data_handler_class = load_data_handler(
|
|
91
|
-
backtest_module, config["data_handler"]
|
|
92
|
-
)
|
|
93
|
-
except Exception as e:
|
|
94
|
-
raise ValueError(f"Invalid data handler: {e}")
|
|
95
|
-
else:
|
|
96
|
-
data_handler_class = DATA_HANDLER_MAP[config["data_handler"]]
|
|
97
|
-
|
|
98
|
-
config["execution_handler"] = exc_handler_class
|
|
99
|
-
config["data_handler"] = data_handler_class
|
|
100
|
-
|
|
101
|
-
return config
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def backtest(unknown):
|
|
105
|
-
HELP_MSG = """
|
|
106
|
-
Usage:
|
|
107
|
-
python -m bbstrader --run backtest [options]
|
|
108
|
-
|
|
109
|
-
Options:
|
|
110
|
-
-s, --strategy: Strategy class name to run
|
|
111
|
-
-c, --config: Configuration file path (default: ~/.bbstrader/backtest/backtest.json)
|
|
112
|
-
-p, --path: Path to the backtest file (default: ~/.bbstrader/backtest/backtest.py)
|
|
113
|
-
|
|
114
|
-
Note:
|
|
115
|
-
The configuration file must contain all the required parameters
|
|
116
|
-
for the data handler and execution handler and strategy.
|
|
117
|
-
See bbstrader.btengine.BacktestEngine for more details on the parameters.
|
|
118
|
-
"""
|
|
119
|
-
if "-h" in unknown or "--help" in unknown:
|
|
120
|
-
print(HELP_MSG)
|
|
121
|
-
sys.exit(0)
|
|
122
|
-
|
|
123
|
-
parser = argparse.ArgumentParser(description="Backtesting Engine CLI")
|
|
124
|
-
parser.add_argument(
|
|
125
|
-
"-s", "--strategy", type=str, required=True, help="Strategy class name to run"
|
|
126
|
-
)
|
|
127
|
-
parser.add_argument(
|
|
128
|
-
"-c", "--config", type=str, default=CONFIG_PATH, help="Configuration file path"
|
|
129
|
-
)
|
|
130
|
-
parser.add_argument(
|
|
131
|
-
"-p",
|
|
132
|
-
"--path",
|
|
133
|
-
type=str,
|
|
134
|
-
default=BACKTEST_PATH,
|
|
135
|
-
help="Path to the backtest file",
|
|
136
|
-
)
|
|
137
|
-
args = parser.parse_args(unknown)
|
|
138
|
-
config = load_config(args.config, args.strategy)
|
|
139
|
-
strategy_module = load_module(args.path)
|
|
140
|
-
strategy_class = load_strategy(strategy_module, args.strategy)
|
|
141
|
-
|
|
142
|
-
symbol_list = config.pop("symbol_list")
|
|
143
|
-
start_date = config.pop("start_date")
|
|
144
|
-
data_handler = config.pop("data_handler")
|
|
145
|
-
execution_handler = config.pop("execution_handler")
|
|
146
|
-
|
|
147
|
-
try:
|
|
148
|
-
run_backtest(
|
|
149
|
-
symbol_list,
|
|
150
|
-
start_date,
|
|
151
|
-
data_handler,
|
|
152
|
-
strategy_class,
|
|
153
|
-
exc_handler=execution_handler,
|
|
154
|
-
**config,
|
|
155
|
-
)
|
|
156
|
-
except Exception as e:
|
|
157
|
-
print(f"Error: {e}")
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
from bbstrader.btengine.backtest import run_backtest
|
|
8
|
+
from bbstrader.btengine.data import (
|
|
9
|
+
CSVDataHandler,
|
|
10
|
+
DataHandler,
|
|
11
|
+
EODHDataHandler,
|
|
12
|
+
FMPDataHandler,
|
|
13
|
+
MT5DataHandler,
|
|
14
|
+
YFDataHandler,
|
|
15
|
+
)
|
|
16
|
+
from bbstrader.btengine.execution import (
|
|
17
|
+
ExecutionHandler,
|
|
18
|
+
MT5ExecutionHandler,
|
|
19
|
+
SimExecutionHandler,
|
|
20
|
+
)
|
|
21
|
+
from bbstrader.core.utils import load_class, load_module
|
|
22
|
+
|
|
23
|
+
BACKTEST_PATH = os.path.expanduser("~/.bbstrader/backtest/backtest.py")
|
|
24
|
+
CONFIG_PATH = os.path.expanduser("~/.bbstrader/backtest/backtest.json")
|
|
25
|
+
|
|
26
|
+
DATA_HANDLER_MAP = {
|
|
27
|
+
"csv": CSVDataHandler,
|
|
28
|
+
"mt5": MT5DataHandler,
|
|
29
|
+
"yf": YFDataHandler,
|
|
30
|
+
"eodh": EODHDataHandler,
|
|
31
|
+
"fmp": FMPDataHandler,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
EXECUTION_HANDLER_MAP = {
|
|
35
|
+
"sim": SimExecutionHandler,
|
|
36
|
+
"mt5": MT5ExecutionHandler,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def load_exc_handler(module, handler_name):
|
|
41
|
+
return load_class(module, handler_name, ExecutionHandler)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def load_data_handler(module, handler_name):
|
|
45
|
+
return load_class(module, handler_name, DataHandler)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def load_strategy(module, strategy_name):
|
|
49
|
+
from bbstrader.btengine.strategy import MT5Strategy, Strategy
|
|
50
|
+
|
|
51
|
+
return load_class(module, strategy_name, (Strategy, MT5Strategy))
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def load_config(config_path, strategy_name):
|
|
55
|
+
if not os.path.exists(config_path):
|
|
56
|
+
raise FileNotFoundError(
|
|
57
|
+
f"Configuration file {config_path} not found. Please create it."
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
with open(config_path, "r") as f:
|
|
61
|
+
config = json.load(f)
|
|
62
|
+
try:
|
|
63
|
+
config = config[strategy_name]
|
|
64
|
+
except KeyError:
|
|
65
|
+
raise ValueError(
|
|
66
|
+
f"Strategy {strategy_name} not found in the configuration file."
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
required_fields = ["symbol_list", "start_date", "data_handler", "execution_handler"]
|
|
70
|
+
for field in required_fields:
|
|
71
|
+
if not config.get(field):
|
|
72
|
+
raise ValueError(f"{field} is required in the configuration file.")
|
|
73
|
+
|
|
74
|
+
config["start_date"] = datetime.strptime(config["start_date"], "%Y-%m-%d")
|
|
75
|
+
|
|
76
|
+
if config.get("execution_handler") not in EXECUTION_HANDLER_MAP:
|
|
77
|
+
try:
|
|
78
|
+
backtest_module = load_module(BACKTEST_PATH)
|
|
79
|
+
exc_handler_class = load_exc_handler(
|
|
80
|
+
backtest_module, config["execution_handler"]
|
|
81
|
+
)
|
|
82
|
+
except Exception as e:
|
|
83
|
+
raise ValueError(f"Invalid execution handler: {e}")
|
|
84
|
+
else:
|
|
85
|
+
exc_handler_class = EXECUTION_HANDLER_MAP[config["execution_handler"]]
|
|
86
|
+
|
|
87
|
+
if config.get("data_handler") not in DATA_HANDLER_MAP:
|
|
88
|
+
try:
|
|
89
|
+
backtest_module = load_module(BACKTEST_PATH)
|
|
90
|
+
data_handler_class = load_data_handler(
|
|
91
|
+
backtest_module, config["data_handler"]
|
|
92
|
+
)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
raise ValueError(f"Invalid data handler: {e}")
|
|
95
|
+
else:
|
|
96
|
+
data_handler_class = DATA_HANDLER_MAP[config["data_handler"]]
|
|
97
|
+
|
|
98
|
+
config["execution_handler"] = exc_handler_class
|
|
99
|
+
config["data_handler"] = data_handler_class
|
|
100
|
+
|
|
101
|
+
return config
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def backtest(unknown):
|
|
105
|
+
HELP_MSG = """
|
|
106
|
+
Usage:
|
|
107
|
+
python -m bbstrader --run backtest [options]
|
|
108
|
+
|
|
109
|
+
Options:
|
|
110
|
+
-s, --strategy: Strategy class name to run
|
|
111
|
+
-c, --config: Configuration file path (default: ~/.bbstrader/backtest/backtest.json)
|
|
112
|
+
-p, --path: Path to the backtest file (default: ~/.bbstrader/backtest/backtest.py)
|
|
113
|
+
|
|
114
|
+
Note:
|
|
115
|
+
The configuration file must contain all the required parameters
|
|
116
|
+
for the data handler and execution handler and strategy.
|
|
117
|
+
See bbstrader.btengine.BacktestEngine for more details on the parameters.
|
|
118
|
+
"""
|
|
119
|
+
if "-h" in unknown or "--help" in unknown:
|
|
120
|
+
print(HELP_MSG)
|
|
121
|
+
sys.exit(0)
|
|
122
|
+
|
|
123
|
+
parser = argparse.ArgumentParser(description="Backtesting Engine CLI")
|
|
124
|
+
parser.add_argument(
|
|
125
|
+
"-s", "--strategy", type=str, required=True, help="Strategy class name to run"
|
|
126
|
+
)
|
|
127
|
+
parser.add_argument(
|
|
128
|
+
"-c", "--config", type=str, default=CONFIG_PATH, help="Configuration file path"
|
|
129
|
+
)
|
|
130
|
+
parser.add_argument(
|
|
131
|
+
"-p",
|
|
132
|
+
"--path",
|
|
133
|
+
type=str,
|
|
134
|
+
default=BACKTEST_PATH,
|
|
135
|
+
help="Path to the backtest file",
|
|
136
|
+
)
|
|
137
|
+
args = parser.parse_args(unknown)
|
|
138
|
+
config = load_config(args.config, args.strategy)
|
|
139
|
+
strategy_module = load_module(args.path)
|
|
140
|
+
strategy_class = load_strategy(strategy_module, args.strategy)
|
|
141
|
+
|
|
142
|
+
symbol_list = config.pop("symbol_list")
|
|
143
|
+
start_date = config.pop("start_date")
|
|
144
|
+
data_handler = config.pop("data_handler")
|
|
145
|
+
execution_handler = config.pop("execution_handler")
|
|
146
|
+
|
|
147
|
+
try:
|
|
148
|
+
run_backtest(
|
|
149
|
+
symbol_list,
|
|
150
|
+
start_date,
|
|
151
|
+
data_handler,
|
|
152
|
+
strategy_class,
|
|
153
|
+
exc_handler=execution_handler,
|
|
154
|
+
**config,
|
|
155
|
+
)
|
|
156
|
+
except Exception as e:
|
|
157
|
+
print(f"Error: {e}")
|