backtrader和tushare进行量化交易
由于第一次还没创建目录,所以需要运行2次才能看到结果
代码:
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import datetime # For datetime objects
import os.path # To manage paths
import sys # To find out the script name (in argv[0])
import tushare as ts
import pandas as pd
import matplotlib.pyplot as plt
# Import the backtrader platform
import backtrader as bt
#%matplotlib inline
class MyStrategy(bt.Strategy):
params = (('short', 40),
('long', 70),)
def __init__(self):
self.rsi = bt.indicators.RSI_SMA(
self.data.close, period=6)
def next(self):
if not self.position:
if self.rsi < self.params.short:
self.buy()
else:
if self.rsi > self.params.long:
self.sell()
# Create a Stratey
class TestStrategy(bt.Strategy):
params = (
('maperiod', 15),('short',40),('long', 50),('mafast', 7), ('maslow', 24)
)
def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
if 'EXECUTED' in txt:
wfile.writelines('\n %s, %s' % (dt.isoformat(), txt))
def __init__(self):
macd=bt.ind.MACD()
self.macd=macd.macd
self.signal=macd.signal
self.histo=bt.ind.MACDHisto()
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
# To keep track of pending orders and buy price/commission
self.order = None
self.buyprice = None
self.buycomm = None
# Add a MovingAverageSimple indicator
self.sma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.mafast)
self.sma_slow = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maslow)
# Indicators for the plotting show
#bt.indicators.ExponentialMovingAverage(self.datas[0], period=25)
#bt.indicators.WeightedMovingAverage(self.datas[0], period=25,subplot=True)
self.rsi = bt.indicators.RSI_EMA(self.data.close, period=21)
#bt.indicators.StochasticSlow(self.datas[0])
#bt.indicators.MACDHisto(self.datas[0])
rsi = bt.indicators.RSI(self.datas[0])
#bt.indicators.SmoothedMovingAverage(rsi, period=10)
#bt.indicators.ATR(self.datas[0], plot=False)
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
return
# Check if an order has been completed
# Attention: broker could reject order if not enough cash
if order.status in [order.Completed]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f,position,%.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm,
self.position.size
))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f,position,%.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm,
self.position.size))
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Margin:'+str(order.status))
# Write down: no pending order
self.order = None
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def next(self):
# Simply log the closing price of the series from the reference
self.log('self.histo, %.2f self.macd %.2f self.signal %.2f== %.2f,self.rsi==%.2f' % (self.histo[0],self.signal[0],self.macd[0],self.macd[0]-self.signal[0],self.rsi[0]))
self.log('Close, %.2f' % self.dataclose[0])
# Check if an order is pending ... if yes, we cannot send a 2nd one
if self.order:
return
if self.position.size <400:
if (self.macd[0]-self.signal[0])<-0.2 and self.rsi < self.params.short:
# self.log('buy position, %.2f' % self.position.size)
self.log('BUY CREATE, %.2f' % self.dataclose[0])
self.buy()
if self.position.size >0 :
if self.histo>0.5 or self.rsi>self.params.long:
#self.log('sell position, %.2f' % self.position.size)
self.log('SELL CREATE, %.2f' % self.dataclose[0])
self.sell()
if __name__ == '__main__':
ts_code='000063'
wfile = open('../hist_data/'+ts_code+'.txt','w')
start_datetime='2020-02-01'
end_datetime='2020-09-22'
csv_path='../hist_data/'+ts_code+'_'+start_datetime+'_'+end_datetime+'.csv'
# Create a cerebro entity
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(TestStrategy)
if os.path.exists(csv_path):
df = pd.read_csv(csv_path,index_col=0)
else:
df=ts.get_hist_data(ts_code, start_datetime, end_datetime)
df = df.sort_index(ascending = True)
features=['open','high','low','close','volume']
df = df[features]
df['openinterest'] = -1
df.to_csv(csv_path,index=True)
# Create a Data Feed
data = bt.feeds.BacktraderCSVData(dataname=csv_path)
# Add the Data Feed to Cerebro
cerebro.adddata(data)
# Set our desired cash start
cerebro.broker.setcash(20000.0)
# Add a FixedSize sizer according to the stake
cerebro.addsizer(bt.sizers.FixedSize, stake=100)
# Set the commission
cerebro.broker.setcommission(commission=0.002)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Run over everything
cerebro.run()
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Plot the result
cerebro.plot()