There is no such thing as a sample implementation.
You send an order to the market: self.buy(price=myprice, exectype=bt.Order.MyPreferredExecutionType)
The order is completed and notified to notify_order(order)
order.executed.price contains the actual execution price
A new order is sent to act as a stop-loss order: self.sell(price=% of order.executed.price, exectype=probably Stop)
You want to use replay. The strategy doesn't actually run every minute but runs with every tick of the data, slowly recreating the day. The indicators attached to the replayed data are re-calculated automatically for the current day with each new tick (there is no need to recalculate the previous days)
See: Docs - Data Replaying
The length (len(data_in_use)) determines if the replaying has moved to a new day.
That's all in the link above: Docs - Platform Concepts
There is a section about indexing and how 0 is the current point in time. Last is the last produced value before the current point in time and addressable with -1
@ab_trader In theory yes, because there was a use case with spreads (which oscillate around 0). The problem there was that some of Python tests for existence would fail because the price was zero. It was dealt with a long time ago.
This is covered by raising a exception during __init__. See Docs - Exceptions
import backtrader as bt
@xnox said in How to add Indicator over resampled data? E.g. 10-day sma for minute data:
I'm trying to use btrun, and code a generic strategy which I can control with btrun. My data is typically minute bars, however, in the strategy, I would like to use a 10-day indicator. How can I do this in the strategy? Or btrun options?
If the only data feed in the strategy is has a Minutes/x timeframe/compression specification, you cannot have an indicator calculating in days.
self.sma = bt.indicators.SimpleMovingAverage(self.data, resample=bt.TimeFrame.Days, period=self.params.sma)
That's not possible. An indicator can run several levels deep and only be accessing data which has not datetime information. An indicator is a dumb math calculator.
I guess I could do sma over 1440... but that assumes 24h trading with no missing minutes and is not the same as resampling to days first, and then doing 10-day sma.
You need to resample the minutes-data-feed to Days/1 and then create the indicator on that data feed.
An Order instance (let's call it order) carries an attribute data which is the asset on which the order has been issued. The ticker name should be available as: order.data._name (where _name is the name you have assigned when using adddata)
Names are actually a late addition to backtrader, because one of the underlying design concepts is that the development of a trading idea should, ideally, not be bound to a specific asset.
A signal / indicator has (like a Strategy) receives an array of the available data feeds in the environment in which they are instantiated (an Indicator can be instantiated inside a Strategy or inside another Indicator)
If your Strategy has 4 data feeds, the indicator will default to receiving 4 data feeds, which will be available in the iterable self.datas and as self.data0, ..., self.data3. Most indicators actually only use 1 data feed. One can actually declare that a given indicator must receive more than 1 data feed.
See: Blog - Crossing over numbers
Notice that it defaults to receiving the data feeds from the environment.. Because if the user specifies which data feeds go by passing them to the instantiation, those will be the ones passed.
Another reason not to rely on names is that an indicator can receive another indicator as data feed. For example:
sma_on_sma = bt.ind.SMA(bt.ind.SMA(self.data1, period=10), period=20)
The outer SMA receives the inner SMA as data feed. And this data feed carries no name, even if it's calculating the simple moving average of self.data1. We still don't know what self.data1 is. It could be an RSI for example. See:
lines = ('sma_on_sma',)
self.lines.sma_on_sma = bt.ind.SMA(bt.ind.SMA(self.data1, period=10), period=20)
lines = ('myline',)
self.lines.myline = MyInd1(self.data, bt.ind.RSI(self.data))
MyInd2 passes 2 data feeds, one is the main data feed received (which can be anythin) and the 2nd is the RSI. As such MyInd1 receives an RSI instance as self.data1, but it doesn't know it. It simply does an SMA on it and then a 2nd SMA
If your signal is going to be name-bound, it will be limited to real data feeds which carry a _name attribute and will fail to be generic for any kind of actual data feed, like in the examples above.
lines = ('name_bound',)
if self.data0._name == 'my-preferred-name':
self.lines.name_bound = bt.ind.SMA(self.data3)
self.lines.name_bound = bt.ind.SMA(self.data2)
At least data0 must be a real data feed with a name in that example.
@Taewoo-Kim said in Data Analysis all wrong?:
limiting # of posts I can per day
Spam anti-measures limit # of posts within short time spans (not per day)
Now i get this error (on the same code base)
Probably because downgrading to pyfolio-0.5.1 doesn't downgrade the packages with which it works. In this case and due to the changes in the pyfolio API, it will take sometime to get it working again.