bbstrader 0.3.6__py3-none-any.whl → 0.3.7__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/tseries.py CHANGED
@@ -5,7 +5,7 @@ some simple time series analysis in financial markets.
5
5
 
6
6
  import pprint
7
7
  import warnings
8
- from typing import List, Tuple, Union
8
+ from typing import Any, Dict, List, Optional, Tuple, Union
9
9
 
10
10
  import matplotlib.pyplot as plt
11
11
  import numpy as np
@@ -94,7 +94,7 @@ def get_corr(tickers: Union[List[str], Tuple[str, ...]], start: str, end: str) -
94
94
  )
95
95
 
96
96
 
97
- def plot_price_series(df: pd.DataFrame, ts1: str, ts2: str):
97
+ def plot_price_series(df: pd.DataFrame, ts1: str, ts2: str) -> None:
98
98
  """
99
99
  Plot both time series on the same line graph for
100
100
  the specified date range.
@@ -117,7 +117,7 @@ def plot_price_series(df: pd.DataFrame, ts1: str, ts2: str):
117
117
  plt.show()
118
118
 
119
119
 
120
- def plot_scatter_series(df: pd.DataFrame, ts1: str, ts2: str):
120
+ def plot_scatter_series(df: pd.DataFrame, ts1: str, ts2: str) -> None:
121
121
  """
122
122
  Plot a scatter plot of both time series for
123
123
  via the provided DataFrame.
@@ -146,7 +146,7 @@ def plot_scatter_series(df: pd.DataFrame, ts1: str, ts2: str):
146
146
  plt.show()
147
147
 
148
148
 
149
- def plot_residuals(df: pd.DataFrame):
149
+ def plot_residuals(df: pd.DataFrame) -> None:
150
150
  """
151
151
  Plot the residuals of OLS procedure for both
152
152
  time series.
@@ -299,7 +299,7 @@ def run_hurst_test(symbol: str, start: str, end: str):
299
299
  )
300
300
 
301
301
 
302
- def test_cointegration(ticker1, ticker2, start, end):
302
+ def test_cointegration(ticker1: str, ticker2: str, start: str, end: str) -> None:
303
303
  warnings.warn(
304
304
  "`test_cointegration` is deprecated, see statsmodels.tsa.stattools.coint instead.",
305
305
  DeprecationWarning,
@@ -307,13 +307,15 @@ def test_cointegration(ticker1, ticker2, start, end):
307
307
 
308
308
 
309
309
  def run_coint_test(tickers: List[str], start: str, end: str) -> None:
310
- test_cointegration()
310
+ test_cointegration(tickers[0], tickers[1], start, end)
311
311
 
312
312
 
313
313
  # *********************************
314
314
  # KALMAN FILTER *
315
315
  # *********************************
316
- def draw_date_coloured_scatterplot(etfs, prices):
316
+ def draw_date_coloured_scatterplot(
317
+ etfs: Union[List[str], Tuple[str, ...]], prices: pd.DataFrame
318
+ ) -> None:
317
319
  """
318
320
  Create a scatterplot of the two ETF prices, which is
319
321
  coloured by the date of the price to indicate the
@@ -341,7 +343,9 @@ def draw_date_coloured_scatterplot(etfs, prices):
341
343
  plt.show()
342
344
 
343
345
 
344
- def calc_slope_intercept_kalman(etfs, prices):
346
+ def calc_slope_intercept_kalman(
347
+ etfs: Union[List[str], Tuple[str, ...]], prices: pd.DataFrame
348
+ ) -> Tuple[np.ndarray, np.ndarray]:
345
349
  """
346
350
  Utilize the Kalman Filter from the filterpy library
347
351
  to calculate the slope and intercept of the regressed
@@ -371,7 +375,7 @@ def calc_slope_intercept_kalman(etfs, prices):
371
375
  return np.array(state_means), np.array(state_covs)
372
376
 
373
377
 
374
- def draw_slope_intercept_changes(prices, state_means):
378
+ def draw_slope_intercept_changes(prices: pd.DataFrame, state_means: np.ndarray) -> None:
375
379
  """
376
380
  Plot the slope and intercept of the regressed ETF prices
377
381
  between the two ETFs, with the changing values of the
@@ -438,7 +442,9 @@ class KalmanFilterModel:
438
442
  You can learn more here https://en.wikipedia.org/wiki/Kalman_filter
