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

@@ -17,19 +17,19 @@ def markowitz_weights(prices=None, rfr=0.0, freq=252):
17
17
  """
18
18
  Calculates optimal portfolio weights using Markowitz's mean-variance optimization (Max Sharpe Ratio) with multiple solvers.
19
19
 
20
- Parameters:
20
+ Parameters
21
21
  ----------
22
22
  prices : pd.DataFrame, optional
23
23
  Price data for assets, where rows represent time periods and columns represent assets.
24
24
  freq : int, optional
25
25
  Frequency of the data, such as 252 for daily returns in a year (default is 252).
26
26
 
27
- Returns:
27
+ Returns
28
28
  -------
29
29
  dict
30
30
  Dictionary containing the optimal asset weights for maximizing the Sharpe ratio, normalized to sum to 1.
31
31
 
32
- Notes:
32
+ Notes
33
33
  -----
34
34
  This function attempts to maximize the Sharpe ratio by iterating through various solvers ('SCS', 'ECOS', 'OSQP')
35
35
  from the PyPortfolioOpt library. If a solver fails, it proceeds to the next one. If none succeed, an error message
@@ -37,7 +37,7 @@ def markowitz_weights(prices=None, rfr=0.0, freq=252):
37
37
 
38
38
  This function is useful for portfolio with a small number of assets, as it may not scale well for large portfolios.
39
39
 
40
- Raises:
40
+ Raises
41
41
  ------
42
42
  Exception
43
43
  If all solvers fail, each will print an exception error message during runtime.
@@ -61,7 +61,7 @@ def hierarchical_risk_parity(prices=None, returns=None, freq=252):
61
61
  """
62
62
  Computes asset weights using Hierarchical Risk Parity (HRP) for risk-averse portfolio allocation.
63
63
 
64
- Parameters:
64
+ Parameters
65
65
  ----------
66
66
  prices : pd.DataFrame, optional
67
67
  Price data for assets; if provided, daily returns will be calculated.
@@ -70,17 +70,17 @@ def hierarchical_risk_parity(prices=None, returns=None, freq=252):
70
70
  freq : int, optional
71
71
  Number of days to consider in calculating portfolio weights (default is 252).
72
72
 
73
- Returns:
73
+ Returns
74
74
  -------
75
75
  dict
76
76
  Optimized asset weights using the HRP method, with asset weights summing to 1.
77
77
 
78
- Raises:
78
+ Raises
79
79
  ------
80
80
  ValueError
81
81
  If neither `prices` nor `returns` are provided.
82
82
 
83
- Notes:
83
+ Notes
84
84
  -----
85
85
  Hierarchical Risk Parity is particularly useful for portfolios with a large number of assets,
86
86
  as it mitigates issues of multicollinearity and estimation errors in covariance matrices by
@@ -101,7 +101,7 @@ def equal_weighted(prices=None, returns=None, round_digits=5):
101
101
  """
102
102
  Generates an equal-weighted portfolio by assigning an equal proportion to each asset.
103
103
 
104
- Parameters:
104
+ Parameters
105
105
  ----------
106
106
  prices : pd.DataFrame, optional
107
107
  Price data for assets, where each column represents an asset.
@@ -110,21 +110,22 @@ def equal_weighted(prices=None, returns=None, round_digits=5):
110
110
  round_digits : int, optional
111
111
  Number of decimal places to round each weight to (default is 5).
112
112
 
113
- Returns:
113
+ Returns
114
114
  -------
115
115
  dict
116
116
  Dictionary with equal weights assigned to each asset, summing to 1.
117
117
 
118
- Raises:
118
+ Raises
119
119
  ------
120
120
  ValueError
121
121
  If neither `prices` nor `returns` are provided.
122
122
 
123
- Notes:
123
+ Notes
124
124
  -----
125
125
  Equal weighting is a simple allocation method that assumes equal importance across all assets,
126
126
  useful as a baseline model and when no strong views exist on asset return expectations or risk.
127
127
  """
128
+
128
129
  if returns is None and prices is None:
129
130
  raise ValueError("Either prices or returns must be provided")
130
131
  if returns is None:
