class 的 backtrader 循环函数
backtrader loop functions with class
有一个 pickle 文件有很多(比如 10 个)股票名称
还有一个包含所有股票数据的文件夹
我正在尝试运行代码做MACD分析,希望能写下结果买卖时间、价格、头寸、手头现金。
当我走到这一步并尝试 运行 所有股票的 MACD 时。
但是经过两次循环,数据加载是错误的。并重复结果。
'''
import backtrader as bt
import pandas as pd
import pickle
import math
def run_test_macd():
with open("sp500tickers.pickle", "rb") as f:
tickers = pickle.load(f)
cerebro.addstrategy(GoldenCross.gold_cross_class)
for ticker in tickers:
macd_stock_test2(ticker)
def macd_stock_test2(ticker):
# print("stock test")
# print("ticker")
cerebro.broker.set_cash(1000000)
ticker_prices = pd.read_csv('stock_dfs/{}.csv'.format(ticker), index_col='Date', parse_dates=True)
# print(ticker_prices)
# ticker prices
feed = bt.feeds.PandasData(dataname=ticker_prices)
print(feed)
print(ticker)
cerebro.adddata(feed)
# cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='drawdown')
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='returns')
print('starting protfolio value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('final protfolio value: %.2f' % cerebro.broker.getvalue())
# cerebro.addanalyzer(SQN)
#
# cerebro.addwriter(bt.WriterFile, csv=args.writercsv, rounding=2)
# cerebro.plot(style='candle')
class gold_cross_class(bt.Strategy):
#set parameters to define fast and slow
params = (('fast',40),('slow',150),('order_percentage',0.99),('ticker', "stock"))
#define constractors
def __init__(self):
print("position size:",self.position.size)
self.fast_moving_average=bt.indicators.EMA(
self.data.close, period=self.params.fast, plotname='40 day moving average'
)
self.slow_moving_average = bt.indicators.EMA(
self.data.close, period=self.params.slow, plotname='150 day moving average'
)
self.crossover = bt.indicators.CrossOver(self.fast_moving_average, self.slow_moving_average)
def next(self):
if self.position.size == 0:
if self.crossover >0:
amount_to_invest = (self.params.order_percentage *self.broker.cash)
self.size=math.floor(amount_to_invest/self.data.close)
print("Buy {} shares of {} at {} on {}".format(self.size,self.params.ticker, self.data.close[0],self.data.close[0]))
self.buy(size=self.size)
if self.position.size > 0:
if self.crossover<0:
print("Sell {} shares of {} at {}".format(self.size,self.params.ticker, self.data.close[0]))
self.sell(size=self.size)
'''
buy and sell price issue
buy order issue when 100% cash is used
updated buy & sell price issues
在代码开头的文档字符串中查看我的注释。我已经注释掉了你的一些数据加载,所以我可以加载我自己的数据,因为我没有你的数据。
import datetime
import backtrader as bt
import pandas as pd
import pickle
import math
"""
You have a number of issues.
1. Establish cerebro in `macd_stock_test2`
2. Call the `run_test_macd` from if __name__ == "__main__":
3. Add in print log
4. Add in order and trade notify.
5. Don't pass in the strategy, create it in `macd_stock_test2`.
6. Change name of GoldCross class to python standard.
"""
def run_test_macd():
# with open("sp500tickers.pickle", "rb") as f:
# tickers = pickle.load(f)
tickers = ["TSLA", "FB"]
for ticker in tickers:
macd_stock_test2(ticker)
def macd_stock_test2(ticker):
# print("stock test")
# print("ticker")
cerebro = bt.Cerebro()
cerebro.addstrategy(GoldCross)
cerebro.broker.set_cash(1000000)
# ticker_prices = pd.read_csv(
# "stock_dfs/{}.csv".format(ticker), index_col="Date", parse_dates=True
# )
# print(ticker_prices)
# ticker prices
# feed = bt.feeds.PandasData(dataname=ticker_prices)
# print(feed)
# print(ticker)
feed = bt.feeds.YahooFinanceData(
dataname=ticker,
timeframe=bt.TimeFrame.Days,
fromdate=datetime.datetime(2019, 1, 1),
todate=datetime.datetime(2020, 12, 31),
reverse=False,
)
cerebro.adddata(feed)
# cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='drawdown')
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='returns')
print("starting portfolio value: %.2f" % cerebro.broker.getvalue())
cerebro.run()
print("final portfolio value: %.2f" % cerebro.broker.getvalue())
# cerebro.addanalyzer(SQN)
#
# cerebro.addwriter(bt.WriterFile, csv=args.writercsv, rounding=2)
# cerebro.plot(style='candle')
class GoldCross(bt.Strategy):
# set parameters to define fast and slow
params = (
("fast", 40),
("slow", 150),
("order_percentage", 0.99),
("ticker", "stock"),
)
# define constractors
def __init__(self):
print("position size:", self.position.size)
self.fast_moving_average = bt.indicators.EMA(
self.data.close, period=self.params.fast, plotname="40 day moving average"
)
self.slow_moving_average = bt.indicators.EMA(
self.data.close, period=self.params.slow, plotname="150 day moving average"
)
self.crossover = bt.indicators.CrossOver(
self.fast_moving_average, self.slow_moving_average
)
def log(self, txt, dt=None):
""" Logging function fot this strategy"""
dt = dt or self.data.datetime[0]
if isinstance(dt, float):
dt = bt.num2date(dt)
print("%s, %s" % (dt.date(), txt))
def notify_order(self, order):
""" Triggered upon changes to orders. """
# Suppress notification if it is just a submitted order.
if order.status == order.Submitted:
return
# Print out the date, security name, order number and status.
dt, dn = self.datetime.date(), order.data._name
type = "Buy" if order.isbuy() else "Sell"
self.log(
f"{order.data._name:<6} Order: {order.ref:3d}\tType: {type:<5}\tStatus"
f" {order.getstatusname():<8} \t"
f"Size: {order.created.size:9.4f} Price: {order.created.price:9.4f} "
f"Position: {self.getposition(order.data).size}"
)
if order.status == order.Margin:
return
# Check if an order has been completed
if order.status in [order.Completed]:
self.log(
f"{order.data._name:<6} {('BUY' if order.isbuy() else 'SELL'):<5} "
# f"EXECUTED for: {dn} "
f"Price: {order.executed.price:6.2f} "
f"Cost: {order.executed.value:6.2f} "
f"Comm: {order.executed.comm:4.2f} "
f"Size: {order.created.size:9.4f} "
)
def notify_trade(self, trade):
"""Provides notification of closed trades."""
if trade.isclosed:
self.log(
"{} Closed: PnL Gross {}, Net {},".format(
trade.data._name,
round(trade.pnl, 2),
round(trade.pnlcomm, 1),
)
)
def next(self):
if self.position.size == 0:
if self.crossover > 0:
amount_to_invest = self.params.order_percentage * self.broker.cash
self.size = math.floor(amount_to_invest / self.data.close)
self.log(
"Buy {} shares of {} at {}".format(
self.size,
self.params.ticker,
self.data.close[0],
)
)
self.buy(size=self.size)
if self.position.size > 0:
if self.crossover < 0:
self.log(
"Sell {} shares of {} at {}".format(
self.size, self.params.ticker, self.data.close[0],
)
)
self.sell(size=self.size)
if __name__ == "__main__":
run_test_macd()
打印出来如下:
starting protfolio value: 1000000.00
position size: 0
2019-10-28, Buy 15105 shares of stock at 65.54
2019-10-29, TSLA Order: 1 Type: Buy Status Accepted Size: 15105.0000 Price: 65.5400 Position: 15105
2019-10-29, TSLA Order: 1 Type: Buy Status Completed Size: 15105.0000 Price: 65.5400 Position: 15105
2019-10-29, TSLA BUY Price: 64.00 Cost: 966720.00 Comm: 0.00 Size: 15105.0000
final protfolio value: 10527931.90
starting protfolio value: 1000000.00
position size: 0
2020-05-12, Buy 4712 shares of stock at 210.1
2020-05-13, FB Order: 2 Type: Buy Status Accepted Size: 4712.0000 Price: 210.1000 Position: 4712
2020-05-13, FB Order: 2 Type: Buy Status Completed Size: 4712.0000 Price: 210.1000 Position: 4712
2020-05-13, FB BUY Price: 209.43 Cost: 986834.16 Comm: 0.00 Size: 4712.0000
final protfolio value: 1294217.28
Process finished with exit code 0
有一个 pickle 文件有很多(比如 10 个)股票名称 还有一个包含所有股票数据的文件夹 我正在尝试运行代码做MACD分析,希望能写下结果买卖时间、价格、头寸、手头现金。 当我走到这一步并尝试 运行 所有股票的 MACD 时。 但是经过两次循环,数据加载是错误的。并重复结果。
'''
import backtrader as bt
import pandas as pd
import pickle
import math
def run_test_macd():
with open("sp500tickers.pickle", "rb") as f:
tickers = pickle.load(f)
cerebro.addstrategy(GoldenCross.gold_cross_class)
for ticker in tickers:
macd_stock_test2(ticker)
def macd_stock_test2(ticker):
# print("stock test")
# print("ticker")
cerebro.broker.set_cash(1000000)
ticker_prices = pd.read_csv('stock_dfs/{}.csv'.format(ticker), index_col='Date', parse_dates=True)
# print(ticker_prices)
# ticker prices
feed = bt.feeds.PandasData(dataname=ticker_prices)
print(feed)
print(ticker)
cerebro.adddata(feed)
# cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='drawdown')
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='returns')
print('starting protfolio value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('final protfolio value: %.2f' % cerebro.broker.getvalue())
# cerebro.addanalyzer(SQN)
#
# cerebro.addwriter(bt.WriterFile, csv=args.writercsv, rounding=2)
# cerebro.plot(style='candle')
class gold_cross_class(bt.Strategy):
#set parameters to define fast and slow
params = (('fast',40),('slow',150),('order_percentage',0.99),('ticker', "stock"))
#define constractors
def __init__(self):
print("position size:",self.position.size)
self.fast_moving_average=bt.indicators.EMA(
self.data.close, period=self.params.fast, plotname='40 day moving average'
)
self.slow_moving_average = bt.indicators.EMA(
self.data.close, period=self.params.slow, plotname='150 day moving average'
)
self.crossover = bt.indicators.CrossOver(self.fast_moving_average, self.slow_moving_average)
def next(self):
if self.position.size == 0:
if self.crossover >0:
amount_to_invest = (self.params.order_percentage *self.broker.cash)
self.size=math.floor(amount_to_invest/self.data.close)
print("Buy {} shares of {} at {} on {}".format(self.size,self.params.ticker, self.data.close[0],self.data.close[0]))
self.buy(size=self.size)
if self.position.size > 0:
if self.crossover<0:
print("Sell {} shares of {} at {}".format(self.size,self.params.ticker, self.data.close[0]))
self.sell(size=self.size)
'''
buy and sell price issue
buy order issue when 100% cash is used
updated buy & sell price issues
在代码开头的文档字符串中查看我的注释。我已经注释掉了你的一些数据加载,所以我可以加载我自己的数据,因为我没有你的数据。
import datetime
import backtrader as bt
import pandas as pd
import pickle
import math
"""
You have a number of issues.
1. Establish cerebro in `macd_stock_test2`
2. Call the `run_test_macd` from if __name__ == "__main__":
3. Add in print log
4. Add in order and trade notify.
5. Don't pass in the strategy, create it in `macd_stock_test2`.
6. Change name of GoldCross class to python standard.
"""
def run_test_macd():
# with open("sp500tickers.pickle", "rb") as f:
# tickers = pickle.load(f)
tickers = ["TSLA", "FB"]
for ticker in tickers:
macd_stock_test2(ticker)
def macd_stock_test2(ticker):
# print("stock test")
# print("ticker")
cerebro = bt.Cerebro()
cerebro.addstrategy(GoldCross)
cerebro.broker.set_cash(1000000)
# ticker_prices = pd.read_csv(
# "stock_dfs/{}.csv".format(ticker), index_col="Date", parse_dates=True
# )
# print(ticker_prices)
# ticker prices
# feed = bt.feeds.PandasData(dataname=ticker_prices)
# print(feed)
# print(ticker)
feed = bt.feeds.YahooFinanceData(
dataname=ticker,
timeframe=bt.TimeFrame.Days,
fromdate=datetime.datetime(2019, 1, 1),
todate=datetime.datetime(2020, 12, 31),
reverse=False,
)
cerebro.adddata(feed)
# cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='drawdown')
# cerebro.addanalyzer(btanalyzers.DrawDown, _name='returns')
print("starting portfolio value: %.2f" % cerebro.broker.getvalue())
cerebro.run()
print("final portfolio value: %.2f" % cerebro.broker.getvalue())
# cerebro.addanalyzer(SQN)
#
# cerebro.addwriter(bt.WriterFile, csv=args.writercsv, rounding=2)
# cerebro.plot(style='candle')
class GoldCross(bt.Strategy):
# set parameters to define fast and slow
params = (
("fast", 40),
("slow", 150),
("order_percentage", 0.99),
("ticker", "stock"),
)
# define constractors
def __init__(self):
print("position size:", self.position.size)
self.fast_moving_average = bt.indicators.EMA(
self.data.close, period=self.params.fast, plotname="40 day moving average"
)
self.slow_moving_average = bt.indicators.EMA(
self.data.close, period=self.params.slow, plotname="150 day moving average"
)
self.crossover = bt.indicators.CrossOver(
self.fast_moving_average, self.slow_moving_average
)
def log(self, txt, dt=None):
""" Logging function fot this strategy"""
dt = dt or self.data.datetime[0]
if isinstance(dt, float):
dt = bt.num2date(dt)
print("%s, %s" % (dt.date(), txt))
def notify_order(self, order):
""" Triggered upon changes to orders. """
# Suppress notification if it is just a submitted order.
if order.status == order.Submitted:
return
# Print out the date, security name, order number and status.
dt, dn = self.datetime.date(), order.data._name
type = "Buy" if order.isbuy() else "Sell"
self.log(
f"{order.data._name:<6} Order: {order.ref:3d}\tType: {type:<5}\tStatus"
f" {order.getstatusname():<8} \t"
f"Size: {order.created.size:9.4f} Price: {order.created.price:9.4f} "
f"Position: {self.getposition(order.data).size}"
)
if order.status == order.Margin:
return
# Check if an order has been completed
if order.status in [order.Completed]:
self.log(
f"{order.data._name:<6} {('BUY' if order.isbuy() else 'SELL'):<5} "
# f"EXECUTED for: {dn} "
f"Price: {order.executed.price:6.2f} "
f"Cost: {order.executed.value:6.2f} "
f"Comm: {order.executed.comm:4.2f} "
f"Size: {order.created.size:9.4f} "
)
def notify_trade(self, trade):
"""Provides notification of closed trades."""
if trade.isclosed:
self.log(
"{} Closed: PnL Gross {}, Net {},".format(
trade.data._name,
round(trade.pnl, 2),
round(trade.pnlcomm, 1),
)
)
def next(self):
if self.position.size == 0:
if self.crossover > 0:
amount_to_invest = self.params.order_percentage * self.broker.cash
self.size = math.floor(amount_to_invest / self.data.close)
self.log(
"Buy {} shares of {} at {}".format(
self.size,
self.params.ticker,
self.data.close[0],
)
)
self.buy(size=self.size)
if self.position.size > 0:
if self.crossover < 0:
self.log(
"Sell {} shares of {} at {}".format(
self.size, self.params.ticker, self.data.close[0],
)
)
self.sell(size=self.size)
if __name__ == "__main__":
run_test_macd()
打印出来如下:
starting protfolio value: 1000000.00
position size: 0
2019-10-28, Buy 15105 shares of stock at 65.54
2019-10-29, TSLA Order: 1 Type: Buy Status Accepted Size: 15105.0000 Price: 65.5400 Position: 15105
2019-10-29, TSLA Order: 1 Type: Buy Status Completed Size: 15105.0000 Price: 65.5400 Position: 15105
2019-10-29, TSLA BUY Price: 64.00 Cost: 966720.00 Comm: 0.00 Size: 15105.0000
final protfolio value: 10527931.90
starting protfolio value: 1000000.00
position size: 0
2020-05-12, Buy 4712 shares of stock at 210.1
2020-05-13, FB Order: 2 Type: Buy Status Accepted Size: 4712.0000 Price: 210.1000 Position: 4712
2020-05-13, FB Order: 2 Type: Buy Status Completed Size: 4712.0000 Price: 210.1000 Position: 4712
2020-05-13, FB BUY Price: 209.43 Cost: 986834.16 Comm: 0.00 Size: 4712.0000
final protfolio value: 1294217.28
Process finished with exit code 0