How to run backtrader on MacOS

The package backtrader is a Live Trading and backtesting platform written in Python.

Code

The code of a classic Simple Moving Average Crossover strategy is used to verify if backtrader works. The data feed of Yahoo Finance will be replaced with some workable ones, eg. tushare, akshare.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from datetime import datetime
import backtrader as bt

# Create a subclass of SignaStrategy to define the indicators and signals
class SmaCross(bt.SignalStrategy):
def __init__(self):
sma1 = bt.ind.SMA(period=10) # fast moving average
sma2 = bt.ind.SMA(period=30) # slow moving average
crossover = bt.ind.CrossOver(sma1, sma2) # crossover signal
self.signal_add(bt.SIGNAL_LONG, crossover) # use it as LONG signal


cerebro = bt.Cerebro() # create a "Cerebro" engine instance

# Create a data feed
data = bt.feeds.YahooFinanceData(dataname='MSFT',
fromdate=datetime(2011, 1, 1),
todate=datetime(2012, 12, 31))

cerebro.adddata(data) # Add the data feed

cerebro.addstrategy(SmaCross) # Add the trading strategy
cerebro.run() # run it all
cerebro.plot() # and plot it with a single command

Installation

python

Python 3.10 is installed. Tried Python 3.7 before that, but failed to install some packages like tushare.

1
2
$ python --version
Python 3.10.10

backtrader

1
pip install backtrader[plotting] -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com

data feed

1
2
3
pip install tushare -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com

pip install akshare -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com

Errors

Error 1