@@ -139,7 +140,7 @@ def optimized_weights(prices=None, returns=None, rfr=0.0, freq=252, method='equa
139
140
  """
140
141
  Selects an optimization method to calculate portfolio weights based on user preference.
141
142
 
142
- Parameters:
143
+ Parameters
143
144
  ----------
144
145
  prices : pd.DataFrame, optional
145
146
  Price data for assets, required for certain methods.
@@ -150,17 +151,17 @@ def optimized_weights(prices=None, returns=None, rfr=0.0, freq=252, method='equa
150
151
  method : str, optional
151
152
  Optimization method to use ('markowitz', 'hrp', or 'equal') (default is 'markowitz').
152
153
 
153
- Returns:
154
+ Returns
154
155
  -------
155
156
  dict
156
157
  Dictionary containing optimized asset weights based on the chosen method.
157
158
 
158
- Raises:
159
+ Raises
159
160
  ------
160
161
  ValueError
161
162
  If an unknown optimization method is specified.
162
163
 
163
- Notes:
164
+ Notes
164
165
  -----
165
166
  This function integrates different optimization methods:
166
167
  - 'markowitz': mean-variance optimization with max Sharpe ratio
@@ -20,6 +20,15 @@ class EigenPortfolios(object):
20
20
  to derive portfolios (eigenportfolios) that capture distinct risk factors in the asset returns. Each eigenportfolio
21
21
  represents a principal component of the return covariance matrix, ordered by the magnitude of its eigenvalue. These
22
22
  portfolios capture most of the variance in asset returns and are mutually uncorrelated.
23
+
24
+ Notes
25
+ -----
26
+ The implementation is inspired by the book "Machine Learning for Algorithmic Trading" by Stefan Jansen.
27
+
28
+ References
29
+ ----------
30
+ Stefan Jansen (2020). Machine Learning for Algorithmic Trading - Second Edition.
31
+ chapter 13, Data-Driven Risk Factors and Asset Allocation with Unsupervised Learning.
23
32
 
24
33
  """
25
34
  def __init__(self):
@@ -32,12 +41,12 @@ class EigenPortfolios(object):
32
41
  """
33
42
  Returns the computed eigenportfolios (weights of assets in each portfolio).
34
43
 
35
- Returns:
44
+ Returns
36
45
  -------
37
46
  pd.DataFrame
38
47
  DataFrame containing eigenportfolio weights for each asset.
39
48
 
40
- Raises:
49
+ Raises
41
50
  ------
42
51
  ValueError
43
52
  If `fit()` has not been called before retrieving portfolios.
@@ -50,19 +59,19 @@ class EigenPortfolios(object):
50
59
  """
51
60
  Computes the eigenportfolios based on PCA of the asset returns' covariance matrix.
52
61
 
53
- Parameters:
62
+ Parameters
54
63
  ----------
55
64
  returns : pd.DataFrame
56
65
  Historical returns of assets to be used for PCA.
57
66
  n_portfolios : int, optional
58
67
  Number of eigenportfolios to compute (default is 4).
59
68
 
60
- Returns:
69
+ Returns
61
70
  -------
62
71
  pd.DataFrame
63
72
  DataFrame containing normalized weights for each eigenportfolio.
64
73
 
65
- Notes:
74
+ Notes
66
75
  -----
67
76
  This method performs winsorization and normalization on returns to reduce the impact of outliers
68
77
  and achieve zero mean and unit variance. It uses the first `n_portfolios` principal components
@@ -94,7 +103,7 @@ class EigenPortfolios(object):
94
103
  """
95
104
  Plots the weights of each asset in each eigenportfolio as bar charts.
96
105
 
97
- Notes:
106
+ Notes
98
107
  -----
99
108
  Each subplot represents one eigenportfolio, showing the contribution of each asset.
100
109
  """
@@ -118,7 +127,7 @@ class EigenPortfolios(object):
118
127
  """
119
128
  Plots the cumulative returns of each eigenportfolio over time.
120
129
 
121
- Notes:
130
+ Notes
122
131
  -----
123
132
  This method calculates the historical cumulative performance of each eigenportfolio
124
133
  by weighting asset returns according to eigenportfolio weights.
@@ -152,7 +161,7 @@ class EigenPortfolios(object):
152
161
  """
153
162
  Optimizes the chosen eigenportfolio based on a specified optimization method.
154
163
 
155
- Parameters:
164
+ Parameters
156
165
  ----------
157
166
  portfolio : int, optional
158
167
  Index of the eigenportfolio to optimize (default is 1).
@@ -165,17 +174,17 @@ class EigenPortfolios(object):
165
174
  plot : bool, optional
166
175
  Whether to plot the performance of the optimized portfolio (default is True).
167
176
 
168
- Returns:
177
+ Returns
169
178
  -------
170
179
  dict
171
180
  Dictionary of optimized asset weights.
172
181
 
173
- Raises:
182
+ Raises
174
183
  ------
175
184
  ValueError
176
185
  If an unknown optimizer is specified, or if prices are not provided when using Markowitz optimization.
177
186
 
178
- Notes:
187
+ Notes
179
188
  -----
180
189
  The optimization method varies based on risk-return assumptions, with options for traditional Markowitz optimization,
181
190
  Hierarchical Risk Parity, or equal weighting.
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
- df['Returns'] = df['Adj Close'].pct_change()
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)
@@ -377,7 +385,7 @@ def build_hmm_models(symbol_list=None, **kwargs
377
385
  hmm_models[symbol] = hmm
378
386
  if mt5_data:
379
387
  for symbol in symbols:
380
- rates = Rates(symbol, tf, start_pos=hmm_end, session_duration=sd)
388
+ rates = Rates(symbol, timeframe=tf, start_pos=hmm_end, session_duration=sd, **kwargs)
381
389
  data = rates.get_rates_from_pos()
382
390
  assert data is not None, f"No data for {symbol}"
383
391
  hmm = HMMRiskManager(
@@ -85,12 +85,17 @@ def _mt5_execution(
85
85
  time_frame = kwargs.get('time_frame', '15m')
86
86
  STRATEGY = kwargs.get('strategy_name')
87
87
  mtrades = kwargs.get('max_trades')
88
+ check_max_trades = kwargs.get('check_max_trades', True)
88
89
  notify = kwargs.get('notify', False)
89
90
  if notify:
90
91
  telegram = kwargs.get('telegram', False)
91
92
  bot_token = kwargs.get('bot_token')
92
93
  chat_id = kwargs.get('chat_id')
93
-
94
+
95
+ expert_ids = kwargs.get('expert_id')
96
+ if expert_ids is None:
97
+ expert_ids = set([trade.expert_id for trade in trades_instances.values()])
98
+
94
99
  def update_risk(weights):
95
100
  if weights is not None:
96
101
  for symbol in symbols:
@@ -104,7 +109,9 @@ def _mt5_execution(
104
109
  telegram=telegram, token=bot_token, chat_id=chat_id)
105
110
 
106
111
  logger = trades_instances[symbols[0]].logger
107
- max_trades = {symbol: mtrades[symbol] for symbol in symbols}
112
+ max_trades = {symbol: mtrades[symbol]
113
+ if mtrades is not None and symbol in mtrades
114
+ else trades_instances[symbol].max_trade() for symbol in symbols}
108
115
  if comment is None:
109
116
  trade = trades_instances[symbols[0]]
110
117
  comment = f"{trade.expert_name}@{trade.version}"
@@ -123,7 +130,7 @@ def _mt5_execution(
123
130
  long_market = {symbol: False for symbol in symbols}
124
131
  short_market = {symbol: False for symbol in symbols}
125
132
  try:
126
- check_mt5_connection()
133
+ check_mt5_connection(**kwargs)
127
134
  strategy: MT5Strategy = strategy_cls(symbol_list=symbols, mode='live', **kwargs)
128
135
  except Exception as e:
129
136
  logger.error(f"Initializing strategy, {e}, STRATEGY={STRATEGY}")
@@ -133,7 +140,7 @@ def _mt5_execution(
133
140
 
134
141
  while True:
135
142
  try:
136
- check_mt5_connection()
143
+ check_mt5_connection(**kwargs)
137
144
  current_date = datetime.now()
138
145
  today = current_date.strftime("%A").lower()
139
146
  time.sleep(0.5)
@@ -142,8 +149,14 @@ def _mt5_execution(
142
149
  positions_orders[type] = {}
143
150
  for symbol in symbols:
144
151
  positions_orders[type][symbol] = None
145
- func = getattr(trades_instances[symbol], f"get_current_{type}")
146
- positions_orders[type][symbol] = func()
152
+ for id in expert_ids:
153
+ func = getattr(trades_instances[symbol], f"get_current_{type}")
154
+ func_value = func(id=id)
155
+ if func_value is not None:
156
+ if positions_orders[type][symbol] is None:
157
+ positions_orders[type][symbol] = func(id=id)
158
+ else:
159
+ positions_orders[type][symbol] += func(id=id)
147
160
  buys = positions_orders['buys']
148
161
  sells = positions_orders['sells']
149
162
  for symbol in symbols:
@@ -153,41 +166,47 @@ def _mt5_execution(
153
166
  logger.info(
154
167
  f"Current {type.upper()} SYMBOL={symbol}: \
155
168
  {positions_orders[type][symbol]}, STRATEGY={STRATEGY}")
156
- long_market = {
157
- symbol: buys[symbol] is not None
158
- and len(buys[symbol]) >= max_trades[symbol] for symbol in symbols
159
- }
160
- short_market = {
161
- symbol: sells[symbol] is not None
162
- and len(sells[symbol]) >= max_trades[symbol] for symbol in symbols
163
- }
169
+ if check_max_trades:
170
+ long_market = {
171
+ symbol: buys[symbol] is not None
172
+ and len(buys[symbol]) >= max_trades[symbol] for symbol in symbols
173
+ }
174
+ short_market = {
175
+ symbol: sells[symbol] is not None
176
+ and len(sells[symbol]) >= max_trades[symbol] for symbol in symbols
177
+ }
164
178
 
165
179
  except Exception as e:
166
180
  logger.error(f"Handling Positions and Orders, {e}, STRATEGY={STRATEGY}")
167
181
  continue
168
182
  time.sleep(0.5)
169
183
  try:
170
- check_mt5_connection()
184
+ check_mt5_connection(**kwargs)
171
185
  signals = strategy.calculate_signals()
172
- weights = strategy.apply_risk_management(optimizer)
186
+ weights = None
187
+ if hasattr(strategy, 'apply_risk_management'):
188
+ weights = strategy.apply_risk_management(optimizer)
173
189
  update_risk(weights)
174
190
  except Exception as e:
175
191
  logger.error(f"Calculating signal, {e}, STRATEGY={STRATEGY}")
176
192
  continue
177
193
  for symbol in symbols:
178
194
  try:
179
- check_mt5_connection()
195
+ check_mt5_connection(**kwargs)
180
196
  trade: Trade = trades_instances[symbol]
181
197
  tfmsg = f"Time Frame Not completed !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}"
182
198
  riskmsg = f"Risk not allowed !!! SYMBOL={trade.symbol}, STRATEGY={STRATEGY}"
183
199
  signal = signals[symbol]
184
200
  if isinstance(signal, dict):
185
- signal = signal['action']
186
- price = signal['price']
201
+ action = signal.get('action')
202
+ price = signal.get('price')
203
+ id = signal.get('id', trade.expert_id)
187
204
  stoplimit = signal.get('stoplimit')
205
+ signal = action
188
206
  elif isinstance(signal, str):
189
207
  price = None
190
208
  stoplimit = None
209
+ id = trade.expert_id
191
210
  if trade.trading_time() and today in trading_days:
192
211
  if signal is not None:
193
212
  signal = 'BMKT' if signal == 'LONG' else signal
@@ -203,9 +222,9 @@ def _mt5_execution(
203
222
  if notify:
204
223
  _send_notification(info)
205
224
  if position_type in POSITIONS_TYPES:
206
- trade.close_positions(position_type=order_type)
225
+ trade.close_positions(position_type=order_type, id=id)
207
226
  else:
208
- trade.close_orders(order_type=order_type)
227
+ trade.close_orders(order_type=order_type, id=id)
209
228
  elif signal in BUYS and not long_market[symbol]:
210
229
  if use_trade_time:
211
230
  if time_intervals % trade_time == 0 or buys[symbol] is None:
@@ -213,7 +232,7 @@ def _mt5_execution(
213
232
  if notify:
214
233
  _send_notification(info)
215
234
  trade.open_buy_position(
216
- action=signal, price=price, stoplimit=stoplimit, mm=mm, comment=comment)
235
+ action=signal, price=price, stoplimit=stoplimit, id=id, mm=mm, comment=comment)
217
236
  else:
218
237
  logger.info(tfmsg)
219
238
  check(buys[symbol], sells[symbol], symbol)
@@ -222,9 +241,11 @@ def _mt5_execution(
222
241
  if notify:
223
242
  _send_notification(info)
224
243
  trade.open_buy_position(
225
- action=signal, price=price, stoplimit=stoplimit, mm=mm, comment=comment)
226
- elif signal in BUYS and long_market[symbol]:
227
- logger.info(riskmsg)
244
+ action=signal, price=price, stoplimit=stoplimit, id=id, mm=mm, comment=comment)
245
+ elif signal in BUYS:
246
+ if check_max_trades:
247
+ if long_market[symbol]:
248
+ logger.info(riskmsg)
228
249
  check(buys[symbol], sells[symbol], symbol)
229
250
 
230
251
  elif signal in SELLS and not short_market[symbol]:
@@ -234,7 +255,7 @@ def _mt5_execution(
234
255
  if notify:
235
256
  _send_notification(info)
236
257
  trade.open_sell_position(
237
- action=signal, price=price, stoplimit=stoplimit, mm=mm, comment=comment)
258
+ action=signal, price=price, stoplimit=stoplimit, id=id, mm=mm, comment=comment)
238
259
  else:
239
260
  logger.info(tfmsg)
240
261
  check(buys[symbol], sells[symbol], symbol)
@@ -243,9 +264,11 @@ def _mt5_execution(
243
264
  if notify:
244
265
  _send_notification(info)
245
266
  trade.open_sell_position(
246
- action=signal, price=price, stoplimit=stoplimit, mm=mm, comment=comment)
247
- elif signal in SELLS and short_market[symbol]:
248
- logger.info(riskmsg)
267
+ action=signal, price=price, stoplimit=stoplimit, id=id, mm=mm, comment=comment)
268
+ elif signal in SELLS:
269
+ if check_max_trades:
270
+ if short_market[symbol]:
271
+ logger.info(riskmsg)
249
272
  check(buys[symbol], sells[symbol], symbol)
250
273
  else:
251
274
  check(buys[symbol], sells[symbol], symbol)
@@ -269,7 +292,7 @@ def _mt5_execution(
269
292
  )
270
293
  try:
271
294
  FRIDAY = 'friday'
272
- check_mt5_connection()
295
+ check_mt5_connection(**kwargs)
273
296
  day_end = all(trade.days_end() for trade in trades_instances.values())
274
297
  if closing_pnl is not None:
275
298
  closing = all(trade.positive_profit(id=trade.expert_id, th=closing_pnl)
@@ -284,7 +307,8 @@ def _mt5_execution(
284
307
  for symbol in symbols:
285
308
  trade = trades_instances[symbol]
286
309
  if trade.days_end() and closing:
287
- trade.close_positions(position_type='all', comment=comment)
310
+ for id in expert_ids:
311
+ trade.close_positions(position_type='all', id=id, comment=comment)
288
312
  logmsg("Day")
289
313
  trade.statistics(save=True)
290
314
  if day_end:
@@ -308,7 +332,8 @@ def _mt5_execution(
308
332
  logmsg("Day")
309
333
 
310
334
  elif trade.days_end() and today == FRIDAY and closing:
311
- trade.close_positions(position_type='all', comment=comment)
335
+ for id in expert_ids:
336
+ trade.close_positions(position_type='all', id=id, comment=comment)
312
337
  logmsg("Week")
313
338
  trade.statistics(save=True)
314
339
  if day_end and today != FRIDAY:
@@ -337,7 +362,8 @@ def _mt5_execution(
337
362
  and today == FRIDAY
338
363
  and num_days/len(symbols) >= 20
339
364
  ) and closing:
340
- trade.close_positions(position_type='all', comment=comment)
365
+ for id in expert_ids:
366
+ trade.close_positions(position_type='all', id=id, comment=comment)
341
367
  logmsg("Month")
342
368
  trade.statistics(save=True)
343
369
  if day_end and today != FRIDAY:
@@ -461,7 +487,7 @@ class MT5ExecutionEngine():
461
487
  trading_days: Optional[List[str]] = TradingDays,
462
488
  comment: Optional[str] = None,
463
489
  **kwargs
464
- ):
490
+ ):
465
491
  """
466
492
  Args:
467
493
  symbol_list : List of symbols to trade
@@ -505,6 +531,7 @@ class MT5ExecutionEngine():
505
531
 
506
532
  4. All strategies must generate signals for backtesting and live trading.
507
533
  See the `bbstrader.trading.strategies` module for more information on how to create custom strategies.
534
+ See `bbstrader.metatrader.account.check_mt5_connection()` for more details on how to connect to MT5 terminal.
508
535
  """
509
536
  self.symbol_list = symbol_list
510
537
  self.trades_instances = trades_instances
@@ -525,8 +552,13 @@ class MT5ExecutionEngine():
525
552
  self.comment = comment
526
553
  self.kwargs = kwargs
527
554
 
555
+ def __repr__(self):
556
+ trades = self.trades_instances.keys()
557
+ s = self.strategy_cls.__name__
558
+ return f"MT5ExecutionEngine(Symbols={list(trades)}, Strategy={s})"
559
+
528
560
  def run(self):
529
- check_mt5_connection()
561
+ check_mt5_connection(**self.kwargs)
530
562
  _mt5_execution(
531
563
  self.symbol_list,
532
564
  self.trades_instances,
@@ -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
- signals[s] = signal
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)
@@ -404,7 +404,7 @@ class KalmanFilterStrategy(Strategy):
404
404
 
405
405
  self.hmm_tiker = kwargs.get("hmm_tiker")
406
406
  self._assert_tikers()
407
- self.account = Account()
407
+ self.account = Account(**kwargs)
408
408
  self.hmm_window = kwargs.get("hmm_window", 50)
409
409
  self.qty = kwargs.get("quantity", 100)
410
410
  self.tf = kwargs.get("time_frame", "D1")