bbstrader 0.1.4__tar.gz → 0.1.5__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.

Files changed (33) hide show
  1. {bbstrader-0.1.4 → bbstrader-0.1.5}/PKG-INFO +4 -1
  2. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/metatrader/account.py +32 -0
  3. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/metatrader/rates.py +11 -0
  4. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/metatrader/risk.py +52 -30
  5. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/metatrader/trade.py +6 -6
  6. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader.egg-info/PKG-INFO +4 -1
  7. {bbstrader-0.1.4 → bbstrader-0.1.5}/setup.py +6 -1
  8. {bbstrader-0.1.4 → bbstrader-0.1.5}/LICENSE +0 -0
  9. {bbstrader-0.1.4 → bbstrader-0.1.5}/README.md +0 -0
  10. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/__ini__.py +0 -0
  11. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/__init__.py +0 -0
  12. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/backtest.py +0 -0
  13. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/data.py +0 -0
  14. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/event.py +0 -0
  15. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/execution.py +0 -0
  16. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/performance.py +0 -0
  17. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/portfolio.py +0 -0
  18. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/btengine/strategy.py +0 -0
  19. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/metatrader/__init__.py +0 -0
  20. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/metatrader/utils.py +0 -0
  21. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/models/__init__.py +0 -0
  22. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/models/risk.py +0 -0
  23. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/strategies.py +0 -0
  24. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/trading/__init__.py +0 -0
  25. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/trading/execution.py +0 -0
  26. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/trading/run.py +0 -0
  27. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/trading/utils.py +0 -0
  28. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader/tseries.py +0 -0
  29. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader.egg-info/SOURCES.txt +0 -0
  30. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader.egg-info/dependency_links.txt +0 -0
  31. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader.egg-info/requires.txt +0 -0
  32. {bbstrader-0.1.4 → bbstrader-0.1.5}/bbstrader.egg-info/top_level.txt +0 -0
  33. {bbstrader-0.1.4 → bbstrader-0.1.5}/setup.cfg +0 -0
@@ -1,12 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbstrader
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: Simplified Investment & Trading Toolkit
5
5
  Home-page: https://github.com/bbalouki/bbstrader
6
+ Download-URL: https://pypi.org/project/bbstrader/
6
7
  Author: Bertin Balouki SIMYELI
7
8
  Author-email: <bertin@bbstrader.com>
8
9
  Maintainer: Bertin Balouki SIMYELI
9
10
  License: The MIT License (MIT)
11
+ Project-URL: Documentation, https://bbstrader.readthedocs.io/en/latest/
12
+ Project-URL: Source Code, https://github.com/bbalouki/bbstrader
10
13
  Keywords: Finance,Toolkit,Financial,Analysis,Fundamental,Quantitative,Database,Equities,Currencies,Economics,ETFs,Funds,Indices,Moneymarkets,Commodities,Futures,CFDs,Derivatives,Trading,Investing,Portfolio,Optimization,Performance
11
14
  Classifier: Development Status :: 5 - Production/Stable
12
15
  Classifier: Intended Audience :: Developers
@@ -615,6 +615,38 @@ class Account(object):
615
615
  """
616
616
  self._show_info(self.get_tick_info, "tick", symbol=symbol)
617
617
 
618
+ def calculate_margin(self,
619
+ action: Literal['buy', 'sell'],
620
+ symbol: str,
621
+ lot: float,
622
+ price: float) -> float:
623
+ """
624
+ Calculate margin required for an order.
625
+
626
+ Args:
627
+ action (str): The trading action, either 'buy' or 'sell'.
628
+ symbol (str): The symbol of the financial instrument.
629
+ lot (float): The lot size of the order.
630
+ price (float): The price of the order.
631
+
632
+ Returns:
633
+ float: The margin required for the order.
634
+
635
+ Raises:
636
+ MT5TerminalError: A specific exception based on the error code.
637
+ """
638
+ _action = {
639
+ 'buy': mt5.ORDER_TYPE_BUY,
640
+ 'sell': mt5.ORDER_TYPE_SELL
641
+ }
642
+ try:
643
+ margin = mt5.order_calc_margin(_action[action], symbol, lot, price)
644
+ if margin is None:
645
+ return None
646
+ return margin
647
+ except Exception as e:
648
+ raise_mt5_error(e)
649
+
618
650
  def check_order(self,
619
651
  request: Dict[str, Any]) -> OrderCheckResult:
620
652
  """
@@ -191,6 +191,17 @@ class Rates(object):
191
191
 
192
192
  @property
193
193
  def get_returns(self):
