bbstrader 0.1.7__tar.gz → 0.1.8__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 (31) hide show
  1. {bbstrader-0.1.7 → bbstrader-0.1.8}/PKG-INFO +2 -1
  2. {bbstrader-0.1.7 → bbstrader-0.1.8}/README.md +1 -0
  3. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/__init__.py +1 -0
  4. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/backtest.py +11 -9
  5. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/performance.py +9 -30
  6. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/portfolio.py +18 -10
  7. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/metatrader/account.py +11 -4
  8. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/metatrader/rates.py +4 -5
  9. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/metatrader/risk.py +1 -2
  10. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/metatrader/trade.py +269 -214
  11. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/metatrader/utils.py +37 -29
  12. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/trading/execution.py +55 -18
  13. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/trading/strategies.py +5 -3
  14. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/tseries.py +500 -494
  15. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader.egg-info/PKG-INFO +2 -1
  16. {bbstrader-0.1.7 → bbstrader-0.1.8}/setup.py +2 -2
  17. {bbstrader-0.1.7 → bbstrader-0.1.8}/LICENSE +0 -0
  18. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/__ini__.py +0 -0
  19. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/data.py +0 -0
  20. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/event.py +0 -0
  21. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/execution.py +0 -0
  22. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/btengine/strategy.py +0 -0
  23. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/metatrader/__init__.py +0 -0
  24. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/models/__init__.py +0 -0
  25. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/models/risk.py +0 -0
  26. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader/trading/__init__.py +0 -0
  27. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader.egg-info/SOURCES.txt +0 -0
  28. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader.egg-info/dependency_links.txt +0 -0
  29. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader.egg-info/requires.txt +0 -0
  30. {bbstrader-0.1.7 → bbstrader-0.1.8}/bbstrader.egg-info/top_level.txt +0 -0
  31. {bbstrader-0.1.7 → bbstrader-0.1.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbstrader
3
- Version: 0.1.7
3
+ Version: 0.1.8
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/
@@ -47,6 +47,7 @@ Requires-Dist: Metatrader5
47
47
  [![Documentation Status](https://readthedocs.org/projects/bbstrader/badge/?version=latest)](https://bbstrader.readthedocs.io/en/latest/?badge=latest)
48
48
 
49
49
  [Dcoumentation](https://bbstrader.readthedocs.io/en/latest/index.html)
50
+
50
51
  ## Overview
51
52
 
52
53
  BBSTrader is a trading system suite developed for MetaTrader 5 (MT5) and IBKR platforms (comming soon), designed to offer a comprehensive set of tools for developping, backtesting, executing, and managing a wide array of trading strategies. With an emphasis on algorithmic and quantitative trading to provide traders with a robust platform for exploring and deploying sophisticated trading strategies.
@@ -4,6 +4,7 @@
4
4
  [![Documentation Status](https://readthedocs.org/projects/bbstrader/badge/?version=latest)](https://bbstrader.readthedocs.io/en/latest/?badge=latest)
5
5
 
6
6
  [Dcoumentation](https://bbstrader.readthedocs.io/en/latest/index.html)
7
+
7
8
  ## Overview
8
9
 
9
10
  BBSTrader is a trading system suite developed for MetaTrader 5 (MT5) and IBKR platforms (comming soon), designed to offer a comprehensive set of tools for developping, backtesting, executing, and managing a wide array of trading strategies. With an emphasis on algorithmic and quantitative trading to provide traders with a robust platform for exploring and deploying sophisticated trading strategies.
@@ -50,4 +50,5 @@ from bbstrader.btengine.event import *
50
50
  from bbstrader.btengine.execution import *
51
51
  from bbstrader.btengine.performance import *
52
52
  from bbstrader.btengine.backtest import *
53
+ from bbstrader.btengine.strategy import Strategy
53
54
  from bbstrader.btengine.portfolio import Portfolio
@@ -99,6 +99,7 @@ class Backtest(object):
99
99
  self.fills = 0
100
100
 
101
101
  self._generate_trading_instances()
102
+ self.show_equity = kwargs.get("show_equity", False)
102
103
 
103
104
  def _generate_trading_instances(self):
104
105
  """
@@ -186,15 +187,16 @@ class Backtest(object):
186
187
  "\n"
187
188
  )
188
189
 
189
- print("\nCreating equity curve...")
190
- print("\n[======= EQUITY CURVE =======]")
191
- print(
192
- tabulate(
193
- self.portfolio.equity_curve.tail(10),
194
- headers="keys",
195
- tablefmt="outline"),
196
- "\n"
197
- )
190
+ if self.show_equity:
191
+ print("\nCreating equity curve...")
192
+ print("\n[======= EQUITY CURVE =======]")
193
+ print(
194
+ tabulate(
195
+ self.portfolio.equity_curve.tail(10),
196
+ headers="keys",
197
+ tablefmt="outline"),
198
+ "\n"
199
+ )
198
200
 
199
201
  def simulate_trading(self):
200
202
  """
@@ -24,7 +24,7 @@ __all__ = [
24
24
  ]
25
25
 
26
26
 
27
- def create_sharpe_ratio(returns, periods=252):
27
+ def create_sharpe_ratio(returns, periods=252) -> float:
28
28
  """
29
29
  Create the Sharpe ratio for the strategy, based on a
30
30
  benchmark of zero (i.e. no risk-free rate information).
@@ -36,15 +36,10 @@ def create_sharpe_ratio(returns, periods=252):
36
36
  Returns:
37
37
  S (float): Sharpe ratio
38
38
  """
39
- if np.std(returns) != 0:
40
- return np.sqrt(periods) * (np.mean(returns)) / np.std(returns)
41
- else:
42
- return 0.0
39
+ return qs.stats.sharpe(returns, periods=periods)
43
40
 
44
41
  # Define a function to calculate the Sortino Ratio
45
-
46
-
47
- def create_sortino_ratio(returns, periods=252):
42
+ def create_sortino_ratio(returns, periods=252) -> float:
48
43
  """
49
44
  Create the Sortino ratio for the strategy, based on a
50
45
  benchmark of zero (i.e. no risk-free rate information).
@@ -56,17 +51,7 @@ def create_sortino_ratio(returns, periods=252):
56
51
  Returns:
57
52
  S (float): Sortino ratio
58
53
  """
59
- # Calculate the annualized return
60
- annualized_return = np.power(1 + np.mean(returns), periods) - 1
61
- # Calculate the downside deviation
62
- downside_returns = returns.copy()
63
- downside_returns[returns > 0] = 0
64
- annualized_downside_std = np.std(downside_returns) * np.sqrt(periods)
65
- if annualized_downside_std != 0:
66
- return annualized_return / annualized_downside_std
67
- else:
68
- return 0.0
69
-
54
+ return qs.stats.sortino(returns, periods=periods)
70
55
 
71
56
  def create_drawdowns(pnl):
72
57
  """
@@ -311,19 +296,19 @@ def plot_monthly_yearly_returns(df, title):
311
296
  # Show the plot
312
297
  plt.show()
313
298
 
314
- def show_qs_stats(equity_curve, benchmark, strategy_name):
299
+ def show_qs_stats(returns, benchmark, strategy_name, save_dir=None):
315
300
  """
316
301
  Generate the full quantstats report for the strategy.
317
302
 
318
303
  Args:
319
- equity_curve (pd.DataFrame):
304
+ returns (pd.Serie):
320
305
  The DataFrame containing the strategy returns and drawdowns.
321
306
  benchmark (str):
322
307
  The ticker symbol of the benchmark to compare the strategy to.
323
308
  strategy_name (str): The name of the strategy.
324
309
  """
325
310
  # Load the returns data
326
- returns = equity_curve.copy()
311
+ returns = returns.copy()
327
312
 
328
313
  # Drop duplicate index entries
329
314
  returns = returns[~returns.index.duplicated(keep='first')]
@@ -332,11 +317,5 @@ def show_qs_stats(equity_curve, benchmark, strategy_name):
332
317
  qs.extend_pandas()
333
318
 
334
319
  # Generate the full report with a benchmark
335
- file = strategy_name.replace(' ', '_')
336
- qs.reports.full(
337
- returns['Returns'], mode='full', benchmark=benchmark)
338
- qs.reports.html(
339
- returns['Returns'],
340
- benchmark='SPY',
341
- output=f"{file}_report.html",
342
- title=strategy_name)
320
+ qs.reports.full(returns, mode='full', benchmark=benchmark)
321
+ qs.reports.html(returns, benchmark=benchmark, output=save_dir, title=strategy_name)
@@ -1,13 +1,15 @@
1
1
  import pandas as pd
2
2
  from queue import Queue
3
+ from pathlib import Path
3
4
  from datetime import datetime
4
5
  from bbstrader.btengine.event import (
5
6
  OrderEvent, FillEvent, MarketEvent, SignalEvent
6
7
  )
7
8
  from bbstrader.btengine.data import DataHandler
8
9
  from bbstrader.btengine.performance import (
9
- create_drawdowns, plot_performance, show_qs_stats,
10
- plot_returns_and_dd, plot_monthly_yearly_returns
10
+ create_drawdowns, create_sharpe_ratio, create_sortino_ratio,
11
+ plot_performance, show_qs_stats,plot_returns_and_dd,
12
+ plot_monthly_yearly_returns
11
13
  )
12
14
  import quantstats as qs
13
15
 
@@ -306,8 +308,8 @@ class Portfolio(object):
306
308
  returns = self.equity_curve['Returns']
307
309
  pnl = self.equity_curve['Equity Curve']
308
310
 
309
- sharpe_ratio = qs.stats.sharpe(returns, periods=self.tf)
310
- sortino_ratio = qs.stats.sortino(returns, periods=self.tf)
311
+ sharpe_ratio = create_sharpe_ratio(returns, periods=self.tf)
312
+ sortino_ratio = create_sortino_ratio(returns, periods=self.tf)
311
313
  drawdown, _, _ = create_drawdowns(pnl)
312
314
  max_dd = qs.stats.max_drawdown(returns)
313
315
  dd_details = qs.stats.drawdown_details(drawdown)
@@ -323,14 +325,20 @@ class Portfolio(object):
323
325
  ]
324
326
  now = datetime.now().strftime('%Y%m%d%H%M%S')
325
327
  strategy_name = self.strategy_name.replace(' ', '_')
326
- file = f"{strategy_name}_{now}_equity.csv"
327
- self.equity_curve.to_csv(file)
328
+ results_dir = Path('Backtest_Results') / strategy_name
329
+ results_dir.mkdir(parents=True, exist_ok=True)
330
+
331
+ csv_file = f"{strategy_name}_{now}_equity.csv"
332
+ png_file = f'{strategy_name}_{now}_returns_heatmap.png'
333
+ html_file = f"{strategy_name}_{now}_report.html"
334
+ self.equity_curve.to_csv(results_dir / csv_file)
335
+
328
336
  plot_performance(self.equity_curve, self.strategy_name)
329
- plot_returns_and_dd(self.equity_curve,
330
- self.benchmark, self.strategy_name)
331
- qs.plots.monthly_heatmap(returns, savefig='monthly_heatmap.png')
337
+ plot_returns_and_dd(self.equity_curve, self.benchmark, self.strategy_name)
338
+ qs.plots.monthly_heatmap(returns, savefig=f"{results_dir}/{png_file}")
332
339
  plot_monthly_yearly_returns(self.equity_curve, self.strategy_name)
333
- show_qs_stats(self.equity_curve, self.benchmark, self.strategy_name)
340
+ show_qs_stats(returns, self.benchmark, self.strategy_name,
341
+ save_dir=f"{results_dir}/{html_file}")
334
342
 
335
343
  return stats
336
344
 
@@ -6,10 +6,9 @@ from datetime import datetime
6
6
  import MetaTrader5 as mt5
7
7
  from currency_converter import SINGLE_DAY_ECB_URL, CurrencyConverter
8
8
  from bbstrader.metatrader.utils import (
9
- raise_mt5_error, AccountInfo, TerminalInfo,
9
+ raise_mt5_error, AccountInfo, TerminalInfo, InvalidBroker,
10
10
  SymbolInfo, TickInfo, TradeRequest, OrderCheckResult,
11
- OrderSentResult, TradePosition, TradeOrder, TradeDeal,
12
- )
11
+ OrderSentResult, TradePosition, TradeOrder, TradeDeal,)
13
12
  from typing import Tuple, Union, List, Dict, Any, Optional, Literal
14
13
 
15
14
 
@@ -18,6 +17,13 @@ __BROKERS__ = {
18
17
  'JGM': "Just Global Markets Ltd.",
19
18
  'FTMO': "FTMO S.R.O."
20
19
  }
20
+
21
+ BROKERS_TIMEZONES = {
22
+ 'AMG': 'Europe/Helsinki',
23
+ 'JGM': 'Europe/Helsinki',
24
+ 'FTMO': 'Europe/Helsinki'
25
+ }
26
+
21
27
  _ADMIRAL_MARKETS_URL_ = "https://cabinet.a-partnership.com/visit/?bta=35537&brand=admiralmarkets"
22
28
  _ADMIRAL_MARKETS_PRODUCTS_ = ["Stocks", "ETFs",
23
29
  "Indices", "Commodities", "Futures", "Forex"]
@@ -93,13 +99,14 @@ class Account(object):
93
99
  supported = __BROKERS__.copy()
94
100
  broker = self.get_terminal_info().company
95
101
  if broker not in supported.values():
96
- raise ValueError(
102
+ msg = (
97
103
  f"{broker} is not currently supported broker for the Account() class\n"
98
104
  f"Currently Supported brokers are: {', '.join(supported.values())}\n"
99
105
  f"For {supported['AMG']}, See [{amg_url}]\n"
100
106
  f"For {supported['JGM']}, See [{jgm_url}]\n"
101
107
  f"For {supported['FTMO']}, See [{ftmo_url}]\n"
102
108
  )
109
+ raise InvalidBroker(message=msg)
103
110
 
104
111
  def get_account_info(
105
112
  self,
@@ -3,8 +3,7 @@ import MetaTrader5 as Mt5
3
3
  from datetime import datetime
4
4
  from typing import Union, Optional
5
5
  from bbstrader.metatrader.utils import (
6
- raise_mt5_error, TimeFrame, TIMEFRAMES
7
- )
6
+ raise_mt5_error, TimeFrame, TIMEFRAMES)
8
7
  from bbstrader.metatrader.account import INIT_MSG
9
8
  from pandas.tseries.offsets import CustomBusinessDay
10
9
  from pandas.tseries.holiday import USFederalHolidayCalendar
@@ -28,7 +27,7 @@ class Rates(object):
28
27
  In your MT5 terminal, go to `Tools` -> `Options` -> `Charts` -> `Max bars in chart`.
29
28
 
30
29
  2. The `get_open, get_high, get_low, get_close, get_adj_close, get_returns,
31
- get_volume` properties return data in Broker's timezone.
30
+ get_volume` properties returns data in Broker's timezone.
32
31
 
33
32
  Example:
34
33
  >>> rates = Rates("EURUSD", "1h")
@@ -226,7 +225,7 @@ class Rates(object):
226
225
 
227
226
  @property
228
227
  def get_volume(self):
229
- return self.data['Volume']
228
+ return self.__data['Volume']
230
229
 
231
230
  def get_historical_data(
232
231
  self,
@@ -252,7 +251,7 @@ class Rates(object):
252
251
  ValueError: If the starting date is greater than the ending date.
253
252
 
254
253
  Notes:
255
- The Datetime for this method is in UTC timezone.
254
+ The Datetime for this method is in Local timezone.
256
255
  """
257
256
  df = self._fetch_data(date_from, date_to)
258
257
  if save_csv and df is not None:
@@ -7,8 +7,7 @@ import MetaTrader5 as Mt5
7
7
  from bbstrader.metatrader.account import Account
8
8
  from bbstrader.metatrader.rates import Rates
9
9
  from bbstrader.metatrader.utils import (
10
- TIMEFRAMES, raise_mt5_error, TimeFrame
11
- )
10
+ TIMEFRAMES, raise_mt5_error, TimeFrame)
12
11
  from typing import List, Dict, Optional, Literal, Union, Any
13
12
 
14
13