代码有所删减,完整版及在线运行可访问Backtrader官方中文文档
一. backtrader介绍
- 制定策略
- 1.1 确定潜在的可调参数
- 1.2 实例化您在策略中需要的指标
- 1.3 写下进入/退出市场的逻辑
- 创建Cerebro引擎(西班牙语大脑的意思)
- 2.1 注入策略
- 2.2 使用cerebro.adddata加载回测数据
- 2.3 执行cerebro.run
- 2.4 使用cerebro.plot绘制可视化图表
backtrader是高度可配置的,希望大家发现其中的乐趣。
二. backtrader安装
基本要求是: Python 2.7 Python 3.2 / 3.3 / 3.4 / 3.5 如有绘图需求,则要求 Matplotlib> = 1.4.1
!pip install backtrader -i https://mirrors.cloud.tencent.com/pypi/simple
Looking in indexes: https://mirrors.cloud.tencent.com/pypi/simple
Requirement already satisfied: backtrader in /opt/conda/lib/python3.6/site-packages (1.9.76.123)
[33mWARNING: You are using pip version 20.3.3; however, version 21.3.1 is available.
You should consider upgrading via the '/opt/conda/bin/python -m pip install --upgrade pip' command.[0m
三. backtrader快速开始
3.1 折线
交易数据(Data Feeds)、技术指标(Indicators)和策略(Strategies)都是折线(Line)。 折线(Line)是由一系列的点组成的。
通常交易数据(Data Feeds)包含以下几个组成部分: 开盘价( Open)、最高价(High)、最低价(Low)、收盘价(Close)、成交量(Volume)、持仓量(OpenInterest)等。 比如:所有的开盘价( Open)按时间组成一条折线(Line),那么一组交易数据(Data Feeds)就 应该包含了6条折线(Line)。
再加上时间(DateTime)一共有7条折线(Line)。时间,一般用作一组交易数据的主键。
3.2 索引从0开始
当访问一条折线(Line)的数据时,会默认从下标为0的位置开始,最后一个数据通过下标-1来获取。这样的设计和Python的迭代器是一致的,所以折线(Line)是可以迭代遍历的。
例如:创建一个简单移动平均值的策略(均值策略): self.sma = SimpleMovingAverage(…)
访问此移动平均线的当前值的最简单方法:av = self.sma[0]
所以在回测过程中,无需知道已经处理了多少条/分钟/天/月,“0”一直指向当前值。
按照Python遍历数组的方式,用下标-1来访问最后一个值: previous_value = self.sma[-1] 同理:-2、-3下标也是可以照常使用。
3.3 从0到100
先跑一个基本框架
import backtrader as bt
import time
# 创建Cerebro引擎
cerebro = bt.Cerebro()
#Cerebro引擎在后台创建broker(经纪人),系统默认资金量为10000
# 引擎运行前打印期出资金
print('组合期初资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
# 引擎运行后打期末资金
print('组合期末资金: %.2f' % cerebro.broker.getvalue())
组合期初资金: 10000.00
组合期末资金: 10000.00
3.4 设定现金
在金融世界中,可以肯定的是,只有Losser才以1万开始。让我们更改现金并再次运行该示例。
#导入backtrader框架
import backtrader as bt
# 创建Cerebro引擎
cerebro = bt.Cerebro()
# Cerebro引擎在后台创建broker(经纪人),系统默认资金量为10000
# 设置投资金额100000.0
cerebro.broker.setcash(100000.0)
# 引擎运行前打印期出资金
print('组合期初资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
# 引擎运行后打期末资金
print('组合期末资金: %.2f' % cerebro.broker.getvalue())
组合期初资金: 100000.00
组合期末资金: 100000.00
3.5 加入交易数据
拥有现金是一件快乐的事,这一切背后最终的目的就是: 不动一根手指,就能让自动化策略通过操作资产的交易数据来增加现金。 无数据,不快乐,让我们继续加入交易数据。
import datetime #
import os.path # 路径管理
import sys # 获取当前运行脚本的路径 (in argv[0])
#导入backtrader框架
import backtrader as bt
# 创建Cerebro引擎
cerebro = bt.Cerebro()
# Cerebro引擎在后台创建broker(经纪人),系统默认资金量为10000
# 获取当前运行脚本所在目录
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
# 拼接加载路径
datapath = os.path.join(modpath, '/home/mw/input/backtrader7822/orcl-1995-2014.txt')
# 创建交易数据集
data = bt.feeds.YahooFinanceCSVData(
dataname=datapath,
# 数据必须大于fromdate
fromdate=datetime.datetime(2000, 1, 1),
# 数据必须小于todate
todate=datetime.datetime(2000, 12, 31),
reverse=False)
# 加载交易数据
cerebro.adddata(data)
# 设置投资金额100000.0
cerebro.broker.setcash(100000.0)
# 引擎运行前打印期出资金
print('组合期初资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
# 引擎运行后打期末资金
print('组合期末资金: %.2f' % cerebro.broker.getvalue())
组合期初资金: 100000.00
组合期末资金: 100000.00
代码量略有增加,因为我们添加了:找出数据文件所在的路径通过datetime对象过滤我们想要操作的数据
注意: Yahoo的价格数据有点非主流,它是以时间倒序排列的。datetime.datetime()中的reversed=True参数是将顺序反转一次,这样就得到了我们想要的正序数据。
3.6 第一个策略
资金和交易数据都有了,探险即将开始。让我们给策略加点代码,打印出每天的”收盘价”。 DataSeries(交易数据的基类)对象,可以直接访问到 OHLC (开盘价、最高价、最低价、收盘价)等数据。这使我们打印数据很方便。
import datetime #
import os.path # 路径管理
import sys # 获取当前运行脚本的路径 (in argv[0])
#导入backtrader框架
import backtrader as bt
# 创建策略继承bt.Strategy
class TestStrategy(bt.Strategy):
def log(self, txt, dt=None):
# 记录策略的执行日志
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# 保存收盘价的引用
self.dataclose = self.datas[0].close
def next(self):
# 记录收盘价
self.log('Close, %.2f' % self.dataclose[0])
# 创建Cerebro引擎
cerebro = bt.Cerebro()
# Cerebro引擎在后台创建broker(经纪人),系统默认资金量为10000
# 为Cerebro引擎添加策略
cerebro.addstrategy(TestStrategy)
# 获取当前运行脚本所在目录
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
# 拼接加载路径
datapath = os.path.join(modpath, '/home/mw/input/backtrader7822/orcl-1995-2014.txt')
# 创建交易数据集
data = bt.feeds.YahooFinanceCSVData( dataname=datapath,
# 数据必须大于fromdate
fromdate=datetime.datetime(2000, 1, 1),
# 数据必须小于todate
todate=datetime.datetime(2000, 12, 31),
reverse=False)
# 加载交易数据
cerebro.adddata(data)
# 设置投资金额100000.0
cerebro.broker.setcash(100000.0)
# 引擎运行前打印期出资金
print('组合期初资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
# 引擎运行后打期末资金
print('组合期末资金: %.2f' % cerebro.broker.getvalue())
组合期初资金: 100000.00
2000-01-03, Close, 26.27
2000-01-04, Close, 23.95
2000-01-05, Close, 22.68
2000-01-06, Close, 21.35
2000-01-07, Close, 22.99
2000-01-10, Close, 25.74
2000-01-11, Close, 24.99
2000-01-12, Close, 23.49
2000-01-13, Close, 23.36
2000-01-14, Close, 23.75
2000-01-18, Close, 24.74
2000-01-19, Close, 25.41
2000-01-20, Close, 26.35
2000-01-21, Close, 26.55
2000-01-24, Close, 24.10
2000-01-25, Close, 25.10
2000-01-26, Close, 24.49
2000-01-27, Close, 23.04
2000-01-28, Close, 21.07
2000-01-31, Close, 22.22
2000-02-01, Close, 24.02
2000-02-02, Close, 24.16
2000-02-03, Close, 25.21
2000-02-04, Close, 25.71
2000-02-07, Close, 26.66
2000-02-08, Close, 26.49
2000-02-09, Close, 26.66
2000-02-10, Close, 27.71
2000-02-11, Close, 26.55
2000-02-14, Close, 27.66
2000-02-15, Close, 27.30
2000-02-16, Close, 27.24
2000-02-17, Close, 27.41
2000-02-18, Close, 26.05
2000-02-22, Close, 26.38
2000-02-23, Close, 28.05
2000-02-24, Close, 27.55
2000-02-25, Close, 31.41
2000-02-28, Close, 30.52
2000-02-29, Close, 33.02
2000-03-01, Close, 31.80
2000-03-02, Close, 30.47
2000-03-03, Close, 33.36
2000-03-06, Close, 33.69
2000-03-07, Close, 33.33
2000-03-08, Close, 36.97
2000-03-09, Close, 37.36
2000-03-10, Close, 36.30
2000-03-13, Close, 35.02
2000-03-14, Close, 34.25
2000-03-15, Close, 34.97
2000-03-16, Close, 36.44
2000-03-17, Close, 35.50
2000-03-20, Close, 34.75
2000-03-21, Close, 35.89
2000-03-22, Close, 37.39
2000-03-23, Close, 38.64
2000-03-24, Close, 38.69
2000-03-27, Close, 39.33
2000-03-28, Close, 38.50
2000-03-29, Close, 36.69
2000-03-30, Close, 34.88
2000-03-31, Close, 34.72
2000-04-03, Close, 34.19
2000-04-04, Close, 33.77
2000-04-05, Close, 34.80
2000-04-06, Close, 36.55
2000-04-07, Close, 38.75
2000-04-10, Close, 36.69
2000-04-11, Close, 34.41
2000-04-12, Close, 32.52
2000-04-13, Close, 31.99
2000-04-14, Close, 27.80
2000-04-17, Close, 33.27
2000-04-18, Close, 35.11
2000-04-19, Close, 33.16
2000-04-20, Close, 31.49
2000-04-24, Close, 32.22
2000-04-25, Close, 33.61
2000-04-26, Close, 32.11
2000-04-27, Close, 34.38
2000-04-28, Close, 35.55
2000-05-01, Close, 35.44
2000-05-02, Close, 34.61
2000-05-03, Close, 33.72
2000-05-04, Close, 33.02
2000-05-05, Close, 34.16
2000-05-08, Close, 32.16
2000-05-09, Close, 32.02
2000-05-10, Close, 30.08
2000-05-11, Close, 32.19
2000-05-12, Close, 32.99
2000-05-15, Close, 34.25
2000-05-16, Close, 35.22
2000-05-17, Close, 34.77
2000-05-18, Close, 32.49
2000-05-19, Close, 31.16
2000-05-22, Close, 30.16
2000-05-23, Close, 27.85
2000-05-24, Close, 28.57
2000-05-25, Close, 29.55
2000-05-26, Close, 29.80
2000-05-30, Close, 32.99
2000-05-31, Close, 31.97
2000-06-01, Close, 34.63
2000-06-02, Close, 35.66
2000-06-05, Close, 36.00
2000-06-06, Close, 34.27
2000-06-07, Close, 35.58
2000-06-08, Close, 36.64
2000-06-09, Close, 36.77
2000-06-12, Close, 35.83
2000-06-13, Close, 36.33
2000-06-14, Close, 35.13
2000-06-15, Close, 36.69
2000-06-16, Close, 36.41
2000-06-19, Close, 38.25
2000-06-20, Close, 38.27
2000-06-21, Close, 38.33
2000-06-22, Close, 36.25
2000-06-23, Close, 35.36
2000-06-26, Close, 36.77
2000-06-27, Close, 36.58
2000-06-28, Close, 36.89
2000-06-29, Close, 35.97
2000-06-30, Close, 37.39
2000-07-03, Close, 35.66
2000-07-05, Close, 32.16
2000-07-06, Close, 33.63
2000-07-07, Close, 33.75
2000-07-10, Close, 32.97
2000-07-11, Close, 32.16
2000-07-12, Close, 33.22
2000-07-13, Close, 33.69
2000-07-14, Close, 33.86
2000-07-17, Close, 33.86
2000-07-18, Close, 32.99
2000-07-19, Close, 32.80
2000-07-20, Close, 34.75
2000-07-21, Close, 33.55
2000-07-24, Close, 33.36
2000-07-25, Close, 33.80
2000-07-26, Close, 34.13
2000-07-27, Close, 33.38
2000-07-28, Close, 32.19
2000-07-31, Close, 33.44
2000-08-01, Close, 32.52
2000-08-02, Close, 32.52
2000-08-03, Close, 34.44
2000-08-04, Close, 36.27
2000-08-07, Close, 36.41
2000-08-08, Close, 36.91
2000-08-09, Close, 36.19
2000-08-10, Close, 35.61
2000-08-11, Close, 36.08
2000-08-14, Close, 36.64
2000-08-15, Close, 36.14
2000-08-16, Close, 36.11
2000-08-17, Close, 37.33
2000-08-18, Close, 36.16
2000-08-21, Close, 37.00
2000-08-22, Close, 37.16
2000-08-23, Close, 36.86
2000-08-24, Close, 37.66
2000-08-25, Close, 37.64
2000-08-28, Close, 38.58
2000-08-29, Close, 39.03
2000-08-30, Close, 39.25
2000-08-31, Close, 40.44
2000-09-01, Close, 41.19
2000-09-05, Close, 40.50
2000-09-06, Close, 39.69
2000-09-07, Close, 40.56
2000-09-08, Close, 38.50
2000-09-11, Close, 37.11
2000-09-12, Close, 35.30
2000-09-13, Close, 36.39
2000-09-14, Close, 37.78
2000-09-15, Close, 34.83
2000-09-18, Close, 34.01
2000-09-19, Close, 35.27
2000-09-20, Close, 35.55
2000-09-21, Close, 35.11
2000-09-22, Close, 35.91
2000-09-25, Close, 35.02
2000-09-26, Close, 35.33
2000-09-27, Close, 35.52
2000-09-28, Close, 36.24
2000-09-29, Close, 35.02
2000-10-02, Close, 35.02
2000-10-03, Close, 30.91
2000-10-04, Close, 30.30
2000-10-05, Close, 30.38
2000-10-06, Close, 30.08
2000-10-09, Close, 29.69
2000-10-10, Close, 28.74
2000-10-11, Close, 27.69
2000-10-12, Close, 28.02
2000-10-13, Close, 31.69
2000-10-16, Close, 30.74
2000-10-17, Close, 29.96
2000-10-18, Close, 29.85
2000-10-19, Close, 32.36
2000-10-20, Close, 31.35
2000-10-23, Close, 30.30
2000-10-24, Close, 31.85
2000-10-25, Close, 30.58
2000-10-26, Close, 30.30
2000-10-27, Close, 30.41
2000-10-30, Close, 28.13
2000-10-31, Close, 29.35
2000-11-01, Close, 27.91
2000-11-02, Close, 26.30
2000-11-03, Close, 26.96
2000-11-06, Close, 24.85
2000-11-07, Close, 23.63
2000-11-08, Close, 22.07
2000-11-09, Close, 24.18
2000-11-10, Close, 22.63
2000-11-13, Close, 22.01
2000-11-14, Close, 25.24
2000-11-15, Close, 25.68
2000-11-16, Close, 24.35
2000-11-17, Close, 25.63
2000-11-20, Close, 22.01
2000-11-21, Close, 21.24
2000-11-22, Close, 19.85
2000-11-24, Close, 21.46
2000-11-27, Close, 20.57
2000-11-28, Close, 20.15
2000-11-29, Close, 20.35
2000-11-30, Close, 23.57
2000-12-01, Close, 23.52
2000-12-04, Close, 25.07
2000-12-05, Close, 28.02
2000-12-06, Close, 26.85
2000-12-07, Close, 25.18
2000-12-08, Close, 26.74
2000-12-11, Close, 28.41
2000-12-12, Close, 27.35
2000-12-13, Close, 25.24
2000-12-14, Close, 24.46
2000-12-15, Close, 25.41
2000-12-18, Close, 28.46
2000-12-19, Close, 27.24
2000-12-20, Close, 25.35
2000-12-21, Close, 26.24
2000-12-22, Close, 28.35
2000-12-26, Close, 27.52
2000-12-27, Close, 27.30
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
组合期末资金: 100000.00
有人说股市有风险,看起来不像啊。 一些解释说明:
框架在调用init时,该策略已经具有一个数据列表datas,这是标准的Python列表,可以按插入顺序访问数据。 列表中的第一个数据 self.datas[0]是用于交易操作,并且策略中的所有元素都是由框架的系统时钟进行同步的。 由于只需访问收盘价数据,于是使用 self.dataclose = self.datas[0].close将第一条价格数据的收盘价赋值给新变量。 系统时钟当经过一个 K线柱的时候,策略的next()方法就会被调用一次。这一过程 将一直循环,直到其他指标信号出现为止。此时,便会输出最终结果。关于这些,后继内容会讲到。
3.7 给策略加点逻辑
如果K线收盘价出现三连跌,则买入。
import datetime #
import os.path # 路径管理
import sys # 获取当前运行脚本的路径 (in argv[0])
#导入backtrader框架
import backtrader as bt
# 创建策略继承bt.Strategy
class TestStrategy(bt.Strategy):
def log(self, txt, dt=None):
# 记录策略的执行日志
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# 保存收盘价的引用
self.dataclose = self.datas[0].close
def next(self):
# 记录收盘价
self.log('Close, %.2f' % self.dataclose[0])
# 今天的收盘价 < 昨天收盘价
if self.dataclose[0] < self.dataclose[-1]:
# 昨天收盘价 < 前天的收盘价
if self.dataclose[-1] < self.dataclose[-2]:
# 买入
self.log('买入, %.2f' % self.dataclose[0])
self.buy()
# 创建Cerebro引擎
cerebro = bt.Cerebro()
# Cerebro引擎在后台创建broker(经纪人),系统默认资金量为10000
# 为Cerebro引擎添加策略
cerebro.addstrategy(TestStrategy)
# 获取当前运行脚本所在目录
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
# 拼接加载路径
datapath = os.path.join(modpath, '/home/mw/input/backtrader7822/orcl-1995-2014.txt')
# 创建交易数据集
data = bt.feeds.YahooFinanceCSVData(
dataname=datapath,
# 数据必须大于fromdate
fromdate=datetime.datetime(2000, 1, 1),
# 数据必须小于todate
todate=datetime.datetime(2000, 12, 31),
reverse=False)
# 加载交易数据
cerebro.adddata(data)
# 设置投资金额100000.0
cerebro.broker.setcash(100000.0)
# 引擎运行前打印期出资金
print('组合期初资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
# 引擎运行后打期末资金
print('组合期末资金: %.2f' % cerebro.broker.getvalue())
组合期初资金: 100000.00
2000-01-03, Close, 26.27
2000-01-04, Close, 23.95
2000-01-05, Close, 22.68
2000-01-05, 买入, 22.68
2000-01-06, Close, 21.35
2000-01-06, 买入, 21.35
2000-01-07, Close, 22.99
2000-01-10, Close, 25.74
2000-01-11, Close, 24.99
2000-01-12, Close, 23.49
2000-01-12, 买入, 23.49
2000-01-13, Close, 23.36
2000-01-13, 买入, 23.36
2000-01-14, Close, 23.75
2000-01-18, Close, 24.74
2000-01-19, Close, 25.41
2000-01-20, Close, 26.35
2000-01-21, Close, 26.55
2000-01-24, Close, 24.10
2000-01-25, Close, 25.10
2000-01-26, Close, 24.49
2000-01-27, Close, 23.04
2000-01-27, 买入, 23.04
2000-01-28, Close, 21.07
2000-01-28, 买入, 21.07
2000-01-31, Close, 22.22
2000-02-01, Close, 24.02
2000-02-02, Close, 24.16
2000-02-03, Close, 25.21
2000-02-04, Close, 25.71
2000-02-07, Close, 26.66
2000-02-08, Close, 26.49
2000-02-09, Close, 26.66
2000-02-10, Close, 27.71
2000-02-11, Close, 26.55
2000-02-14, Close, 27.66
2000-02-15, Close, 27.30
2000-02-16, Close, 27.24
2000-02-16, 买入, 27.24
2000-02-17, Close, 27.41
2000-02-18, Close, 26.05
2000-02-22, Close, 26.38
2000-02-23, Close, 28.05
2000-02-24, Close, 27.55
2000-02-25, Close, 31.41
2000-02-28, Close, 30.52
2000-02-29, Close, 33.02
2000-03-01, Close, 31.80
2000-03-02, Close, 30.47
2000-03-02, 买入, 30.47
2000-03-03, Close, 33.36
2000-03-06, Close, 33.69
2000-03-07, Close, 33.33
2000-03-08, Close, 36.97
2000-03-09, Close, 37.36
2000-03-10, Close, 36.30
2000-03-13, Close, 35.02
2000-03-13, 买入, 35.02
2000-03-14, Close, 34.25
2000-03-14, 买入, 34.25
2000-03-15, Close, 34.97
2000-03-16, Close, 36.44
2000-03-17, Close, 35.50
2000-03-20, Close, 34.75
2000-03-20, 买入, 34.75
2000-03-21, Close, 35.89
2000-03-22, Close, 37.39
2000-03-23, Close, 38.64
2000-03-24, Close, 38.69
2000-03-27, Close, 39.33
2000-03-28, Close, 38.50
2000-03-29, Close, 36.69
2000-03-29, 买入, 36.69
2000-03-30, Close, 34.88
2000-03-30, 买入, 34.88
2000-03-31, Close, 34.72
2000-03-31, 买入, 34.72
2000-04-03, Close, 34.19
2000-04-03, 买入, 34.19
2000-04-04, Close, 33.77
2000-04-04, 买入, 33.77
2000-04-05, Close, 34.80
2000-04-06, Close, 36.55
2000-04-07, Close, 38.75
2000-04-10, Close, 36.69
2000-04-11, Close, 34.41
2000-04-11, 买入, 34.41
2000-04-12, Close, 32.52
2000-04-12, 买入, 32.52
2000-04-13, Close, 31.99
2000-04-13, 买入, 31.99
2000-04-14, Close, 27.80
2000-04-14, 买入, 27.80
2000-04-17, Close, 33.27
2000-04-18, Close, 35.11
2000-04-19, Close, 33.16
2000-04-20, Close, 31.49
2000-04-20, 买入, 31.49
2000-04-24, Close, 32.22
2000-04-25, Close, 33.61
2000-04-26, Close, 32.11
2000-04-27, Close, 34.38
2000-04-28, Close, 35.55
2000-05-01, Close, 35.44
2000-05-02, Close, 34.61
2000-05-02, 买入, 34.61
2000-05-03, Close, 33.72
2000-05-03, 买入, 33.72
2000-05-04, Close, 33.02
2000-05-04, 买入, 33.02
2000-05-05, Close, 34.16
2000-05-08, Close, 32.16
2000-05-09, Close, 32.02
2000-05-09, 买入, 32.02
2000-05-10, Close, 30.08
2000-05-10, 买入, 30.08
2000-05-11, Close, 32.19
2000-05-12, Close, 32.99
2000-05-15, Close, 34.25
2000-05-16, Close, 35.22
2000-05-17, Close, 34.77
2000-05-18, Close, 32.49
2000-05-18, 买入, 32.49
2000-05-19, Close, 31.16
2000-05-19, 买入, 31.16
2000-05-22, Close, 30.16
2000-05-22, 买入, 30.16
2000-05-23, Close, 27.85
2000-05-23, 买入, 27.85
2000-05-24, Close, 28.57
2000-05-25, Close, 29.55
2000-05-26, Close, 29.80
2000-05-30, Close, 32.99
2000-05-31, Close, 31.97
2000-06-01, Close, 34.63
2000-06-02, Close, 35.66
2000-06-05, Close, 36.00
2000-06-06, Close, 34.27
2000-06-07, Close, 35.58
2000-06-08, Close, 36.64
2000-06-09, Close, 36.77
2000-06-12, Close, 35.83
2000-06-13, Close, 36.33
2000-06-14, Close, 35.13
2000-06-15, Close, 36.69
2000-06-16, Close, 36.41
2000-06-19, Close, 38.25
2000-06-20, Close, 38.27
2000-06-21, Close, 38.33
2000-06-22, Close, 36.25
2000-06-23, Close, 35.36
2000-06-23, 买入, 35.36
2000-06-26, Close, 36.77
2000-06-27, Close, 36.58
2000-06-28, Close, 36.89
2000-06-29, Close, 35.97
2000-06-30, Close, 37.39
2000-07-03, Close, 35.66
2000-07-05, Close, 32.16
2000-07-05, 买入, 32.16
2000-07-06, Close, 33.63
2000-07-07, Close, 33.75
2000-07-10, Close, 32.97
2000-07-11, Close, 32.16
2000-07-11, 买入, 32.16
2000-07-12, Close, 33.22
2000-07-13, Close, 33.69
2000-07-14, Close, 33.86
2000-07-17, Close, 33.86
2000-07-18, Close, 32.99
2000-07-19, Close, 32.80
2000-07-19, 买入, 32.80
2000-07-20, Close, 34.75
2000-07-21, Close, 33.55
2000-07-24, Close, 33.36
2000-07-24, 买入, 33.36
2000-07-25, Close, 33.80
2000-07-26, Close, 34.13
2000-07-27, Close, 33.38
2000-07-28, Close, 32.19
2000-07-28, 买入, 32.19
2000-07-31, Close, 33.44
2000-08-01, Close, 32.52
2000-08-02, Close, 32.52
2000-08-03, Close, 34.44
2000-08-04, Close, 36.27
2000-08-07, Close, 36.41
2000-08-08, Close, 36.91
2000-08-09, Close, 36.19
2000-08-10, Close, 35.61
2000-08-10, 买入, 35.61
2000-08-11, Close, 36.08
2000-08-14, Close, 36.64
2000-08-15, Close, 36.14
2000-08-16, Close, 36.11
2000-08-16, 买入, 36.11
2000-08-17, Close, 37.33
2000-08-18, Close, 36.16
2000-08-21, Close, 37.00
2000-08-22, Close, 37.16
2000-08-23, Close, 36.86
2000-08-24, Close, 37.66
2000-08-25, Close, 37.64
2000-08-28, Close, 38.58
2000-08-29, Close, 39.03
2000-08-30, Close, 39.25
2000-08-31, Close, 40.44
2000-09-01, Close, 41.19
2000-09-05, Close, 40.50
2000-09-06, Close, 39.69
2000-09-06, 买入, 39.69
2000-09-07, Close, 40.56
2000-09-08, Close, 38.50
2000-09-11, Close, 37.11
2000-09-11, 买入, 37.11
2000-09-12, Close, 35.30
2000-09-12, 买入, 35.30
2000-09-13, Close, 36.39
2000-09-14, Close, 37.78
2000-09-15, Close, 34.83
2000-09-18, Close, 34.01
2000-09-18, 买入, 34.01
2000-09-19, Close, 35.27
2000-09-20, Close, 35.55
2000-09-21, Close, 35.11
2000-09-22, Close, 35.91
2000-09-25, Close, 35.02
2000-09-26, Close, 35.33
2000-09-27, Close, 35.52
2000-09-28, Close, 36.24
2000-09-29, Close, 35.02
2000-10-02, Close, 35.02
2000-10-03, Close, 30.91
2000-10-04, Close, 30.30
2000-10-04, 买入, 30.30
2000-10-05, Close, 30.38
2000-10-06, Close, 30.08
2000-10-09, Close, 29.69
2000-10-09, 买入, 29.69
2000-10-10, Close, 28.74
2000-10-10, 买入, 28.74
2000-10-11, Close, 27.69
2000-10-11, 买入, 27.69
2000-10-12, Close, 28.02
2000-10-13, Close, 31.69
2000-10-16, Close, 30.74
2000-10-17, Close, 29.96
2000-10-17, 买入, 29.96
2000-10-18, Close, 29.85
2000-10-18, 买入, 29.85
2000-10-19, Close, 32.36
2000-10-20, Close, 31.35
2000-10-23, Close, 30.30
2000-10-23, 买入, 30.30
2000-10-24, Close, 31.85
2000-10-25, Close, 30.58
2000-10-26, Close, 30.30
2000-10-26, 买入, 30.30
2000-10-27, Close, 30.41
2000-10-30, Close, 28.13
2000-10-31, Close, 29.35
2000-11-01, Close, 27.91
2000-11-02, Close, 26.30
2000-11-02, 买入, 26.30
2000-11-03, Close, 26.96
2000-11-06, Close, 24.85
2000-11-07, Close, 23.63
2000-11-07, 买入, 23.63
2000-11-08, Close, 22.07
2000-11-08, 买入, 22.07
2000-11-09, Close, 24.18
2000-11-10, Close, 22.63
2000-11-13, Close, 22.01
2000-11-13, 买入, 22.01
2000-11-14, Close, 25.24
2000-11-15, Close, 25.68
2000-11-16, Close, 24.35
2000-11-17, Close, 25.63
2000-11-20, Close, 22.01
2000-11-21, Close, 21.24
2000-11-21, 买入, 21.24
2000-11-22, Close, 19.85
2000-11-22, 买入, 19.85
2000-11-24, Close, 21.46
2000-11-27, Close, 20.57
2000-11-28, Close, 20.15
2000-11-28, 买入, 20.15
2000-11-29, Close, 20.35
2000-11-30, Close, 23.57
2000-12-01, Close, 23.52
2000-12-04, Close, 25.07
2000-12-05, Close, 28.02
2000-12-06, Close, 26.85
2000-12-07, Close, 25.18
2000-12-07, 买入, 25.18
2000-12-08, Close, 26.74
2000-12-11, Close, 28.41
2000-12-12, Close, 27.35
2000-12-13, Close, 25.24
2000-12-13, 买入, 25.24
2000-12-14, Close, 24.46
2000-12-14, 买入, 24.46
2000-12-15, Close, 25.41
2000-12-18, Close, 28.46
2000-12-19, Close, 27.24
2000-12-20, Close, 25.35
2000-12-20, 买入, 25.35
2000-12-21, Close, 26.24
2000-12-22, Close, 28.35
2000-12-26, Close, 27.52
2000-12-27, Close, 27.30
2000-12-27, 买入, 27.30
2000-12-28, Close, 27.63
2000-12-29, Close, 25.85
组合期末资金: 99740.45
若干个买入操作被执行,所以余额在减少。 细心的朋友可能会问,买了多少?买的什么?订单怎么被执行的?BackTrader框架替我们做了这些事: 如果没有指定的话, self.datas[0]即是标的物当前交易数据。 交易数量 =仓位数量,默认值等于1,后面例子我们会修改此参数。
订单被以”市价”成交了。 Broker(经纪人,之前提到过)使用了下一个交易日的开盘价,因为是broker在当前的交日易收盘后天提交的订单,下一个交易日开盘价是他接触到的第一个价格。 这里没有为订单设置佣金费,后边会加上。
3.8 不光有买入,还得有卖出
在知道如何买入(做多)之后,需要知道如何卖出,并且还需要了解该策略是否在市场中。 Strategy类有一个变量position保存当前持有的资产数量(可以理解为金融术语中的头寸), buy()和sell()会返回被创建的订单(尚未执行的), 订单状态的更改将通过 notify方法通知给策略Strategy。
卖出逻辑也很简单: 5个K线柱后(第6个K线柱)不管涨跌都卖。 请注意,这里没有指定具体时间,而是指定的柱的数量。一个柱可能代表 1分钟、1小时、1天、1星期等等,这取决于你价格数据文件里一条数据代表的周期。 虽然我们知道每个柱代表一天,但策略并不知道。
因为买入的时候,用的是交易日,所以这里应翻译为:5个交易日(第6个交易日)不管涨跌都卖。
另外,当还有头寸的时候,就不再买入了。
注意: 没有将柱的下标传给 next()方法,怎么知道已经经过了5个柱了呢? 这里用了 Python的len()方法获取它Line数据的长度。 交易发生时记下它的长度,后边比较大小,看是否经过了5个柱。
import datetime #
import os.path # 路径管理
import sys # 获取当前运行脚本的路径 (in argv[0])
#导入backtrader框架
import backtrader as bt
# 创建策略继承bt.Strategy
class TestStrategy(bt.Strategy):
def log(self, txt, dt=None):
# 记录策略的执行日志
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# 保存收盘价的引用
self.dataclose = self.datas[0].close
# 跟踪挂单
self.order = None
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# broker 提交/接受了,买/卖订单则什么都不做
return
# 检查一个订单是否完成
# 注意: 当资金不足时,broker会拒绝订单
if order.status in [order.Completed]:
if order.isbuy():
self.log('已买入, %.2f' % order.executed.price)
elif order.issell():
self.log('已卖出, %.2f' % order.executed.price)
# 记录当前交易数量
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('订单取消/保证金不足/拒绝')
# 其他状态记录为:无挂起订单
self.order = None
def next(self):
# 记录收盘价
self.log('Close, %.2f' % self.dataclose[0])
# 如果有订单正在挂起,不操作
if self.order:
return
# 如果没有持仓则买入
if not self.position:
# 今天的收盘价 < 昨天收盘价
if self.dataclose[0] < self.dataclose[-1]:
# 昨天收盘价 < 前天的收盘价
if self.dataclose[-1] < self.dataclose[-2]:
# 买入
self.log('买入, %.2f' % self.dataclose[0])
# 跟踪订单避免重复
self.order = self.buy()
else:
# 如果已经持仓,且当前交易数据量在买入后5个单位后
if len(self) >= (self.bar_executed + 5):
# 全部卖出
self.log('卖出, %.2f' % self.dataclose[0])
# 跟踪订单避免重复
self.order = self.sell()
# 创建Cerebro引擎
cerebro = bt.Cerebro()
# Cerebro引擎在后台创建broker(经纪人),系统默认资金量为10000
# 为Cerebro引擎添加策略
cerebro.addstrategy(TestStrategy)
# 获取当前运行脚本所在目录
modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
# 拼接加载路径
datapath = os.path.join(modpath, '/home/mw/input/backtrader7822/orcl-1995-2014.txt')
# 创建交易数据集
data = bt.feeds.YahooFinanceCSVData(
dataname=datapath,
# 数据必须大于fromdate
fromdate=datetime.datetime(2000, 1, 1),
# 数据必须小于todate
todate=datetime.datetime(2000, 12, 31),
reverse=False)
# 加载交易数据
cerebro.adddata(data)
# 设置投资金额100000.0
cerebro.broker.setcash(100000.0)
# 引擎运行前打印期出资金
print('组合期初资金: %.2f' % cerebro.broker.getvalue())
cerebro.run()
# 引擎运行后打期末资金
print(