bbstrader 2.0.3__cp312-cp312-macosx_11_0_arm64.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.
Files changed (45) hide show
  1. bbstrader/__init__.py +27 -0
  2. bbstrader/__main__.py +92 -0
  3. bbstrader/api/__init__.py +96 -0
  4. bbstrader/api/handlers.py +245 -0
  5. bbstrader/api/metatrader_client.cpython-312-darwin.so +0 -0
  6. bbstrader/api/metatrader_client.pyi +624 -0
  7. bbstrader/assets/bbs_.png +0 -0
  8. bbstrader/assets/bbstrader.ico +0 -0
  9. bbstrader/assets/bbstrader.png +0 -0
  10. bbstrader/assets/qs_metrics_1.png +0 -0
  11. bbstrader/btengine/__init__.py +54 -0
  12. bbstrader/btengine/backtest.py +358 -0
  13. bbstrader/btengine/data.py +737 -0
  14. bbstrader/btengine/event.py +229 -0
  15. bbstrader/btengine/execution.py +287 -0
  16. bbstrader/btengine/performance.py +408 -0
  17. bbstrader/btengine/portfolio.py +393 -0
  18. bbstrader/btengine/strategy.py +588 -0
  19. bbstrader/compat.py +28 -0
  20. bbstrader/config.py +100 -0
  21. bbstrader/core/__init__.py +27 -0
  22. bbstrader/core/data.py +628 -0
  23. bbstrader/core/strategy.py +466 -0
  24. bbstrader/metatrader/__init__.py +48 -0
  25. bbstrader/metatrader/_copier.py +720 -0
  26. bbstrader/metatrader/account.py +865 -0
  27. bbstrader/metatrader/broker.py +418 -0
  28. bbstrader/metatrader/copier.py +1487 -0
  29. bbstrader/metatrader/rates.py +495 -0
  30. bbstrader/metatrader/risk.py +667 -0
  31. bbstrader/metatrader/trade.py +1692 -0
  32. bbstrader/metatrader/utils.py +402 -0
  33. bbstrader/models/__init__.py +39 -0
  34. bbstrader/models/nlp.py +932 -0
  35. bbstrader/models/optimization.py +182 -0
  36. bbstrader/scripts.py +665 -0
  37. bbstrader/trading/__init__.py +33 -0
  38. bbstrader/trading/execution.py +1159 -0
  39. bbstrader/trading/strategy.py +362 -0
  40. bbstrader/trading/utils.py +69 -0
  41. bbstrader-2.0.3.dist-info/METADATA +396 -0
  42. bbstrader-2.0.3.dist-info/RECORD +45 -0
  43. bbstrader-2.0.3.dist-info/WHEEL +5 -0
  44. bbstrader-2.0.3.dist-info/entry_points.txt +3 -0
  45. bbstrader-2.0.3.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,182 @@
