bbstrader 0.3.5__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.

Files changed (45) hide show
  1. bbstrader/__init__.py +11 -2
  2. bbstrader/__main__.py +6 -1
  3. bbstrader/apps/_copier.py +43 -40
  4. bbstrader/btengine/backtest.py +33 -28
  5. bbstrader/btengine/data.py +105 -81
  6. bbstrader/btengine/event.py +21 -22
  7. bbstrader/btengine/execution.py +51 -24
  8. bbstrader/btengine/performance.py +23 -12
  9. bbstrader/btengine/portfolio.py +40 -30
  10. bbstrader/btengine/scripts.py +13 -12
  11. bbstrader/btengine/strategy.py +396 -134
  12. bbstrader/compat.py +4 -3
  13. bbstrader/config.py +20 -36
  14. bbstrader/core/data.py +76 -48
  15. bbstrader/core/scripts.py +22 -21
  16. bbstrader/core/utils.py +13 -12
  17. bbstrader/metatrader/account.py +51 -26
  18. bbstrader/metatrader/analysis.py +30 -16
  19. bbstrader/metatrader/copier.py +75 -40
  20. bbstrader/metatrader/trade.py +29 -39
  21. bbstrader/metatrader/utils.py +5 -4
  22. bbstrader/models/nlp.py +83 -66
  23. bbstrader/trading/execution.py +45 -22
  24. bbstrader/tseries.py +158 -166
  25. {bbstrader-0.3.5.dist-info → bbstrader-0.3.7.dist-info}/METADATA +7 -21
  26. bbstrader-0.3.7.dist-info/RECORD +62 -0
  27. bbstrader-0.3.7.dist-info/top_level.txt +3 -0
  28. docs/conf.py +56 -0
  29. tests/__init__.py +0 -0
  30. tests/engine/__init__.py +1 -0
  31. tests/engine/test_backtest.py +58 -0
  32. tests/engine/test_data.py +536 -0
  33. tests/engine/test_events.py +300 -0
  34. tests/engine/test_execution.py +219 -0
  35. tests/engine/test_portfolio.py +308 -0
  36. tests/metatrader/__init__.py +0 -0
  37. tests/metatrader/test_account.py +1769 -0
  38. tests/metatrader/test_rates.py +292 -0
  39. tests/metatrader/test_risk_management.py +700 -0
  40. tests/metatrader/test_trade.py +439 -0
  41. bbstrader-0.3.5.dist-info/RECORD +0 -49
  42. bbstrader-0.3.5.dist-info/top_level.txt +0 -1
  43. {bbstrader-0.3.5.dist-info → bbstrader-0.3.7.dist-info}/WHEEL +0 -0
  44. {bbstrader-0.3.5.dist-info → bbstrader-0.3.7.dist-info}/entry_points.txt +0 -0
  45. {bbstrader-0.3.5.dist-info → bbstrader-0.3.7.dist-info}/licenses/LICENSE +0 -0
bbstrader/models/nlp.py CHANGED
@@ -577,44 +577,55 @@ class SentimentAnalyzer(object):
577
577
  **kwargs,
578
578
  ) -> Dict[str, float]:
