bbstrader 0.2.99__py3-none-any.whl → 0.2.991__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 ADDED
@@ -0,0 +1,19 @@
1
+ """
2
+ Simplified Investment & Trading Toolkit
3
+
4
+ """
5
+
6
+ __author__ = "Bertin Balouki SIMYELI"
7
+ __copyright__ = "2023-2025 Bertin Balouki SIMYELI"
8
+ __email__ = "bertin@bbstrader.com"
9
+ __license__ = "MIT"
10
+ __version__ = "0.2.0"
11
+
12
+ from bbstrader import compat # noqa: F401
13
+ from bbstrader import core # noqa: F401
14
+ from bbstrader import btengine # noqa: F401
15
+ from bbstrader import metatrader # noqa: F401
16
+ from bbstrader import models # noqa: F401
17
+ from bbstrader import trading # noqa: F401
18
+ from bbstrader import tseries # noqa: F401
19
+ from bbstrader.config import config_logger # noqa: F401
@@ -2,7 +2,7 @@ from datetime import datetime
2
2
  from enum import Enum
3
3
  from typing import Literal
4
4
 
5
- __all__ = ["Event", "MarketEvent", "SignalEvent", "OrderEvent", "FillEvent"]
5
+ __all__ = ["Event", "Events", "MarketEvent", "SignalEvent", "OrderEvent", "FillEvent"]
6
6
 
7
7
 
8
8
  class Event(object):
@@ -134,20 +134,21 @@ class OrderEvent(Event):
134
134
  self.price = price
135
135
  self.signal = signal
136
136
 
