bbstrader 0.1.8__py3-none-any.whl → 0.1.9__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.

@@ -325,7 +325,7 @@ class Portfolio(object):
325
325
  ]
326
326
  now = datetime.now().strftime('%Y%m%d%H%M%S')
327
327
  strategy_name = self.strategy_name.replace(' ', '_')
328
- results_dir = Path('Backtest_Results') / strategy_name
328
+ results_dir = Path('.backtests') / strategy_name
329
329
  results_dir.mkdir(parents=True, exist_ok=True)
330
330
 
331
331
  csv_file = f"{strategy_name}_{now}_equity.csv"
@@ -54,6 +54,14 @@ _SYMBOLS_TYPE_ = {
54
54
  "CRYPTO": r'\b(Cryptos?)\b'
55
55
  }
56
56
 
57
+ def check_mt5_connection():
58
+ try:
59
+ init = mt5.initialize()
60
+ if not init:
61
+ raise_mt5_error(INIT_MSG)
62
+ except Exception:
63
+ raise_mt5_error(INIT_MSG)
64
+
57
65
  class Account(object):
58
66
  """
59
67
  The `Account` class is utilized to retrieve information about
@@ -91,8 +99,7 @@ class Account(object):
91
99
  """
92
100
 
93
101
  def __init__(self):
94
- if not mt5.initialize():
95
- raise_mt5_error(message=INIT_MSG)
102
+ check_mt5_connection()
96
103
  self._check_brokers()
97
104
 
98
105
  def _check_brokers(self):
@@ -4,7 +4,7 @@ from datetime import datetime
4
4
  from typing import Union, Optional
5
5
  from bbstrader.metatrader.utils import (
6
6
  raise_mt5_error, TimeFrame, TIMEFRAMES)
7
- from bbstrader.metatrader.account import INIT_MSG
7
+ from bbstrader.metatrader.account import check_mt5_connection
8
8
  from pandas.tseries.offsets import CustomBusinessDay
9
9
  from pandas.tseries.holiday import USFederalHolidayCalendar
10
10
 
@@ -74,9 +74,7 @@ class Rates(object):
74
74
 
75
75
 
76
76
  def _mt5_initialized(self):
77
- """Ensures the MetaTrader 5 Terminal is initialized."""
78
- if not Mt5.initialize():
79
- raise_mt5_error(message=INIT_MSG)
77
+ check_mt5_connection()
80
78
 
81
79
  def _get_start_pos(self, index, time_frame):
82
80
  if isinstance(index, int):