SSL issues when fetching data with tushare

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ python sma.py 
本接口即将停止更新,请尽快使用Pro版接口:https://tushare.pro/document/2
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
/path/to/py310/lib/python3.10/site-packages/tushare/stock/trading.py:706: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
data = data.append(_get_k_data(url, dataflag,
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>
<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)>

Solution:

1
2
3
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

Error 2

The last update of backtrader is about 2 years ago. It’s not compatible with the latest matplotlib. Have to fix some lines in backtrader/plot/locator.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Fontconfig warning: "/usr/local/etc/fonts/fonts.conf", line 86: unknown element "blank"
Fontconfig warning: ignoring UTF-8: not a valid region tag
Traceback (most recent call last):
File "/path/to/python/code/sma.py", line 40, in <module>
cerebro.plot()
File "/path/to/python/py310/lib/python3.10/site-packages/backtrader/cerebro.py", line 974, in plot
from . import plot
File "/path/to/python/py310/lib/python3.10/site-packages/backtrader/plot/__init__.py", line 42, in <module>
from .plot import Plot, Plot_OldSync
File "/path/to/python/py310/lib/python3.10/site-packages/backtrader/plot/plot.py", line 44, in <module>
from . import locator as loc
File "/path/to/python/py310/lib/python3.10/site-packages/backtrader/plot/locator.py", line 35, in <module>
from matplotlib.dates import (HOURS_PER_DAY, MIN_PER_HOUR, SEC_PER_MIN,
ImportError: cannot import name 'warnings' from 'matplotlib.dates' (/path/to/python/py310/lib/python3.10/site-packages/matplotlib/dates.py)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Before

from matplotlib.dates import (HOURS_PER_DAY, MIN_PER_HOUR, SEC_PER_MIN,
MONTHS_PER_YEAR, DAYS_PER_WEEK,
SEC_PER_HOUR, SEC_PER_DAY,
num2date, rrulewrapper, YearLocator,
MicrosecondLocator, warnings)


# After

from matplotlib.dates import (HOURS_PER_DAY, MIN_PER_HOUR, SEC_PER_MIN,
MONTHS_PER_YEAR, DAYS_PER_WEEK,
SEC_PER_HOUR, SEC_PER_DAY,
num2date, rrulewrapper, YearLocator,
MicrosecondLocator)
import warnings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Traceback (most recent call last):
File "/path/to/python/code/sma.py", line 40, in <module>
cerebro.plot()
File "/path/to/python/py310/lib/python3.10/site-packages/backtrader/cerebro.py", line 989, in plot
rfig = plotter.plot(strat, figid=si * 100,
File "/path/to/python/py310/lib/python3.10/site-packages/backtrader/plot/plot.py", line 262, in plot
self.mpyplot.setp(ax.get_xticklabels(), visible=False)
File "/path/to/python/py310/lib/python3.10/site-packages/matplotlib/axes/_base.py", line 74, in wrapper
return get_method(self)(*args, **kwargs)
File "/path/to/python/py310/lib/python3.10/site-packages/matplotlib/axis.py", line 1451, in get_ticklabels
return self.get_majorticklabels()
File "/path/to/python/py310/lib/python3.10/site-packages/matplotlib/axis.py", line 1408, in get_majorticklabels
self._update_ticks()
File "/path/to/python/py310/lib/python3.10/site-packages/matplotlib/axis.py", line 1257, in _update_ticks
major_locs = self.get_majorticklocs()
File "/path/to/python/py310/lib/python3.10/site-packages/matplotlib/axis.py", line 1479, in get_majorticklocs
return self.major.locator()
File "/path/to/python/py310/lib/python3.10/site-packages/matplotlib/dates.py", line 1378, in __call__
locator = self.get_locator(dmin, dmax)
File "/path/to/python/py310/lib/python3.10/site-packages/backtrader/plot/locator.py", line 227, in get_locator
locator.set_view_interval(*self.axis.get_view_interval())
AttributeError: 'RRuleLocator' object has no attribute 'set_view_interval'
1
2
3
4
5
6
7
8
9
# Before

locator.set_view_interval(*self.axis.get_view_interval())
locator.set_data_interval(*self.axis.get_data_interval())

# After

# locator.set_view_interval(*self.axis.get_view_interval())
# locator.set_data_interval(*self.axis.get_data_interval())

Result

To verify if backtrader works, run the strategy against daily prices of 300750. It will buy 100 stakes if SMA10 crosses up SMA30, then close if crossing down. This strategy may not work well when declining or vibrating.

info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

from datetime import datetime
import backtrader as bt
import pandas as pd
import tushare as ts
import os.path
import ssl

ssl._create_default_https_context = ssl._create_unverified_context

stock='300750'

def get_data(code,start='2019-01-01',end='2023-03-31'):
df=ts.get_k_data(code,autype='qfq',start=start,end=end)
print(df)
df.index=pd.to_datetime(df.date)
df['openinterest']=0
df=df[['open','high','low','close','volume','openinterest']]
return df

class SmaCross(bt.SignalStrategy):
def __init__(self):
sma1, sma2 = bt.ind.SMA(period=10), bt.ind.SMA(period=30)
crossover = bt.ind.CrossOver(sma1, sma2)
self.signal_add(bt.SIGNAL_LONG, crossover)
def notify_order(self, order):
if not order.alive():
print(','.join(str(x) for x in
(self.data.num2date(order.executed.dt).date(),
order.executed.size * 1 if order.isbuy() else -1,
order.executed.price)))
#def notify_trade(self, trade):
# print(trade)

cerebro = bt.Cerebro()
cerebro.addstrategy(SmaCross)


data_file = 'prices/' + stock + '.csv'

if (os.path.exists(data_file)):
dataframe = pd.read_csv(data_file, index_col="date", parse_dates=True)
else:
dataframe=get_data(stock)
dataframe.to_csv(data_file)


start=datetime(2022, 3, 4)
end=datetime(2023, 3, 4)

data0 = bt.feeds.PandasData(dataname=dataframe,fromdate=start,todate=end)

#data0 = bt.feeds.YahooFinanceData(dataname='MSFT', fromdate=datetime(2011, 1, 1),
# todate=datetime(2012, 12, 31))
cerebro.adddata(data0)

cerebro.broker.setcash(100000.0)
cerebro.broker.setcommission(commission=0.0003)
cerebro.addsizer(bt.sizers.FixedSize, stake=100)


cerebro.run()
cerebro.plot()
文章目录
  1. 1. Code
  2. 2. Installation
    1. 2.1. python
    2. 2.2. backtrader
    3. 2.3. data feed
  3. 3. Errors
    1. 3.1. Error 1
    2. 3.2. Error 2
  4. 4. Result
,