在Backtrader中使用macd指标的多空策略



我刚刚从Matlab切换到python,甚至更新到用于backtestingtrading策略的backtrader库。我的问题似乎很明显。

我的问题似乎与此类似:https://community.backtrader.com/topic/2857/wanted-exit-long-and-open-short-on-the-same-bar-and-vice-versa

并且这个:https://community.backtrader.com/topic/2797/self-close-does-not-clear-position下面的代码是一个简单的MACD策略。这是代码:

# -*- coding: utf-8 -*-
"""
"""
import backtrader as bt
import argparse
import backtrader.feeds as btFeeds
import numpy as np
import yfinance as yf
import pandas as pd
import talib

class SimpleMACDStrat(bt.Strategy):

def __init__(self):
#Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
self.order = None
def log(self, txt, dt=None):
dt = dt or self.datas[0].datetime.date(0)
print(f'{dt.isoformat()} {txt}')
#Print date and close


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('LONG EXECUTED, %.2f' % order.executed.price)

elif order.issell():
self.log('SELL EXECUTED, %.2f' % order.executed.price)
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
# Write down: no pending order
self.order = None

def next(self):
self.log("Close: '{0}'" .format(self.data.adj_close[0]))
print('%f %f %f %f %f %f %f %f %f %f %f %f %f' % (self.data.Indexx[0],self.data.open[0],
self.data.high[0],self.data.low[0],
self.data.close[0],self.data.adj_close[0],
self.data.volume[0],self.data.EMA_100[0], 
self.data.RSI[0], self.data.CCI[0],
self.data.MACD_macd[0],self.data.MACD_sign[0],self.data.MACD_hist[0]))
if self.order:
return

if self.data.MACD_hist[0]>0:
if self.position.size<0 and self.data.MACD_hist[-1]<0  :
self.close()
self.log('CLOSE SHORT POSITION, %.2f' % self.dataclose[0])

elif self.position.size==0:
self.order=self.buy()
self.log('OPEN LONG POSITION, %.2f' % self.dataclose[0])


elif self.data.MACD_hist[0]<0:
if self.position.size>0 and self.data.MACD_hist[-1]>0:
self.order=self.close()
self.log('CLOSE LONG POSITION, %.2f' % self.dataclose[0])

elif self.position.size==0:
self.order=self.sell()
self.log('OPEN SHORT POSITION, %.2f' % self.dataclose[0])
print('')


class BasicIndicatorsFeeded(btFeeds.PandasData):
lines = ('Indexx', 'adj_close', 'EMA_100', 'RSI', 'CCI', 'MACD_macd', 'MACD_sign', 'MACD_hist',)
params = ( ('Indexx', 0), ('adj_close', 5), ('volume', 6), 
('EMA_100', 7), ('RSI', 8), ('CCI', 9),
('MACD_macd', 10), ('MACD_sign', 11), ('MACD_hist', 12),)



if __name__ == '__main__':

cerebro = bt.Cerebro()

#Add data feed to Cerebro
data1 = yf.download("AAPL",start="2021-08-09", end="2021-12-21",group_by="ticker")
data1.insert(0,'Indexx',' ')
data1['Indexx']=range(len(data1))
data1['EMA_100']=talib.EMA(data1['Adj Close'],100)
data1['RSI']=talib.RSI(data1['Adj Close'],14)
data1['CCI']=talib.CCI(data1['High'], data1['Low'], data1['Adj Close'], timeperiod=14)
data1['MACD_macd']=talib.MACD(data1['Adj Close'], fastperiod=12, slowperiod=26, signalperiod=9)[0]
data1['MACD_sign']=talib.MACD(data1['Adj Close'], fastperiod=12, slowperiod=26, signalperiod=9)[1]
data1['MACD_hist']=talib.MACD(data1['Adj Close'], fastperiod=12, slowperiod=26, signalperiod=9)[2]
# data1['Long_position']
# Run Cerebro Engine
cerebro.broker.setcash(8000000000)
start_portfolio_value = cerebro.broker.getvalue()
cerebro.addstrategy(SimpleMACDStrat)

