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.
- bbstrader/__init__.py +11 -2
- bbstrader/__main__.py +6 -1
- bbstrader/apps/_copier.py +43 -40
- bbstrader/btengine/backtest.py +33 -28
- bbstrader/btengine/data.py +105 -81
- bbstrader/btengine/event.py +21 -22
- bbstrader/btengine/execution.py +51 -24
- bbstrader/btengine/performance.py +23 -12
- bbstrader/btengine/portfolio.py +40 -30
- bbstrader/btengine/scripts.py +13 -12
- bbstrader/btengine/strategy.py +396 -134
- bbstrader/compat.py +4 -3
- bbstrader/config.py +20 -36
- bbstrader/core/data.py +76 -48
- bbstrader/core/scripts.py +22 -21
- bbstrader/core/utils.py +13 -12
- 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 +45 -22
- bbstrader/tseries.py +158 -166
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.7.dist-info}/METADATA +7 -21
- bbstrader-0.3.7.dist-info/RECORD +62 -0
- bbstrader-0.3.7.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 +308 -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/RECORD +0 -49
- bbstrader-0.3.5.dist-info/top_level.txt +0 -1
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.7.dist-info}/WHEEL +0 -0
- {bbstrader-0.3.5.dist-info → bbstrader-0.3.7.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
|
581
|
-
|
|
582
|
-
Process
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
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
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
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
|
-
|
|
804
|
-
|
|
805
|
-
|
|
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}
|
bbstrader/trading/execution.py
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
553
|
+
if today not in WEEK_ENDS:
|
|
556
554
|
self._sleep_over_night(sessionmsg)
|
|
557
|
-
|
|
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
|
|
563
|
+
if today not in WEEK_ENDS and not self._is_month_ends():
|
|
566
564
|
self._sleep_over_night(sessionmsg)
|
|
567
|
-
elif
|
|
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 =
|
|
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
|
-
"""
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
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
|
|