137
- def print_order(self):
138
- """
139
- Outputs the values within the Order.
140
- """
141
- print(
142
- "Order: Symbol=%s, Type=%s, Quantity=%s, Direction=%s, Price=%s"
143
- % (
144
- self.symbol,
145
- self.order_type,
146
- self.quantity,
147
- self.direction,
148
- self.price,
149
- )
137
+ def print_order(self):
138
+ """
139
+ Outputs the values within the Order.
140
+ """
141
+ print(
142
+ "Order: Symbol=%s, Type=%s, Quantity=%s, Direction=%s, Price=%s"
143
+ % (
144
+ self.symbol,
145
+ self.order_type,
146
+ self.quantity,
147
+ self.direction,
148
+ self.price,
150
149
  )
150
+ )
151
+
151
152
 
152
153
 
153
154
  class FillEvent(Event):
bbstrader/core/data.py CHANGED
@@ -2,7 +2,7 @@ import json
2
2
  import re
3
3
  import ssl
4
4
  from datetime import datetime
5
- from typing import List
5
+ from typing import List, Literal
6
6
  from urllib.request import urlopen
7
7
 
8
8
  import certifi
@@ -18,7 +18,7 @@ __all__ = ["FmpData", "FmpNews", "FinancialNews"]
18
18
 
19
19
 
20
20
  def _get_search_query(query: str) -> str:
21
- if " " in query:
21
+ if " " in query or query == "":
22
22
  return query
23
23
  try:
24
24
  name = yf.Ticker(query).info["shortName"]
@@ -422,6 +422,102 @@ class FinancialNews(object):
422
422
  def get_fmp_news(self, api=None) -> FmpNews:
423
423
  return FmpNews(api=api)
424
424
 
425
+ def get_coindesk_news(
426
+ self,
427
+ query="",
428
+ lang: Literal["EN", "ES", "TR", "FR", "JP", "PT"] = "EN",
429
+ limit=50,
430
+ list_of_str=False,
431
+ ) -> List[str] | List[dict]:
432
+ """
433
+ Fetches and filters recent news articles from CoinDesk's News API.
434
+
435
+ Args:
436
+ query : str, optional
437
+ A search term to filter articles by title, body, or keywords.
438
+ If empty, all articles are returned without filtering (default is "").
439
+
440
+ lang : Literal["EN", "ES", "TR", "FR", "JP", "PT"], optional
441
+ Language in which to fetch news articles. Supported languages:
442
+ English (EN), Spanish (ES), Turkish (TR), French (FR), Japanese (JP), and Portuguese (PT).
443
+ Default is "EN".
444
+
445
+ limit : int, optional
446
+ Maximum number of articles to retrieve. Default is 50.
447
+
448
+ list_of_str : bool, optional
449
+ If True, returns a list of strings (concatenated article content).
450
+ If False, returns a list of filtered article dictionaries.
451
+ Default is False.
452
+
453
+ Returns:
454
+ List[str] | List[dict]
455
+ - If `query` is empty: returns a list of filtered article dictionaries.
456
+ - If `query` is provided:
457
+ - Returns a list of strings if `list_of_str=True`.
458
+ - Returns a list of filtered article dictionaries otherwise.
459
+
460
+ Each article dictionary contains the following fields:
461
+ - 'published_on': datetime of publication
462
+ - 'title': article headline
463
+ - 'subtitle': secondary headline
464
+ - 'url': direct link to the article
465
+ - 'body': article content
466
+ - 'keywords': associated tags
467
+ - 'sentiment': sentiment label
468
+ - 'status': publication status
469
+
470
+ Notes:
471
+ - Articles marked as sponsored are automatically excluded.
472
+ """
473
+ maximum = 100
474
+ if limit > maximum:
475
+ raise ValueError(f"Number of total news articles allowed is {maximum}")
476
+
477
+ response = requests.get(
478
+ "https://data-api.coindesk.com/news/v1/article/list",
479
+ params={"lang": lang, "limit": limit},
480
+ headers={"Content-type": "application/json; charset=UTF-8"},
481
+ )
482
+ json_response = response.json()
483
+ articles = json_response["Data"]
484
+ if len(articles) == 0:
485
+ return []
486
+ to_keep = [
487
+ "PUBLISHED_ON",
488
+ "TITLE",
489
+ "SUBTITLE",
490
+ "URL",
491
+ "BODY",
492
+ "KEYWORDS",
493
+ "SENTIMENT",
494
+ "STATUS",
495
+ ]
496
+ filtered_articles = []
497
+ for article in articles:
498
+ filtered_articles.append(
499
+ {
500
+ k.lower(): article[k]
501
+ if k in article and k != "PUBLISHED_ON"
502
+ else datetime.fromtimestamp(article[k])
503
+ for k in to_keep
504
+ if article[k] is not None and "sponsored" not in str(article[k])
505
+ }
506
+ )
507
+ if query == "" or len(filtered_articles) == 0:
508
+ return filtered_articles
509
+ to_return = []
510
+ query = _get_search_query(query)
511
+ for article in filtered_articles:
512
+ if not all(k in article for k in ("title", "body", "keywords")):
513
+ continue
514
+ text = article["title"] + " " + article["body"] + " " + article["keywords"]
515
+ if list_of_str and _find_news(query, text=text):
516
+ to_return.append(text)
517
+ if not list_of_str and _find_news(query, text=text):
518
+ to_return.append(article)
519
+ return to_return
520
+
425
521
 
426
522
  class FmpData(Toolkit):
427
523
  """
@@ -531,6 +531,7 @@ class Trade(RiskManagement):
531
531
  mm (bool): Weither to put stop loss and tp or not
532
532
  trail (bool): Weither to trail the stop loss or not
533
533
  comment (str): The comment for the opening position
534
+ volume (float): The volume (lot) to trade
534
535
  sl (float): The stop loss price
535
536
  tp (float): The take profit price
536
537
  """
@@ -621,7 +622,6 @@ class Trade(RiskManagement):
621
622
  mm (bool): Weither to put stop loss and tp or not
622
623
  trail (bool): Weither to trail the stop loss or not
623
624
  comment (str): The comment for the closing position
624
- symbol (str): The symbol to trade
625
625
  volume (float): The volume (lot) to trade
626
626
  sl (float): The stop loss price
627
627
  tp (float): The take profit price
bbstrader/models/nlp.py CHANGED
@@ -506,6 +506,7 @@ class SentimentAnalyzer(object):
506
506
  reddit_posts = news.get_reddit_posts(
507
507
  ticker, n_posts=top_news, **{k: kwargs.get(k) for k in rd_params}
508
508
  )
509
+ coindesk_news = news.get_coindesk_news(query=ticker, list_of_str=True)
509
510
  fmp_source_news = []
510
511
  fmp_news = news.get_fmp_news(kwargs.get("fmp_api"))
511
512
  for source in ["articles"]: # , "releases", asset_type]:
@@ -518,7 +519,7 @@ class SentimentAnalyzer(object):
518
519
  source_news = []
519
520
  if any([len(s) > 0 for s in [yahoo_news, google_news]]):
520
521
  sources += 1
521
- for source in [reddit_posts, fmp_source_news]:
522
+ for source in [reddit_posts, fmp_source_news, coindesk_news]:
522
523
  if len(source) > 0:
523
524
  sources += 1
524
525
  # Compute sentiment
@@ -531,11 +532,17 @@ class SentimentAnalyzer(object):
531
532
  fmp_sentiment = self.analyze_sentiment(
532
533
  fmp_source_news, lexicon=lexicon, textblob=True
533
534
  )
535
+ coindesk_sentiment = self.analyze_sentiment(
536
+ coindesk_news, lexicon=lexicon, textblob=True
537
+ )
534
538
 
535
539
  # Weighted average sentiment score
536
540
  if sources != 0:
537
541
  overall_sentiment = (
538
- news_sentiment + reddit_sentiment + fmp_sentiment
542
+ news_sentiment
543
+ + reddit_sentiment
544
+ + fmp_sentiment
545
+ + coindesk_sentiment
539
546
  ) / sources
540
547
  else:
541
548
  overall_sentiment = 0.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bbstrader
3
- Version: 0.2.99
3
+ Version: 0.2.991
4
4
  Summary: Simplified Investment & Trading Toolkit
5
5
  Home-page: https://github.com/bbalouki/bbstrader
6
6
  Download-URL: https://pypi.org/project/bbstrader/
@@ -81,8 +81,6 @@ Dynamic: requires-dist
81
81
  Dynamic: summary
82
82
 
83
83
  # Simplified Investment & Trading Toolkit
84
- ![bbstrader](https://github.com/bbalouki/bbstrader/blob/main/assets/bbstrader_logo.png?raw=true)
85
-
86
84
  [![Documentation Status](https://readthedocs.org/projects/bbstrader/badge/?version=latest)](https://bbstrader.readthedocs.io/en/latest/?badge=latest)
87
85
  [![PYPI Version](https://img.shields.io/pypi/v/bbstrader)](https://pypi.org/project/bbstrader/)
88
86
  [![PyPi status](https://img.shields.io/pypi/status/bbstrader.svg?maxAge=60)](https://pypi.python.org/pypi/bbstrader)
@@ -1,4 +1,5 @@
1
1
  bbstrader/__ini__.py,sha256=v6zyJHj5FMRL-_P7AwnTGbCF-riMqhqlTvDgfulj7go,621
2
+ bbstrader/__init__.py,sha256=5q_NaxJHcGYUVhC8cMWO3ZDJhjta7MrphQTYqganepY,581
2
3
  bbstrader/__main__.py,sha256=sDdjoiaHSPrVqdjU_zOLajX3rD_3Ha6dHwIivYc_vp4,1525
3
4
  bbstrader/compat.py,sha256=djbHMvTvy0HYm1zyZ6Ttp_LMwP2PqTSVw1r7pqbz7So,487
4
5
  bbstrader/config.py,sha256=c2nCUw-bYWf5kkyFls5Nqld8HdMczexSilTni7rYUBw,3973
@@ -6,14 +7,14 @@ bbstrader/tseries.py,sha256=H4D_A966HdN8YjBfuCcF8QBQdhjOrTcidR98wP2KN_I,68339
6
7
  bbstrader/btengine/__init__.py,sha256=y1btjaEfhWsH8vuE7mBRpP9Tu-Azt9REhuVYsPCAfBU,2955
7
8
  bbstrader/btengine/backtest.py,sha256=UiOmtqYSh72KZz0DCXz8iKrqTCOkx9Er3XjqK6H9Do8,14765
8
9
  bbstrader/btengine/data.py,sha256=Tuc6M8itbGpPjsfRpZBB8v0FJpPt7-hUkP6I5meP0Sg,26927
9
- bbstrader/btengine/event.py,sha256=gC2nqWU_t1pRzg4DYYey-mbaBo8T_JOPzzAzRF53U7o,8757
10
+ bbstrader/btengine/event.py,sha256=Ydl1avAXp9WAWOBXDAckcb9g1UkcnCO0rRzcJZwIq20,8714
10
11
  bbstrader/btengine/execution.py,sha256=tN7QIx0PHiQmJcn3MdSQiwwAYCDxFDn3C4i5tlM5xoY,10605
11
12
  bbstrader/btengine/performance.py,sha256=1ecWrTzHBQbk4ORvbTEKxwCzlL1brcXOEUwgbnjAwx4,12470
12
13
  bbstrader/btengine/portfolio.py,sha256=z98M65HQeCyma8gMZkAxspxBA9jtIhzxMyJUHPPj34c,16128
13
14
  bbstrader/btengine/scripts.py,sha256=8o66dq4Ex4DsH4s8xvJqUOFjLzZJSnbBvvNBzohtzoE,4837
14
15
  bbstrader/btengine/strategy.py,sha256=FrYoB8ogHODTfRDZf2gW-CGdTxdVoIYwxko1cYgwcgg,31631
15
16
  bbstrader/core/__init__.py,sha256=GIFzFSStPfE0XM2j7mDeZZQeMTh_AwPsDOQXwMVJLgw,97
16
- bbstrader/core/data.py,sha256=VPuynoT0uFYduh7la8gZSnEv_Gq8Xu2vJZJ7TfQMll8,18797
17
+ bbstrader/core/data.py,sha256=hStrx-QTYFjpJdZOJVtV2xmIyywj6T9_Rn3hhNYtFwU,22581
17
18
  bbstrader/core/utils.py,sha256=WjuabzBjhY65ku2KL-f7CMalE2x-wrX-6mCA_qhhFPE,2728
18
19
  bbstrader/ibkr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
20
  bbstrader/ibkr/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -24,12 +25,12 @@ bbstrader/metatrader/copier.py,sha256=pCZkRfkUWxufnmiO0cc1Kz6UF59HTUUGs-c60LYNUb
24
25
  bbstrader/metatrader/rates.py,sha256=0bKyjGnafZ19DwC0-IxXUBJzOdAo-cNmhabwhKLxcos,20585
25
26
  bbstrader/metatrader/risk.py,sha256=pwG4q1_uPGgPlokDGVNtd04O6p28yIbgT-evvHuo-Qc,27029
26
27
  bbstrader/metatrader/scripts.py,sha256=Yjp7Un-wDTInptHS_rPFpXNKWbVM871VEkaHxsO2MPQ,2115
27
- bbstrader/metatrader/trade.py,sha256=2vkoe972OUi5m5rVkWa2DuyXSo04JCSsF5tyahDbL3s,79926
28
+ bbstrader/metatrader/trade.py,sha256=uDlYCHqXk4AB0Nx8CHQfYUj4OODhm7W39es0r6Yuc8Q,79922
28
29
  bbstrader/metatrader/utils.py,sha256=szORxKJW9OG-H6nof_ovOhToSx_n8EtVwe0mkLt3eFg,17424
29
30
  bbstrader/models/__init__.py,sha256=s2mJrtKePXQaw_PvcrtPCD2mPCdVXP4Myzg0MlLVipo,547
30
31
  bbstrader/models/factors.py,sha256=-ODeD2GK4nmxFQAIh5MF3SFM9ofppi2pW6Q728LzLv8,12701
31
32
  bbstrader/models/ml.py,sha256=tCr7YyODl0CDoOUpYqJ1q12ls86Sc-_Fu3b2Y0Z7TJ8,47551
32
- bbstrader/models/nlp.py,sha256=P7SYaTIqEBldjwYfS6IrO66Y6-ioDXUrCSf3bZxQrDE,28073
33
+ bbstrader/models/nlp.py,sha256=eN4VnexOt1intfX1T-GkaReqBoWPjoqRSWjXIa67ib8,28385
33
34
  bbstrader/models/optimization.py,sha256=vnks6uxFZdqXgxaZJNxq8z0IH45KZ8yaXo38JhIVKGc,6399
34
35
  bbstrader/models/portfolio.py,sha256=r-47Zrn2r7iKCHm5YVtwkbBJXAZGM3QYy-rXCWY9-Bg,8079
35
36
  bbstrader/models/risk.py,sha256=JQOXPshMOru6Eb0AMU6oKCNzg6mlGfL6_tN90lWcVBE,14878
@@ -38,9 +39,9 @@ bbstrader/trading/execution.py,sha256=ukOiv1O-a_SdKp35QlU_3_Wt_7CTgh4pLPN9s7qPEd
38
39
  bbstrader/trading/scripts.py,sha256=Tf5q33WqqygjpIv43_8nA82VZ3GM0qgb4Ggo3fHJ_wg,5744
39
40
  bbstrader/trading/strategies.py,sha256=rRNPZM1Z9twzO5UWd5qI3FgkZmOhF3Dd2h7XRn7EoDs,37011
40
41
  bbstrader/trading/utils.py,sha256=57dKF9dcRu04oU2VRqydRrzW39dCW2wlDWhVt-sZdRw,1857
41
- bbstrader-0.2.99.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
42
- bbstrader-0.2.99.dist-info/METADATA,sha256=8JnFfL70KEiiqXvBhDEoqafZ4-KMTNtbheytb3-5HZ4,11508
43
- bbstrader-0.2.99.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
44
- bbstrader-0.2.99.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
45
- bbstrader-0.2.99.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
46
- bbstrader-0.2.99.dist-info/RECORD,,
42
+ bbstrader-0.2.991.dist-info/licenses/LICENSE,sha256=ZwC_RqqGmOPBUiMDKqLyJZ5HBeHq53LpL7TMRzrJY8c,1094
43
+ bbstrader-0.2.991.dist-info/METADATA,sha256=p3lY0rHksdL6iOhw5Qunyyn_vWPQc8b5CQKrP3mErnM,11411
44
+ bbstrader-0.2.991.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
45
+ bbstrader-0.2.991.dist-info/entry_points.txt,sha256=0yDCbhbgHswOzJnY5wRSM_FjjyMHGvY7lJpSSVh0xtI,54
46
+ bbstrader-0.2.991.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
47
+ bbstrader-0.2.991.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5