439
443
  """
440
444
 
441
- def __init__(self, tickers: List | Tuple, **kwargs):
445
+ def __init__(
446
+ self, tickers: Union[List[str], Tuple[str, ...]], **kwargs: Any
447
+ ) -> None:
442
448
  """
443
449
  Initializes the Kalman Filter strategy.
444
450
 
@@ -452,7 +458,8 @@ class KalmanFilterModel:
452
458
  self.tickers = tickers
453
459
  assert self.tickers is not None
454
460
 
455
- self.R = None
461
+ self.R: Optional[np.ndarray] = None
462
+ self.C: Optional[np.ndarray] = None
456
463
  self.theta = np.zeros(2)
457
464
  self.P = np.zeros((2, 2))
458
465
  self.delta = kwargs.get("delta", 1e-4)
@@ -461,7 +468,7 @@ class KalmanFilterModel:
461
468
  self.latest_prices = np.array([-1.0, -1.0])
462
469
  self.kf = self._init_kalman()
463
470
 
464
- def _init_kalman(self):
471
+ def _init_kalman(self) -> KalmanFilter:
465
472
  """
466
473
  Initializes and returns a Kalman Filter configured
467
474
  for the trading strategy. The filter is set up with initial
@@ -477,9 +484,7 @@ class KalmanFilterModel:
477
484
 
478
485
  return kf
479
486
 
480
- Array = np.ndarray
481
-
482
- def calc_slope_intercep(self, prices: Array) -> Tuple:
487
+ def calc_slope_intercep(self, prices: np.ndarray) -> Tuple[float, float]:
483
488
  """
484
489
  Calculates and returns the slope and intercept
485
490
  of the relationship between the provided prices using the Kalman Filter.
@@ -500,7 +505,7 @@ class KalmanFilterModel:
500
505
 
501
506
  return slope, intercept
502
507
 
503
- def calculate_etqt(self, prices: Array) -> Tuple:
508
+ def calculate_etqt(self, prices: np.ndarray) -> Optional[Tuple[float, float]]:
504
509
  """
505
510
  Calculates the ``forecast error`` and ``standard deviation`` of the predictions
506
511
  using the Kalman Filter.
@@ -530,7 +535,7 @@ class KalmanFilterModel:
530
535
  # The prior value of the states {\theta_t} is
531
536
  # distributed as a multivariate Gaussian with
532
537
  # mean a_t and variance-covariance {R_t}
533
- if self.R is not None:
538
+ if self.R is not None and self.C is not None:
534
539
  self.R = self.C + self.wt
535
540
  else:
536
541
  self.R = np.zeros((2, 2))
@@ -554,7 +559,7 @@ class KalmanFilterModel:
554
559
  At = self.R.dot(F.T) / Qt
555
560
  self.theta = self.theta + At.flatten() * et
556
561
  self.C = self.R - At * F.dot(self.R)
557
- return (et[0], sqrt_Qt.flatten()[0])
562
+ return (et, sqrt_Qt.flatten()[0])
558
563
  else:
559
564
  return None
560
565
 
@@ -567,7 +572,7 @@ class OrnsteinUhlenbeck:
567
572
  )
568
573
 
569
574
 
570
- def remove_correlated_assets(df: pd.DataFrame, cutoff=0.99):
575
+ def remove_correlated_assets(df: pd.DataFrame, cutoff: float = 0.99) -> pd.DataFrame:
571
576
  """
572
577
  Removes highly correlated assets from a DataFrame based on a specified correlation cutoff threshold.
573
578
  This is useful in financial data analysis to reduce redundancy and multicollinearity in portfolios or datasets.
@@ -612,7 +617,7 @@ def remove_correlated_assets(df: pd.DataFrame, cutoff=0.99):
612
617
  return df.drop(drop, axis=1)
613
618
 
614
619
 
615
- def check_stationarity(df: pd.DataFrame):
620
+ def check_stationarity(df: pd.DataFrame) -> pd.DataFrame:
616
621
  """
617
622
  Tests the stationarity of time-series data for each asset in the DataFrame
618
623
  using the Augmented Dickey-Fuller (ADF) test. Stationarity is a key property
@@ -645,7 +650,7 @@ def check_stationarity(df: pd.DataFrame):
645
650
  return pd.DataFrame(results, columns=["ticker", "adf"]).sort_values("adf")
646
651
 
647
652
 
648
- def remove_stationary_assets(df: pd.DataFrame, pval=0.05):
653
+ def remove_stationary_assets(df: pd.DataFrame, pval: float = 0.05) -> pd.DataFrame:
649
654
  """