@@ -341,7 +341,7 @@ class RiskManagement(Account):
341
341
  """
342
342
  P = self.get_account_info().margin_free
343
343
  trade_risk = self.get_trade_risk()
344
- loss_allowed = P * trade_risk
344
+ loss_allowed = P * trade_risk / 100
345
345
  var = self.calculate_var(c=self.var_level, tf=self.var_tf)
346
346
  return min(var, loss_allowed)
347
347
 
@@ -9,7 +9,7 @@ from tabulate import tabulate
9
9
  from typing import List, Tuple, Dict, Any, Optional, Literal
10
10
  from bbstrader.btengine.performance import create_sharpe_ratio
11
11
  from bbstrader.metatrader.risk import RiskManagement
12
- from bbstrader.metatrader.account import INIT_MSG
12
+ from bbstrader.metatrader.account import check_mt5_connection, INIT_MSG
13
13
  from bbstrader.metatrader.utils import (
14
14
  TimeFrame, TradePosition, TickInfo,
15
15
  raise_mt5_error, trade_retcode_message, config_logger)
@@ -75,7 +75,6 @@ class Trade(RiskManagement):
75
75
  expert_id: int = 9818,
76
76
  version: str = '1.0',
77
77
  target: float = 5.0,
78
- be_on_trade_open: bool = True,
79
78
  start_time: str = "1:00",
80
79
  finishing_time: str = "23:00",
81
80
  ending_time: str = "23:30",
@@ -93,8 +92,7 @@ class Trade(RiskManagement):
93
92
  expert_id (int): The `unique ID` used to identify the expert advisor
94
93
  or the strategy used on the symbol.
95
94
  version (str): The `version` of the expert advisor.
96
- target (float): `Trading period (day, week, month) profit target` in percentage
97
- be_on_trade_open (bool): Whether to check for break-even when opening a trade.
95
+ target (float): `Trading period (day, week, month) profit target` in percentage.
98
96
  start_time (str): The` hour and minutes` that the expert advisor is able to start to run.
99
97
  finishing_time (str): The time after which no new position can be opened.
100
98
  ending_time (str): The time after which any open position will be closed.
@@ -131,7 +129,6 @@ class Trade(RiskManagement):
131
129
  self.expert_id = expert_id
132
130
  self.version = version
133
131
  self.target = target
134
- self.be_on_trade_open = be_on_trade_open
135
132
  self.verbose = verbose
136
133
  self.start = start_time
137
134
  self.end = ending_time
@@ -151,7 +148,7 @@ class Trade(RiskManagement):
151
148
  self.opened_orders = []
152
149
  self.break_even_status = []
153
150
  self.break_even_points = {}
154
- self.trail_after_points = {}
151
+ self.trail_after_points = []
155
152
 
156
153
  self.initialize()
157
154
  self.select_symbol()
@@ -168,7 +165,7 @@ class Trade(RiskManagement):
168
165
  def _get_logger(self, logger: str | Logger, consol_log: bool) -> Logger:
169
166
  """Get the logger object"""
170
167
  if isinstance(logger, str):
171
- return config_logger(logger, consol_log=consol_log)
168
+ return config_logger(logger, consol_log)
172
169
  return logger
173
170
 
174
171
  def initialize(self):
@@ -184,8 +181,7 @@ class Trade(RiskManagement):
184
181
  try:
185
182
  if self.verbose:
186
183
  print("\nInitializing the basics.")
187
- if not Mt5.initialize():
188
- raise_mt5_error(message=INIT_MSG)
184
+ check_mt5_connection()
189
185
  if self.verbose:
190
186
  print(
191
187
  f"You are running the @{self.expert_name} Expert advisor,"
@@ -363,7 +359,7 @@ class Trade(RiskManagement):
363
359
  }
364
360
  # Create the directory if it doesn't exist
365
361
  if dir is None:
366
- dir = f"{self.expert_name}_session_stats"
362
+ dir = f".{self.expert_name}_session_stats"
367
363
  os.makedirs(dir, exist_ok=True)
368
364
  if '.' in self.symbol:
369
365
  symbol = self.symbol.split('.')[0]
@@ -435,8 +431,7 @@ class Trade(RiskManagement):
435
431
  if action != 'BMKT':
436
432
  request["action"] = Mt5.TRADE_ACTION_PENDING
437
433
  request["type"] = self._order_type()[action][0]
438
- if self.be_on_trade_open:
439
- self.break_even(mm=mm, id=Id)
434
+ self.break_even(mm=mm, id=Id)
440
435
  if self.check(comment):
441
436
  self.request_result(_price, request, action),
442
437
 
@@ -505,8 +500,7 @@ class Trade(RiskManagement):
505
500
  if action != 'SMKT':
506
501
  request["action"] = Mt5.TRADE_ACTION_PENDING
507
502
  request["type"] = self._order_type()[action][0]
508
- if self.be_on_trade_open:
509
- self.break_even(mm=mm, id=Id)
503
+ self.break_even(mm=mm, id=Id)
510
504
  if self.check(comment):
511
505
  self.request_result(_price, request, action)
512
506
 
@@ -862,7 +856,7 @@ class Trade(RiskManagement):
862
856
  # This ensures that the position rich the minimum points required
863
857
  # before the trail can be set
864
858
  new_be = trail_after_points - be
865
- self.trail_after_points[position.ticket] = True
859
+ self.trail_after_points.append(position.ticket)
866
860
  new_be_points = self.break_even_points[position.ticket] + new_be
867
861
  favorable_move = float(points/point) >= new_be_points
868
862
  if favorable_move:
@@ -1342,30 +1336,68 @@ class Trade(RiskManagement):
1342
1336
  def create_trade_instance(
1343
1337
  symbols: List[str],
1344
1338
  params: Dict[str, Any],
1345
- logger: Logger = ...) -> Dict[str, Trade]:
1339
+ daily_risk: Optional[Dict[str, float]] = None,
1340
+ max_risk: Optional[Dict[str, float]] = None,
1341
+ pchange_sl: Optional[Dict[str, float] | float] = None,
1342
+ logger: Logger = None) -> Dict[str, Trade]:
1346
1343
  """
