bbstrader 0.3.5__py3-none-any.whl → 0.3.6__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/__init__.py +10 -1
- bbstrader/__main__.py +5 -0
- bbstrader/apps/_copier.py +3 -3
- bbstrader/btengine/strategy.py +113 -38
- bbstrader/metatrader/account.py +51 -26
- bbstrader/metatrader/analysis.py +30 -16
- bbstrader/metatrader/copier.py +75 -40
- bbstrader/metatrader/trade.py +29 -39
- bbstrader/metatrader/utils.py +5 -4
- bbstrader/models/nlp.py +83 -66
- bbstrader/trading/execution.py +39 -22
- bbstrader/tseries.py +103 -127
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.6.dist-info}/METADATA +7 -21
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.6.dist-info}/RECORD +31 -18
- bbstrader-0.3.6.dist-info/top_level.txt +3 -0
- docs/conf.py +56 -0
- tests/__init__.py +0 -0
- tests/engine/__init__.py +1 -0
- tests/engine/test_backtest.py +58 -0
- tests/engine/test_data.py +536 -0
- tests/engine/test_events.py +300 -0
- tests/engine/test_execution.py +219 -0
- tests/engine/test_portfolio.py +307 -0
- tests/metatrader/__init__.py +0 -0
- tests/metatrader/test_account.py +1769 -0
- tests/metatrader/test_rates.py +292 -0
- tests/metatrader/test_risk_management.py +700 -0
- tests/metatrader/test_trade.py +439 -0
- bbstrader-0.3.5.dist-info/top_level.txt +0 -1
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.6.dist-info}/WHEEL +0 -0
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.6.dist-info}/entry_points.txt +0 -0
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.6.dist-info}/licenses/LICENSE +0 -0
bbstrader/tseries.py
CHANGED
|
@@ -24,7 +24,6 @@ from statsmodels.tsa.vector_ar.var_model import VAR
|
|
|
24
24
|
from statsmodels.tsa.vector_ar.vecm import coint_johansen
|
|
25
25
|
from tqdm import tqdm
|
|
26
26
|
|
|
27
|
-
|
|
28
27
|
__all__ = [
|
|
29
28
|
"run_kalman_filter",
|
|
30
29
|
"KalmanFilterModel",
|
|
@@ -746,32 +745,40 @@ def select_assets(df: pd.DataFrame, n=100, start=None, end=None, rolling_window=
|
|
|
746
745
|
|
|
747
746
|
|
|
748
747
|
def compute_pair_metrics(security: pd.Series, candidates: pd.DataFrame):
|
|
749
|
-
"""
|
|
750
|
-
Calculates statistical and econometric metrics for a target security and a set of candidate securities.
|
|
751
|
-
These metrics are useful in financial modeling and pairs trading strategies,
|
|
752
|
-
providing information about drift, volatility, correlation, and cointegration.
|
|
748
|
+
"""Calculate statistical and econometric metrics for a security pair.
|
|
753
749
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
candidates (pd.DataFrame): A DataFrame where each column represents a time-series of prices
|
|
758
|
-
for candidate securities to be evaluated against the target security.
|
|
750
|
+
These metrics are useful in financial modeling and pairs trading strategies,
|
|
751
|
+
providing information about drift, volatility, correlation, and
|
|
752
|
+
cointegration.
|
|
759
753
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
754
|
+
Parameters
|
|
755
|
+
----------
|
|
756
|
+
security : pd.Series
|
|
757
|
+
A time-series of the target security's prices. The name of the
|
|
758
|
+
Series should correspond to the security's identifier (e.g., ticker
|
|
759
|
+
symbol).
|
|
760
|
+
candidates : pd.DataFrame
|
|
761
|
+
A DataFrame where each column represents a time-series of prices
|
|
762
|
+
for candidate securities to be evaluated against the target security.
|
|
763
|
+
|
|
764
|
+
Returns
|
|
765
|
+
-------
|
|
766
|
+
pd.DataFrame
|
|
767
|
+
A DataFrame containing the following metrics as columns:
|
|
768
|
+
* ``Drift``: Estimated drift of spreads.
|
|
769
|
+
* ``Volatility``: Standard deviation of spreads.
|
|
770
|
+
* ``corr``: Correlation of normalized prices.
|
|
771
|
+
* ``corr_ret``: Correlation of returns (percentage change).
|
|
772
|
+
* ``t1``, ``p1``: Engle-Granger test statistic and p-value.
|
|
773
|
+
* ``t2``, ``p2``: Engle-Granger test statistic and p-value (alternate form).
|
|
774
|
+
* ``trace0``, ``trace1``: Johansen test trace statistics.
|
|
775
|
+
* ``k_ar_diff``: Selected lag order for the Johansen test.
|
|
770
776
|
|
|
771
777
|
References
|
|
772
778
|
----------
|
|
773
|
-
|
|
774
|
-
|
|
779
|
+
* [1] Jansen, S. (2020). Machine Learning for Algorithmic Trading -
|
|
780
|
+
Second Edition. Packt Publishing. Chapter 9, Time-Series Models
|
|
781
|
+
for Volatility Forecasts and Statistical Arbitrage.
|
|
775
782
|
"""
|
|
776
783
|
security = security.div(security.iloc[0])
|
|
777
784
|
ticker = security.name
|
|
@@ -834,102 +841,65 @@ def find_cointegrated_pairs(
|
|
|
834
841
|
such as cointegration and Engle-Granger significance, to determine pairs suitable
|
|
835
842
|
for financial strategies like pairs trading.
|
|
836
843
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
844
|
+
Parameters
|
|
845
|
+
----------
|
|
846
|
+
securities : pd.DataFrame
|
|
847
|
+
A DataFrame where each column represents the time-series
|
|
848
|
+
prices of target securities to evaluate.
|
|
849
|
+
candidates : pd.DataFrame
|
|
850
|
+
A DataFrame where each column represents the time-series
|
|
851
|
+
prices of candidate securities to compare against the target securities.
|
|
852
|
+
n : int, optional
|
|
853
|
+
The number of top pairs to return. If ``None``, returns all pairs.
|
|
854
|
+
start : str, optional
|
|
855
|
+
Start date for slicing the data (e.g., 'YYYY-MM-DD').
|
|
856
|
+
stop : str, optional
|
|
857
|
+
End date for slicing the data (e.g., 'YYYY-MM-DD').
|
|
858
|
+
coint : bool, optional, default=False
|
|
859
|
+
If ``True``, filters for pairs identified as cointegrated.
|
|
860
|
+
If ``False``, returns all evaluated pairs.
|
|
861
|
+
|
|
862
|
+
Returns
|
|
863
|
+
-------
|
|
864
|
+
pd.DataFrame
|
|
865
|
+
A DataFrame containing:
|
|
866
|
+
|
|
867
|
+
**Johansen and Engle-Granger cointegration metrics**
|
|
868
|
+
* ``t1``, ``t2`` : Engle-Granger test statistics for two directions.
|
|
869
|
+
* ``p1``, ``p2`` : Engle-Granger p-values for two directions.
|
|
870
|
+
* ``trace0``, ``trace1`` : Johansen test trace statistics for 0 and 1 cointegration relationships.
|
|
871
|
+
|
|
872
|
+
**Indicators and filters**
|
|
873
|
+
* ``joh_sig`` : Indicates Johansen cointegration significance.
|
|
874
|
+
* ``eg_sig`` : Indicates Engle-Granger significance (p-value < 0.05).
|
|
875
|
+
* ``s1_dep`` : Indicates whether the first series depends on the second (based on p-values).
|
|
876
|
+
* ``coint`` : Combined cointegration indicator (Johansen & Engle-Granger).
|
|
877
|
+
|
|
878
|
+
**Spread and ranking**
|
|
879
|
+
* ``t`` : Minimum of ``t1`` and ``t2``.
|
|
880
|
+
* ``p`` : Minimum of ``p1`` and ``p2``.
|
|
848
881
|
|
|
849
|
-
Returns:
|
|
850
|
-
- ``pd.DataFrame``: A DataFrame containing:
|
|
851
|
-
- Johansen and Engle-Granger cointegration metrics:
|
|
852
|
-
- `t1`, `t2`: Engle-Granger test statistics for two directions.
|
|
853
|
-
- `p1`, `p2`: Engle-Granger p-values for two directions.
|
|
854
|
-
- `trace0`, `trace1`: Johansen test trace statistics for 0 and 1 cointegration relationships.
|
|
855
|
-
- Indicators and filters:
|
|
856
|
-
- `joh_sig`: Indicates Johansen cointegration significance.
|
|
857
|
-
- `eg_sig`: Indicates Engle-Granger significance (p-value < 0.05).
|
|
858
|
-
- `s1_dep`: Indicates whether the first series depends on the second (based on p-values).
|
|
859
|
-
- `coint`: Combined cointegration indicator (Johansen & Engle-Granger).
|
|
860
|
-
- Spread and ranking:
|
|
861
|
-
- `t`: Minimum of `t1` and `t2`.
|
|
862
|
-
- `p`: Minimum of `p1` and `p2`.
|
|
863
882
|
References
|
|
864
883
|
----------
|
|
865
|
-
Stefan Jansen (2020). Machine Learning for Algorithmic Trading - Second Edition
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
Example:
|
|
869
|
-
>>> import pandas as pd
|
|
884
|
+
Stefan Jansen (2020). *Machine Learning for Algorithmic Trading - Second Edition*.
|
|
885
|
+
Chapter 9, Time-Series Models for Volatility Forecasts and Statistical Arbitrage.
|
|
870
886
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
...
|
|
876
|
-
|
|
877
|
-
...
|
|
878
|
-
|
|
879
|
-
...
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
>>>
|
|
883
|
-
|
|
884
|
-
>>>
|
|
885
|
-
>>>
|
|
886
|
-
>>> print(top_pairs)
|
|
887
|
-
|
|
888
|
-
>>> | s1 | s2 | t | p | joh_sig | eg_sig | coint |
|
|
889
|
-
>>> |----------|-----------|------|-------|---------|--------|-------|
|
|
890
|
-
>>> | Security1| Candidate1| -3.5 | 0.01 | 1 | 1 | 1 |
|
|
891
|
-
>>> | Security2| Candidate2| -2.9 | 0.04 | 1 | 1 | 1 |
|
|
887
|
+
Examples
|
|
888
|
+
--------
|
|
889
|
+
>>> import pandas as pd
|
|
890
|
+
>>> data_securities = {
|
|
891
|
+
... 'Security1': [100, 102, 101, 103, 105],
|
|
892
|
+
... 'Security2': [50, 52, 53, 51, 54]
|
|
893
|
+
... }
|
|
894
|
+
>>> data_candidates = {
|
|
895
|
+
... 'Candidate1': [100, 101, 99, 102, 104],
|
|
896
|
+
... 'Candidate2': [200, 202, 201, 203, 205]
|
|
897
|
+
... }
|
|
898
|
+
>>> securities = pd.DataFrame(data_securities, index=pd.date_range('2023-01-01', periods=5))
|
|
899
|
+
>>> candidates = pd.DataFrame(data_candidates, index=pd.date_range('2023-01-01', periods=5))
|
|
900
|
+
>>> top_pairs = find_cointegrated_pairs(securities, candidates, n=2, coint=True)
|
|
901
|
+
>>> print(top_pairs)
|
|
892
902
|
"""
|
|
893
|
-
trace0_cv = __CRITICAL_VALUES[0][
|
|
894
|
-
0.95
|
|
895
|
-
] # critical value for 0 cointegration relationships
|
|
896
|
-
# critical value for 1 cointegration relationship
|
|
897
|
-
trace1_cv = __CRITICAL_VALUES[1][0.95]
|
|
898
|
-
spreads = []
|
|
899
|
-
if start is not None and stop is not None:
|
|
900
|
-
securities = securities.loc[str(start) : str(stop), :]
|
|
901
|
-
candidates = candidates.loc[str(start) : str(stop), :]
|
|
902
|
-
for i, (ticker, prices) in enumerate(securities.items(), 1):
|
|
903
|
-
try:
|
|
904
|
-
df = compute_pair_metrics(prices, candidates)
|
|
905
|
-
spreads.append(df.set_index("s1", append=True))
|
|
906
|
-
except np.linalg.LinAlgError:
|
|
907
|
-
continue
|
|
908
|
-
spreads = pd.concat(spreads)
|
|
909
|
-
spreads.index.names = ["s2", "s1"]
|
|
910
|
-
spreads = spreads.swaplevel()
|
|
911
|
-
spreads["t"] = spreads[["t1", "t2"]].min(axis=1)
|
|
912
|
-
spreads["p"] = spreads[["p1", "p2"]].min(axis=1)
|
|
913
|
-
spreads["joh_sig"] = (
|
|
914
|
-
(spreads.trace0 > trace0_cv) & (spreads.trace1 > trace1_cv)
|
|
915
|
-
).astype(int)
|
|
916
|
-
spreads["eg_sig"] = (spreads.p < 0.05).astype(int)
|
|
917
|
-
spreads["s1_dep"] = spreads.p1 < spreads.p2
|
|
918
|
-
spreads["coint"] = (spreads.joh_sig & spreads.eg_sig).astype(int)
|
|
919
|
-
# select top n pairs
|
|
920
|
-
if coint:
|
|
921
|
-
if n is not None:
|
|
922
|
-
top_pairs = (
|
|
923
|
-
spreads.query("coint == 1").sort_values("t", ascending=False).head(n)
|
|
924
|
-
)
|
|
925
|
-
else:
|
|
926
|
-
top_pairs = spreads.query("coint == 1").sort_values("t", ascending=False)
|
|
927
|
-
else:
|
|
928
|
-
if n is not None:
|
|
929
|
-
top_pairs = spreads.sort_values("t", ascending=False).head(n)
|
|
930
|
-
else:
|
|
931
|
-
top_pairs = spreads.sort_values("t", ascending=False)
|
|
932
|
-
return top_pairs
|
|
933
903
|
|
|
934
904
|
|
|
935
905
|
def analyze_cointegrated_pairs(
|
|
@@ -1121,25 +1091,31 @@ def KFSmoother(prices: pd.Series | np.ndarray) -> pd.Series | np.ndarray:
|
|
|
1121
1091
|
|
|
1122
1092
|
|
|
1123
1093
|
def KFHedgeRatio(x: pd.Series | np.ndarray, y: pd.Series | np.ndarray) -> np.ndarray:
|
|
1124
|
-
"""
|
|
1125
|
-
Estimate Hedge Ratio using Kalman Filter.
|
|
1126
|
-
Args:
|
|
1127
|
-
x : pd.Series or np.ndarray
|
|
1128
|
-
The independent variable, which can be either a pandas Series or a numpy array.
|
|
1129
|
-
y : pd.Series or np.ndarray
|
|
1130
|
-
The dependent variable, which can be either a pandas Series or a numpy array.
|
|
1094
|
+
"""Estimate Hedge Ratio using Kalman Filter.
|
|
1131
1095
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
The estimated hedge ratio as a numpy array.
|
|
1096
|
+
This function uses a Kalman Filter to dynamically estimate the hedge ratio
|
|
1097
|
+
(beta) and intercept (alpha) for a pair of assets over time.
|
|
1135
1098
|
|
|
1136
|
-
The function returns the negative of the first state variable
|
|
1137
|
-
which
|
|
1099
|
+
The function returns the negative of the first state variable (the hedge ratio)
|
|
1100
|
+
for each time step, which is a common convention in pairs trading.
|
|
1101
|
+
|
|
1102
|
+
Parameters
|
|
1103
|
+
----------
|
|
1104
|
+
x : pd.Series or np.ndarray
|
|
1105
|
+
The independent variable (e.g., price series of asset X).
|
|
1106
|
+
y : pd.Series or np.ndarray
|
|
1107
|
+
The dependent variable (e.g., price series of asset Y).
|
|
1108
|
+
|
|
1109
|
+
Returns
|
|
1110
|
+
-------
|
|
1111
|
+
np.ndarray
|
|
1112
|
+
The time-varying estimated hedge ratio as a numpy array.
|
|
1138
1113
|
|
|
1139
1114
|
References
|
|
1140
1115
|
----------
|
|
1141
|
-
|
|
1142
|
-
|
|
1116
|
+
* [1] Jansen, S. (2020). Machine Learning for Algorithmic Trading -
|
|
1117
|
+
Second Edition. Packt Publishing. Chapter 9, Time-Series Models
|
|
1118
|
+
for Volatility Forecasts and Statistical Arbitrage.
|
|
1143
1119
|
"""
|
|
1144
1120
|
if not isinstance(x, (np.ndarray, pd.Series)) or not isinstance(
|
|
1145
1121
|
y, (np.ndarray, pd.Series)
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bbstrader
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: Simplified Investment & Trading Toolkit
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
License: MIT
|
|
5
|
+
Author-email: Bertin Balouki SIMYELI <bertin@bbstrader.com>
|
|
6
|
+
Maintainer-email: Bertin Balouki SIMYELI <bertin@bbstrader.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/bbalouki/bbstrader
|
|
9
|
+
Project-URL: Download, https://pypi.org/project/bbstrader/
|
|
11
10
|
Project-URL: Documentation, https://bbstrader.readthedocs.io/en/latest/
|
|
12
11
|
Project-URL: Source Code, https://github.com/bbalouki/bbstrader
|
|
13
12
|
Keywords: Finance,Toolkit,Financial,Analysis,Fundamental,Quantitative,Database,Equities,Currencies,Economics,ETFs,Funds,Indices,Moneymarkets,Commodities,Futures,CFDs,Derivatives,Trading,Investing,Portfolio,Optimization,Performance
|
|
@@ -19,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
18
|
Classifier: Operating System :: Microsoft :: Windows
|
|
20
19
|
Classifier: Operating System :: POSIX :: Linux
|
|
21
20
|
Classifier: Operating System :: MacOS
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
Requires-Dist: alphalens-reloaded>=0.4.6
|
|
@@ -58,21 +58,7 @@ Requires-Dist: vaderSentiment>=3.3.2
|
|
|
58
58
|
Requires-Dist: yfinance>=0.2.65
|
|
59
59
|
Provides-Extra: mt5
|
|
60
60
|
Requires-Dist: MetaTrader5; extra == "mt5"
|
|
61
|
-
Dynamic: author
|
|
62
|
-
Dynamic: author-email
|
|
63
|
-
Dynamic: classifier
|
|
64
|
-
Dynamic: description
|
|
65
|
-
Dynamic: description-content-type
|
|
66
|
-
Dynamic: download-url
|
|
67
|
-
Dynamic: home-page
|
|
68
|
-
Dynamic: keywords
|
|
69
|
-
Dynamic: license
|
|
70
61
|
Dynamic: license-file
|
|
71
|
-
Dynamic: maintainer
|
|
72
|
-
Dynamic: project-url
|
|
73
|
-
Dynamic: provides-extra
|
|
74
|
-
Dynamic: requires-dist
|
|
75
|
-
Dynamic: summary
|
|
76
62
|
|
|
77
63
|
# Simplified Investment & Trading Toolkit
|
|
78
64
|
[](https://bbstrader.readthedocs.io/en/latest/?badge=latest)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
bbstrader/__init__.py,sha256
|
|
2
|
-
bbstrader/__main__.py,sha256=
|
|
1
|
+
bbstrader/__init__.py,sha256=kUjCDqDwFaqgcJkaLrgRGiaTwyxG3iTTbOy8V3iefYk,747
|
|
2
|
+
bbstrader/__main__.py,sha256=Cc3cSqHSCOdhk6gsg0lfL5TOaNz_ODXoe1wWgr_DewQ,2745
|
|
3
3
|
bbstrader/compat.py,sha256=bHTPTalffQNVv7MNRPaimJ4d9rQEwQFLSovHlUbxNgA,647
|
|
4
4
|
bbstrader/config.py,sha256=Q8xi6laFo-R-NNGotbHOgy8GLLuwvH6MaoiLhfTbYok,3548
|
|
5
|
-
bbstrader/tseries.py,sha256=
|
|
5
|
+
bbstrader/tseries.py,sha256=fEIsG0kkMuG1TSrMnPK1u-tihzfFIOR675s18p3pg4A,41953
|
|
6
6
|
bbstrader/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
bbstrader/apps/_copier.py,sha256=
|
|
7
|
+
bbstrader/apps/_copier.py,sha256=wI33uEKEw8WElb4QA34UBbsXl4o7OqpjPSV023n_bb8,25393
|
|
8
8
|
bbstrader/btengine/__init__.py,sha256=y1btjaEfhWsH8vuE7mBRpP9Tu-Azt9REhuVYsPCAfBU,2955
|
|
9
9
|
bbstrader/btengine/backtest.py,sha256=o3eoCVzpjykDx-9VgkxK6DKZdGDAuLVeeWLCa2U_zeY,14652
|
|
10
10
|
bbstrader/btengine/data.py,sha256=WcBLtabboZkQdtOQS3SjbiJD9BcWc75sdhZ2voQ_lUw,27061
|
|
@@ -13,7 +13,7 @@ bbstrader/btengine/execution.py,sha256=4MytWjcKg8J_w14P43emHqsvKOElkQTfhVYNakU6e
|
|
|
13
13
|
bbstrader/btengine/performance.py,sha256=1ecWrTzHBQbk4ORvbTEKxwCzlL1brcXOEUwgbnjAwx4,12470
|
|
14
14
|
bbstrader/btengine/portfolio.py,sha256=z98M65HQeCyma8gMZkAxspxBA9jtIhzxMyJUHPPj34c,16128
|
|
15
15
|
bbstrader/btengine/scripts.py,sha256=8o66dq4Ex4DsH4s8xvJqUOFjLzZJSnbBvvNBzohtzoE,4837
|
|
16
|
-
bbstrader/btengine/strategy.py,sha256=
|
|
16
|
+
bbstrader/btengine/strategy.py,sha256=6MR2atgXA4bkMQ9TE1lPr6P8vKAUoT0YoLmOFYEJiaA,39242
|
|
17
17
|
bbstrader/core/__init__.py,sha256=GIFzFSStPfE0XM2j7mDeZZQeMTh_AwPsDOQXwMVJLgw,97
|
|
18
18
|
bbstrader/core/data.py,sha256=5-ByClb-E3-iqDz8CBJ4om9wBIA7DmUWezu4A-tv5ys,25095
|
|
19
19
|
bbstrader/core/scripts.py,sha256=7lNddfX7WaZfiE5dENEfzv3XrAPrwoE9FYSaTie3cwM,5524
|
|
@@ -21,29 +21,42 @@ bbstrader/core/utils.py,sha256=tHXQimmmlYZHktNnYNKn_wVq6v-85pI7DXF6xlJV7ps,2780
|
|
|
21
21
|
bbstrader/ibkr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
bbstrader/ibkr/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
bbstrader/metatrader/__init__.py,sha256=A5Ye9tpc2sp9Xk5qjKw-EfYsoRcZtAt8nqvC3tCtZs8,333
|
|
24
|
-
bbstrader/metatrader/account.py,sha256=
|
|
25
|
-
bbstrader/metatrader/analysis.py,sha256=
|
|
26
|
-
bbstrader/metatrader/copier.py,sha256=
|
|
24
|
+
bbstrader/metatrader/account.py,sha256=5YdvRggBxfZ6MQX70EFfwAZ7tuHvGzkwyEw1GgtiR4c,65501
|
|
25
|
+
bbstrader/metatrader/analysis.py,sha256=HuxYiKwa7VYmI_noqc4OAKSoC7bJpYm-OosQGZdMEnU,3694
|
|
26
|
+
bbstrader/metatrader/copier.py,sha256=VOo0RfuNoItc10CRGdX8MsUtcBBAzoY42sfolmvgptg,56052
|
|
27
27
|
bbstrader/metatrader/rates.py,sha256=w9mr6FB6E1zLcHCDtDGt-oMnw6sakIU6Qe3455KDsSg,20782
|
|
28
28
|
bbstrader/metatrader/risk.py,sha256=NhW8qtSg350Z6H9oLcDqOU_erqd_7Y7F5FwpfPN5Qso,27262
|
|
29
29
|
bbstrader/metatrader/scripts.py,sha256=8meq6_zz6jPSibNgtYtaO8Ba-uJZOoLkpqYUIjidk-U,4010
|
|
30
|
-
bbstrader/metatrader/trade.py,sha256
|
|
31
|
-
bbstrader/metatrader/utils.py,sha256=
|
|
30
|
+
bbstrader/metatrader/trade.py,sha256=-tMbMBSTGAFJe9xK706uhR0Na8lJu7vfEhmud9Q3XnU,81003
|
|
31
|
+
bbstrader/metatrader/utils.py,sha256=Yt3mx8EgS6u1-irQG6uQn-LhC3kyWOVE00VepnDAtCI,20802
|
|
32
32
|
bbstrader/models/__init__.py,sha256=B-bn2h_SCK6gRAs2li6dDVnvV8jDT5suZimldk5xxcw,497
|
|
33
33
|
bbstrader/models/factors.py,sha256=J7yxtDr1sCTw1AI59kluF89e2b9HkpEXfFyIcfPHUCQ,13008
|
|
34
34
|
bbstrader/models/ml.py,sha256=NVN9zxRRDJn2S8KSgGBkiSHvdFjsDiaNsW2Y6rs51Io,50314
|
|
35
|
-
bbstrader/models/nlp.py,sha256=
|
|
35
|
+
bbstrader/models/nlp.py,sha256=z_mbL58U5UGXc7ocVtvUR_zUYSk7Om2Gu7xXYBerxQY,32619
|
|
36
36
|
bbstrader/models/optimization.py,sha256=Fa4tdhynMmvKt5KHV9cH1TXmmJVJwU4QWpYkbeVq4aI,6395
|
|
37
37
|
bbstrader/models/portfolio.py,sha256=r-47Zrn2r7iKCHm5YVtwkbBJXAZGM3QYy-rXCWY9-Bg,8079
|
|
38
38
|
bbstrader/models/risk.py,sha256=MKCk53HtGIcivrNzH8Ikm5KMs1rXhFT5zkorUf30PyQ,506
|
|
39
39
|
bbstrader/trading/__init__.py,sha256=ycLyuuxN5SujqtzR9X0Q74UQfK93q2va-GGAXdr-KS8,457
|
|
40
|
-
bbstrader/trading/execution.py,sha256=
|
|
40
|
+
bbstrader/trading/execution.py,sha256=CPjOKvVFq8ZnANQrOtpakp64ZAhn-73Bu-D9UPCKUws,41832
|
|
41
41
|
bbstrader/trading/scripts.py,sha256=Tf5q33WqqygjpIv43_8nA82VZ3GM0qgb4Ggo3fHJ_wg,5744
|
|
42
42
|
bbstrader/trading/strategies.py,sha256=RZ6P4SfIyRW72v0OnPnrc4Hv8X00FdxR-_sD23xe_Pg,11756
|
|
43
43
|
bbstrader/trading/utils.py,sha256=57dKF9dcRu04oU2VRqydRrzW39dCW2wlDWhVt-sZdRw,1857
|
|
44
|
-
bbstrader-0.3.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
bbstrader-0.3.6.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
|
|
45
|
+
docs/conf.py,sha256=q_Z8_iz-YDgHhe4PpCOAtvN5Q-2hHquliG07FDEXdjo,1686
|
|
46
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
|
+
tests/engine/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
48
|
+
tests/engine/test_backtest.py,sha256=OmHimBp518BBv0Eg-t_cIrBXMzfiYOGki5FW7kqFeFs,2136
|
|
49
|
+
tests/engine/test_data.py,sha256=jAVICMt4YTKF5PN6ZIxhQ9CuUjbw9_gIPAC4sNA9GsE,19907
|
|
50
|
+
tests/engine/test_events.py,sha256=is3v3mtQVKFVNyn-xF4F7yuBGA5vqgunqsoFgNJeH0c,11755
|
|
51
|
+
tests/engine/test_execution.py,sha256=Sk3d_Rl9T0GjArficd75hEeVyeB_7yOcTD8ltpN4UlY,7961
|
|
52
|
+
tests/engine/test_portfolio.py,sha256=csKWO4W0xWn3obxuPRBFAUHHR60j-IZfAz5bv7Y_u9M,9872
|
|
53
|
+
tests/metatrader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
+
tests/metatrader/test_account.py,sha256=UiAWP0IRd6a1kmA_pTcEuCZAJjtq0U_Q-PcOdd2l69A,68627
|
|
55
|
+
tests/metatrader/test_rates.py,sha256=dc43jAvkZby9TMJcwkcaEvH21jQudk1D8KQxWLlAYoQ,10424
|
|
56
|
+
tests/metatrader/test_risk_management.py,sha256=lMT0m7dmT3iWihTkEwpMoHdJPPWU3XJmqgCV4qKT-uw,31019
|
|
57
|
+
tests/metatrader/test_trade.py,sha256=gMyinOOgVC2SOV8xLMIKqUTwqXbSUuDGnhSmspXK9cw,15177
|
|
58
|
+
bbstrader-0.3.6.dist-info/METADATA,sha256=zPS1ez6FJWRlX70OAjC9tSNerd1GuQJP9Hxv4mzorgc,26693
|
|
59
|
+
bbstrader-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
60
|
+
bbstrader-0.3.6.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
|
|
61
|
+
bbstrader-0.3.6.dist-info/top_level.txt,sha256=raTnmqZJ2B3Mvrhy_fV9szurE9yVctrKHBLZ1NJ5vnU,21
|
|
62
|
+
bbstrader-0.3.6.dist-info/RECORD,,
|
docs/conf.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Configuration file for the Sphinx documentation builder.
|
|
2
|
+
#
|
|
3
|
+
# For the full list of built-in configuration values, see the documentation:
|
|
4
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
5
|
+
|
|
6
|
+
# -- Project information -----------------------------------------------------
|
|
7
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from unittest.mock import MagicMock
|
|
11
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
12
|
+
|
|
13
|
+
os.system('pip install ..')
|
|
14
|
+
sys.path.insert(0, os.path.abspath('../bbstrader'))
|
|
15
|
+
|
|
16
|
+
class Mock(MagicMock):
|
|
17
|
+
@classmethod
|
|
18
|
+
def __getattr__(cls, name):
|
|
19
|
+
return MagicMock()
|
|
20
|
+
|
|
21
|
+
# List the mock modules to avoid import errors
|
|
22
|
+
MOCK_MODULES = ['MetaTrader5', 'talib', 'posix']
|
|
23
|
+
sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES)
|
|
24
|
+
|
|
25
|
+
project = 'bbstrader'
|
|
26
|
+
copyright = '2023 - 2025, Bertin Balouki SIMYELI'
|
|
27
|
+
author = 'Bertin Balouki SIMYELI'
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
release = version("bbstrader")
|
|
31
|
+
except PackageNotFoundError:
|
|
32
|
+
release = "unknown"
|
|
33
|
+
version = ".".join(release.split('.')[:2])
|
|
34
|
+
|
|
35
|
+
# -- General configuration ---------------------------------------------------
|
|
36
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
extensions = [
|
|
40
|
+
'sphinx.ext.autodoc',
|
|
41
|
+
'sphinx.ext.napoleon',
|
|
42
|
+
'sphinx.ext.viewcode',
|
|
43
|
+
'sphinx.ext.todo',
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
templates_path = ['_templates']
|
|
48
|
+
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# -- Options for HTML output -------------------------------------------------
|
|
53
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
|
54
|
+
|
|
55
|
+
html_theme = 'sphinx_rtd_theme'
|
|
56
|
+
html_static_path = ['_static']
|
tests/__init__.py
ADDED
|
File without changes
|
tests/engine/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest.mock import MagicMock
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from bbstrader.btengine.backtest import BacktestEngine
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestBacktestEngine(unittest.TestCase):
|
|
8
|
+
def setUp(self):
|
|
9
|
+
# Create mock classes with minimum expected interface
|
|
10
|
+
self.symbol_list = ['FAKE']
|
|
11
|
+
self.initial_capital = 100000.0
|
|
12
|
+
self.heartbeat = 0.0
|
|
13
|
+
self.start_date = datetime(2020, 1, 1)
|
|
14
|
+
|
|
15
|
+
self.mock_data_handler_cls = MagicMock()
|
|
16
|
+
self.mock_strategy_cls = MagicMock()
|
|
17
|
+
self.mock_execution_handler_cls = MagicMock()
|
|
18
|
+
|
|
19
|
+
# Mock data_handler instance
|
|
20
|
+
self.mock_data_handler = MagicMock()
|
|
21
|
+
self.mock_data_handler.continue_backtest = False
|
|
22
|
+
self.mock_data_handler.get_latest_bar_datetime.return_value = self.start_date
|
|
23
|
+
self.mock_data_handler.update_bars.return_value = None
|
|
24
|
+
|
|
25
|
+
# Strategy and portfolio mock
|
|
26
|
+
self.mock_strategy = MagicMock()
|
|
27
|
+
self.mock_strategy.check_pending_orders.return_value = None
|
|
28
|
+
self.mock_strategy.get_update_from_portfolio.return_value = None
|
|
29
|
+
|
|
30
|
+
self.mock_portfolio = MagicMock()
|
|
31
|
+
self.mock_portfolio.all_holdings = [{"Total": self.initial_capital}]
|
|
32
|
+
self.mock_portfolio.current_positions = {}
|
|
33
|
+
self.mock_portfolio.current_holdings = {}
|
|
34
|
+
|
|
35
|
+
self.mock_execution_handler = MagicMock()
|
|
36
|
+
|
|
37
|
+
# Bind mock return values
|
|
38
|
+
self.mock_data_handler_cls.return_value = self.mock_data_handler
|
|
39
|
+
self.mock_strategy_cls.return_value = self.mock_strategy
|
|
40
|
+
self.mock_execution_handler_cls.return_value = self.mock_execution_handler
|
|
41
|
+
|
|
42
|
+
def test_backtest_engine_runs(self):
|
|
43
|
+
engine = BacktestEngine(
|
|
44
|
+
self.symbol_list,
|
|
45
|
+
self.initial_capital,
|
|
46
|
+
self.heartbeat,
|
|
47
|
+
self.start_date,
|
|
48
|
+
self.mock_data_handler_cls,
|
|
49
|
+
self.mock_execution_handler_cls,
|
|
50
|
+
self.mock_strategy_cls,
|
|
51
|
+
)
|
|
52
|
+
engine.portfolio = self.mock_portfolio
|
|
53
|
+
|
|
54
|
+
result = engine.simulate_trading()
|
|
55
|
+
self.assertTrue(hasattr(result, '__class__'))
|
|
56
|
+
|
|
57
|
+
if __name__ == "__main__":
|
|
58
|
+
unittest.main()
|