在backtrader上进行backtest测试时,我收到许多取消/取消/拒绝的购买订单 [英] Running backtest on backtrader I get many BUY ORDERS CANCELLED/MARGIN/REJECTED when they should not

查看:342
本文介绍了在backtrader上进行backtest测试时,我收到许多取消/取消/拒绝的购买订单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

许多购买订单在回测中被取消,我找不到原因.查看Writefile日志,似乎在第二天的收盘时创建了买单.在大多数情况下,买入价在当天的范围内,但仍未执行.

Many buy orders are cancelled in the backtests and I cannot find why. Looking at the Writefile log it seems the buy orders are created at the next day's close. In most cases the buy price is in the day's range but still not executed.

我尝试了不同的资产,不同大小的数据源,不同的策略,并且结果相同.

I have tried on different assets, different sizes of the data feed, different strategies, with the same result.

在Jupyter笔记本上运行.我包括代码和日志.

Running on Jupyter notebook. I include the code and the log.

最后,我将AllInSizerInt()中的默认参数('100')更改为低于100,并且可以正常工作.我真的不明白为什么,我认为规模确定者会从经纪人那里获得现金头寸并调整订单.

Finally I changed the default parameter ('100') in AllInSizerInt() below 100 and it worked. I do not really understand why, I thought the sizer would get the cash position from the broker and adjust the order.

这里是解决方法:

''''
python
#Add the sizer.  We plan to go 'all in' every time  
cerebro.addsizer(bt.sizers.AllInSizerInt, percents = 95)  

''''

这是原始代码:

''''
python
#### Import databases
from datetime import datetime
import backtrader as bt
import backtrader.indicators as btind

abspath = '/mypath/'
logfile = 'abs_momentum.csv'
# Create a Strategy

class Abs_momentum(bt.Strategy):
    alias = ('Abs_momentum',)
    params = (
    # period for momentum calculation
    ('lookback', 252),
    ('range', 100))
    

def __init__(self):
    # keep track of close price in the series
    self.data_close = self.datas[0].close

    # keep track of pending orders/buy price/buy commission
    self.order  = None
    self.price  = None
    self.comm   = None

    # add a momentum indicator
    self.mom    = btind.MomentumOsc(self.data_close, \
                                    period = self.p.lookback, \
                                    band = self.p.range)

    self.buysig = self.mom
    
    
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))


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' %
                (order.executed.price,
                 order.executed.value,
                 order.executed.comm))

            self.buyprice = order.executed.price
            self.buycomm = order.executed.comm
        else:  # Sell
            self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                     (order.executed.price,
                      order.executed.value,
                      order.executed.comm))

        #self.bar_executed = len(self)

    elif order.status in [order.Canceled, order.Margin, order.Rejected]:
        self.log('Order Canceled/Margin/Rejected')

    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):
    
    # do nothing if an order is pending
    if self.order:
        return

    # check if there is already a position
    if not self.position:
        # buy condition
        if self.buysig > 100:
            self.log(f'BUY CREATED --- Price: {self.data_close[0]:.2f}')
            self.order = self.buy(size = None)
    else:
        # sell condition
        if self.buysig < 100:
            self.log(f'SELL CREATED --- Price: {self.data_close[0]:.2f}')
            self.order = self.sell(Size = None)
###
#### Download data from Yahoo Finance
data = bt.feeds.YahooFinanceData(dataname= 'SPY', \
                             fromdate=datetime(2018, 6, 15),\
                             todate=datetime(2021, 3, 17),\
                               reverse = False)
####

# create a Cerebro entity
cerebro = bt.Cerebro(stdstats = False)

### Set up the backtest
# Add the Data Feed to Cerebro
cerebro.adddata(data)

# Set our desired cash start
cerebro.broker.setcash(100000.0)

# Set the commission - 0.1% ... divide by 100 to remove the %
cerebro.broker.setcommission(commission=0.001)

#Add the sizer.  We plan to go 'all in' every time
cerebro.addsizer(bt.sizers.AllInSizerInt)

#Add the strategy
cerebro.addstrategy(Abs_momentum)

#Add the observers to the plot
cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)

#Write to a csv file
cerebro.addwriter(bt.WriterFile, out = (abspath + logfile), csv=True,\ data(csv) = False)

# 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 results
cerebro.plot(iplot=True, volume=False)
###

''''

这是日志:

>Starting Portfolio Value: 100000.00
>2019-06-18, BUY CREATED --- Price: 282.95
>2019-06-19, Order Canceled/Margin/Rejected
>2019-06-19, BUY CREATED --- Price: 283.58
>2019-06-20, Order Canceled/Margin/Rejected
>2019-06-20, BUY CREATED --- Price: 286.29
>2019-06-21, Order Canceled/Margin/Rejected
>2019-06-21, BUY CREATED --- Price: 285.88
>2019-06-24, BUY EXECUTED, Price: 286.10, Cost: 99848.90, Comm 99.85
>2020-03-12, SELL CREATED --- Price: 243.56
>2020-03-13, SELL EXECUTED, Price: 258.27, Cost: 99848.90, Comm 90.14
>2020-03-13, OPERATION PROFIT, GROSS -9712.67, NET -9902.66
>2020-04-17, BUY CREATED --- Price: 283.04
>2020-04-20, BUY EXECUTED, Price: 279.06, Cost: 88741.08, Comm 88.74
>2020-04-20, SELL CREATED --- Price: 278.05
>2020-04-21, SELL EXECUTED, Price: 273.25, Cost: 88741.08, Comm 86.89
>2020-04-21, OPERATION PROFIT, GROSS -1847.58, NET -2023.21
>2020-04-29, BUY CREATED --- Price: 289.53
>2020-04-30, Order Canceled/Margin/Rejected
>2020-04-30, BUY CREATED --- Price: 286.83
>2020-05-01, Order Canceled/Margin/Rejected
>2020-05-06, BUY CREATED --- Price: 280.68
>2020-05-07, Order Canceled/Margin/Rejected
>2020-05-07, BUY CREATED --- Price: 284.07
>2020-05-08, Order Canceled/Margin/Rejected
>2020-05-08, BUY CREATED --- Price: 288.77
>2020-05-11, BUY EXECUTED, Price: 286.69, Cost: 87153.76, Comm 87.15
>Final Portfolio Value: 121189.86

推荐答案

从100%规模交易调整为95%规模交易的原因更正了该问题,那就是试图对所有投资组合进行100%的交易总会导致一路上有一些余地.这可以在您的日志中看到:

The reason your adjustment from 100% size trade to 95% size trade corrected the problem is that trying to by all in 100% on a portfolio will always result in some margins along the way . This can be seen here in your logs:

>2019-06-19, Order Canceled/Margin/Rejected

问题在于您正在计算要交换上一个收盘价的股票数量.如果市场价格在下一个价位上上涨,您将没有足够的现金购买.有一个称为 cheat-on-open 的选项,该选项允许在下一个开盘价出现峰值,以允许对股份进行规模调整.这有帮助.

The problem is you are calculating the number of shares to trade off the previous close. If the market price gaps up on the next bar, you won't have enough cash to buy. There is an option called cheat-on-open that allows a peak at the next open price to permit sizing of the shares. This helps.

但是实际上,最好是在100%以下交易.

But in reality, it's best to trade below 100%.

这篇关于在backtrader上进行backtest测试时,我收到许多取消/取消/拒绝的购买订单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