├── .gitignore ├── LICENSE ├── README.md ├── requirements.txt ├── run.py ├── settings.py ├── strategies ├── __init__.py ├── bbands.py ├── bbands_rsi.py ├── bbands_sideway.py ├── cross.py ├── rsi.py └── template.py ├── strategy.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | env*/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Grupo Python para Trading 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Backtrader Wrapper 2 | 3 | It is a Backtrader wrapper to implement trading strategies. 4 | 5 | Also, you can find some example strategies implemented. 6 | 7 | # Deploy (python 3.7) 8 | 9 | ```sh 10 | $ git clone https://github.com/Python-para-Trading/wrapper-backtrader.git 11 | $ cd wrapper-backtrader 12 | $ virtualenv -p python3.7 env 13 | $ source env/bin/activate 14 | $ pip install -r requirements.txt 15 | ``` 16 | 17 | # Run 18 | 19 | ```sh 20 | $ python run.py 21 | ``` 22 | 23 | # Advanced use 24 | 25 | You can modify the `settings.py` file to run strategies with different 26 | configurations. 27 | 28 | You can write your own strategy on a new file in `strategies` folder and import 29 | this strategy in strategies/__init__.py 30 | After, you can use your strategy on the parameter 'strategy' in settings.CONFIG. 31 | 32 | # Define tu propia estrategia paso a paso: 33 | 34 | 1 - Escribimos nuestra estrategia en un fichero python situado en la carpeta `strategies`. 35 | 36 | 2 - Importamos nuestra estrategia en `strategies.__init__.py`. Ejemplo: 37 | 38 | from .nombre_fichero import NombreEstrategia 39 | 40 | 3 - En el `settings.py` modificamos la variable CONFIG['strategies'] para añadir nuestra estrategia. 41 | 42 | 4 - Ejecutamos el wrapper mediante: 43 | 44 | python run.py 45 | 46 | 47 | # TODO: 48 | 49 | * Documentation for settings 50 | * Improve 'optimization' mode: https://backtest-rookies.com/2017/06/26/optimize-strategies-backtrader/ (code 3) 51 | * ML strategy utils 52 | * 'walk_forward', 'paper', 'live' modes utils 53 | * Communication module with Darwinex: https://github.com/darwinex/dwx-zeromq-connector/ 54 | * Communication module with IB 55 | * PyMC3 strategy utils 56 | * Implement Sortino Ratio like a new analyzer on Backtrader: https://backtest-rookies.com/2017/11/08/backtrader-creating-analyzers/ 57 | * pep8 linter(flake8) 58 | * codecov 59 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | backtrader==1.9.70.122 2 | requests==2.21.0 3 | matplotlib==3.0.3 4 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | import backtrader as bt 2 | 3 | from utils import run_strategy, add_analyzers 4 | from settings import CONFIG 5 | 6 | cerebro = bt.Cerebro() 7 | 8 | # Data input 9 | data = bt.feeds.YahooFinanceData(dataname=CONFIG['asset'], 10 | fromdate=CONFIG['init_date'], 11 | todate=CONFIG['end_date']) 12 | cerebro.adddata(data) 13 | 14 | if CONFIG['mode'] == 'optimization': 15 | # Parameters Optimization 16 | for strat in CONFIG['strategies']: 17 | cerebro.optstrategy(strat, period=range(14,21)) 18 | elif CONFIG['mode'] == 'backtest': 19 | for strat in CONFIG['strategies']: 20 | cerebro.addstrategy(strat) 21 | else: 22 | raise ValueError('CONFIG["mode"] value should be "backtest", "optimization" or "walk_forward".') 23 | 24 | # Analyzer 25 | cerebro = add_analyzers(cerebro) 26 | 27 | # Set our desired cash start 28 | cerebro.broker.setcash(CONFIG['capital_base']) 29 | 30 | # Add a FixedSize sizer according to the stake 31 | cerebro.addsizer(bt.sizers.FixedSize, stake=5) 32 | 33 | # Set the commission 34 | cerebro.broker.setcommission(commission=CONFIG['commission']) 35 | 36 | # Run Strategy 37 | strats = run_strategy(cerebro) 38 | 39 | if CONFIG['plot'] and CONFIG['mode'] != 'optimization': 40 | # Plot the result 41 | cerebro.plot() 42 | -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from strategies import * 4 | 5 | 6 | CONFIG = { 7 | 'mode': 'backtest', # 'backtest', 'optimization', 'walk_forward', 'paper', 'live' 8 | 'plot': True, 9 | 'init_date': datetime(2017, 1, 1), 10 | 'end_date': datetime(2019, 2, 28), 11 | 'asset': 'BTC-USD', 12 | # TODO: 'data_freq': 'daily', 13 | 'capital_base': 100000.0, 14 | 'commission': 0.002, 15 | 'size': 2, 16 | 'log': False, 17 | 'take_profit': { 18 | 'enabled': False, 19 | 'value': 0.01, 20 | }, 21 | 'stop_loss': { 22 | 'enabled': False, 23 | 'value': 0.02, 24 | }, 25 | 'strategies': [ # One or more strategies to run 26 | Aberration_RSI 27 | # Aberration, 28 | # AberrationSideway, 29 | # RSI, 30 | ], 31 | } 32 | 33 | # TODO: "slippage_allowed": 0.01, 34 | -------------------------------------------------------------------------------- /strategies/__init__.py: -------------------------------------------------------------------------------- 1 | from .bbands import Aberration 2 | from .bbands_sideway import AberrationSideway 3 | from .rsi import RSI 4 | from .bbands_rsi import Aberration_RSI 5 | from .cross import Cross 6 | -------------------------------------------------------------------------------- /strategies/bbands.py: -------------------------------------------------------------------------------- 1 | import backtrader as bt 2 | 3 | from strategy import Strategy 4 | 5 | 6 | class Aberration(Strategy): 7 | """Bollinger Bands Strategy 8 | """ 9 | 10 | params = ( 11 | ('period', 20), 12 | ('devfactor', 2), 13 | ) 14 | 15 | def __init__(self): 16 | # Add a BBand indicator 17 | self.bband = bt.indicators.BBands(self.datas[0], 18 | period=self.params.period, 19 | devfactor=self.params.devfactor) 20 | super(Aberration, self).__init__() 21 | 22 | def next(self): 23 | super(Aberration, self).next() 24 | 25 | # Check if an order is pending ... if yes, we cannot send a 2nd one 26 | if self.order: 27 | return 28 | 29 | if self.orefs: 30 | return 31 | 32 | if self.dataclose < self.bband.lines.bot and not self.position: 33 | self.buy() 34 | 35 | if self.dataclose > self.bband.lines.top and self.position: 36 | self.sell() 37 | 38 | def stop(self): 39 | from settings import CONFIG 40 | pnl = round(self.broker.getvalue() - CONFIG['capital_base'], 2) 41 | print('Aberration Period: {} Final PnL: {}'.format( 42 | self.params.period, pnl)) 43 | -------------------------------------------------------------------------------- /strategies/bbands_rsi.py: -------------------------------------------------------------------------------- 1 | import backtrader as bt 2 | 3 | from strategy import Strategy 4 | 5 | 6 | class Aberration_RSI(Strategy): 7 | """Bollinger Bands Strategy 8 | """ 9 | 10 | params = ( 11 | ('period', 20), 12 | ('devfactor', 2), 13 | ) 14 | 15 | def __init__(self): 16 | # Add a BBand indicator 17 | self.bband = bt.indicators.BBands(self.datas[0], 18 | period=self.params.period, 19 | devfactor=self.params.devfactor) 20 | self.rsi = bt.indicators.RSI_SMA(self.data.close, period=self.params.period) 21 | super(Aberration_RSI, self).__init__() 22 | 23 | def next(self): 24 | super(Aberration_RSI, self).next() 25 | 26 | # Check if an order is pending ... if yes, we cannot send a 2nd one 27 | if self.order: 28 | return 29 | 30 | if self.orefs: 31 | return 32 | 33 | if self.dataclose < self.bband.lines.bot and not self.position and self.rsi < 30: 34 | self.buy() 35 | 36 | if self.dataclose > self.bband.lines.top and self.position and self.rsi > 70: 37 | self.sell() 38 | 39 | def stop(self): 40 | from settings import CONFIG 41 | pnl = round(self.broker.getvalue() - CONFIG['capital_base'], 2) 42 | print('Aberration Period: {} Final PnL: {}'.format( 43 | self.params.period, pnl)) 44 | -------------------------------------------------------------------------------- /strategies/bbands_sideway.py: -------------------------------------------------------------------------------- 1 | import backtrader as bt 2 | 3 | from strategy import Strategy 4 | 5 | # Based on: https://community.backtrader.com/topic/122/bband-strategy 6 | 7 | # Create a Strategy 8 | class AberrationSideway(Strategy): 9 | """This strategy uses Backtrader's BBand indicator and buys after the 10 | market dips into the lower band and sells on the moving average after the 11 | market hits the top band. This works great in sideways/bull markets. 12 | The idea is to buy during a low period and sell if the market dips below 13 | a moving average. Also note I am new to algotrading and programming in 14 | general so don't laugh to hard at this idea/strategy. 15 | """ 16 | params = ( 17 | ('period', 20), 18 | ('devfactor', 2), 19 | ) 20 | 21 | def __init__(self): 22 | 23 | self.redline = None 24 | self.blueline = None 25 | 26 | # Add a BBand indicator 27 | self.bband = bt.indicators.BBands(self.datas[0], 28 | period=self.params.period, 29 | devfactor=self.params.devfactor) 30 | 31 | super(AberrationSideway, self).__init__() 32 | 33 | def next(self): 34 | super(AberrationSideway, self).next() 35 | 36 | # Check if an order is pending ... if yes, we cannot send a 2nd one 37 | if self.order: 38 | return 39 | 40 | if self.orefs: 41 | return 42 | 43 | if self.dataclose < self.bband.lines.bot and not self.position: 44 | self.redline = True 45 | 46 | if self.dataclose > self.bband.lines.top and self.position: 47 | self.blueline = True 48 | 49 | if self.dataclose > self.bband.lines.mid and not self.position and self.redline: 50 | self.buy() 51 | 52 | if self.dataclose < self.bband.lines.mid and self.position and self.blueline: 53 | self.sell() 54 | self.blueline = False 55 | self.redline = False 56 | 57 | def stop(self): 58 | from settings import CONFIG 59 | pnl = round(self.broker.getvalue() - CONFIG['capital_base'], 2) 60 | print('AberrationSideway Period: {} Final PnL: {}'.format( 61 | self.params.period, pnl)) 62 | -------------------------------------------------------------------------------- /strategies/cross.py: -------------------------------------------------------------------------------- 1 | 2 | import backtrader as bt 3 | 4 | from strategy import Strategy 5 | 6 | class Cross(Strategy): 7 | params = ( 8 | ('slow', 11), 9 | ('fast', 33), 10 | ) 11 | 12 | def __init__(self): 13 | super(Cross, self).__init__() 14 | 15 | self.slow = bt.indicators.SimpleMovingAverage(self.datas[0], 16 | period=self.params.slow) 17 | 18 | self.fast = bt.indicators.SimpleMovingAverage(self.datas[0], 19 | period=self.params.fast) 20 | 21 | def next(self): 22 | if self.slow > self.fast and not self.position: 23 | self.buy() 24 | elif self.slow < self.fast and self.position: 25 | self.sell() 26 | -------------------------------------------------------------------------------- /strategies/rsi.py: -------------------------------------------------------------------------------- 1 | import backtrader as bt 2 | 3 | from strategy import Strategy 4 | 5 | class RSI(Strategy): 6 | 7 | params = ( 8 | ('period', 21), 9 | ) 10 | 11 | def __init__(self): 12 | self.rsi = bt.indicators.RSI_SMA(self.data.close, 13 | period=self.params.period) 14 | super(RSI, self).__init__() 15 | 16 | def next(self): 17 | if not self.position: 18 | if self.rsi < 30: 19 | self.buy() 20 | else: 21 | if self.rsi > 70: 22 | self.sell() 23 | 24 | def stop(self): 25 | from settings import CONFIG 26 | pnl = round(self.broker.getvalue() - CONFIG['capital_base'], 2) 27 | print('RSI Period: {} Final PnL: {}'.format( 28 | self.params.period, pnl)) 29 | -------------------------------------------------------------------------------- /strategies/template.py: -------------------------------------------------------------------------------- 1 | import backtrader as bt 2 | 3 | from strategy import Strategy 4 | 5 | class StrategyTemplate(Strategy): 6 | # definición de parámetros necesarios para el indicador 7 | params = () 8 | 9 | def __init__(self): 10 | # llamadas a algún indicador 11 | super(StrategyTemplate, self).__init__() 12 | 13 | def next(self): 14 | 15 | # lógica a seguir 16 | if something: 17 | pass 18 | # self.buy() 19 | else: 20 | pass 21 | # self.sell() 22 | -------------------------------------------------------------------------------- /strategy.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | import backtrader as bt 4 | 5 | 6 | class Strategy(bt.Strategy): 7 | 8 | def __init__(self): 9 | # Keep a reference to the "close" line in the data[0] dataseries 10 | self.dataclose = self.datas[0].close 11 | 12 | # To keep track of pending orders and buy price/commission 13 | self.order = None 14 | self.buyprice = None 15 | self.buycomm = None 16 | 17 | self.orefs = None 18 | 19 | def log(self, txt, dt=None): 20 | ''' Logging function fot this strategy''' 21 | dt = dt or self.datas[0].datetime.date(0) 22 | print('%s, %s' % (dt.isoformat(), txt)) 23 | 24 | def next(self): 25 | from settings import CONFIG 26 | 27 | # Simply log the closing price of the series from the reference 28 | if CONFIG['log']: 29 | self.log('Close, %.2f' % self.dataclose[0]) 30 | 31 | def buy(self): 32 | from settings import CONFIG 33 | close = self.dataclose[0] 34 | 35 | if CONFIG['take_profit']['enabled'] or CONFIG['stop_loss']['enabled']: 36 | 37 | aux_orefs = [] 38 | limit = 0.005 # TODO: settings 39 | p1 = close * (1.0 - limit) 40 | p2 = p1 - CONFIG['stop_loss']['value'] * close 41 | p3 = p1 + CONFIG['take_profit']['value'] * close 42 | 43 | limdays = 3 # TODO: settings 44 | limdays2 = 1000 # TODO: settings 45 | valid1 = datetime.timedelta(limdays) 46 | valid2 = valid3 = datetime.timedelta(limdays2) 47 | 48 | o1 = super(Strategy, self).buy(exectype=bt.Order.Limit, 49 | price=p1, 50 | valid=valid1, 51 | transmit=False, 52 | size=CONFIG['size']) 53 | self.log('BUY CREATE, %.2f' % p1) 54 | aux_orefs.append(o1.ref) 55 | 56 | if CONFIG['stop_loss']['enabled']: 57 | o2 = super(Strategy, self).sell(exectype=bt.Order.Stop, 58 | price=p2, 59 | valid=valid2, 60 | parent=o1, 61 | transmit=False, 62 | size=CONFIG['size']) 63 | self.log('STOP LOSS CREATED, %.2f' % p2) 64 | aux_orefs.append(o2.ref) 65 | 66 | if CONFIG['take_profit']['enabled']: 67 | o3 = super(Strategy, self).sell(exectype=bt.Order.Limit, 68 | price=p3, 69 | valid=valid3, 70 | parent=o1, 71 | transmit=True, 72 | size=CONFIG['size']) 73 | self.log('TAKE PROFIT CREATED, %.2f' % p3) 74 | aux_orefs.append(o3.ref) 75 | 76 | self.orefs = aux_orefs 77 | 78 | else: 79 | self.log('BUY CREATE, %.2f' % self.dataclose[0]) 80 | self.order = super(Strategy, self).buy(size=CONFIG['size']) 81 | 82 | def sell(self): 83 | from settings import CONFIG 84 | 85 | if not CONFIG['take_profit']['enabled'] and not CONFIG['stop_loss']['enabled']: 86 | self.log('SELL CREATE, %.2f' % self.dataclose[0]) 87 | self.order = super(Strategy, self).sell(size=CONFIG['size']) 88 | 89 | def notify_order(self, order): 90 | from settings import CONFIG 91 | 92 | if order.status in [order.Submitted, order.Accepted]: 93 | # Buy/Sell order submitted/accepted to/by broker - Nothing to do 94 | return 95 | 96 | # Check if an order has been completed 97 | # Attention: broker could reject order if not enougth cash 98 | if order.status in [order.Completed, order.Canceled, order.Margin]: 99 | if order.isbuy(): 100 | self.log( 101 | 'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % 102 | (order.executed.price, 103 | order.executed.value, 104 | order.executed.comm)) 105 | 106 | self.buyprice = order.executed.price 107 | self.buycomm = order.executed.comm 108 | else: # Sell 109 | self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % 110 | (order.executed.price, 111 | order.executed.value, 112 | order.executed.comm)) 113 | 114 | self.bar_executed = len(self) 115 | 116 | if CONFIG['stop_loss']['enabled'] or CONFIG['take_profit']['enabled']: 117 | if not order.alive() and order.ref in self.orefs: 118 | self.orefs = [] 119 | else: 120 | # Write down: no pending order 121 | self.order = None 122 | 123 | def notify_trade(self, trade): 124 | if not trade.isclosed: 125 | return 126 | 127 | self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % 128 | (trade.pnl, trade.pnlcomm)) 129 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import backtrader.analyzers as btanalyzers 2 | 3 | from settings import CONFIG 4 | 5 | 6 | def run_strategy(cerebro): 7 | 8 | # Print out the starting conditions 9 | _show_backtest_init(cerebro.broker) 10 | 11 | # Run over everything 12 | strats = cerebro.run() 13 | 14 | _show_config_settings(CONFIG) 15 | 16 | if CONFIG['mode'] == 'backtest': 17 | # Print out the final result 18 | _show_backtest_end(cerebro.broker) 19 | _show_analyzers_end(strats[0]) 20 | 21 | 22 | def add_analyzers(cerebro): 23 | cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='sharpe_ratio') 24 | cerebro.addanalyzer(btanalyzers.SharpeRatio_A, _name='sharpe_ratio_a') # sharpe ratio anualized 25 | cerebro.addanalyzer(btanalyzers.VWR, _name='vwr') # sharpe ratio with log returns 26 | cerebro.addanalyzer(btanalyzers.DrawDown, _name='draw_down') 27 | cerebro.addanalyzer(btanalyzers.Returns, _name='returns') 28 | cerebro.addanalyzer(btanalyzers.SQN, _name='sqn') 29 | cerebro.addanalyzer(btanalyzers.TimeDrawDown, _name='time_drawdown') 30 | cerebro.addanalyzer(btanalyzers.AnnualReturn, _name='annual_return') 31 | cerebro.addanalyzer(btanalyzers.TradeAnalyzer, _name='trade_analyzer') 32 | # cerebro.addanalyzer(btanalyzers.Calmar, _name='calmar') 33 | # cerebro.addanalyzer(btanalyzers.LogReturnsRolling, _name='log_returns_rolling') 34 | # cerebro.addanalyzer(btanalyzers.PeriodStats, _name='periods_stats') 35 | # cerebro.addanalyzer(btanalyzers.PyFolio, _name='pyfolio') 36 | # cerebro.addanalyzer(btanalyzers.Transactions, _name='transactions') 37 | # cerebro.addanalyzer(btanalyzers.TimeReturn, _name='time_return') 38 | return cerebro 39 | 40 | 41 | def _show_config_settings(config): 42 | print(config) 43 | 44 | 45 | def _show_backtest_init(broker): 46 | print('Initial Portfolio Value: %.2f' % broker.getvalue()) 47 | 48 | 49 | def _show_backtest_end(broker): 50 | print('Final portfolio value: %.2f' % broker.getvalue()) 51 | print('Fund value: ' + str(broker.fundvalue)) 52 | print('Number of orders executed: %.2f' % len(broker.orders)) 53 | # print('Number of positions: %.2f' % len(broker.positions)) 54 | 55 | 56 | def _printTradeAnalysis(analyzer): 57 | ''' 58 | Function to print the Technical Analysis results in a nice format. 59 | https://backtest-rookies.com/2017/06/11/using-analyzers-backtrader/ 60 | ''' 61 | # Get the results we are interested in 62 | total_open = analyzer.total.open 63 | total_closed = analyzer.total.closed 64 | total_won = analyzer.won.total 65 | total_lost = analyzer.lost.total 66 | 67 | # Designate the rows 68 | h1 = ['Total Open', 'Total Closed', 'Total Won', 'Total Lost'] 69 | r1 = [total_open, total_closed,total_won,total_lost] 70 | 71 | header_length = len(h1) 72 | 73 | # Print the rows 74 | print_list = [h1, r1] 75 | row_format ="{:<15}" * (header_length + 1) 76 | print("Trade Analysis Results:") 77 | for row in print_list: 78 | print(row_format.format('', *row)) 79 | 80 | 81 | def _show_analyzers_end(strats): 82 | print('Sharpe Ratio: ' + str(strats.analyzers.sharpe_ratio.get_analysis())) 83 | print('Sharpe Ratio Annualized: ' + str(strats.analyzers.sharpe_ratio_a.get_analysis())) # sharpe ratio anualized 84 | #print('Sharpe Ratio Log Returns: ' + str(strats.analyzers.vwr.get_analysis())) # sharpe ratio with log returns 85 | print('Draw Down: ' + str(strats.analyzers.draw_down.get_analysis())) 86 | print('Returns: ' + str(strats.analyzers.returns.get_analysis())) 87 | print('SQN: ' + str(strats.analyzers.sqn.get_analysis())) 88 | print('Time Drawdown: ' + str(strats.analyzers.time_drawdown.get_analysis())) 89 | print('Annual Return: ' + str(strats.analyzers.annual_return.get_analysis())) 90 | # print('TradeAnalyzer: ' + str(strats.analyzers.trade_analyzer.get_analysis())) 91 | _printTradeAnalysis(strats.analyzers.trade_analyzer.get_analysis()) 92 | 93 | # print('Calmar: ' + str(strats.analyzers.calmar.get_analysis())) 94 | # print('Log Returns Rolling: ' + str(strats.analyzers.log_returns_rolling.get_analysis())) 95 | # print('Periods Stats: ' + str(strats.analyzers.periods_stats.get_analysis())) 96 | # print('PyFolio: ' + str(strats.analyzers.pyfolio.get_analysis())) 97 | 98 | # print('Transactions: ' + str(strats.analyzers.transactions.get_analysis())) 99 | # print('Time Return: ' + str(strats.analyzers.time_return.get_analysis())) 100 | --------------------------------------------------------------------------------