194
+ """
195
+ Fractional change between the current and a prior element.
196
+
197
+ Computes the fractional change from the immediately previous row by default.
198
+ This is useful in comparing the fraction of change in a time series of elements.
199
+
200
+ Note
201
+ ----
202
+ It calculates fractional change (also known as `per unit change or relative change`)
203
+ and `not percentage change`. If you need the percentage change, multiply these values by 100.
204
+ """
194
205
  data = self.data.copy()
195
206
  data['Returns'] = data['Adj Close'].pct_change()
196
207
  data = data.dropna()
@@ -1,4 +1,5 @@
1
1
  import random
2
+ import re
2
3
  import numpy as np
3
4
  from scipy.stats import norm
4
5
  from datetime import datetime
@@ -67,6 +68,8 @@ class RiskManagement(Account):
67
68
  max_trades: Optional[int] = None,
68
69
  std_stop: bool = False,
69
70
  pchange_sl: Optional[float] = None,
71
+ var_level: float = 0.95,
72
+ var_time_frame: TimeFrame = 'D1',
70
73
  account_leverage: bool = True,
71
74
  time_frame: TimeFrame = 'D1',
72
75
  start_time: str = "1:00",
@@ -91,6 +94,9 @@ class RiskManagement(Account):
91
94
  On `historical volatility` of the trading instrument. Defaults to False.
92
95
  pchange_sl (float, optional): If set, the Stop loss is calculated based
93
96
  On `percentage change` of the trading instrument.
97
+ var_level (float, optional): Confidence level for Value-at-Risk,e.g., 0.99 for 99% confidence interval.
98
+ The default is 0.95.
99
+ var_time_frame (str, optional): Time frame to use to calculate the VaR.
94
100
  account_leverage (bool, optional): If set to True the account leverage will be used
95
101
  In risk management setting. Defaults to False.
96
102
  time_frame (str, optional): The time frame on which the program is working
@@ -118,7 +124,9 @@ class RiskManagement(Account):
118
124
  if be is not None and (not isinstance(be, int) or be <= 0):
119
125
  raise ValueError("be must be a positive integer number")
120
126
  if time_frame not in TIMEFRAMES:
121
- raise ValueError("Unsupported time frame")
127
+ raise ValueError("Unsupported time frame {}".format(time_frame))
128
+ if var_time_frame not in TIMEFRAMES:
129
+ raise ValueError("Unsupported time frame {}".format(var_time_frame))
122
130
 
123
131
  self.symbol = symbol
124
132
  self.start_time = start_time
@@ -126,6 +134,8 @@ class RiskManagement(Account):
126
134
  self.max_trades = max_trades
127
135
  self.std = std_stop
128
136
  self.pchange = pchange_sl
137
+ self.var_level = var_level
138
+ self.var_tf = var_time_frame
129
139
  self.daily_dd = daily_risk
130
140
  self.max_risk = max_risk
131
141
  self.rr = rr
@@ -136,8 +146,21 @@ class RiskManagement(Account):
136
146
  self.account_leverage = account_leverage
137
147
  self.symbol_info = super().get_symbol_info(self.symbol)
138
148
 
139
- self.TF = self.get_minutes(
140
- ) if time_frame == 'D1' else TIMEFRAMES[time_frame]
149
+ self._tf = time_frame
150
+
151
+ def _convert_time_frame(self, tf: str) -> int:
152
+ """Convert time frame to minutes"""
153
+ if tf == 'D1':
154
+ tf_int = self.get_minutes()
155
+ elif 'm' in tf:
156
+ tf_int = TIMEFRAMES[tf]
157
+ elif 'h' in tf:
158
+ tf_int = int(tf[0])*60
159
+ elif tf == 'W1':
160
+ tf_int = self.get_minutes() * 5
161
+ elif tf == 'MN1':
162
+ tf_int = self.get_minutes() * 22
163
+ return tf_int
141
164
 
142
165
  def risk_level(self) -> float:
143
166
  """
@@ -194,10 +217,11 @@ class RiskManagement(Account):
194
217
  def max_trade(self) -> int:
195
218
  """calculates the maximum number of trades allowed"""
196
219
  minutes = self.get_minutes()
220
+ tf_int = self._convert_time_frame(self._tf)
197
221
  if self.max_trades is not None:
198
222
  max_trades = self.max_trades
199
223
  else:
200
- max_trades = round(minutes / self.TF)
224
+ max_trades = round(minutes / tf_int)
201
225
  return max(max_trades, 1)
202
226
 
203
227
  def get_minutes(self) -> int:
@@ -217,24 +241,22 @@ class RiskManagement(Account):
217
241
 
218
242
  return hours
219
243
 
220
- def get_std_stop(self, tf: TimeFrame = 'D1', interval: int = 252):
244
+ def get_std_stop(self):
221
245
  """
222
246
  Calculate the standard deviation-based stop loss level
223
247
  for a given financial instrument.
224
248
 
