Ah, that makes sense. Thanks a lot for your response.
Posts made by nimrare
Orders executed in weird sequence
I am having a problem with a strategy where I am rebalancing two assets. See the code below:
class RebalancingStrategy(bt.Strategy): def __init__(self, verbose=1): # verbosity self.verbose = verbose def next(self): asset_0_target = 0.75 asset_1_target = 0.25 rebalance_spread = 0.05 # calculate current position weights asset_0_weight = round((self.getposition(self.datas).size * self.datas.close) / self.broker.getvalue(), 4) asset_1_weight = round((self.getposition(self.datas).size * self.datas.close) / self.broker.getvalue(), 4) asset_0_spread = abs(asset_0_target - asset_0_weight) asset_1_spread = abs(asset_1_target - asset_1_weight) total_spread = asset_0_spread + asset_1_spread if total_spread > rebalance_spread: # determine sell order and issue it first if asset_0_weight > asset_0_target: sell_asset_num = 0 sell_asset_target = asset_0_target buy_asset_num = 1 buy_asset_target = asset_1_target else: sell_asset_num = 1 sell_asset_target = asset_1_target buy_asset_num = 0 buy_asset_target = asset_0_target self.order_target_percent(data=self.datas[sell_asset_num], target=sell_asset_target, exectype=bt.Order.Limit, price=self.datas[sell_asset_num].open) self.order_target_percent(data=self.datas[buy_asset_num], target=buy_asset_target, exectype=bt.Order.Limit, price=self.datas[buy_asset_num].open)
For optical reasons I excluded the notify functions. From what I see in the docs, I assume that the order that gets issued first, will be executed first. As you can see, I am issuing the "sell" order first to get free cash for the buy order. Below is the output from the notify functions.
2018-10-02 - BUY VIXY 1148 @ 21.76 2018-10-02 - BUY SPY 257 @ 291.56 2018-10-11 - SELL VIXY -222 @ 27.6 2018-10-11 - BUY SPY 22 @ 277.08 2018-10-25 - SELL VIXY -121 @ 31.58 2018-10-25 - BUY SPY 14 @ 267.38 2018-11-07 - REJ VIXY 99 @ 0.0 2018-11-07 - SELL SPY -9 @ 277.56 2018-11-08 - REJ VIXY 165 @ 0.0 2018-11-08 - SELL SPY -6 @ 280.11 2018-12-10 - SELL VIXY -19 @ 33.23 2018-12-10 - BUY SPY 19 @ 263.37 2018-12-21 - SELL VIXY -92 @ 36.91 2018-12-21 - BUY SPY 13 @ 246.74 2018-12-26 - SELL VIXY -73 @ 40.38 2018-12-26 - BUY SPY 13 @ 235.97
What I don't understand is why sometimes the BUY order is still issued first and therefore obviously rejected. Could you point me to what I am missing. Would be really grateful. :)
RE: next() called multiple times with resampled data feeds
Thanks for your reply. What you say makes sense and I will use the trading calendar feature. But just to make sure I understand the behavior correctly, let's look at the duplicate timestamp of 2018-02-09 shown in my first post above.
2018-02-09 is a Friday. So the the backtrader resampling mechanism creates a daily bar at the end of the day 2018-02-09. At this point it cannot know whether trading might continue on the weekend so it basically looks at the days 2018-02-10 and 2018-02-11. It cannot find that data, so it produces a weekly bar with the timestamp 2018-02-09 in a separate call to next().
Am I assuming correctly that backtrader assumes by default that a week is ending on Sunday if nothing else is specified in terms of trading calendars?
Also in the above code you see that I am using two resampled data feeds but NOT the original data feed. If I am using the original data feed together with one resampled data feed this alignment problem does not seem to happen. I understand that you may need more information to give an answer to this but maybe it's obvious and I am missing something.
RE: next() called multiple times with resampled data feeds
UPDATE: I found out that this does not seem to be happening if I use the original data feed and only one resampled data feed like so:
# convert the dataframe to a data feed, the timeframe of the original data feed must be set data = bt.feeds.PandasData(dataname=dataframe, timeframe=bt.TimeFrame.Minutes, compression=1, fromdate=fromdate, todate=todate, plot=True) # add the original data feed to cerebro cerebro.adddata(data) # add upsampled data feeds cerebro.resampledata(data, timeframe=bt.TimeFrame.Days, compression=1)
If I run this, I don't get the duplicated timestamps as shown above. However, another thing that I noticed is that the close of a resampled bar will only be available during the next bar of the fast data feed (in the case above the minute data feed). Is this expected behavior?
next() called multiple times with resampled data feeds
Hello backtrader community
First of all, thanks for this awesome piece of software. My favorite backtesting framework by far. ;)
Recently, I started working with mixed time frames and stumbled upon the following problem.
I have a daily data feed and a weekly data feed. At the end of the week, when the weekly bar forms, next seems to be called twice. The output for the code below looks like the following:
2018-02-02 27.3 27.3
2018-02-05 36.51 27.3
2018-02-06 35.5 27.3
2018-02-07 36.94 27.3
2018-02-08 45.79 27.3
2018-02-09 41.48 27.3
2018-02-09 41.48 41.48
2018-02-12 39.71 41.48
2018-02-13 39.75 41.48
2018-02-14 35.16 41.48
2018-02-15 34.41 41.48
2018-02-16 34.95 41.48
2018-02-16 34.95 34.95
2018-02-20 36.4 34.95
2018-02-21 36.81 34.95
2018-02-22 36.3 34.95
2018-02-23 33.49 34.95
2018-02-23 33.49 33.49
2018-02-26 32.1 33.49
2018-02-27 35.13 33.49
2018-02-28 36.7 35.13
import matplotlib.pyplot as plt import backtrader as bt import backtrader.indicators as btind import backtrader.analyzers as btanalyzers import pandas as pd class MultiTimeFrameStrategy(bt.Strategy): def __init__(self): pass def next(self): print(self.datetime.date(), self.datas.close, self.datas.close) def stop(self): pass def run_strategy(): fromdate = "2018-02-01" todate = "2018-03-01" fromdate = datetime.datetime.strptime(fromdate, "%Y-%m-%d") todate = datetime.datetime.strptime(todate, "%Y-%m-%d") cerebro = bt.Cerebro() # add a strategy cerebro.addstrategy( MultiTimeFrameStrategy ) try: # load data dataframe = pd.read_csv("/path/to/data.csv") dataframe = dataframe[["timestamp", "open", "high", "low", "close", "volume"]].copy() dataframe = dataframe.set_index("timestamp") dataframe.index = pd.to_datetime(dataframe.index) # convert the dataframe to a data feed, the timeframe of the original data feed must be set data = bt.feeds.PandasData(dataname=dataframe, timeframe=bt.TimeFrame.Minutes, compression=1, fromdate=fromdate, todate=todate, plot=True) # add the original data feed to cerebro #cerebro.adddata(data) # add upsampled data feeds cerebro.resampledata(data, timeframe=bt.TimeFrame.Days, compression=1) cerebro.resampledata(data, timeframe=bt.TimeFrame.Weeks, compression=1) except Exception as e: print(e) cerebro.broker.setcash(100000) results = cerebro.run() if __name__ == "__main__": run_strategy()
I don't really understand this behavior. Maybe you could help me out. When I plot the results, the bars seem to be correctly aligend. Thanks a lot for your help.
order.ref keeps increasing after new cerebro instantiation
I am a new backtrader user and I really love it so far. Thanks for this awesome piece of software. One thing I noticed though, was that the order reference always keeps increasing, even after creating a new cerebro instance.
Concretely, I have a function that calculates a portfolio performance, given some input assets. This function is called in a loop. Every function call should create a new cerebro instance, yet the order reference always keeps increasing. Is this expected behavior and why?
The program looks like the following:
def calculate_performance(assets, start, end): cerebro = bt.Cerebro() ... results = cerebro.run() return cerebro.broker.getvalue() if __name__ == "__main__": for assets in asset_list: ending_value = calculate_performance(assets, start, end)
Thanks a lot in advance!