bbstrader 0.1.92__py3-none-any.whl → 0.1.94__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/btengine/backtest.py +20 -14
- bbstrader/btengine/data.py +230 -39
- bbstrader/btengine/execution.py +3 -2
- bbstrader/btengine/performance.py +2 -0
- bbstrader/btengine/portfolio.py +12 -16
- bbstrader/btengine/strategy.py +140 -45
- bbstrader/metatrader/account.py +67 -13
- bbstrader/metatrader/rates.py +22 -18
- bbstrader/metatrader/risk.py +34 -6
- bbstrader/metatrader/trade.py +14 -9
- bbstrader/models/__init__.py +5 -1
- bbstrader/models/optimization.py +12 -5
- bbstrader/models/portfolios.py +3 -0
- bbstrader/models/risk.py +9 -1
- bbstrader/trading/execution.py +38 -15
- bbstrader/trading/strategies.py +4 -4
- {bbstrader-0.1.92.dist-info → bbstrader-0.1.94.dist-info}/METADATA +5 -3
- bbstrader-0.1.94.dist-info/RECORD +32 -0
- {bbstrader-0.1.92.dist-info → bbstrader-0.1.94.dist-info}/WHEEL +1 -1
- bbstrader-0.1.92.dist-info/RECORD +0 -32
- {bbstrader-0.1.92.dist-info → bbstrader-0.1.94.dist-info}/LICENSE +0 -0
- {bbstrader-0.1.92.dist-info → bbstrader-0.1.94.dist-info}/top_level.txt +0 -0
bbstrader/metatrader/trade.py
CHANGED
|
@@ -138,6 +138,7 @@ class Trade(RiskManagement):
|
|
|
138
138
|
- tp
|
|
139
139
|
- be
|
|
140
140
|
See the RiskManagement class for more details on these parameters.
|
|
141
|
+
See `bbstrader.metatrader.account.check_mt5_connection()` for more details on how to connect to MT5 terminal.
|
|
141
142
|
"""
|
|
142
143
|
# Call the parent class constructor first
|
|
143
144
|
super().__init__(
|
|
@@ -160,6 +161,7 @@ class Trade(RiskManagement):
|
|
|
160
161
|
self.console_log = console_log
|
|
161
162
|
self.logger = self._get_logger(logger, console_log)
|
|
162
163
|
self.tf = kwargs.get("time_frame", 'D1')
|
|
164
|
+
self.kwargs = kwargs
|
|
163
165
|
|
|
164
166
|
self.start_time_hour, self.start_time_minutes = self.start.split(":")
|
|
165
167
|
self.finishing_time_hour, self.finishing_time_minutes = self.finishing.split(
|
|
@@ -174,8 +176,8 @@ class Trade(RiskManagement):
|
|
|
174
176
|
self.break_even_points = {}
|
|
175
177
|
self.trail_after_points = []
|
|
176
178
|
|
|
177
|
-
self.initialize()
|
|
178
|
-
self.select_symbol()
|
|
179
|
+
self.initialize(**kwargs)
|
|
180
|
+
self.select_symbol(**kwargs)
|
|
179
181
|
self.prepare_symbol()
|
|
180
182
|
|
|
181
183
|
if self.verbose:
|
|
@@ -194,7 +196,7 @@ class Trade(RiskManagement):
|
|
|
194
196
|
return config_logger(f'{log_path}/{logger}', consol_log)
|
|
195
197
|
return logger
|
|
196
198
|
|
|
197
|
-
def initialize(self):
|
|
199
|
+
def initialize(self, **kwargs):
|
|
198
200
|
"""
|
|
199
201
|
Initializes the MetaTrader 5 (MT5) terminal for trading operations.
|
|
200
202
|
This method attempts to establish a connection with the MT5 terminal.
|
|
@@ -207,7 +209,7 @@ class Trade(RiskManagement):
|
|
|
207
209
|
try:
|
|
208
210
|
if self.verbose:
|
|
209
211
|
print("\nInitializing the basics.")
|
|
210
|
-
check_mt5_connection()
|
|
212
|
+
check_mt5_connection(**kwargs)
|
|
211
213
|
if self.verbose:
|
|
212
214
|
print(
|
|
213
215
|
f"You are running the @{self.expert_name} Expert advisor,"
|
|
@@ -216,7 +218,7 @@ class Trade(RiskManagement):
|
|
|
216
218
|
except Exception as e:
|
|
217
219
|
self.logger.error(f"During initialization: {e}")
|
|
218
220
|
|
|
219
|
-
def select_symbol(self):
|
|
221
|
+
def select_symbol(self, **kwargs):
|
|
220
222
|
"""
|
|
221
223
|
Selects the trading symbol in the MetaTrader 5 (MT5) terminal.
|
|
222
224
|
This method ensures that the specified trading
|
|
@@ -228,6 +230,7 @@ class Trade(RiskManagement):
|
|
|
228
230
|
MT5TerminalError: If symbole selection fails.
|
|
229
231
|
"""
|
|
230
232
|
try:
|
|
233
|
+
check_mt5_connection(**kwargs)
|
|
231
234
|
if not Mt5.symbol_select(self.symbol, True):
|
|
232
235
|
raise_mt5_error(message=INIT_MSG)
|
|
233
236
|
except Exception as e:
|
|
@@ -848,10 +851,11 @@ class Trade(RiskManagement):
|
|
|
848
851
|
positions = self.get_positions(symbol=self.symbol)
|
|
849
852
|
if positions is not None:
|
|
850
853
|
positions = [position for position in positions if position.magic == id]
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
854
|
+
|
|
855
|
+
if positions is not None:
|
|
856
|
+
profit = 0.0
|
|
857
|
+
balance = self.get_account_info().balance
|
|
858
|
+
target = round((balance * self.target)/100, 2)
|
|
855
859
|
for position in positions:
|
|
856
860
|
profit += position.profit
|
|
857
861
|
fees = self.get_stats()[0]["average_fee"] * len(positions)
|
|
@@ -1489,6 +1493,7 @@ def create_trade_instance(
|
|
|
1489
1493
|
daily_risk: Optional[Dict[str, float]] = None,
|
|
1490
1494
|
max_risk: Optional[Dict[str, float]] = None,
|
|
1491
1495
|
pchange_sl: Optional[Dict[str, float] | float] = None,
|
|
1496
|
+
**kwargs
|
|
1492
1497
|
) -> Dict[str, Trade]:
|
|
1493
1498
|
"""
|
|
1494
1499
|
Creates Trade instances for each symbol provided.
|
bbstrader/models/__init__.py
CHANGED
|
@@ -3,4 +3,8 @@ The `models` module provides a foundational framework for implementing various q
|
|
|
3
3
|
|
|
4
4
|
It is designed to be a versatile base module for different types of models used in financial analysis and trading.
|
|
5
5
|
"""
|
|
6
|
-
from bbstrader.models.risk import *
|
|
6
|
+
from bbstrader.models.risk import *
|
|
7
|
+
from bbstrader.models.optimization import *
|
|
8
|
+
from bbstrader.models.portfolios import *
|
|
9
|
+
from bbstrader.models.factors import *
|
|
10
|
+
from bbstrader.models.ml import *
|
bbstrader/models/optimization.py
CHANGED
|
@@ -6,7 +6,14 @@ from pypfopt.efficient_frontier import EfficientFrontier
|
|
|
6
6
|
from pypfopt.hierarchical_portfolio import HRPOpt
|
|
7
7
|
import warnings
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
__all__ = [
|
|
10
|
+
'markowitz_weights',
|
|
11
|
+
'hierarchical_risk_parity',
|
|
12
|
+
'equal_weighted',
|
|
13
|
+
'optimized_weights'
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
def markowitz_weights(prices=None, rfr=0.0, freq=252):
|
|
10
17
|
"""
|
|
11
18
|
Calculates optimal portfolio weights using Markowitz's mean-variance optimization (Max Sharpe Ratio) with multiple solvers.
|
|
12
19
|
|
|
@@ -45,7 +52,7 @@ def markowitz_weights(prices=None, freq=252):
|
|
|
45
52
|
weight_bounds=(0, 1),
|
|
46
53
|
solver=solver)
|
|
47
54
|
try:
|
|
48
|
-
weights = ef.max_sharpe()
|
|
55
|
+
weights = ef.max_sharpe(risk_free_rate=rfr)
|
|
49
56
|
return ef.clean_weights()
|
|
50
57
|
except Exception as e:
|
|
51
58
|
print(f"Solver {solver} failed with error: {e}")
|
|
@@ -83,7 +90,7 @@ def hierarchical_risk_parity(prices=None, returns=None, freq=252):
|
|
|
83
90
|
if returns is None and prices is None:
|
|
84
91
|
raise ValueError("Either prices or returns must be provided")
|
|
85
92
|
if returns is None:
|
|
86
|
-
returns = prices.pct_change().dropna()
|
|
93
|
+
returns = prices.pct_change().dropna(how='all')
|
|
87
94
|
# Remove duplicate columns and index
|
|
88
95
|
returns = returns.loc[:, ~returns.columns.duplicated()]
|
|
89
96
|
returns = returns.loc[~returns.index.duplicated(keep='first')]
|
|
@@ -128,7 +135,7 @@ def equal_weighted(prices=None, returns=None, round_digits=5):
|
|
|
128
135
|
columns = returns.columns
|
|
129
136
|
return {col: round(1/n, round_digits) for col in columns}
|
|
130
137
|
|
|
131
|
-
def optimized_weights(prices=None, returns=None, freq=252, method='
|
|
138
|
+
def optimized_weights(prices=None, returns=None, rfr=0.0, freq=252, method='equal'):
|
|
132
139
|
"""
|
|
133
140
|
Selects an optimization method to calculate portfolio weights based on user preference.
|
|
134
141
|
|
|
@@ -161,7 +168,7 @@ def optimized_weights(prices=None, returns=None, freq=252, method='markowitz'):
|
|
|
161
168
|
- 'equal': Equal weighting across all assets
|
|
162
169
|
"""
|
|
163
170
|
if method == 'markowitz':
|
|
164
|
-
return markowitz_weights(prices=prices, freq=freq)
|
|
171
|
+
return markowitz_weights(prices=prices, rfr=rfr, freq=freq)
|
|
165
172
|
elif method == 'hrp':
|
|
166
173
|
return hierarchical_risk_parity(prices=prices, returns=returns, freq=freq)
|
|
167
174
|
elif method == 'equal':
|
bbstrader/models/portfolios.py
CHANGED
bbstrader/models/risk.py
CHANGED
|
@@ -310,7 +310,15 @@ class HMMRiskManager(RiskModel):
|
|
|
310
310
|
and data filtered up to the end date if specified.
|
|
311
311
|
"""
|
|
312
312
|
df = data_frame.copy()
|
|
313
|
-
|
|
313
|
+
if 'Returns' or 'returns' not in df.columns:
|
|
314
|
+
if 'Close' in df.columns:
|
|
315
|
+
df['Returns'] = df['Close'].pct_change()
|
|
316
|
+
elif 'Adj Close' in df.columns:
|
|
317
|
+
df['Returns'] = df['Adj Close'].pct_change()
|
|
318
|
+
else:
|
|
319
|
+
raise ValueError("No 'Close' or 'Adj Close' columns found.")
|
|
320
|
+
elif 'returns' in df.columns:
|
|
321
|
+
df.rename(columns={'returns': 'Returns'}, inplace=True)
|
|
314
322
|
if end is not None:
|
|
315
323
|
df = df[:end.strftime('%Y-%m-%d')]
|
|
316
324
|
df.dropna(inplace=True)
|
bbstrader/trading/execution.py
CHANGED
|
@@ -78,10 +78,11 @@ EXIT_SIGNAL_ACTIONS = {
|
|
|
78
78
|
|
|
79
79
|
def _mt5_execution(
|
|
80
80
|
symbol_list, trades_instances, strategy_cls, /,
|
|
81
|
-
mm, trail, stop_trail, trail_after_points, be_plus_points, show_positions_orders,
|
|
82
|
-
|
|
81
|
+
mm, optimizer, trail, stop_trail, trail_after_points, be_plus_points, show_positions_orders,
|
|
82
|
+
iter_time, use_trade_time, period, period_end_action, closing_pnl, trading_days,
|
|
83
83
|
comment, **kwargs):
|
|
84
84
|
symbols = symbol_list.copy()
|
|
85
|
+
time_frame = kwargs.get('time_frame', '15m')
|
|
85
86
|
STRATEGY = kwargs.get('strategy_name')
|
|
86
87
|
mtrades = kwargs.get('max_trades')
|
|
87
88
|
notify = kwargs.get('notify', False)
|
|
@@ -89,13 +90,23 @@ def _mt5_execution(
|
|
|
89
90
|
telegram = kwargs.get('telegram', False)
|
|
90
91
|
bot_token = kwargs.get('bot_token')
|
|
91
92
|
chat_id = kwargs.get('chat_id')
|
|
93
|
+
|
|
94
|
+
def update_risk(weights):
|
|
95
|
+
if weights is not None:
|
|
96
|
+
for symbol in symbols:
|
|
97
|
+
if symbol not in weights:
|
|
98
|
+
continue
|
|
99
|
+
trade = trades_instances[symbol]
|
|
100
|
+
trade.dailydd = round(weights[symbol], 5)
|
|
92
101
|
|
|
93
102
|
def _send_notification(signal):
|
|
94
103
|
send_message(message=signal, notify_me=notify,
|
|
95
104
|
telegram=telegram, token=bot_token, chat_id=chat_id)
|
|
96
105
|
|
|
97
106
|
logger = trades_instances[symbols[0]].logger
|
|
98
|
-
max_trades = {symbol: mtrades[symbol]
|
|
107
|
+
max_trades = {symbol: mtrades[symbol]
|
|
108
|
+
if mtrades is not None and symbol in mtrades
|
|
109
|
+
else trades_instances[symbol].max_trade() for symbol in symbols}
|
|
99
110
|
if comment is None:
|
|
100
111
|
trade = trades_instances[symbols[0]]
|
|
101
112
|
comment = f"{trade.expert_name}@{trade.version}"
|
|
@@ -114,7 +125,7 @@ def _mt5_execution(
|
|
|
114
125
|
long_market = {symbol: False for symbol in symbols}
|
|
115
126
|
short_market = {symbol: False for symbol in symbols}
|
|
116
127
|
try:
|
|
117
|
-
check_mt5_connection()
|
|
128
|
+
check_mt5_connection(**kwargs)
|
|
118
129
|
strategy: MT5Strategy = strategy_cls(symbol_list=symbols, mode='live', **kwargs)
|
|
119
130
|
except Exception as e:
|
|
120
131
|
logger.error(f"Initializing strategy, {e}, STRATEGY={STRATEGY}")
|
|
@@ -124,7 +135,7 @@ def _mt5_execution(
|
|
|
124
135
|
|
|
125
136
|
while True:
|
|
126
137
|
try:
|
|
127
|
-
check_mt5_connection()
|
|
138
|
+
check_mt5_connection(**kwargs)
|
|
128
139
|
current_date = datetime.now()
|
|
129
140
|
today = current_date.strftime("%A").lower()
|
|
130
141
|
time.sleep(0.5)
|
|
@@ -158,14 +169,18 @@ def _mt5_execution(
|
|
|
158
169
|
continue
|
|
159
170
|
time.sleep(0.5)
|
|
160
171
|
try:
|
|
161
|
-
check_mt5_connection()
|
|
172
|
+
check_mt5_connection(**kwargs)
|
|
162
173
|
signals = strategy.calculate_signals()
|
|
174
|
+
weights = None
|
|
175
|
+
if hasattr(strategy, 'apply_risk_management'):
|
|
176
|
+
weights = strategy.apply_risk_management(optimizer)
|
|
177
|
+
update_risk(weights)
|
|
163
178
|
except Exception as e:
|
|
164
179
|
logger.error(f"Calculating signal, {e}, STRATEGY={STRATEGY}")
|
|
165
180
|
continue
|
|
166
181
|
for symbol in symbols:
|
|
167
182
|
try:
|
|
168
|
-
check_mt5_connection()
|
|
183
|
+
check_mt5_connection(**kwargs)
|
|
169
184
|
trade: Trade = trades_instances[symbol]
|
|
170
185
|
tfmsg = f"Time Frame Not completed !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}"
|
|
171
186
|
riskmsg = f"Risk not allowed !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}"
|
|
@@ -181,7 +196,7 @@ def _mt5_execution(
|
|
|
181
196
|
if signal is not None:
|
|
182
197
|
signal = 'BMKT' if signal == 'LONG' else signal
|
|
183
198
|
signal = 'SMKT' if signal == 'SHORT' else signal
|
|
184
|
-
info = f"SIGNAL = {signal}, SYMBOL={trade.symbol}, STRATEGY={STRATEGY}"
|
|
199
|
+
info = f"SIGNAL = {signal}, SYMBOL={trade.symbol}, STRATEGY={STRATEGY}, TIMEFRAME={time_frame}"
|
|
185
200
|
msg = f"Sending {signal} Order ... SYMBOL={trade.symbol}, STRATEGY={STRATEGY}"
|
|
186
201
|
if signal not in EXIT_SIGNAL_ACTIONS:
|
|
187
202
|
logger.info(info)
|
|
@@ -258,7 +273,7 @@ def _mt5_execution(
|
|
|
258
273
|
)
|
|
259
274
|
try:
|
|
260
275
|
FRIDAY = 'friday'
|
|
261
|
-
check_mt5_connection()
|
|
276
|
+
check_mt5_connection(**kwargs)
|
|
262
277
|
day_end = all(trade.days_end() for trade in trades_instances.values())
|
|
263
278
|
if closing_pnl is not None:
|
|
264
279
|
closing = all(trade.positive_profit(id=trade.expert_id, th=closing_pnl)
|
|
@@ -436,12 +451,12 @@ class MT5ExecutionEngine():
|
|
|
436
451
|
strategy_cls: Strategy,
|
|
437
452
|
/,
|
|
438
453
|
mm: bool = True,
|
|
454
|
+
optimizer: str = 'equal',
|
|
439
455
|
trail: bool = True,
|
|
440
456
|
stop_trail: Optional[int] = None,
|
|
441
457
|
trail_after_points: Optional[int] = None,
|
|
442
458
|
be_plus_points: Optional[int] = None,
|
|
443
459
|
show_positions_orders: bool = False,
|
|
444
|
-
time_frame: str = '15m',
|
|
445
460
|
iter_time: int | float = 5,
|
|
446
461
|
use_trade_time: bool = True,
|
|
447
462
|
period: Literal['day', 'week', 'month'] = 'week',
|
|
@@ -450,15 +465,16 @@ class MT5ExecutionEngine():
|
|
|
450
465
|
trading_days: Optional[List[str]] = TradingDays,
|
|
451
466
|
comment: Optional[str] = None,
|
|
452
467
|
**kwargs
|
|
453
|
-
|
|
468
|
+
):
|
|
454
469
|
"""
|
|
455
470
|
Args:
|
|
456
471
|
symbol_list : List of symbols to trade
|
|
457
472
|
trades_instances : Dictionary of Trade instances
|
|
458
473
|
strategy_cls : Strategy class to use for trading
|
|
459
474
|
mm : Enable Money Management. Defaults to False.
|
|
475
|
+
optimizer : Risk management optimizer. Defaults to 'equal'.
|
|
476
|
+
See `bbstrader.models.optimization` module for more information.
|
|
460
477
|
show_positions_orders : Print open positions and orders. Defaults to False.
|
|
461
|
-
time_frame : Time frame to trade. Defaults to '15m'.
|
|
462
478
|
iter_time : Interval to check for signals and `mm`. Defaults to 5.
|
|
463
479
|
use_trade_time : Open trades after the time is completed. Defaults to True.
|
|
464
480
|
period : Period to trade. Defaults to 'week'.
|
|
@@ -468,6 +484,7 @@ class MT5ExecutionEngine():
|
|
|
468
484
|
trading_days : Trading days in a week. Defaults to monday to friday.
|
|
469
485
|
comment: Comment for trades. Defaults to None.
|
|
470
486
|
**kwargs: Additional keyword arguments
|
|
487
|
+
_ time_frame : Time frame to trade. Defaults to '15m'.
|
|
471
488
|
- strategy_name (Optional[str]): Strategy name. Defaults to None.
|
|
472
489
|
- max_trades (Dict[str, int]): Maximum trades per symbol. Defaults to None.
|
|
473
490
|
- notify (bool): Enable notifications. Defaults to False.
|
|
@@ -492,17 +509,18 @@ class MT5ExecutionEngine():
|
|
|
492
509
|
|
|
493
510
|
4. All strategies must generate signals for backtesting and live trading.
|
|
494
511
|
See the `bbstrader.trading.strategies` module for more information on how to create custom strategies.
|
|
512
|
+
See `bbstrader.metatrader.account.check_mt5_connection()` for more details on how to connect to MT5 terminal.
|
|
495
513
|
"""
|
|
496
514
|
self.symbol_list = symbol_list
|
|
497
515
|
self.trades_instances = trades_instances
|
|
498
516
|
self.strategy_cls = strategy_cls
|
|
499
517
|
self.mm = mm
|
|
518
|
+
self.optimizer = optimizer
|
|
500
519
|
self.trail = trail
|
|
501
520
|
self.stop_trail = stop_trail
|
|
502
521
|
self.trail_after_points = trail_after_points
|
|
503
522
|
self.be_plus_points = be_plus_points
|
|
504
523
|
self.show_positions_orders = show_positions_orders
|
|
505
|
-
self.time_frame = time_frame
|
|
506
524
|
self.iter_time = iter_time
|
|
507
525
|
self.use_trade_time = use_trade_time
|
|
508
526
|
self.period = period
|
|
@@ -512,19 +530,24 @@ class MT5ExecutionEngine():
|
|
|
512
530
|
self.comment = comment
|
|
513
531
|
self.kwargs = kwargs
|
|
514
532
|
|
|
533
|
+
def __repr__(self):
|
|
534
|
+
trades = self.trades_instances.keys()
|
|
535
|
+
s = self.strategy_cls.__name__
|
|
536
|
+
return f"MT5ExecutionEngine(Symbols={list(trades)}, Strategy={s})"
|
|
537
|
+
|
|
515
538
|
def run(self):
|
|
516
|
-
check_mt5_connection()
|
|
539
|
+
check_mt5_connection(**self.kwargs)
|
|
517
540
|
_mt5_execution(
|
|
518
541
|
self.symbol_list,
|
|
519
542
|
self.trades_instances,
|
|
520
543
|
self.strategy_cls,
|
|
521
544
|
mm=self.mm,
|
|
545
|
+
optimizer=self.optimizer,
|
|
522
546
|
trail=self.trail,
|
|
523
547
|
stop_trail=self.stop_trail,
|
|
524
548
|
trail_after_points=self.trail_after_points,
|
|
525
549
|
be_plus_points=self.be_plus_points,
|
|
526
550
|
show_positions_orders=self.show_positions_orders,
|
|
527
|
-
time_frame=self.time_frame,
|
|
528
551
|
iter_time=self.iter_time,
|
|
529
552
|
use_trade_time=self.use_trade_time,
|
|
530
553
|
period=self.period,
|
bbstrader/trading/strategies.py
CHANGED
|
@@ -80,17 +80,17 @@ class SMAStrategy(Strategy):
|
|
|
80
80
|
self.symbol_list = symbol_list or self.bars.symbol_list
|
|
81
81
|
self.mode = mode
|
|
82
82
|
|
|
83
|
+
self.kwargs = kwargs
|
|
83
84
|
self.short_window = kwargs.get("short_window", 50)
|
|
84
85
|
self.long_window = kwargs.get("long_window", 200)
|
|
85
86
|
self.tf = kwargs.get("time_frame", 'D1')
|
|
86
87
|
self.qty = get_quantities(
|
|
87
88
|
kwargs.get('quantities', 100), self.symbol_list)
|
|
88
89
|
self.sd = kwargs.get("session_duration", 23.0)
|
|
89
|
-
self.risk_models = build_hmm_models(self.symbol_list, **kwargs)
|
|
90
|
+
self.risk_models = build_hmm_models(self.symbol_list, **self.kwargs)
|
|
90
91
|
self.risk_window = kwargs.get("risk_window", self.long_window)
|
|
91
92
|
self.bought = self._calculate_initial_bought()
|
|
92
93
|
|
|
93
|
-
|
|
94
94
|
def _calculate_initial_bought(self):
|
|
95
95
|
bought = {}
|
|
96
96
|
for s in self.symbol_list:
|
|
@@ -151,13 +151,13 @@ class SMAStrategy(Strategy):
|
|
|
151
151
|
signal = SignalEvent(
|
|
152
152
|
1, s, dt, 'SHORT', quantity=self.qty[s], price=price)
|
|
153
153
|
self.bought[s] = 'SHORT'
|
|
154
|
-
|
|
154
|
+
signals[s] = signal
|
|
155
155
|
return signals
|
|
156
156
|
|
|
157
157
|
def get_live_data(self):
|
|
158
158
|
symbol_data = {symbol: None for symbol in self.symbol_list}
|
|
159
159
|
for symbol in self.symbol_list:
|
|
160
|
-
sig_rate = Rates(symbol, self.tf, 0, self.risk_window)
|
|
160
|
+
sig_rate = Rates(symbol, self.tf, 0, self.risk_window+2, **self.kwargs)
|
|
161
161
|
hmm_data = sig_rate.returns.values
|
|
162
162
|
prices = sig_rate.close.values
|
|
163
163
|
current_regime = self.risk_models[symbol].which_trade_allowed(hmm_data)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bbstrader
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.94
|
|
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/
|
|
@@ -23,7 +23,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
25
|
Requires-Dist: pandas
|
|
26
|
-
Requires-Dist: numpy
|
|
26
|
+
Requires-Dist: numpy==1.26.4
|
|
27
27
|
Requires-Dist: yfinance
|
|
28
28
|
Requires-Dist: scipy
|
|
29
29
|
Requires-Dist: hmmlearn
|
|
@@ -47,8 +47,10 @@ Requires-Dist: scikit-learn
|
|
|
47
47
|
Requires-Dist: notify-py
|
|
48
48
|
Requires-Dist: python-telegram-bot
|
|
49
49
|
Requires-Dist: pyportfolioopt
|
|
50
|
+
Requires-Dist: eodhd
|
|
51
|
+
Requires-Dist: financetoolkit
|
|
50
52
|
Provides-Extra: mt5
|
|
51
|
-
Requires-Dist: MetaTrader5
|
|
53
|
+
Requires-Dist: MetaTrader5; extra == "mt5"
|
|
52
54
|
|
|
53
55
|
# Simplified Investment & Trading Toolkit
|
|
54
56
|

|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
bbstrader/__ini__.py,sha256=rCTy-3g2RlDAgIZ7cSET9-I74MwuCXpp-xGVTFS8NNc,482
|
|
2
|
+
bbstrader/config.py,sha256=_AD_Cd-w5zyabm1CBPNGhzcZuSjThB7jyzTcjbrIlUQ,3618
|
|
3
|
+
bbstrader/tseries.py,sha256=qJKLxHnPOjB7dXon-ITK7vU1fAuvl8evzET6lSSnijQ,53572
|
|
4
|
+
bbstrader/btengine/__init__.py,sha256=OaXZTjgDwqWrjPq-CNE4kJkmriKXt9t5pIghW1MDTeo,2911
|
|
5
|
+
bbstrader/btengine/backtest.py,sha256=A3S84jpGTE_zhguOEGoGu6H_4ws4Iq5sf0n7TZaUYfQ,14615
|
|
6
|
+
bbstrader/btengine/data.py,sha256=3bdd50hMrszNmcOXd8BYtkjTjg56fiThW2EJsItsCJA,26509
|
|
7
|
+
bbstrader/btengine/event.py,sha256=zF_ST4tcjV5uJJVV1IbRXQgCLbca2R2fmE7A2MaIno4,8748
|
|
8
|
+
bbstrader/btengine/execution.py,sha256=Fs6Hk64DxEOEVzAjsQ3CIVvYifWLLgkDjOixSh_Ghsc,10282
|
|
9
|
+
bbstrader/btengine/performance.py,sha256=WTYzB50lUD5aShPIEebbQPlaC2NVW6VfxdgGHjcIIAw,10707
|
|
10
|
+
bbstrader/btengine/portfolio.py,sha256=wCRmGxaZvihUPlXIlZp9cQo9fqPP-Tk5oALjknMfnos,16055
|
|
11
|
+
bbstrader/btengine/strategy.py,sha256=6IN1KQ-a-IQgbCEOflKTtGh-ouztwsVjik6TuMg6CY0,30210
|
|
12
|
+
bbstrader/metatrader/__init__.py,sha256=OLVOB_EieEb1P72I8V4Vem8kQWJ__D_L3c_wfwqY-9k,211
|
|
13
|
+
bbstrader/metatrader/account.py,sha256=tkcAEgFIYZwtFRQc07lXQQFWRqglzR4H4LjX2BDRvj8,56371
|
|
14
|
+
bbstrader/metatrader/rates.py,sha256=RLzeq26LJ8dzFccgTcMjSUut4lsnt7xrWPXf5Z8xVuQ,21073
|
|
15
|
+
bbstrader/metatrader/risk.py,sha256=uLarOF-g9-RBdJuKSmIfT5WrPn47bmrvMxP21pQg4xo,26793
|
|
16
|
+
bbstrader/metatrader/trade.py,sha256=xAdwe00qNP0qeDzXGCK1_i4lsa9LpUkhbj82XqwJe6Y,70464
|
|
17
|
+
bbstrader/metatrader/utils.py,sha256=BTaZun4DKWpCxBBzY0SLQqqz7n_7F_R1F59APfyaa3E,17666
|
|
18
|
+
bbstrader/models/__init__.py,sha256=mpxtXYEcE8hwNDbzJf8MRqnBIa2T1voraEk0U0ri53c,437
|
|
19
|
+
bbstrader/models/factors.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
bbstrader/models/ml.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
bbstrader/models/optimization.py,sha256=JlMsda9L-ADSgw4YPE4o3CsL1Yyxfeahf9kUb-EZqqM,6699
|
|
22
|
+
bbstrader/models/portfolios.py,sha256=dFTZ3maRVY_O3UOIoRlLCbAow3SiLTQYt1q5DNaRUxE,8223
|
|
23
|
+
bbstrader/models/risk.py,sha256=k1f78_a6oYk24kv-iURecsSfpgCTWi6IpLsoR4LwnWg,15530
|
|
24
|
+
bbstrader/trading/__init__.py,sha256=3CCzV5rQbH8NthjDJhD0_2FABvpiCmkeC9cVeoW7bi4,438
|
|
25
|
+
bbstrader/trading/execution.py,sha256=EhrTtDVV1Dz7T7_RglY4he3ZZMzijgl5tcRhQvbfIWA,26545
|
|
26
|
+
bbstrader/trading/scripts.py,sha256=rQmnG_4F_MuUEc96RXpAQT4kXrC-FkscsgHKgDAR_-Y,1902
|
|
27
|
+
bbstrader/trading/strategies.py,sha256=6bj-xXIEzhTfWrGHAkjWJg7U1OkARu7YzoaWeSrfuZY,36460
|
|
28
|
+
bbstrader-0.1.94.dist-info/LICENSE,sha256=1EudjwwP2oTJy8Vh0e-Kzv8VZZU95y-t6c3DYhR51uc,1115
|
|
29
|
+
bbstrader-0.1.94.dist-info/METADATA,sha256=JKdBaA3tjT_Deirxlf_2jSQkvlvZh6UxdVqWMph84mI,9983
|
|
30
|
+
bbstrader-0.1.94.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
31
|
+
bbstrader-0.1.94.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
|
|
32
|
+
bbstrader-0.1.94.dist-info/RECORD,,
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
bbstrader/__ini__.py,sha256=rCTy-3g2RlDAgIZ7cSET9-I74MwuCXpp-xGVTFS8NNc,482
|
|
2
|
-
bbstrader/config.py,sha256=_AD_Cd-w5zyabm1CBPNGhzcZuSjThB7jyzTcjbrIlUQ,3618
|
|
3
|
-
bbstrader/tseries.py,sha256=qJKLxHnPOjB7dXon-ITK7vU1fAuvl8evzET6lSSnijQ,53572
|
|
4
|
-
bbstrader/btengine/__init__.py,sha256=OaXZTjgDwqWrjPq-CNE4kJkmriKXt9t5pIghW1MDTeo,2911
|
|
5
|
-
bbstrader/btengine/backtest.py,sha256=bgQNiS_kb1zWyX_8_OIDGTBlHGC5pw7ZMIQ5csYDahA,14115
|
|
6
|
-
bbstrader/btengine/data.py,sha256=A6jUqDnjl-w1OSzbLLPfS1WfJ8Se25AqigJs9pbe0wc,17966
|
|
7
|
-
bbstrader/btengine/event.py,sha256=zF_ST4tcjV5uJJVV1IbRXQgCLbca2R2fmE7A2MaIno4,8748
|
|
8
|
-
bbstrader/btengine/execution.py,sha256=i-vI9LGqVtEIKfH_T5Airv-gI4t1X75CfuFIuQdogkA,10187
|
|
9
|
-
bbstrader/btengine/performance.py,sha256=bKwj1_CSygvggLKTXPASp2eWhDdwyCf06ayUaXwdh4E,10655
|
|
10
|
-
bbstrader/btengine/portfolio.py,sha256=9Jw0UA2gPu-YkUNenoMSHt8t-axtbl6veWXgcRMTQ14,16074
|
|
11
|
-
bbstrader/btengine/strategy.py,sha256=w5vwlpJNIVjslaHprWDr-3j-JJPiO1EvqeyrJmorByE,25721
|
|
12
|
-
bbstrader/metatrader/__init__.py,sha256=OLVOB_EieEb1P72I8V4Vem8kQWJ__D_L3c_wfwqY-9k,211
|
|
13
|
-
bbstrader/metatrader/account.py,sha256=hVH83vnAdfMOzUsF9PiWelqxa7HaLSTpCVlUEePnSZg,53912
|
|
14
|
-
bbstrader/metatrader/rates.py,sha256=1dJHbVqoT41m3EhF0wRe7dSGe5Kf3o5Maskkw-i5qsQ,20810
|
|
15
|
-
bbstrader/metatrader/risk.py,sha256=8FcLY8pgV8_rxAcjx179sdqaMu66wl-fDFPZvdihfUw,25953
|
|
16
|
-
bbstrader/metatrader/trade.py,sha256=uigDah9n_rVJiwSslTAArLP94sde1dxYyGyRVIPPgb4,70210
|
|
17
|
-
bbstrader/metatrader/utils.py,sha256=BTaZun4DKWpCxBBzY0SLQqqz7n_7F_R1F59APfyaa3E,17666
|
|
18
|
-
bbstrader/models/__init__.py,sha256=6tAj9V9vgwesgPVMKznwRB3k8-Ec8Q73Di5p2UO0qlA,274
|
|
19
|
-
bbstrader/models/factors.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
bbstrader/models/ml.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
-
bbstrader/models/optimization.py,sha256=0ZOCinveMCSxpL4gTBO5lbZ6jb1HXp0CeIjO-_fNGro,6521
|
|
22
|
-
bbstrader/models/portfolios.py,sha256=TyLcYwxW86t1qH6YS5xBaiKB9Owezq3ovffjR0Othlw,8184
|
|
23
|
-
bbstrader/models/risk.py,sha256=Pm_WoGI-vtPW75fwo_7ptF2Br-xQYBwrAAOIgqDQmy8,15120
|
|
24
|
-
bbstrader/trading/__init__.py,sha256=3CCzV5rQbH8NthjDJhD0_2FABvpiCmkeC9cVeoW7bi4,438
|
|
25
|
-
bbstrader/trading/execution.py,sha256=Ze_YFrdgU9mRZsS4J08lZNE77HBwxrun5rdqHkS4dzE,25348
|
|
26
|
-
bbstrader/trading/scripts.py,sha256=rQmnG_4F_MuUEc96RXpAQT4kXrC-FkscsgHKgDAR_-Y,1902
|
|
27
|
-
bbstrader/trading/strategies.py,sha256=ztKNL4Nmlb-4N8_cq0OJyn3E2cRcdKdKu3FeTbZrHsU,36402
|
|
28
|
-
bbstrader-0.1.92.dist-info/LICENSE,sha256=1EudjwwP2oTJy8Vh0e-Kzv8VZZU95y-t6c3DYhR51uc,1115
|
|
29
|
-
bbstrader-0.1.92.dist-info/METADATA,sha256=LZdzZUHKait-lIvprJ85AxfRuHp8VE5QPS69y8uZIIs,9932
|
|
30
|
-
bbstrader-0.1.92.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
31
|
-
bbstrader-0.1.92.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
|
|
32
|
-
bbstrader-0.1.92.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|