bbstrader 0.2.95__tar.gz → 0.2.97__tar.gz
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-0.2.95/bbstrader.egg-info → bbstrader-0.2.97}/PKG-INFO +11 -2
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/__main__.py +3 -2
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/data.py +6 -6
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/execution.py +1 -1
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/strategy.py +87 -99
- bbstrader-0.2.97/bbstrader/core/__init__.py +2 -0
- bbstrader-0.2.97/bbstrader/core/data.py +439 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/core/utils.py +2 -58
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/copier.py +1 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/trade.py +157 -11
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/models/__init__.py +1 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/models/ml.py +7 -7
- bbstrader-0.2.97/bbstrader/models/nlp.py +784 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/models/risk.py +2 -2
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/trading/execution.py +18 -7
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/trading/strategies.py +6 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97/bbstrader.egg-info}/PKG-INFO +11 -2
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader.egg-info/SOURCES.txt +3 -2
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader.egg-info/requires.txt +8 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/requirements.txt +8 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/setup.py +1 -1
- bbstrader-0.2.95/bbstrader/core/data.py +0 -22
- bbstrader-0.2.95/bbstrader/ibkr/__init__.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/LICENSE +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/MANIFEST.in +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/README.md +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/__ini__.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/__init__.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/backtest.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/event.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/performance.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/portfolio.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/btengine/scripts.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/compat.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/config.py +0 -0
- {bbstrader-0.2.95/bbstrader/core → bbstrader-0.2.97/bbstrader/ibkr}/__init__.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/ibkr/utils.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/__init__.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/account.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/rates.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/risk.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/scripts.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/metatrader/utils.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/models/factors.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/models/optimization.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/models/portfolio.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/trading/__init__.py +0 -0
- /bbstrader-0.2.95/bbstrader/trading/script.py → /bbstrader-0.2.97/bbstrader/trading/scripts.py +0 -0
- /bbstrader-0.2.95/bbstrader/trading/scripts.py → /bbstrader-0.2.97/bbstrader/trading/utils.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader/tseries.py +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader.egg-info/dependency_links.txt +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader.egg-info/entry_points.txt +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/bbstrader.egg-info/top_level.txt +0 -0
- {bbstrader-0.2.95 → bbstrader-0.2.97}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: bbstrader
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.97
|
|
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/
|
|
@@ -58,6 +58,14 @@ Requires-Dist: lightgbm
|
|
|
58
58
|
Requires-Dist: alphalens-reloaded
|
|
59
59
|
Requires-Dist: pyfiglet
|
|
60
60
|
Requires-Dist: colorama
|
|
61
|
+
Requires-Dist: praw
|
|
62
|
+
Requires-Dist: tweepy
|
|
63
|
+
Requires-Dist: beautifulsoup4
|
|
64
|
+
Requires-Dist: dash
|
|
65
|
+
Requires-Dist: nltk
|
|
66
|
+
Requires-Dist: spacy
|
|
67
|
+
Requires-Dist: textblob
|
|
68
|
+
Requires-Dist: vaderSentiment
|
|
61
69
|
Provides-Extra: mt5
|
|
62
70
|
Requires-Dist: MetaTrader5; extra == "mt5"
|
|
63
71
|
Dynamic: author
|
|
@@ -69,6 +77,7 @@ Dynamic: download-url
|
|
|
69
77
|
Dynamic: home-page
|
|
70
78
|
Dynamic: keywords
|
|
71
79
|
Dynamic: license
|
|
80
|
+
Dynamic: license-file
|
|
72
81
|
Dynamic: maintainer
|
|
73
82
|
Dynamic: project-url
|
|
74
83
|
Dynamic: provides-extra
|
|
@@ -6,7 +6,7 @@ from colorama import Fore
|
|
|
6
6
|
|
|
7
7
|
from bbstrader.btengine.scripts import backtest
|
|
8
8
|
from bbstrader.metatrader.scripts import copy_trades
|
|
9
|
-
from bbstrader.trading.
|
|
9
|
+
from bbstrader.trading.scripts import execute_strategy
|
|
10
10
|
|
|
11
11
|
DESCRIPTION = "BBSTRADER"
|
|
12
12
|
USAGE_TEXT = """
|
|
@@ -26,6 +26,7 @@ FONT = pyfiglet.figlet_format("BBSTRADER", font="big")
|
|
|
26
26
|
|
|
27
27
|
def main():
|
|
28
28
|
print(Fore.BLUE + FONT)
|
|
29
|
+
print(Fore.WHITE + "")
|
|
29
30
|
parser = argparse.ArgumentParser(
|
|
30
31
|
prog="BBSTRADER",
|
|
31
32
|
usage=USAGE_TEXT,
|
|
@@ -36,7 +37,7 @@ def main():
|
|
|
36
37
|
parser.add_argument("--run", type=str, nargs="?", default=None, help="Run a module")
|
|
37
38
|
args, unknown = parser.parse_known_args()
|
|
38
39
|
if ("-h" in sys.argv or "--help" in sys.argv) and args.run is None:
|
|
39
|
-
print(USAGE_TEXT)
|
|
40
|
+
print(Fore.WHITE + USAGE_TEXT)
|
|
40
41
|
sys.exit(0)
|
|
41
42
|
if args.run == "copier":
|
|
42
43
|
copy_trades(unknown)
|
|
@@ -66,21 +66,21 @@ class DataHandler(metaclass=ABCMeta):
|
|
|
66
66
|
"""
|
|
67
67
|
Returns the last bar updated.
|
|
68
68
|
"""
|
|
69
|
-
|
|
69
|
+
pass
|
|
70
70
|
|
|
71
71
|
@abstractmethod
|
|
72
72
|
def get_latest_bars(self, symbol, N=1, df=True) -> pd.DataFrame | List[pd.Series]:
|
|
73
73
|
"""
|
|
74
74
|
Returns the last N bars updated.
|
|
75
75
|
"""
|
|
76
|
-
|
|
76
|
+
pass
|
|
77
77
|
|
|
78
78
|
@abstractmethod
|
|
79
79
|
def get_latest_bar_datetime(self, symbol) -> datetime | pd.Timestamp:
|
|
80
80
|
"""
|
|
81
81
|
Returns a Python datetime object for the last bar.
|
|
82
82
|
"""
|
|
83
|
-
|
|
83
|
+
pass
|
|
84
84
|
|
|
85
85
|
@abstractmethod
|
|
86
86
|
def get_latest_bar_value(self, symbol, val_type) -> float:
|
|
@@ -88,7 +88,7 @@ class DataHandler(metaclass=ABCMeta):
|
|
|
88
88
|
Returns one of the Open, High, Low, Close, Adj Close, Volume or Returns
|
|
89
89
|
from the last bar.
|
|
90
90
|
"""
|
|
91
|
-
|
|
91
|
+
pass
|
|
92
92
|
|
|
93
93
|
@abstractmethod
|
|
94
94
|
def get_latest_bars_values(self, symbol, val_type, N=1) -> np.ndarray:
|
|
@@ -96,7 +96,7 @@ class DataHandler(metaclass=ABCMeta):
|
|
|
96
96
|
Returns the last N bar values from the
|
|
97
97
|
latest_symbol list, or N-k if less available.
|
|
98
98
|
"""
|
|
99
|
-
|
|
99
|
+
pass
|
|
100
100
|
|
|
101
101
|
@abstractmethod
|
|
102
102
|
def update_bars(self):
|
|
@@ -105,7 +105,7 @@ class DataHandler(metaclass=ABCMeta):
|
|
|
105
105
|
in a tuple OHLCVI format: (datetime, Open, High, Low,
|
|
106
106
|
Close, Adj Close, Volume, Retruns).
|
|
107
107
|
"""
|
|
108
|
-
|
|
108
|
+
pass
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
class BaseCSVDataHandler(DataHandler):
|
|
@@ -12,7 +12,7 @@ from loguru import logger
|
|
|
12
12
|
from bbstrader.btengine.data import DataHandler
|
|
13
13
|
from bbstrader.btengine.event import FillEvent, SignalEvent
|
|
14
14
|
from bbstrader.config import BBSTRADER_DIR
|
|
15
|
-
from bbstrader.
|
|
15
|
+
from bbstrader.metatrader.trade import TradeSignal
|
|
16
16
|
from bbstrader.metatrader.account import (
|
|
17
17
|
Account,
|
|
18
18
|
AdmiralMarktsGroup,
|
|
@@ -55,7 +55,7 @@ class Strategy(metaclass=ABCMeta):
|
|
|
55
55
|
|
|
56
56
|
@abstractmethod
|
|
57
57
|
def calculate_signals(self, *args, **kwargs) -> List[TradeSignal]:
|
|
58
|
-
|
|
58
|
+
pass
|
|
59
59
|
|
|
60
60
|
def check_pending_orders(self, *args, **kwargs): ...
|
|
61
61
|
def get_update_from_portfolio(self, *args, **kwargs): ...
|
|
@@ -503,108 +503,96 @@ class MT5Strategy(Strategy):
|
|
|
503
503
|
"""
|
|
504
504
|
Check for pending orders and handle them accordingly.
|
|
505
505
|
"""
|
|
506
|
-
for symbol in self.symbols:
|
|
507
|
-
dtime = self.data.get_latest_bar_datetime(symbol)
|
|
508
506
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
507
|
+
def logmsg(order, type, symbol, dtime):
|
|
508
|
+
return self.logger.info(
|
|
509
|
+
f"{type} ORDER EXECUTED: SYMBOL={symbol}, QUANTITY={order.quantity}, "
|
|
510
|
+
f"PRICE @ {order.price}",
|
|
511
|
+
custom_time=dtime,
|
|
512
|
+
)
|
|
515
513
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
)
|
|
521
|
-
try:
|
|
522
|
-
self._orders[symbol]["BLMT"].remove(order)
|
|
523
|
-
assert order not in self._orders[symbol]["BLMT"]
|
|
524
|
-
logmsg(order, "BUY LIMIT")
|
|
525
|
-
except AssertionError:
|
|
526
|
-
self._orders[symbol]["BLMT"] = [
|
|
527
|
-
o for o in self._orders[symbol]["BLMT"] if o != order
|
|
528
|
-
]
|
|
529
|
-
logmsg(order, "BUY LIMIT")
|
|
530
|
-
for order in self._orders[symbol]["SLMT"].copy():
|
|
531
|
-
if self.data.get_latest_bar_value(symbol, "close") >= order.price:
|
|
532
|
-
self.sell_mkt(
|
|
533
|
-
order.strategy_id, symbol, order.price, order.quantity, dtime
|
|
534
|
-
)
|
|
514
|
+
def process_orders(order_type, condition, execute_fn, log_label, symbol, dtime):
|
|
515
|
+
for order in self._orders[symbol][order_type].copy():
|
|
516
|
+
if condition(order):
|
|
517
|
+
execute_fn(order)
|
|
535
518
|
try:
|
|
536
|
-
self._orders[symbol][
|
|
537
|
-
assert order not in self._orders[symbol][
|
|
538
|
-
logmsg(order, "SELL LIMIT")
|
|
519
|
+
self._orders[symbol][order_type].remove(order)
|
|
520
|
+
assert order not in self._orders[symbol][order_type]
|
|
539
521
|
except AssertionError:
|
|
540
|
-
self._orders[symbol][
|
|
541
|
-
o for o in self._orders[symbol][
|
|
522
|
+
self._orders[symbol][order_type] = [
|
|
523
|
+
o for o in self._orders[symbol][order_type] if o != order
|
|
542
524
|
]
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
self.
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
dtime
|
|
598
|
-
)
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
525
|
+
logmsg(order, log_label, symbol, dtime)
|
|
526
|
+
|
|
527
|
+
for symbol in self.symbols:
|
|
528
|
+
dtime = self.data.get_latest_bar_datetime(symbol)
|
|
529
|
+
latest_close = self.data.get_latest_bar_value(symbol, "close")
|
|
530
|
+
|
|
531
|
+
process_orders(
|
|
532
|
+
"BLMT",
|
|
533
|
+
lambda o: latest_close <= o.price,
|
|
534
|
+
lambda o: self.buy_mkt(
|
|
535
|
+
o.strategy_id, symbol, o.price, o.quantity, dtime
|
|
536
|
+
),
|
|
537
|
+
"BUY LIMIT",
|
|
538
|
+
symbol,
|
|
539
|
+
dtime,
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
process_orders(
|
|
543
|
+
"SLMT",
|
|
544
|
+
lambda o: latest_close >= o.price,
|
|
545
|
+
lambda o: self.sell_mkt(
|
|
546
|
+
o.strategy_id, symbol, o.price, o.quantity, dtime
|
|
547
|
+
),
|
|
548
|
+
"SELL LIMIT",
|
|
549
|
+
symbol,
|
|
550
|
+
dtime,
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
process_orders(
|
|
554
|
+
"BSTP",
|
|
555
|
+
lambda o: latest_close >= o.price,
|
|
556
|
+
lambda o: self.buy_mkt(
|
|
557
|
+
o.strategy_id, symbol, o.price, o.quantity, dtime
|
|
558
|
+
),
|
|
559
|
+
"BUY STOP",
|
|
560
|
+
symbol,
|
|
561
|
+
dtime,
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
process_orders(
|
|
565
|
+
"SSTP",
|
|
566
|
+
lambda o: latest_close <= o.price,
|
|
567
|
+
lambda o: self.sell_mkt(
|
|
568
|
+
o.strategy_id, symbol, o.price, o.quantity, dtime
|
|
569
|
+
),
|
|
570
|
+
"SELL STOP",
|
|
571
|
+
symbol,
|
|
572
|
+
dtime,
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
process_orders(
|
|
576
|
+
"BSTPLMT",
|
|
577
|
+
lambda o: latest_close >= o.price,
|
|
578
|
+
lambda o: self.buy_limit(
|
|
579
|
+
o.strategy_id, symbol, o.stoplimit, o.quantity, dtime
|
|
580
|
+
),
|
|
581
|
+
"BUY STOP LIMIT",
|
|
582
|
+
symbol,
|
|
583
|
+
dtime,
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
process_orders(
|
|
587
|
+
"SSTPLMT",
|
|
588
|
+
lambda o: latest_close <= o.price,
|
|
589
|
+
lambda o: self.sell_limit(
|
|
590
|
+
o.strategy_id, symbol, o.stoplimit, o.quantity, dtime
|
|
591
|
+
),
|
|
592
|
+
"SELL STOP LIMIT",
|
|
593
|
+
symbol,
|
|
594
|
+
dtime,
|
|
595
|
+
)
|
|
608
596
|
|
|
609
597
|
@staticmethod
|
|
610
598
|
def calculate_pct_change(current_price, lh_price):
|