1347
1344
  Creates Trade instances for each symbol provided.
1348
1345
 
1349
1346
  Args:
1350
1347
  symbols: A list of trading symbols (e.g., ['AAPL', 'MSFT']).
1351
1348
  params: A dictionary containing parameters for the Trade instance.
1349
+ daily_risk: A dictionary containing daily risk weight for each symbol.
1350
+ max_risk: A dictionary containing maximum risk weight for each symbol.
1351
+ logger: A logger instance.
1352
1352
 
1353
1353
  Returns:
1354
1354
  A dictionary where keys are symbols and values are corresponding Trade instances.
1355
1355
 
1356
1356
  Raises:
1357
1357
  ValueError: If the 'symbols' list is empty or the 'params' dictionary is missing required keys.
1358
+
1359
+ Note:
1360
+ `daily_risk` and `max_risk` can be used to manage the risk of each symbol
1361
+ based on the importance of the symbol in the portfolio or strategy.
1358
1362
  """
1359
1363
  instances = {}
1360
1364
  if not symbols:
1361
1365
  raise ValueError("The 'symbols' list cannot be empty.")
1366
+ if not params:
1367
+ raise ValueError("The 'params' dictionary cannot be empty.")
1368
+
1369
+ if daily_risk is not None:
1370
+ for symbol in symbols:
1371
+ if symbol not in daily_risk:
1372
+ raise ValueError(f"Missing daily risk weight for symbol '{symbol}'.")
1373
+ if max_risk is not None:
1374
+ for symbol in symbols:
1375
+ if symbol not in max_risk:
1376
+ raise ValueError(f"Missing maximum risk percentage for symbol '{symbol}'.")
1377
+ if pchange_sl is not None:
1378
+ if isinstance(pchange_sl, dict):
1379
+ for symbol in symbols:
1380
+ if symbol not in pchange_sl:
1381
+ raise ValueError(f"Missing percentage change for symbol '{symbol}'.")
1382
+
1362
1383
  for symbol in symbols:
1363
1384
  try:
1364
- instances[symbol] = Trade(symbol=symbol, **params)
1385
+ params['symbol'] = symbol
1386
+ params['pchange_sl'] = (
1387
+ pchange_sl[symbol] if pchange_sl is not None
1388
+ and isinstance(pchange_sl, dict) else pchange_sl
1389
+ )
1390
+ params['daily_risk'] = daily_risk[symbol] if daily_risk is not None else params['daily_risk']
1391
+ params['max_risk'] = max_risk[symbol] if max_risk is not None else params['max_risk']
1392
+ instances[symbol] = Trade(**params)
1365
1393
  except Exception as e:
1366
1394
  logger.error(f"Creating Trade instance, SYMBOL={symbol} {e}")
1395
+
1367
1396
  if len(instances) != len(symbols):
1368
1397
  for symbol in symbols:
1369
1398
  if symbol not in instances:
1370
- logger.error(f"Failed to create Trade instance for SYMBOL={symbol}")
1371
- return instances
1399
+ if logger is not None:
1400
+ logger.error(f"Failed to create Trade instance for SYMBOL={symbol}")
1401
+ else:
1402
+ raise ValueError(f"Failed to create Trade instance for SYMBOL={symbol}")
1403
+ return instances
@@ -1,11 +1,10 @@
1
1
  import time
2
+ import MetaTrader5 as mt5
2
3
  from datetime import datetime
3
4
  from bbstrader.metatrader.trade import Trade
4
5
  from bbstrader.trading.strategies import Strategy
5
- from typing import Optional, Literal, List, Tuple, Dict
6
- import MetaTrader5 as mt5
7
- from bbstrader.metatrader.account import INIT_MSG
8
- from bbstrader.metatrader.utils import raise_mt5_error
6
+ from bbstrader.metatrader.account import check_mt5_connection
7
+ from typing import Optional, Literal, Tuple, List, Dict
9
8
 
10
9
 
11
10
  _TF_MAPPING = {
@@ -29,13 +28,6 @@ TradingDays = [
29
28
  'friday'
30
29
  ]
31
30
 
32
- def _check_mt5_connection():
33
- try:
34
- init = mt5.initialize()
35
- if not init:
36
- raise_mt5_error(INIT_MSG)
37
- except Exception:
38
- raise_mt5_error(INIT_MSG)
39
31
 
40
32
  def _mt5_execution(
41
33
  symbol_list, trades_instances, strategy_cls, /,
@@ -45,7 +37,7 @@ def _mt5_execution(
45
37
  symbols = symbol_list.copy()
46
38
  STRATEGY = kwargs.get('strategy_name')
47
39
  _max_trades = kwargs.get('max_trades')
48
- logger = kwargs.get('logger')
40
+ logger = trades_instances[symbols[0]].logger
49
41
  max_trades = {symbol: _max_trades[symbol] for symbol in symbols}
50
42
  if comment is None:
51
43
  trade = trades_instances[symbols[0]]
@@ -72,15 +64,18 @@ def _mt5_execution(
72
64
 
73
65
  long_market = {symbol: False for symbol in symbols}
74
66
  short_market = {symbol: False for symbol in symbols}
75
-
67
+ try:
68
+ check_mt5_connection()
69
+ strategy: Strategy = strategy_cls(symbol_list=symbols, mode='live', **kwargs)
70
+ except Exception as e:
71
+ logger.error(f"Error initializing strategy, {e}, STRATEGY={STRATEGY}")
72
+ return
76
73
  logger.info(
77
74
  f'Running {STRATEGY} Strategy on {symbols} in {time_frame} Interval ...')
78
- strategy: Strategy = strategy_cls(
79
- symbol_list=symbols, mode='live', **kwargs)
80
-
75
+
81
76
  while True:
82
77
  try:
83
- _check_mt5_connection()
78
+ check_mt5_connection()
84
79
  current_date = datetime.now()
85
80
  today = current_date.strftime("%A").lower()
86
81
  time.sleep(0.5)
@@ -105,13 +100,21 @@ def _mt5_execution(
105
100
  sells[symbol]) >= max_trades[symbol] for symbol in symbols}
106
101
  except Exception as e:
107
102
  logger.error(f"{e}, STRATEGY={STRATEGY}")
103
+ continue
108
104
  time.sleep(0.5)
105
+ try:
106
+ check_mt5_connection()
107
+ signals = strategy.calculate_signals()
108
+ except Exception as e:
109
+ logger.error(f"Calculating signal, {e}, STRATEGY={STRATEGY}")
110
+ continue
109
111
  for symbol in symbols:
110
112
  try:
113
+ check_mt5_connection()
111
114
  trade = trades_instances[symbol]
112
115
  logger.info(
113
116
  f"Calculating signal... SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
114
- signal = strategy.calculate_signals()[symbol]
117
+ signal = signals[symbol]
115
118
  if trade.trading_time() and today in trading_days:
116
119
  if signal is not None:
117
120
  logger.info(
@@ -155,7 +158,7 @@ def _mt5_execution(
155
158
 
156
159
  except Exception as e:
157
160
  logger.error(f"{e}, SYMBOL={symbol}, STRATEGY={STRATEGY}")
158
-
161
+ continue
159
162
  time.sleep((60 * iter_time) - 1.0)
160
163
  if iter_time == 1:
161
164
  time_intervals += 1
@@ -167,86 +170,92 @@ def _mt5_execution(
167
170
  f"(e.g; if time_frame is 15m, iter_time must be 1.5, 3, 3, 15 etc)"
168
171
  )
169
172
  print()
170
- if period.lower() == 'day':
171
- for symbol in symbols:
172
- trade = trades_instances[symbol]
173
- if trade.days_end():
174
- trade.close_positions(position_type='all', comment=comment)
175
- logger.info(
176
- f"End of the Day !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
177
- trade.statistics(save=True)
178
- if trades_instances[symbols[-1]].days_end():
179
- if period_end_action == 'break':
180
- break
181
- elif period_end_action == 'sleep':
173
+ try:
174
+ check_mt5_connection()
175
+ day_end = all(trade.days_end() for trade in trades_instances.values())
176
+ if period.lower() == 'day':
177
+ for symbol in symbols:
178
+ trade = trades_instances[symbol]
179
+ if trade.days_end():
180
+ trade.close_positions(position_type='all', comment=comment)
181
+ logger.info(
182
+ f"End of the Day !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
183
+ trade.statistics(save=True)
184
+ if day_end:
185
+ if period_end_action == 'break':
186
+ break
187
+ elif period_end_action == 'sleep':
188
+ sleep_time = trades_instances[symbols[-1]].sleep_time()
189
+ logger.info(f"Sleeping for {sleep_time} minutes ...\n")
190
+ time.sleep(60 * sleep_time)
191
+ logger.info("STARTING NEW TRADING SESSION ...\n")
192
+
193
+ elif period.lower() == 'week':
194
+ for symbol in symbols:
195
+ trade = trades_instances[symbol]
196
+ if trade.days_end() and today != 'friday':
197
+ logger.info(
198
+ f"End of the Day !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
199
+
200
+ elif trade.days_end() and today == 'friday':
201
+ trade.close_positions(position_type='all', comment=comment)
202
+ logger.info(
203
+ f"End of the Week !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
204
+ trade.statistics(save=True)
205
+ if day_end and today != 'friday':
182
206
  sleep_time = trades_instances[symbols[-1]].sleep_time()
183
- logger.info(f"Sleeping for {sleep_time} minutes ...")
207
+ logger.info(f"Sleeping for {sleep_time} minutes ...\n")
184
208
  time.sleep(60 * sleep_time)
185
209
  logger.info("STARTING NEW TRADING SESSION ...\n")
210
+ elif day_end and today == 'friday':
211
+ if period_end_action == 'break':
212
+ break
213
+ elif period_end_action == 'sleep':
214
+ sleep_time = trades_instances[symbols[-1]].sleep_time(weekend=True)
215
+ logger.info(f"Sleeping for {sleep_time} minutes ...\n")
216
+ time.sleep(60 * sleep_time)
217
+ logger.info("STARTING NEW TRADING SESSION ...\n")
186
218
 
187
- elif period.lower() == 'week':
188
- for symbol in symbols:
189
- trade = trades_instances[symbol]
190
- if trade.days_end() and today != 'friday':
191
- logger.info(
192
- f"End of the Day !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
219
+ elif period.lower() == 'month':
220
+ for symbol in symbols:
221
+ trade = trades_instances[symbol]
222
+ if trade.days_end() and today != 'friday':
223
+ logger.info(
224
+ f"End of the Day !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
193
225
 
194
- elif trade.days_end() and today == 'friday':
195
- trade.close_positions(position_type='all', comment=comment)
196
- logger.info(
197
- f"End of the Week !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
198
- trade.statistics(save=True)
199
- if trades_instances[symbols[-1]].days_end() and today != 'friday':
200
- sleep_time = trades_instances[symbols[-1]].sleep_time()
201
- logger.info(f"Sleeping for {sleep_time} minutes ...")
202
- time.sleep(60 * sleep_time)
203
- logger.info("STARTING NEW TRADING SESSION ...\n")
204
- elif trades_instances[symbols[-1]].days_end() and today == 'friday':
205
- if period_end_action == 'break':
206
- break
207
- elif period_end_action == 'sleep':
208
- sleep_time = trades_instances[symbols[-1]].sleep_time(weekend=True)
209
- logger.info(f"Sleeping for {sleep_time} minutes ...")
226
+ elif trade.days_end() and today == 'friday':
227
+ logger.info(
228
+ f"End of the Week !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
229
+ elif (
230
+ trade.days_end()
231
+ and today == 'friday'
232
+ and num_days/len(symbols) >= 20
233
+ ):
234
+ trade.close_positions(position_type='all', comment=comment)
235
+ logger.info(
236
+ f"End of the Month !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
237
+ trade.statistics(save=True)
238
+ if day_end and today != 'friday':
239
+ sleep_time = trades_instances[symbols[-1]].sleep_time()
240
+ logger.info(f"Sleeping for {sleep_time} minutes ...\n")
210
241
  time.sleep(60 * sleep_time)
211
242
  logger.info("STARTING NEW TRADING SESSION ...\n")
212
-
213
- elif period.lower() == 'month':
214
- for symbol in symbols:
215
- trade = trades_instances[symbol]
216
- if trade.days_end() and today != 'friday':
217
- logger.info(
218
- f"End of the Day !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
219
-
220
- elif trade.days_end() and today == 'friday':
221
- logger.info(
222
- f"End of the Week !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
223
- elif (
224
- trade.days_end()
225
- and today == 'friday'
226
- and num_days/len(symbols) >= 20
227
- ):
228
- trade.close_positions(position_type='all', comment=comment)
229
- logger.info(
230
- f"End of the Month !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}")
231
- trade.statistics(save=True)
232
- if trades_instances[symbols[-1]].days_end() and today != 'friday':
233
- sleep_time = trades_instances[symbols[-1]].sleep_time()
234
- logger.info(f"Sleeping for {sleep_time} minutes ...")
235
- time.sleep(60 * sleep_time)
236
- logger.info("STARTING NEW TRADING SESSION ...\n")
237
- num_days += 1
238
- elif trades_instances[symbols[-1]].days_end() and today == 'friday':
239
- sleep_time = trades_instances[symbols[-1]
240
- ].sleep_time(weekend=True)
241
- logger.info(f"Sleeping for {sleep_time} minutes ...")
242
- time.sleep(60 * sleep_time)
243
- logger.info("STARTING NEW TRADING SESSION ...\n")
244
- num_days += 1
245
- elif (trades_instances[symbols[-1]].days_end()
246
- and today == 'friday'
247
- and num_days/len(symbols) >= 20
248
- ):
249
- break
243
+ num_days += 1
244
+ elif day_end and today == 'friday':
245
+ sleep_time = trades_instances[symbols[-1]
246
+ ].sleep_time(weekend=True)
247
+ logger.info(f"Sleeping for {sleep_time} minutes ...\n")
248
+ time.sleep(60 * sleep_time)
249
+ logger.info("STARTING NEW TRADING SESSION ...\n")
250
+ num_days += 1
251
+ elif (day_end
252
+ and today == 'friday'
253
+ and num_days/len(symbols) >= 20
254
+ ):
255
+ break
256
+ except Exception as e:
257
+ logger.error(f"Handling period end actions, {e}, STRATEGY={STRATEGY}")
258
+ continue
250
259
 
251
260
 
252
261
  def _tws_execution(*args, **kwargs):
@@ -364,7 +373,6 @@ class ExecutionEngine():
364
373
  **kwargs: Additional keyword arguments
365
374
  - strategy_name (Optional[str]): Strategy name. Defaults to None.
366
375
  - max_trades (Dict[str, int]): Maximum trades per symbol. Defaults to None.
367
- - logger (Optional[logging.Logger]): Logger instance. Defaults to None.
368
376
 
369
377
  Note:
370
378
  1. For `trail` , `stop_trail` , `trail_after_points` , `be_plus_points` see `bbstrader.metatrader.trade.Trade.break_even()` .
@@ -404,6 +412,8 @@ class ExecutionEngine():
404
412
  if terminal not in _TERMINALS:
405
413
  raise ValueError(
406
414
  f"Invalid terminal: {terminal}. Must be either 'MT5' or 'TWS'")
415
+ elif terminal == 'MT5':
416
+ check_mt5_connection()
407
417
  _TERMINALS[terminal](
408
418
  self.symbol_list,
409
419
  self.trades_instances,
@@ -7,7 +7,6 @@ import pandas as pd
7
7
  from queue import Queue
8
8
  import yfinance as yf
9
9
  from datetime import datetime
10
- from typing import List, Literal, Dict, Union, Optional
11
10
  from bbstrader.metatrader.rates import Rates
12
11
  from bbstrader.metatrader.account import Account
13
12
  from bbstrader.btengine.event import SignalEvent
@@ -20,17 +19,19 @@ from bbstrader.btengine.execution import *
20
19
  from bbstrader.btengine.data import *
21
20
  from bbstrader.tseries import (
22
21
  KalmanFilterModel, ArimaGarchModel)
22
+ from typing import Union, Optional, Literal, Dict, List
23
23
 
24
24
  __all__ = [
25
25
  'SMAStrategy',
26
26
  'ArimaGarchStrategy',
27
27
  'KalmanFilterStrategy',
28
28
  'StockIndexSTBOTrading',
29
- 'test_strategy'
29
+ 'test_strategy',
30
+ 'get_quantities'
30
31
  ]
31
32
 
32
33
 
33
- def _get_quantities(quantities, symbol_list):
34
+ def get_quantities(quantities, symbol_list):
34
35
  if isinstance(quantities, dict):
35
36
  return quantities
36
37
  elif isinstance(quantities, int):
@@ -84,7 +85,7 @@ class SMAStrategy(Strategy):
84
85
  self.short_window = kwargs.get("short_window", 50)
85
86
  self.long_window = kwargs.get("long_window", 200)
86
87
  self.tf = kwargs.get("time_frame", 'D1')
87
- self.qty = _get_quantities(
88
+ self.qty = get_quantities(
88
89
  kwargs.get('quantities', 100), self.symbol_list)
89
90
  self.sd = kwargs.get("session_duration", 23.0)
90
91
  self.risk_models = build_hmm_models(self.symbol_list, **kwargs)
@@ -246,7 +247,7 @@ class ArimaGarchStrategy(Strategy):
246
247
  self.symbol_list = self.bars.symbol_list
247
248
  self.mode = mode
248
249
 
249
- self.qty = _get_quantities(
250
+ self.qty = get_quantities(
250
251
  kwargs.get('quantities', 100), self.symbol_list)
251
252
  self.arima_window = kwargs.get('arima_window', 252)
252
253
  self.tf = kwargs.get('time_frame', 'D1')
@@ -557,6 +558,7 @@ class KalmanFilterStrategy(Strategy):
557
558
  self.calculate_backtest_signals()
558
559
  elif self.mode == 'live':
559
560
  return self.calculate_live_signals()
561
+
560
562
 
561
563
  class StockIndexSTBOTrading(Strategy):
562
564
  """