225
- Args:
226
- tf (str): Timeframe for data, default is 'D1' (Daily).
227
- interval (int): Number of historical data points to consider
228
- for calculating standard deviation, default is 252.
229
-
230
249
  Returns:
231
250
  - Standard deviation-based stop loss level, rounded to the nearest point.
232
251
  - 0 if the calculated stop loss is less than or equal to 0.
233
252
  """
234
- rate = Rates(self.symbol, tf, 0, interval)
235
- data = rate.get_rates_from_pos()
236
- returns = np.diff(data['Close'])
237
- std = np.std(returns)
253
+ minutes = self.get_minutes()
254
+ tf_int = self._convert_time_frame(self._tf)
255
+ interval = round((minutes / tf_int) * 252)
256
+
257
+ rate = Rates(self.symbol, self._tf, 0, interval)
258
+ returns = rate.get_returns*100
259
+ std = returns.std()
238
260
  point = self.get_symbol_info(self.symbol).point
239
261
  av_price = (self.symbol_info.bid + self.symbol_info.ask)/2
240
262
  price_interval = av_price * ((100-std))/100
@@ -271,26 +293,27 @@ class RiskManagement(Account):
271
293
  # Use std as default pchange
272
294
  return self.get_std_stop()
273
295
 
274
- def calculate_var(self, tf: TimeFrame = 'D1', interval=252, c=0.95):
296
+ def calculate_var(self, tf: TimeFrame = 'D1', c=0.95):
275
297
  """
276
298
  Calculate Value at Risk (VaR) for a given portfolio.
277
299
 
278
300
  Args:
279
301
  tf (str): Time frame to use to calculate volatility.
280
- interval (int): How many periods to use based on time frame.
281
302
  c (float): Confidence level for VaR calculation (default is 95%).
282
303
 
283
304
  Returns:
284
305
  - VaR value
285
306
  """
307
+ minutes = self.get_minutes()
308
+ tf_int = self._convert_time_frame(tf)
309
+ interval = round((minutes / tf_int) * 252)
310
+
286
311
  rate = Rates(self.symbol, tf, 0, interval)
287
- prices = rate.get_rates_from_pos()
288
- prices['return'] = prices['Close'].pct_change()
289
- prices.dropna(inplace=True)
290
- P = self.get_account_info().margin_free
291
- mu = np.mean(prices['return'])
292
- sigma = np.std(prices['return'])
293
- var = self.var_cov_var(P, c, mu, sigma)
312
+ returns = rate.get_returns*100
313
+ p = self.get_account_info().margin_free
314
+ mu = returns.mean()
315
+ sigma = returns.std()
316
+ var = self.var_cov_var(p, c, mu, sigma)
294
317
  return var
295
318
 
296
319
  def var_cov_var(self, P: float, c: float, mu: float, sigma: float):
@@ -312,11 +335,15 @@ class RiskManagement(Account):
312
335
  def var_loss_value(self):
313
336
  """
314
337
  Calculate the stop-loss level based on VaR.