1
+ import warnings
2
+
3
+ from pypfopt import expected_returns, risk_models
4
+ from pypfopt.efficient_frontier import EfficientFrontier
5
+ from pypfopt.hierarchical_portfolio import HRPOpt
6
+
7
+ __all__ = [
8
+ "markowitz_weights",
9
+ "hierarchical_risk_parity",
10
+ "equal_weighted",
11
+ "optimized_weights",
12
+ ]
13
+
14
+
15
+ def markowitz_weights(prices=None, rfr=0.0, freq=252):
16
+ """
17
+ Calculates optimal portfolio weights using Markowitz's mean-variance optimization (Max Sharpe Ratio) with multiple solvers.
18
+
19
+ Parameters
20
+ ----------
21
+ prices : pd.DataFrame, optional
22
+ Price data for assets, where rows represent time periods and columns represent assets.
23
+ freq : int, optional
24
+ Frequency of the data, such as 252 for daily returns in a year (default is 252).
25
+
26
+ Returns
27
+ -------
28
+ dict
29
+ Dictionary containing the optimal asset weights for maximizing the Sharpe ratio, normalized to sum to 1.
30
+
31
+ Notes
32
+ -----
33
+ This function attempts to maximize the Sharpe ratio by iterating through various solvers ('SCS', 'ECOS', 'OSQP')
34
+ from the PyPortfolioOpt library. If a solver fails, it proceeds to the next one. If none succeed, an error message
35
+ is printed for each solver that fails.
36
+
37
+ This function is useful for portfolio with a small number of assets, as it may not scale well for large portfolios.
38
+
39
+ Raises
40
+ ------
41
+ Exception
42
+ If all solvers fail, each will print an exception error message during runtime.
43
+ """
44
+ returns = expected_returns.mean_historical_return(prices, frequency=freq)
45
+ cov = risk_models.sample_cov(prices, frequency=freq)
46
+
47
+ # Try different solvers to maximize Sharpe ratio
48
+ for solver in ["SCS", "ECOS", "OSQP"]:
49
+ ef = EfficientFrontier(
50
+ expected_returns=returns,
51
+ cov_matrix=cov,
52
+ weight_bounds=(0, 1),
53
+ solver=solver,
54
+ )
55
+ try:
56
+ ef.max_sharpe(risk_free_rate=rfr)
57
+ return ef.clean_weights()
58
+ except Exception as e:
59
+ print(f"Solver {solver} failed with error: {e}")
60
+
61
+
62
+ def hierarchical_risk_parity(prices=None, returns=None, freq=252):
63
+ """
64
+ Computes asset weights using Hierarchical Risk Parity (HRP) for risk-averse portfolio allocation.
65
+
66
+ Parameters
67
+ ----------
68
+ prices : pd.DataFrame, optional
69
+ Price data for assets; if provided, daily returns will be calculated.
70
+ returns : pd.DataFrame, optional
71
+ Daily returns for assets. One of `prices` or `returns` must be provided.
72
+ freq : int, optional
73
+ Number of days to consider in calculating portfolio weights (default is 252).
74
+
75
+ Returns
76
+ -------
77
+ dict
78
+ Optimized asset weights using the HRP method, with asset weights summing to 1.
79
+
80
+ Raises
81
+ ------
82
+ ValueError
83
+ If neither `prices` nor `returns` are provided.
84
+
85
+ Notes
86
+ -----
87
+ Hierarchical Risk Parity is particularly useful for portfolios with a large number of assets,
88
+ as it mitigates issues of multicollinearity and estimation errors in covariance matrices by
89
+ using hierarchical clustering.
90
+ """
91
+ warnings.filterwarnings("ignore")
92
+ if returns is None and prices is None:
93
+ raise ValueError("Either prices or returns must be provided")
94
+ if returns is None:
95
+ returns = prices.pct_change().dropna(how="all")
96
+ # Remove duplicate columns and index
97
+ returns = returns.loc[:, ~returns.columns.duplicated()]
98
+ returns = returns.loc[~returns.index.duplicated(keep="first")]
99
+ hrp = HRPOpt(returns=returns.iloc[-freq:])
100
+ return hrp.optimize()
101
+
102
+
103
+ def equal_weighted(prices=None, returns=None, round_digits=5):
104
+ """
105
+ Generates an equal-weighted portfolio by assigning an equal proportion to each asset.
106
+
107
+ Parameters
108
+ ----------
109
+ prices : pd.DataFrame, optional
110
+ Price data for assets, where each column represents an asset.
111
+ returns : pd.DataFrame, optional
112
+ Return data for assets. One of `prices` or `returns` must be provided.
113
+ round_digits : int, optional
114
+ Number of decimal places to round each weight to (default is 5).
115
+
116
+ Returns
117
+ -------
118
+ dict
119
+ Dictionary with equal weights assigned to each asset, summing to 1.
120
+
121
+ Raises
122
+ ------
123
+ ValueError
124
+ If neither `prices` nor `returns` are provided.
125
+
126
+ Notes
127
+ -----
128
+ Equal weighting is a simple allocation method that assumes equal importance across all assets,
129
+ useful as a baseline model and when no strong views exist on asset return expectations or risk.
130
+ """
131
+
132
+ if returns is None and prices is None:
133
+ raise ValueError("Either prices or returns must be provided")
134
+ if returns is None:
135
+ n = len(prices.columns)
136
+ columns = prices.columns
137
+ else:
138
+ n = len(returns.columns)
139
+ columns = returns.columns
140
+ return {col: round(1 / n, round_digits) for col in columns}
141
+
142
+
143
+ def optimized_weights(prices=None, returns=None, rfr=0.0, freq=252, method="equal"):
144
+ """
145
+ Selects an optimization method to calculate portfolio weights based on user preference.
146
+
147
+ Parameters
148
+ ----------
149
+ prices : pd.DataFrame, optional
150
+ Price data for assets, required for certain methods.
151
+ returns : pd.DataFrame, optional
152
+ Returns data for assets, an alternative input for certain methods.
153
+ freq : int, optional
154
+ Number of days for calculating portfolio weights, such as 252 for a year's worth of daily returns (default is 252).
155
+ method : str, optional
156
+ Optimization method to use ('markowitz', 'hrp', or 'equal') (default is 'equal').
157
+
158
+ Returns
159
+ -------
160
+ dict
161
+ Dictionary containing optimized asset weights based on the chosen method.
162
+
163
+ Raises
164
+ ------
165
+ ValueError
166
+ If an unknown optimization method is specified.
167
+
168
+ Notes
169
+ -----
170
+ This function integrates different optimization methods:
171
+ - 'markowitz': mean-variance optimization with max Sharpe ratio
172
+ - 'hrp': Hierarchical Risk Parity, for risk-based clustering of assets
173
+ - 'equal': Equal weighting across all assets
174
+ """
175
+ if method == "markowitz":
176
+ return markowitz_weights(prices=prices, rfr=rfr, freq=freq)
177
+ elif method == "hrp":
178
+ return hierarchical_risk_parity(prices=prices, returns=returns, freq=freq)
179
+ elif method == "equal":
180
+ return equal_weighted(prices=prices, returns=returns)
181
+ else:
182
+ raise ValueError(f"Unknown method: {method}")