@@ -617,7 +619,7 @@ class StockIndexSTBOTrading(Strategy):
617
619
  self.lowerst_price = {index: None for index in symbols}
618
620
 
619
621
  if self.mode == 'backtest':
620
- self.qty = _get_quantities(quantities, symbols)
622
+ self.qty = get_quantities(quantities, symbols)
621
623
  self.num_buys = {index: 0 for index in symbols}
622
624
  self.buy_prices = {index: [] for index in symbols}
623
625
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbstrader
3
- Version: 0.1.8
3
+ Version: 0.1.9
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/
@@ -6,21 +6,21 @@ bbstrader/btengine/data.py,sha256=B2cqkZZGIhedqMHeZBNB6RHGyeP-TFGOSlMoZq4uFUw,14
6
6
  bbstrader/btengine/event.py,sha256=dY2DFwRPDCEdsX7GnLiwpth73tOpnbjgqIqbkNMZu1U,8286
7
7
  bbstrader/btengine/execution.py,sha256=noat6ZxhbBYZQ0GLFYw78enp0vZCbeoGyOok4aSjWCA,5077
8
8
  bbstrader/btengine/performance.py,sha256=STb5xJQiTa25xZdYYmjpKW46iWWcB_-6wB6PCPbhREI,10745
9
- bbstrader/btengine/portfolio.py,sha256=Tjoloav3Mccj675w6LO8vdGpDdvWcTgpQN0eykpDJXo,14888
9
+ bbstrader/btengine/portfolio.py,sha256=LFsl38GbdYTJwd08ep1n4_1FPsRodQz1DHDPVSj-rBU,14882
10
10
  bbstrader/btengine/strategy.py,sha256=uLQdsEzI8-86Cj7HWkL8blVFxT0sNxEcLVnkBil6ZLk,1550