579
579
  """
580
- Computes sentiment scores for a list of financial tickers based on news and social media data.
581
-
582
- Process:
583
- 1. Collects news articles and posts related to each ticker from various sources:
584
- - Yahoo Finance News
585
- - Google Finance News
586
- - Reddit posts
587
- - Financial Modeling Prep (FMP) news
588
- 2. Analyzes sentiment from each source:
589
- - Uses VADER for Yahoo and Google Finance news.
590
- - Uses TextBlob for Reddit and FMP news.
591
- 3. Computes an overall sentiment score using a weighted average approach.
592
-
593
- Args:
594
- tickers (List[str] | List[Tuple[str, str]]): A list of asset tickers to analyze
595
- - if using tuples, the first element is the ticker and the second is the asset type.
596
- - if using a single string, the asset type must be specified or the default is "stock".
597
- lexicon (dict, optional): A custom sentiment lexicon to update VADER's default lexicon.
598
- asset_type (str, optional): The type of asset, Defaults to "stock",
599
- supported types include:
600
- - "stock": Stock symbols (e.g., AAPL, MSFT)
601
- - "etf": Exchange-traded funds (e.g., SPY, QQQ)
602
- - "future": Futures contracts (e.g., CL=F for crude oil)
603
- - "forex": Forex pairs (e.g., EURUSD=X, USDJPY=X)
604
- - "crypto": Cryptocurrency pairs (e.g., BTC-USD, ETH-USD)
605
- - "index": Stock market indices (e.g., ^GSPC for S&P 500)
606
- top_news (int, optional): Number of news articles/posts to fetch per source. Defaults to 10.
607
- **kwargs: Additional parameters for API authentication and data retrieval, including:
608
- - fmp_api (str): API key for Financial Modeling Prep.
609
- - client_id, client_secret, user_agent (str): Credentials for accessing Reddit API.
610
-
611
- Returns:
612
- Dict[str, float]: A dictionary mapping each ticker to its overall sentiment score.
613
- - Positive values indicate positive sentiment.
614
- - Negative values indicate negative sentiment.
615
- - Zero indicates neutral sentiment.
616
- Notes:
617
- The tickers names must follow yahoo finance conventions.
580
+ Compute sentiment scores for a list of financial tickers based on news and social media data.
581
+
582
+ Process
583
+ -------
584
+ 1. Collect news articles and posts related to each ticker from various sources:
585
+ * Yahoo Finance News
586
+ * Google Finance News
587
+ * Reddit posts
588
+ * Financial Modeling Prep (FMP) news
589
+ 2. Analyze sentiment from each source:
590
+ * Uses VADER for Yahoo and Google Finance news.
591
+ * Uses TextBlob for Reddit and FMP news.
592
+ 3. Compute an overall sentiment score using a weighted average approach.
593
+
594
+ Parameters
595
+ ----------
596
+ tickers : list of str or list of tuple
597
+ A list of asset tickers to analyze.
598
+ * If using tuples, the first element is the ticker and the second is the asset type.
599
+ * If using a single string, the asset type must be specified or defaults to "stock".
600
+ lexicon : dict, optional
601
+ A custom sentiment lexicon to update VADER's default lexicon. Default is None.
602
+ asset_type : str, optional
603
+ The type of asset. Default is "stock".
604
+ Supported types include:
605
+ * "stock": Stock symbols (e.g., AAPL, MSFT)
606
+ * "etf": Exchange-traded funds (e.g., SPY, QQQ)
607
+ * "future": Futures contracts (e.g., CL=F for crude oil)
608
+ * "forex": Forex pairs (e.g., EURUSD=X, USDJPY=X)
609
+ * "crypto": Cryptocurrency pairs (e.g., BTC-USD, ETH-USD)
610
+ * "index": Stock market indices (e.g., ^GSPC for S&P 500)
611
+ top_news : int, optional
612
+ Number of news articles/posts to fetch per source. Default is 10.
613
+ **kwargs : dict
614
+ Additional parameters for API authentication and data retrieval. Must include:
615
+ * fmp_api (str): API key for Financial Modeling Prep.
616
+ * client_id, client_secret, user_agent (str): Credentials for Reddit API.
617
+
618
+ Returns
619
+ -------
620
+ dict of str to float
621
+ A dictionary mapping each ticker to its overall sentiment score.
622
+ * Positive values indicate positive sentiment.
623
+ * Negative values indicate negative sentiment.
624
+ * Zero indicates neutral sentiment.
625
+
626
+ Notes
627
+ -----
628
+ Ticker names must follow Yahoo Finance conventions.
618
629
  """
619
630
 
620
631
  sentiment_results = {}
@@ -761,30 +772,36 @@ class SentimentAnalyzer(object):
761
772
  The dashboard visualizes sentiment scores for given tickers using interactive
762
773
  bar and scatter plots. It fetches new sentiment data at specified intervals.
763
774
 