650
655
  Filters out stationary assets from the DataFrame based on the p-value obtained
651
656
  from the Augmented Dickey-Fuller test.
@@ -677,7 +682,13 @@ def remove_stationary_assets(df: pd.DataFrame, pval=0.05):
677
682
  return df.drop(stationary, axis=1).sort_index()
678
683
 
679
684
 
680
- def select_assets(df: pd.DataFrame, n=100, start=None, end=None, rolling_window=None):
685
+ def select_assets(
686
+ df: pd.DataFrame,
687
+ n: int = 100,
688
+ start: Optional[str] = None,
689
+ end: Optional[str] = None,
690
+ rolling_window: Optional[int] = None,
691
+ ) -> pd.DataFrame:
681
692
  """
682
693
  Selects the top N assets based on the average trading volume from the input DataFrame.
683
694
  These assets are used as universe in which we can search cointegrated pairs for pairs trading strategies.
@@ -744,7 +755,7 @@ def select_assets(df: pd.DataFrame, n=100, start=None, end=None, rolling_window=
744
755
  return df.sort_index()
745
756
 
746
757
 
747
- def compute_pair_metrics(security: pd.Series, candidates: pd.DataFrame):
758
+ def compute_pair_metrics(security: pd.Series, candidates: pd.DataFrame) -> pd.DataFrame:
748
759
  """Calculate statistical and econometric metrics for a security pair.
749
760
 
750
761
  These metrics are useful in financial modeling and pairs trading strategies,
@@ -830,11 +841,11 @@ __CRITICAL_VALUES = {
830
841
  def find_cointegrated_pairs(
831
842
  securities: pd.DataFrame,
832
843
  candidates: pd.DataFrame,
833
- n=None,
834
- start=None,
835
- stop=None,
836
- coint=False,
837
- ):
844
+ n: Optional[int] = None,
845
+ start: Optional[str] = None,
846
+ stop: Optional[str] = None,
847
+ coint: bool = False,
848
+ ) -> pd.DataFrame:
838
849
  """
839
850
  Identifies cointegrated pairs between a target set of securities and candidate securities
840
851
  based on econometric tests. The function evaluates statistical relationships,
@@ -900,16 +911,17 @@ def find_cointegrated_pairs(
900
911
  >>> top_pairs = find_cointegrated_pairs(securities, candidates, n=2, coint=True)
901
912
  >>> print(top_pairs)
902
913
  """
914
+ ...
903
915
 
904
916
 
905
917
  def analyze_cointegrated_pairs(
906
918
  spreads: pd.DataFrame,
907
- plot_coint=True,
908
- crosstab=False,
909
- heuristics=False,
910
- log_reg=False,
911
- decis_tree=False,
912
- ):
919
+ plot_coint: bool = True,
920
+ crosstab: bool = False,
921
+ heuristics: bool = False,
922
+ log_reg: bool = False,
923
+ decis_tree: bool = False,
924
+ ) -> None:
913
925
  """
914
926
  Analyzes cointegrated pairs by visualizing, summarizing, and applying predictive models.
915
927
 
@@ -919,7 +931,7 @@ def analyze_cointegrated_pairs(
919
931
  Required columns: 'coint', 't', 'trace0', 'trace1', 'drift', 'vol', 'corr', 'corr_ret', 'eg_sig', 'joh_sig'.
920
932
  plot_coint (bool, optional):
921
933
  If True, generates scatterplots and boxplots to visualize cointegration characteristics.
922
- cosstab (bool, optional):
934
+ crosstab (bool, optional):
923
935
  If True, displays crosstabulations of Engle-Granger and Johansen test significance.
924
936
  heuristics (bool, optional):
925
937
  If True, prints descriptive statistics for drift, volatility, and correlation grouped by cointegration status.
@@ -948,7 +960,7 @@ def analyze_cointegrated_pairs(
948
960
  ... })
949
961
 
950
962
  >>> pairs = find_cointegrated_pairs(securities, candidates, n=2, coint=True)
951
- >>> analyze_cointegrated_pairs(pairs, plot_coint=True, cosstab=True, heuristics=True, log_reg=True, decis_tree=True
963
+ >>> analyze_cointegrated_pairs(pairs, plot_coint=True, crosstab=True, heuristics=True, log_reg=True, decis_tree=True)
952
964
  """