11
11
  bbstrader/metatrader/__init__.py,sha256=y4JLz05esm3PKerHMgtd3dmRpa7yUvWVuj_xOnlhXSA,261
12
- bbstrader/metatrader/account.py,sha256=bZRIxeg_t3QnSboEHoBQhp7HASlnfDydbsLSor5RwAE,44572
13
- bbstrader/metatrader/rates.py,sha256=QulMnr5LyveMausH1TaiLzI5wjz18RkaKY7OAeO3v2A,9707
14
- bbstrader/metatrader/risk.py,sha256=XzHdUZ9dz1C__L6WLG6htd5cnRgwUqhs8JAJzLVNhC4,25825
15
- bbstrader/metatrader/trade.py,sha256=uUkVVsYsAV94I9BD6yyMC0YpnNmniEGLWwvTzCAqOCM,61404
12
+ bbstrader/metatrader/account.py,sha256=5f6emtVEvXmxUnlmqFpC4hhL8sxOzOrdp7_pwJhXPhw,44716
13
+ bbstrader/metatrader/rates.py,sha256=FyG4WWq1NaCdHNxEW_8u3eOt0Wms7E_U4FIOIcUDWco,9605
14
+ bbstrader/metatrader/risk.py,sha256=Nz3RqkVFNA5FeXIqINjmGUaj88YaYGw23XsVOvaHjB8,25831
15
+ bbstrader/metatrader/trade.py,sha256=M5ho8x_NRVCEWO_dmDCiJrhhbcfpnia6tOmQRfV7p4U,62967
16
16
  bbstrader/metatrader/utils.py,sha256=xc5VYQ-eejpHIPJIhLi8vxAF5zjix5NSXywXu2Eb7LI,19186