data = BasicIndicatorsFeeded(dataname=data1)
cerebro.adddata(data)

cerebro.run()
cerebro.plot()
# print(data1)
print('-------------------')
#print('%f' %data)
# print(data)
end_portfolio_value = cerebro.broker.getvalue()
pnl = end_portfolio_value - start_portfolio_value
print(f'Starting Portfolio Value: {start_portfolio_value:2f}')
print(f'Final Portfolio Value: {end_portfolio_value:2f}')
print(f'PnL: {pnl:.2f}')

结果如下:

结果

在2021-11-10,macd_hist从阳性变为阴性。我们预计第二天(2021-11-11(:

a( 多头仓位关闭,紧接着

b( 空仓打开

1( 我们看到a(实际上在同一天关闭。这不是应该在下一天发生吗?

2( 第二天也会执行卖出,这是不应该发生的。

任何关于1(和2(的建议都将受到欢迎。谢谢

Abbe

编辑:

顺便说一句,我知道这个想法可以这样编码(下一步只定义(:

def next(self):
#print('%f' % (self.datas[0].Indexxx[0])
self.log("Close: '{0}'" .format(self.data.adj_close[0]))
print('%f %f %f %f %f %f %f %f %f %f %f %f %f' % (self.data.Indexx[0],self.data.open[0],
self.data.high[0],self.data.low[0],
self.data.close[0],self.data.adj_close[0],
self.data.volume[0],self.data.EMA_100[0], 
self.data.RSI[0], self.data.CCI[0],
self.data.MACD_macd[0],self.data.MACD_sign[0],self.data.MACD_hist[0]))
if self.order:
return

print(self.position)
if self.data.MACD_hist[0]>0 and self.data.MACD_hist[-1]<0:
self.order=self.buy()
self.log('CLOSE SHORT POSITION and open long, %.2f' % self.dataclose[0])


if self.data.MACD_hist[0]<0 and self.data.MACD_hist[-1]>0:
self.order=self.sell()
self.log('CLOSE LONG POSITION and open short, %.2f' % self.dataclose[0])

print('')

但我真的想把分开

self.close()

例如

self.buy()

这将允许我稍后使用不同的条件来平仓和开仓。

非常感谢您的任何意见、想法和评论。

Abbe

在代码中显示以下内容:

if self.data.MACD_hist[0]>0:
if self.position.size<0 and self.data.MACD_hist[-1]<0  :
self.close()
self.log('CLOSE SHORT POSITION, %.2f' % self.dataclose[0])

elif self.position.size==0:
self.order=self.buy()
self.log('OPEN LONG POSITION, %.2f' % self.dataclose[0])


elif self.data.MACD_hist[0]<0:
if self.position.size>0 and self.data.MACD_hist[-1]>0:
self.order=self.close()
self.log('CLOSE LONG POSITION, %.2f' % self.dataclose[0])

elif self.position.size==0:
self.order=self.sell()
self.log('OPEN SHORT POSITION, %.2f' % self.dataclose[0])

根据逻辑,在next中只可能满足其中一个条件。

您表示希望将关闭和进入分开。您需要将elif更改为if。此外,如果您使用self.position.size == 0的条件,则在执行关闭之前不会发生这种情况,因此关闭后的条形图,而不是下一个条形图。但如果您希望有其他条件,可以在另一个if语句之后输入。

if self.data.MACD_hist[0]>0:
if self.position.size<0 and self.data.MACD_hist[-1]<0  :
self.close()
self.log('CLOSE SHORT POSITION, %.2f' % self.dataclose[0])
#### change here  ####
if SOME OTHER CONDITION:
self.order=self.buy()
self.log('OPEN LONG POSITION, %.2f' % self.dataclose[0])

...

一旦您关闭仓位,就没有必要检查仓位是否为0单位。你可以放心地认为它会的。

最新更新