953
965
  if plot_coint:
954
966
  trace0_cv = __CRITICAL_VALUES[0][0.95]
@@ -1006,7 +1018,9 @@ def analyze_cointegrated_pairs(
1006
1018
  print(pd.crosstab(spreads.eg_sig, spreads.joh_sig, normalize=True))
1007
1019
 
1008
1020
 
1009
- def select_candidate_pairs(pairs: pd.DataFrame, period=False):
1021
+ def select_candidate_pairs(
1022
+ pairs: pd.DataFrame, period: bool = False
1023
+ ) -> List[Dict[str, Any]]:
1010
1024
  """
1011
1025
  Select candidate pairs from a DataFrame based on cointegration status.
1012
1026
 
@@ -1039,7 +1053,7 @@ def select_candidate_pairs(pairs: pd.DataFrame, period=False):
1039
1053
  return candidates[["x", "y"]].to_dict(orient="records")
1040
1054
 
1041
1055
 
1042
- def KFSmoother(prices: pd.Series | np.ndarray) -> pd.Series | np.ndarray:
1056
+ def KFSmoother(prices: Union[pd.Series, np.ndarray]) -> Union[pd.Series, np.ndarray]:
1043
1057
  """
1044
1058
  Estimate rolling mean using Kalman Smoothing.
1045
1059
 
@@ -1090,7 +1104,9 @@ def KFSmoother(prices: pd.Series | np.ndarray) -> pd.Series | np.ndarray:
1090
1104
  return state_means.flatten()
1091
1105
 
1092
1106
 
1093
- def KFHedgeRatio(x: pd.Series | np.ndarray, y: pd.Series | np.ndarray) -> np.ndarray:
1107
+ def KFHedgeRatio(
1108
+ x: Union[pd.Series, np.ndarray], y: Union[pd.Series, np.ndarray]
1109
+ ) -> np.ndarray:
1094
1110
  """Estimate Hedge Ratio using Kalman Filter.
1095
1111
 
1096
1112
  This function uses a Kalman Filter to dynamically estimate the hedge ratio
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bbstrader
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: Simplified Investment & Trading Toolkit
5
- Author-email: Bertin Balouki SIMYELI <bertin@bbstrader.com>
6
- Maintainer-email: Bertin Balouki SIMYELI <bertin@bbstrader.com>
5
+ Author-email: Bertin Balouki SIMYELI <bertin@bbs-trading.com>
6
+ Maintainer-email: Bertin Balouki SIMYELI <bertin@bbs-trading.com>
7
7
  License-Expression: MIT
8
8
  Project-URL: Homepage, https://github.com/bbalouki/bbstrader
9
9
  Project-URL: Download, https://pypi.org/project/bbstrader/
@@ -1,23 +1,23 @@
1
- bbstrader/__init__.py,sha256=kUjCDqDwFaqgcJkaLrgRGiaTwyxG3iTTbOy8V3iefYk,747
2
- bbstrader/__main__.py,sha256=Cc3cSqHSCOdhk6gsg0lfL5TOaNz_ODXoe1wWgr_DewQ,2745
3
- bbstrader/compat.py,sha256=bHTPTalffQNVv7MNRPaimJ4d9rQEwQFLSovHlUbxNgA,647
4
- bbstrader/config.py,sha256=Q8xi6laFo-R-NNGotbHOgy8GLLuwvH6MaoiLhfTbYok,3548
5
- bbstrader/tseries.py,sha256=fEIsG0kkMuG1TSrMnPK1u-tihzfFIOR675s18p3pg4A,41953
1
+ bbstrader/__init__.py,sha256=bsyhtdTioj1KZyaAnEN6oE0Wvq8z0HaFEzPe8yWyxFo,749
2
+ bbstrader/__main__.py,sha256=KtGegYzmlp78YGuDIW75ouxLyWaRPNC4nC-Qcg8wheE,2751
3
+ bbstrader/compat.py,sha256=5gj2Yycv3W50BfaPDqC3sKZOwTP2AbD_MFfiL8DJYqg,682
4
+ bbstrader/config.py,sha256=4n6jS0x1E2kEVvCxFaRI6HRaGnJqPz1hhUofquwvsMk,2959
5
+ bbstrader/tseries.py,sha256=O6RG2ame_i6jGT7nETizb3uy7pwxrToRRJDKCUNupoQ,42800
6
6
  bbstrader/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- bbstrader/apps/_copier.py,sha256=wI33uEKEw8WElb4QA34UBbsXl4o7OqpjPSV023n_bb8,25393
7
+ bbstrader/apps/_copier.py,sha256=61PBMo5f429pDJ-XchTivZ1Y0whFLl2ZtdyFHJfmsxQ,25970
8
8
  bbstrader/btengine/__init__.py,sha256=y1btjaEfhWsH8vuE7mBRpP9Tu-Azt9REhuVYsPCAfBU,2955
9
- bbstrader/btengine/backtest.py,sha256=o3eoCVzpjykDx-9VgkxK6DKZdGDAuLVeeWLCa2U_zeY,14652
10
- bbstrader/btengine/data.py,sha256=WcBLtabboZkQdtOQS3SjbiJD9BcWc75sdhZ2voQ_lUw,27061
11
- bbstrader/btengine/event.py,sha256=Ydl1avAXp9WAWOBXDAckcb9g1UkcnCO0rRzcJZwIq20,8714
12
- bbstrader/btengine/execution.py,sha256=4MytWjcKg8J_w14P43emHqsvKOElkQTfhVYNakU6euQ,11190
13
- bbstrader/btengine/performance.py,sha256=1ecWrTzHBQbk4ORvbTEKxwCzlL1brcXOEUwgbnjAwx4,12470
14
- bbstrader/btengine/portfolio.py,sha256=z98M65HQeCyma8gMZkAxspxBA9jtIhzxMyJUHPPj34c,16128
15
- bbstrader/btengine/scripts.py,sha256=8o66dq4Ex4DsH4s8xvJqUOFjLzZJSnbBvvNBzohtzoE,4837
16
- bbstrader/btengine/strategy.py,sha256=6MR2atgXA4bkMQ9TE1lPr6P8vKAUoT0YoLmOFYEJiaA,39242
9
+ bbstrader/btengine/backtest.py,sha256=4O0ZnkhJ1nu3zWaGCrXQVKhfqW46jsqdMIPmsUPLyYo,14979
10
+ bbstrader/btengine/data.py,sha256=03ahVmqXQefx8gaH16fLBP1rIikfKqmJ4PULm1Q29TU,28760
11
+ bbstrader/btengine/event.py,sha256=E_OvwAO23xl0FqH-oe5Dh83fDmSjuF_KS8kOi8SEhTc,8880
12
+ bbstrader/btengine/execution.py,sha256=RFH2xIhiUGv9nqyvupBNuCmw3rjRgO7h2ySP_3Ggei0,12182
13
+ bbstrader/btengine/performance.py,sha256=WT4jz5AnOr8Eenz6NNR6po8Q8brMDIJskCS0o3mWy40,12764
14
+ bbstrader/btengine/portfolio.py,sha256=bqcVuohDZqertLo6LEk7DIY6e3Npi0UKQUKawEmo5Ko,16695
15
+ bbstrader/btengine/scripts.py,sha256=5wRzyxGxA6C8cd_tRDrr-p_7_TtWWk0zIxzblZxP3M4,5178
16
+ bbstrader/btengine/strategy.py,sha256=D72lULYu1tth9KUm4RS7EtrJdDqa1EF4uH8wlqrTTYQ,44666
17
17
  bbstrader/core/__init__.py,sha256=GIFzFSStPfE0XM2j7mDeZZQeMTh_AwPsDOQXwMVJLgw,97
18
- bbstrader/core/data.py,sha256=5-ByClb-E3-iqDz8CBJ4om9wBIA7DmUWezu4A-tv5ys,25095
19
- bbstrader/core/scripts.py,sha256=7lNddfX7WaZfiE5dENEfzv3XrAPrwoE9FYSaTie3cwM,5524
20
- bbstrader/core/utils.py,sha256=tHXQimmmlYZHktNnYNKn_wVq6v-85pI7DXF6xlJV7ps,2780
18
+ bbstrader/core/data.py,sha256=KJCGSfTGJNfLWOAytfRM4-BVNV1M6QfvH4DWB-4v4cA,26146
19
+ bbstrader/core/scripts.py,sha256=cdw0X12-8IHsr8pg6x_fMsUg_UhFFWDy9lXY52Vpou8,5777
20
+ bbstrader/core/utils.py,sha256=8PsJm73LMJf1lCjfxDlqU32U4GhWPVcUTOyyETM7fLs,3124
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
@@ -37,11 +37,11 @@ bbstrader/models/optimization.py,sha256=Fa4tdhynMmvKt5KHV9cH1TXmmJVJwU4QWpYkbeVq
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=CPjOKvVFq8ZnANQrOtpakp64ZAhn-73Bu-D9UPCKUws,41832
40
+ bbstrader/trading/execution.py,sha256=P1SrV5CKhSbi2NhztPO3pEtGVHOXkfHEdWAVYzeaMWw,42086
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.6.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
44
+ bbstrader-0.3.7.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
45
45
  docs/conf.py,sha256=q_Z8_iz-YDgHhe4PpCOAtvN5Q-2hHquliG07FDEXdjo,1686
46
46
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  tests/engine/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
@@ -49,14 +49,14 @@ tests/engine/test_backtest.py,sha256=OmHimBp518BBv0Eg-t_cIrBXMzfiYOGki5FW7kqFeFs
49
49
  tests/engine/test_data.py,sha256=jAVICMt4YTKF5PN6ZIxhQ9CuUjbw9_gIPAC4sNA9GsE,19907
50
50
  tests/engine/test_events.py,sha256=is3v3mtQVKFVNyn-xF4F7yuBGA5vqgunqsoFgNJeH0c,11755
51
51
  tests/engine/test_execution.py,sha256=Sk3d_Rl9T0GjArficd75hEeVyeB_7yOcTD8ltpN4UlY,7961
52
- tests/engine/test_portfolio.py,sha256=csKWO4W0xWn3obxuPRBFAUHHR60j-IZfAz5bv7Y_u9M,9872
52
+ tests/engine/test_portfolio.py,sha256=Anx6TtgCdyyhqfoui2kwuX8X5gtisT2tL5yZNJOUbKw,9865
53
53
  tests/metatrader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  tests/metatrader/test_account.py,sha256=UiAWP0IRd6a1kmA_pTcEuCZAJjtq0U_Q-PcOdd2l69A,68627
55
55
  tests/metatrader/test_rates.py,sha256=dc43jAvkZby9TMJcwkcaEvH21jQudk1D8KQxWLlAYoQ,10424
56
56
  tests/metatrader/test_risk_management.py,sha256=lMT0m7dmT3iWihTkEwpMoHdJPPWU3XJmqgCV4qKT-uw,31019
57
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,,
58
+ bbstrader-0.3.7.dist-info/METADATA,sha256=2l53CAyYDuXnRg0duIlsMFiGjDtGVOVYMrJwgfSWVzQ,26697
59
+ bbstrader-0.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
60
+ bbstrader-0.3.7.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
61
+ bbstrader-0.3.7.dist-info/top_level.txt,sha256=raTnmqZJ2B3Mvrhy_fV9szurE9yVctrKHBLZ1NJ5vnU,21
62
+ bbstrader-0.3.7.dist-info/RECORD,,
@@ -18,7 +18,7 @@ class MockDataHandler:
18
18
  """A mock DataHandler to control market data during tests."""
19
19
 
20
20
  def __init__(self, symbol_list, initial_data):
21
- self.symbol_list = symbol_list
21
+ self.symbols = symbol_list
22
22
  self.latest_symbol_data = initial_data
23
23
 
24
24
  def get_latest_bar_datetime(self, symbol):
@@ -90,7 +90,7 @@ def test_initialization(basic_portfolio):
90
90
  def test_tf_mapping_and_initialization_error():
91
91
  """Tests the timeframe mapping and ensures invalid timeframes raise errors."""
92
92
  mock_bars = MagicMock()
93
- mock_bars.symbol_list = ["DUMMY"]
93
+ mock_bars.symbols = ["DUMMY"]
94
94
 
95
95
  # Test a valid timeframe
96
96
  p = Portfolio(
@@ -210,6 +210,7 @@ def test_update_signal_puts_order_on_queue(basic_portfolio):
210
210
  assert order.direction == "BUY"
211
211
  assert order.quantity == 50 # 100 * 0.5
212
212
 
213
+
213
214
  @pytest.mark.filterwarnings("ignore")
214
215
  @patch("bbstrader.btengine.performance.plt.show")
215
216
  @patch("bbstrader.btengine.portfolio.plot_performance")