338
+
339
+ Notes:
340
+ The Var is Estimated using the Variance-Covariance method on the daily returns.
341
+ If you want to use the VaR for a different time frame .
315
342
  """
316
343
  P = self.get_account_info().margin_free
317
344
  trade_risk = self.get_trade_risk()
318
345
  loss_allowed = P * trade_risk
319
- var = self.calculate_var()
346
+ var = self.calculate_var(c=self.var_level, tf=self.var_tf)
320
347
  return min(var, loss_allowed)
321
348
 
322
349
  def get_take_profit(self) -> int:
@@ -480,13 +507,8 @@ class RiskManagement(Account):
480
507
  if self.get_symbol_type(self.symbol) == 'IDX':
481
508
  rates = self.get_currency_rates(self.symbol)
482
509
  if rates['mc'] == rates['pc'] == 'JPY':
483
- if self.std:
484
- raise ValueError(
485
- f"""Please Set std=False or use pchange_sl=True
486
- or set sl=value or use the default method calculation for {self.symbol}
487
- Currency risk"""
488
- )
489
510
  lot = lot * contract_size
511
+ lot = self._check_lot(lot)
490
512
  volume = round(lot * av_price * contract_size)
491
513
  if contract_size == 1:
492
514
  volume = round(lot * av_price)
@@ -555,7 +555,7 @@ class Trade(RiskManagement):
555
555
  check_result = self.check_order(request)
556
556
  result = self.send_order(request)
557
557
  except Exception as e:
558
- print(f"{self.get_current_time()} -", end=' ')
558
+ print(f"{self.current_datetime()} -", end=' ')
559
559
  trade_retcode_message(
560
560
  result.retcode, display=True, add_msg=f"{e}{addtionnal}")
561
561
  if result.retcode != Mt5.TRADE_RETCODE_DONE:
@@ -571,7 +571,7 @@ class Trade(RiskManagement):
571
571
  check_result = self.check_order(request)
572
572
  result = self.send_order(request)
573
573
  except Exception as e:
574
- print(f"{self.get_current_time()} -", end=' ')
574
+ print(f"{self.current_datetime()} -", end=' ')
575
575
  trade_retcode_message(
576
576
  result.retcode, display=True, add_msg=f"{e}{addtionnal}")
577
577
  if result.retcode == Mt5.TRADE_RETCODE_DONE:
@@ -900,7 +900,7 @@ class Trade(RiskManagement):
900
900
  check_result = self.check_order(request)
901
901
  result = self.send_order(request)
902
902
  except Exception as e:
903
- print(f"{self.get_current_time()} -", end=' ')
903
+ print(f"{self.current_datetime()} -", end=' ')
904
904
  trade_retcode_message(
905
905
  result.retcode, display=True, add_msg=f"{e}{addtionnal}")
906
906
  if result.retcode != Mt5.TRADE_RETCODE_DONE:
@@ -917,7 +917,7 @@ class Trade(RiskManagement):
917
917
  check_result = self.check_order(request)
918
918
  result = self.send_order(request)
919
919
  except Exception as e:
920
- print(f"{self.get_current_time()} -", end=' ')
920
+ print(f"{self.current_datetime()} -", end=' ')
921
921
  trade_retcode_message(
922
922
  result.retcode, display=True, add_msg=f"{e}{addtionnal}")
923
923
  if result.retcode == Mt5.TRADE_RETCODE_DONE:
@@ -1041,7 +1041,7 @@ class Trade(RiskManagement):
1041
1041
  check_result = self.check_order(request)
1042
1042
  result = self.send_order(request)
1043
1043
  except Exception as e:
1044
- print(f"{self.get_current_time()} -", end=' ')
1044
+ print(f"{self.current_datetime()} -", end=' ')
1045
1045
  trade_retcode_message(
1046
1046
  result.retcode, display=True, add_msg=f"{e}{addtionnal}")
1047
1047
  if result.retcode != Mt5.TRADE_RETCODE_DONE:
@@ -1055,7 +1055,7 @@ class Trade(RiskManagement):
1055
1055
  check_result = self.check_order(request)
1056
1056
  result = self.send_order(request)
1057
1057
  except Exception as e:
1058
- print(f"{self.get_current_time()} -", end=' ')
1058
+ print(f"{self.current_datetime()} -", end=' ')
1059
1059
  trade_retcode_message(
1060
1060
  result.retcode, display=True, add_msg=f"{e}{addtionnal}")
1061
1061
  if result.retcode == Mt5.TRADE_RETCODE_DONE:
@@ -1,12 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbstrader
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: Simplified Investment & Trading Toolkit
5
5
  Home-page: https://github.com/bbalouki/bbstrader
6
+ Download-URL: https://pypi.org/project/bbstrader/
6
7
  Author: Bertin Balouki SIMYELI
7
8
  Author-email: <bertin@bbstrader.com>
8
9
  Maintainer: Bertin Balouki SIMYELI
9
10
  License: The MIT License (MIT)
11
+ Project-URL: Documentation, https://bbstrader.readthedocs.io/en/latest/
12
+ Project-URL: Source Code, https://github.com/bbalouki/bbstrader
10
13
  Keywords: Finance,Toolkit,Financial,Analysis,Fundamental,Quantitative,Database,Equities,Currencies,Economics,ETFs,Funds,Indices,Moneymarkets,Commodities,Futures,CFDs,Derivatives,Trading,Investing,Portfolio,Optimization,Performance
11
14
  Classifier: Development Status :: 5 - Production/Stable
12
15
  Classifier: Intended Audience :: Developers
@@ -7,7 +7,7 @@ if sys.version_info < (3, 10):
7
7
  with open("README.md", encoding="utf-8") as fh:
8
8
  long_description = fh.read()
9
9
 
10
- VERSION = '0.1.04'
10
+ VERSION = '0.1.05'
11
11
  DESCRIPTION = 'Simplified Investment & Trading Toolkit'
12
12
 
13
13
  KEYWORDS = [
@@ -44,6 +44,11 @@ setup(
44
44
  version=VERSION,
45
45
  author='Bertin Balouki SIMYELI',
46
46
  url='https://github.com/bbalouki/bbstrader',
47
+ download_url='https://pypi.org/project/bbstrader/',
48
+ project_urls={
49
+ "Documentation": "https://bbstrader.readthedocs.io/en/latest/",
50
+ "Source Code": "https://github.com/bbalouki/bbstrader",
51
+ },
47
52
  license='The MIT License (MIT)',
48
53
  author_email='<bertin@bbstrader.com>',
49
54
  maintainer='Bertin Balouki SIMYELI',
File without changes
File without changes
File without changes