764
- Args:
765
- tickers (List[str] | List[Tuple[str, str]]):
766
- A list of financial asset tickers to analyze.
767
- - If using tuples, the first element is the ticker and the second is the asset type.
768
- - If using a single string, the asset type must be specified or defaults to "stock".
769
- asset_type (str, optional):
770
- The type of financial asset ("stock", "forex", "crypto"). Defaults to "stock".
771
- lexicon (dict, optional):
772
- A custom sentiment lexicon. Defaults to None.
773
- interval (int, optional):
774
- The refresh interval (in milliseconds) for sentiment data updates. Defaults to 100000.
775
- top_n (int, optional):
776
- The number of top and bottom assets to display in the sentiment bar chart. Defaults to 20.
777
- **kwargs (dict):
778
- Additional arguments required for fetching sentiment data. Must include:
779
- - client_id (str): Reddit API client ID.
780
- - client_secret (str): Reddit API client secret.
781
- - user_agent (str): User agent for Reddit API.
782
- - fmp_api (str): Financial Modeling Prep (FMP) API key.
783
-
784
- Returns:
785
- None: The function does not return anything but starts a real-time interactive dashboard.
775
+ Parameters
776
+ ----------
777
+ tickers : list of str or list of tuple
778
+ A list of financial asset tickers to analyze.
779
+ * If using tuples, the first element is the ticker and the second is the asset type.
780
+ * If using a single string, the asset type must be specified or defaults to "stock".
781
+ asset_type : str, optional
782
+ The type of financial asset ("stock", "forex", "crypto"). Default is "stock".
783
+ lexicon : dict, optional
784
+ A custom sentiment lexicon. Default is None.
785
+ interval : int, optional
786
+ The refresh interval (in milliseconds) for sentiment data updates. Default is 100000.
787
+ top_n : int, optional
788
+ The number of top and bottom assets to display in the sentiment bar chart. Default is 20.
789
+ **kwargs : dict
790
+ Additional arguments required for fetching sentiment data. Must include:
791
+ * client_id (str): Reddit API client ID.
792
+ * client_secret (str): Reddit API client secret.
793
+ * user_agent (str): User agent for Reddit API.
794
+ * fmp_api (str): Financial Modeling Prep (FMP) API key.
795
+
796
+ Returns
797
+ -------
798
+ None
799
+ Starts a real-time interactive dashboard. Does not return any value.
800
+
801
+ Example
802
+ -------
803
+ .. code-block:: python
786
804
 
787
- Example Usage:
788
805
  sa = SentimentAnalyzer()
789
806
  sa.display_sentiment_dashboard(
790
807
  tickers=["AAPL", "TSLA", "GOOGL"],
@@ -799,12 +816,12 @@ class SentimentAnalyzer(object):
799
816
  fmp_api="your_fmp_api_key",
800
817
  )
801
818
 