17
17
  bbstrader/models/__init__.py,sha256=6tAj9V9vgwesgPVMKznwRB3k8-Ec8Q73Di5p2UO0qlA,274
18
18
  bbstrader/models/risk.py,sha256=Pm_WoGI-vtPW75fwo_7ptF2Br-xQYBwrAAOIgqDQmy8,15120
19
19
  bbstrader/trading/__init__.py,sha256=3_PeIcuQ7znoCPdq8FqRmbCc0czNiernpIRkBXJZvg0,452
20
- bbstrader/trading/execution.py,sha256=0bMXGczv4qnWBRomkXcQdQT378KTZlpD0GsubEepGzY,20139
21
- bbstrader/trading/strategies.py,sha256=Ks6fR3JtBFit1mcEs1TVqXQsPVCaHADLnYhkyNeXrtg,36943
22
- bbstrader-0.1.8.dist-info/LICENSE,sha256=1EudjwwP2oTJy8Vh0e-Kzv8VZZU95y-t6c3DYhR51uc,1115
23
- bbstrader-0.1.8.dist-info/METADATA,sha256=PYJJW9504JyWi5Mpa3gxE9ZADGI81oKpTbKXCwkYG7o,9660
24
- bbstrader-0.1.8.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
25
- bbstrader-0.1.8.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
26
- bbstrader-0.1.8.dist-info/RECORD,,
20
+ bbstrader/trading/execution.py,sha256=Y3iKLbgCNVLw2XTDUM8Mv6hlcO8H83VyMKlZgjAKX2c,20744
21
+ bbstrader/trading/strategies.py,sha256=uYVeFeqVHHYrkgk4Eiziivj0iIO0RQKXCAoOSQ4XVRE,36972
22
+ bbstrader-0.1.9.dist-info/LICENSE,sha256=1EudjwwP2oTJy8Vh0e-Kzv8VZZU95y-t6c3DYhR51uc,1115
23
+ bbstrader-0.1.9.dist-info/METADATA,sha256=aJILSlgr7yOdyozYyZPseOUUy7WkJcgHUv-TnudXSvY,9660
24
+ bbstrader-0.1.9.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
25
+ bbstrader-0.1.9.dist-info/top_level.txt,sha256=Wwj322jZmxGZ6gD_TdaPiPLjED5ReObm5omerwlmZIg,10
26
+ bbstrader-0.1.9.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5