Backtrader 文档学习-Strategy with Signals
backtrader可以不通过重写策略的方式触发交易,尽管重写策略是首选通用的方式。
下面介绍通过使用信号也是可以实现交易触发的。
1.定义signal
import backtrader as bt
data = bt.feeds.OneOfTheFeeds(dataname='mydataname')
cerebro.adddata(data)
cerebro.add_signal(bt.SIGNAL_LONGSHORT, MySignal)
cerebro.run()
- 做多:收盘价高于简单移动平均线
- 做空:收盘价低于简单移动平均线
class MySignal(bt.Indicator):
lines = ('signal',)
params = (('period', 30),)
def __init__(self):
self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)
执行run时,Cerebro将实例化一个知道如何处理信号的特殊策略实例。
2. 初始化的问题
-
买入/卖出操作数量是如何确定的?
cerebro实例会自动向策略添加一个固定大小的sizer。用户可以使用cerebro.addsizer更改sizer来更改策略 。 -
订单是如何执行的?
执行类型为Market,有效期至取消 。
3.Signals 技术细节
- 调用时返回另一个对象的可调用对象(仅一次),在大多数情况下是类的实例化
- 支持__getitem__接口。唯一请求的键/索引将设置为0
从实操的角度说明上面的例子:
来自BT的生态系统的Line对象,主要是一个指标类。
如在示例中使用简单移动平均线。
4.Signals indications
当用signal[0]查询时,指示其含义是:
- 大于0 ,做多指示
- 小于0 ,做空指示
- 等于0 ,不信号指示
信号的产生是
self.data - SMA
data在SMA上,做多
data在SMA下,做空
如果没有特殊制定,都是使用的close数值
5. Signal分类
有5种类型的信号,分为2组。
(1)主组:
- LONGSHORT signal接受long 和 short 信号
- LONG
- long 做多
- short 在做多的位置上平仓
但是: - 如果是 LONGEXIT 退出做多
- 如果是 SHORT 非 LONGEXIT , 在做空之前平仓。
- SHORT
- short 继续做空
- long 做空过程中,平仓
但是: - 如果是 SHORTEXIT 退出做空
- 如果是 LONG 非 SHORTEXIT , 开多仓之前先平仓。
(2)退出组:
两个信号覆盖其他信号,并为多头/空头仓位的出场提供信号:
- LONGEXIT: 做空信号退出做多位置
- SHORTEXIT: 做多信号退出做空位置
6. Accumulation and Order Concurrency
样本信号会持续发出多头和空头指示,从close中减去SMA值,这个值总是大于0或者小于0 。
因此持续触发order ,将出现两个情况:
-
Accumulation: 即使已经在市场上挂单,signal也会产生新的订单,增加市场中的头寸 。
-
Concurrency: 无需等待其他订单的执行,即可生成新订单产生并发。
在默认设置下,累积和并发是禁止的 。 -
不允许累积
-
不允许并发
如果要启用累积和并发,通过cerebro设置相应参数即可: -
cerebro.signal_accumulate(True) (or False to re-disable it)
-
cerebro.signal_concurrency(True) (or False to re-disable it)
7.示例
主信号:
class SMACloseSignal(bt.Indicator):
lines = ('signal',)
params = (('period', 30),)
def __init__(self):
self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)
退出信号:
class SMAExitSignal(bt.Indicator):
lines = ('signal',)
params = (('p1', 5), ('p2', 30),)
def __init__(self):
sma1 = bt.indicators.SMA(period=self.p.p1)
sma2 = bt.indicators.SMA(period=self.p.p2)
self.lines.signal = sma1 - sma2
(1)long and short
./signals-strategy.py --plot --signal longshort
- 策略真的是多空双向的,可以看到的,现金水平永远不会等于价值水平 。
- 即使是一个愚蠢的想法……(而且没有佣金),这个策略也没有赔钱 。
(2)long only
./signals-strategy.py --plot --signal longonly
- 每次卖出后,现金水平回到价值水平,意味着该策略退出了市场
- 旁注:同样没有金钱损失…
(3)short only
./signals-strategy.py --plot --signal shortonly
- 第一个操作是预期的销售,发生在上述两个示例中的第一个操作之后。直到收盘低于均线,简单的减法得到一个负号 - 每次买入后,现金水平回到价值水平,意味着该策略退出了市场
- 旁注:最后,系统赔钱了
(4)long + longexit
./signals-strategy.py --plot --signal longonly --exitsignal longexit
- 很多交易都是一样,但是有些交易会因为快速移动平均线穿过慢速移动平均线向下移动而中断
- 系统显示了它的longonly属性,现金成为每笔交易结束时的价值
- 旁注:再次赚钱…即使修改交易
(5)代码
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import collections
import datetime
import backtrader as bt
MAINSIGNALS = collections.OrderedDict(
(('longshort', bt.SIGNAL_LONGSHORT),
('longonly', bt.SIGNAL_LONG),
('shortonly', bt.SIGNAL_SHORT),)
)
EXITSIGNALS = {
'longexit': bt.SIGNAL_LONGEXIT,
'shortexit': bt.SIGNAL_LONGEXIT,
}
class SMACloseSignal(bt.Indicator):
lines = ('signal',)
params = (('period', 30),)
def __init__(self):
self.lines.signal = self.data - bt.indicators.SMA(period=self.p.period)
class SMAExitSignal(bt.Indicator):
lines = ('signal',)
params = (('p1', 5), ('p2', 30),)
def __init__(self):
sma1 = bt.indicators.SMA(period=self.p.p1)
sma2 = bt.indicators.SMA(period=self.p.p2)
self.lines.signal = sma1 - sma2
def runstrat(args=None):
args = parse_args(args)
cerebro = bt.Cerebro()
cerebro.broker.set_cash(args.cash)
dkwargs = dict()
if args.fromdate is not None:
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
dkwargs['fromdate'] = fromdate
if args.todate is not None:
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
dkwargs['todate'] = todate
# if dataset is None, args.data has been given
data = bt.feeds.BacktraderCSVData(dataname=args.data, **dkwargs)
cerebro.adddata(data)
cerebro.add_signal(MAINSIGNALS[args.signal],
SMACloseSignal, period=args.smaperiod)
if args.exitsignal is not None:
cerebro.add_signal(EXITSIGNALS[args.exitsignal],
SMAExitSignal,
p1=args.exitperiod,
p2=args.smaperiod)
cerebro.run()
if args.plot:
pkwargs = dict(style='bar')
if args.plot is not True: # evals to True but is not True
npkwargs = eval('dict(' + args.plot + ')') # args were passed
pkwargs.update(npkwargs)
cerebro.plot(**pkwargs)
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Sample for Signal concepts')
parser.add_argument('--data', required=False,
default='./datas/2005-2006-day-001.txt',
help='Specific data to be read in')
parser.add_argument('--fromdate', required=False, default=None,
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--todate', required=False, default=None,
help='Ending date in YYYY-MM-DD format')
parser.add_argument('--cash', required=False, action='store',
type=float, default=50000,
help=('Cash to start with'))
parser.add_argument('--smaperiod', required=False, action='store',
type=int, default=30,
help=('Period for the moving average'))
parser.add_argument('--exitperiod', required=False, action='store',
type=int, default=5,
help=('Period for the exit control SMA'))
parser.add_argument('--signal', required=False, action='store',
default=MAINSIGNALS['longshort'], choices=MAINSIGNALS,
help=('Signal type to use for the main signal'))
parser.add_argument('--exitsignal', required=False, action='store',
default=None, choices=EXITSIGNALS,
help=('Signal type to use for the exit signal'))
# Plot options
parser.add_argument('--plot', '-p', nargs='?', required=False,
metavar='kwargs', const=True,
help=('Plot the read data applying any kwargs passed\n'
'\n'
'For example:\n'
'\n'
' --plot style="candle" (to plot candles)\n'))
if pargs is not None:
return parser.parse_args(pargs)
return parser.parse_args()
if __name__ == '__main__':
runstrat()
help参数说明:
python ./signals-strategy.py --help
usage: signals-strategy.py [-h] [--data DATA] [--fromdate FROMDATE]
[--todate TODATE] [--cash CASH]
[--smaperiod SMAPERIOD] [--exitperiod EXITPERIOD]
[--signal {longshort,longonly,shortonly}]
[--exitsignal {longexit,shortexit}]
[--plot [kwargs]]
Sample for Signal concepts
optional arguments:
-h, --help show this help message and exit
--data DATA Specific data to be read in (default:
./datas/2005-2006-day-001.txt)
--fromdate FROMDATE Starting date in YYYY-MM-DD format (default: None)
--todate TODATE Ending date in YYYY-MM-DD format (default: None)
--cash CASH Cash to start with (default: 50000)
--smaperiod SMAPERIOD
Period for the moving average (default: 30)
--exitperiod EXITPERIOD
Period for the exit control SMA (default: 5)
--signal {longshort,longonly,shortonly}
Signal type to use for the main signal (default: 1)
--exitsignal {longexit,shortexit}
Signal type to use for the exit signal (default: None)
--plot [kwargs], -p [kwargs]
Plot the read data applying any kwargs passed For
example: --plot style="candle" (to plot candles)
(default: None)