802
- Notes:
803
- - Sentiment analysis is performed using financial news and social media discussions.
804
- - The dashboard updates in real-time at the specified interval.
805
- - The dashboard will keep running unless manually stopped (Ctrl+C).
819
+ Notes
820
+ -----
821
+ * Sentiment analysis is performed using financial news and social media discussions.
822
+ * The dashboard updates in real-time at the specified interval.
823
+ * The dashboard will keep running unless manually stopped (Ctrl+C).
806
824
  """
807
-
808
825
  app = dash.Dash(__name__)
809
826
 
810
827
  sentiment_history = {ticker: [] for ticker in tickers}
@@ -45,6 +45,7 @@ MT5_ENGINE_TIMEFRAMES = list(_TF_MAPPING.keys())
45
45
  TradingDays = ["monday", "tuesday", "wednesday", "thursday", "friday"]
46
46
  WEEK_DAYS = TradingDays + ["saturday", "sunday"]
47
47
  FRIDAY = "friday"
48
+ WEEK_ENDS = ["friday", "saturday", "sunday"]
48
49
 
49
50
  BUYS = ["BMKT", "BLMT", "BSTP", "BSTPLMT"]
50
51
  SELLS = ["SMKT", "SLMT", "SSTP", "SSTPLMT"]
@@ -513,17 +514,12 @@ class Mt5ExecutionEngine:
513
514
  logger.info(sessionmsg)
514
515
 
515
516
  def _check_is_day_ends(self, trade: Trade, symbol, period_type, today, closing):
516
- if trade.days_end():
517
- self._logmsgif("Day", symbol) if today != FRIDAY else self._logmsgif(
517
+ if trade.days_end() or (today in WEEK_ENDS and today != FRIDAY):
518
+ self._logmsgif("Day", symbol) if today not in WEEK_ENDS else self._logmsgif(
518
519
  "Week", symbol
519
520
  )
520
521
  if (
521
- (
522
- period_type == "month"
523
- and today == FRIDAY
524
- and self._is_month_ends()
525
- and closing
526
- )
522
+ (period_type == "month" and self._is_month_ends() and closing)
527
523
  or (period_type == "week" and today == FRIDAY and closing)
528
524
  or (period_type == "day" and closing)
529
525
  or (period_type == "24/7" and closing)
@@ -546,15 +542,17 @@ class Mt5ExecutionEngine:
546
542
  self.strategy.perform_period_end_checks()
547
543
  if self.period_end_action == "break" and closing:
548
544
  sys.exit(0)
549
- elif self.period_end_action == "sleep" and today != FRIDAY or not closing:
545
+ elif (
546
+ self.period_end_action == "sleep" and today not in WEEK_ENDS or not closing
547
+ ):
550
548
  self._sleep_over_night(sessionmsg)
551
- elif self.period_end_action == "sleep" and today == FRIDAY:
549
+ elif self.period_end_action == "sleep" and today in WEEK_ENDS:
552
550
  self._sleep_over_weekend(sessionmsg)
553
551
 
554
552
  def _weekly_end_checks(self, today, closing, sessionmsg):
555
- if today != FRIDAY:
553
+ if today not in WEEK_ENDS:
556
554
  self._sleep_over_night(sessionmsg)
557
- elif today == FRIDAY:
555
+ else:
558
556
  self.strategy.perform_period_end_checks()
559
557
  if self.period_end_action == "break" and closing:
560
558
  sys.exit(0)
@@ -562,9 +560,9 @@ class Mt5ExecutionEngine:
562
560
  self._sleep_over_weekend(sessionmsg)
563
561
 
564
562
  def _monthly_end_cheks(self, today, closing, sessionmsg):
565
- if today != FRIDAY:
563
+ if today not in WEEK_ENDS and not self._is_month_ends():
566
564
  self._sleep_over_night(sessionmsg)
567
- elif today == FRIDAY and self._is_month_ends() and closing:
565
+ elif self._is_month_ends() and closing:
568
566
  self.strategy.perform_period_end_checks()
569
567
  sys.exit(0)
570
568
  else:
@@ -956,7 +954,11 @@ class Mt5ExecutionEngine:
956
954
  def _handle_period_end_actions(self, today):
957
955
  try:
958
956
  check_mt5_connection(**self.kwargs)
959
- day_end = all(trade.days_end() for trade in self.trades_instances.values())
957
+ day_end = (
958
+ all(trade.days_end() for trade in self.trades_instances.values())
959
+ or (today in WEEK_ENDS and today != FRIDAY)
960
+ and self.period != "24/7"
961
+ )
960
962
  closing = self._is_closing()
961
963
  sessionmsg = f"{self.ACCOUNT} STARTING NEW TRADING SESSION ...\n"
962
964
  self._perform_period_end_actions(
@@ -969,11 +971,17 @@ class Mt5ExecutionEngine:
969
971
  msg = f"Handling period end actions, STRATEGY={self.STRATEGY} , ACCOUNT={self.ACCOUNT}"
970
972
  self._print_exc(msg, e)
971
973
  pass
974
+
975
+ def select_symbols(self):
976
+ for symbol in self.symbols:
977
+ if not MT5.symbol_select(symbol, True):
978
+ logger.error(f"Failed to select symbol {symbol} error = {MT5.last_error()}")
972
979
 
973
980
  def run(self):
974
981
  while self._running and not self.shutdown_event.is_set():
975
982
  try:
976
983
  check_mt5_connection(**self.kwargs)
984
+ self.select_symbols()
977
985
  positions_orders = self._check_positions_orders()
978
986
  if self.show_positions_orders:
979
987
  self._display_positions_orders(positions_orders)
@@ -1012,13 +1020,28 @@ class Mt5ExecutionEngine:
1012
1020
 
1013
1021
 
1014
1022
  def RunMt5Engine(account_id: str, **kwargs):
1015
- """Starts an MT5 execution engine for a given account.
1016
- Args:
1017
- account_id: Account ID to run the execution engine on.
1018
- **kwargs: Additional keyword arguments
1019
- _ symbol_list : List of symbols to trade.
1020
- - trades_instances : Dictionary of Trade instances.
1021
- - strategy_cls : Strategy class to use for trading.
1023
+ """
1024
+ Start an MT5 execution engine for a given account.
1025
+
1026
+ Parameters
1027
+ ----------
1028
+ account_id : str
1029
+ Account ID to run the execution engine on.
1030
+
1031
+ **kwargs : dict
1032
+ Additional keyword arguments. Possible keys include:
1033
+
1034
+ * symbol_list : list
1035
+ List of symbols to trade.
1036
+ * trades_instances : dict
1037
+ Dictionary of Trade instances.
1038
+ * strategy_cls : class
1039
+ Strategy class to use for trading.
1040
+
1041
+ Returns
1042
+ -------
1043
+ None
1044
+ Initializes and runs the MT5 execution engine.
1022
1045
  """
1023
1046
  log.info(f"Starting execution engine for {account_id}")
1024
1047