Strategy
A Cerebro instance is the pumping heart and controlling brain of
backtrader. A Strategy is the same for the platform user.
The Strategy’s expressed lifecycle in methods
Note
A strategy can be interrupted during birth by raising a
StrategySkipError exception from the module backtrader.errors
This will avoid going through the strategy during a backtesting. See
the section Exceptions
-
Conception:
__init__This is obviously invoked during instantiation:
indicatorswill be created here and other needed attribute. Example:def __init__(self): self.sma = btind.SimpleMovingAverage(period=15) -
Birth:
startThe world (
cerebro) tells the strategy is time to start kicking. A default empty method exists. -
Childhood:
prenextindicatorsdeclared during conception will have put constraints on how long the strategy needs to mature: this is called theminimum period. Above__init__created a SimpleMovingAverage with aperiod=15.As long as the system has seen less than
15bars,prenextwill be called (the default implementation is a no-op) -
Adulthood:
nextOnce the system has seen
15bars and theSimpleMovingAveragehas a buffer large enough to start producing values, the strategy is mature enough to really execute.There is a
nextstartmethod which is called exactly once, to mark the switch fromprenexttonext. The default implementation ofnextstartis to simply callnext -
Reproduction:
NoneOk, strategies do not really reproduce. But in a sense they do, because the system will instantiate them several times if optimizing (with different parameters)
-
Death:
stopThe system tells the strategy the time to come to a reset and put things in order has come. A default empty method exists.
In most cases and for regular usage patterns this will look like:
class MyStrategy(bt.Strategy):
def __init__(self):
self.sma = btind.SimpleMovingAverage(period=15)
def next(self):
if self.sma > self.data.close:
# Do something
pass
elif self.sma < self.data.close:
# Do something else
pass
In this snippet:
-
During
__init__an attribute is assigned an indicator -
The default empty
startmethod is not overriden -
prenextandnexstartare not overriden -
In
nextthe value of the indicator is compared against the closing price to do something -
The default empty
stopmethod is not overriden
Strategies, like a trader in the real world, will get notified when events take
place. Actually once per next cycle in the backtesting process. The
strategy will:
-
be notified through
notify_order(order)of any status change in an order -
be notified through
notify_trade(trade)of any opening/updating/closing trade -
be notified through
notify_cashvalue(cash, value)of the current cash and portfolio in the broker -
be notified through
notify_fund(cash, value, fundvalue, shares)of the current cash and portfolio in the broker and tradking of fundvalue and shares -
Events (implementation specific) via
notify_store(msg, *args, **kwargs)See Cerebro for an explanation on the store notifications. These will delivered to the strategy even if they have also been delivered to a
cerebroinstance (with an overridennotify_storemethod or via a callback)
And Strategies also like traders have the chance to operate in the market
during the next method to try to achieve profit with
-
the
buymethod to go long or reduce/close a short position -
the
sellmethod to go short or reduce/close a long position -
the
closemethod to obviously close an existing position -
the
cancelmethod to cancel a not yet executed order
How to Buy/Sell/Close
The Buy and Sell methods generate orders. When invoked they return an
Order (or subclass) instance that can be used as a reference. This order
has a unique ref identifier that can be used for comparison
Note
Subclasses of Order for speficic broker implementations may carry
additional unique identifiers provided by the broker.
To create the order use the following parameters:
-
data(default:None)For which data the order has to be created. If
Nonethen the first data in the system,self.datas[0] or self.data0(akaself.data) will be used -
size(default:None)Size to use (positive) of units of data to use for the order.
If
Nonethesizerinstance retrieved viagetsizerwill be used to determine the size. -
price(default:None)Price to use (live brokers may place restrictions on the actual format if it does not comply to minimum tick size requirements)
Noneis valid forMarketandCloseorders (the market determines the price)For
Limit,StopandStopLimitorders this value determines the trigger point (in the case ofLimitthe trigger is obviously at which price the order should be matched) -
plimit(default:None)Only applicable to
StopLimitorders. This is the price at which to set the implicit Limit order, once the Stop has been triggered (for whichpricehas been used) -
exectype(default:None)Possible values:
-
Order.MarketorNone. A market order will be executed with the next available price. In backtesting it will be the opening price of the next bar -
Order.Limit. An order which can only be executed at the givenpriceor better -
Order.Stop. An order which is triggered atpriceand executed like anOrder.Marketorder -
Order.StopLimit. An order which is triggered atpriceand executed as an implicit Limit order with price given bypricelimit
-
-
valid(default:None)Possible values:
-
None: this generates an order that will not expire (aka Good til cancel) and remain in the market until matched or canceled. In reality brokers tend to impose a temporal limit, but this is usually so far away in time to consider it as not expiring -
datetime.datetimeordatetime.dateinstance: the date will be used to generate an order valid until the given datetime (aka good til date) -
Order.DAYor0ortimedelta(): a day valid until the End of the Session (aka day order) will be generated -
numeric value: This is assumed to be a value corresponding to a datetime inmatplotlibcoding (the one used bybacktrader) and will used to generate an order valid until that time (good til date)
-
-
tradeid(default:0)This is an internal value applied by
backtraderto keep track of overlapping trades on the same asset. Thistradeidis sent back to the strategy when notifying changes to the status of the orders. -
**kwargs: additional broker implementations may support extra parameters.backtraderwill pass the kwargs down to the created order objectsExample: if the 4 order execution types directly supported by
backtraderare not enough, in the case of for example Interactive Brokers the following could be passed as kwargs:orderType='LIT', lmtPrice=10.0, auxPrice=9.8This would override the settings created by
backtraderand generate aLIMIT IF TOUCHEDorder with a touched price of 9.8 and a limit price of 10.0.
Information Bits:
-
A Strategy has a length which is always equal to that of the main data (
datas[0]) and can of course be gotten withlen(self)nextcan be called without changes in length if data is being replayed or a live feed is being passed and new ticks for the same point in time (length) are arriving
Member Attributes:
-
env: the cerebro entity in which this Strategy lives -
datas: array of data feeds which have been passed to cerebro-
data/data0is an alias for datas[0] -
dataXis an alias for datas[X]
data feeds can also be accessed by name (see the reference) if one has been assigned to it
-
-
dnames: an alternative to reach the data feeds by name (either with[name]or with.namenotation)For example if resampling a data like this:
... data0 = bt.feeds.YahooFinanceData(datname='YHOO', fromdate=..., name='days') cerebro.adddata(data0) cerebro.resampledata(data0, timeframe=bt.TimeFrame.Weeks, name='weeks') ...Later in the strategy one can create indicators on each like this:
... smadays = bt.ind.SMA(self.dnames.days, period=30) # or self.dnames['days'] smaweeks = bt.ind.SMA(self.dnames.weeks, period=10) # or self.dnames['weeks'] ... -
broker: reference to the broker associated to this strategy (received from cerebro) -
stats: list/named tuple-like sequence holding the Observers created by cerebro for this strategy -
analyzers: list/named tuple-like sequence holding the Analyzers created by cerebro for this strategy -
position: actually a property which gives the current position fordata0.Methods to retrieve all possitions are available (see the reference)
Member Attributes (meant for statistics/observers/analyzers):
-
_orderspending: list of orders which will be notified to the strategy beforenextis called -
_tradespending: list of trades which will be notified to the strategy beforenextis called -
_orders: list of order which have been already notified. An order can be several times in the list with different statuses and different execution bits. The list is menat to keep the history. -
_trades: list of order which have been already notified. A trade can be several times in the list just like an order.
Note
Bear in mind that prenext, nextstart and next can be called several
times for the same point in time (ticks updating prices for the daily bar,
when a daily timeframe is in use)
Reference: Strategy
class backtrader.Strategy(*args, **kwargs)
Base class to be subclassed for user defined strategies.
next()
This method will be called for all remaining data points when the minimum period for all datas/indicators have been meet.
nextstart()
This method will be called once, exactly when the minimum period for all datas/indicators have been meet. The default behavior is to call next
prenext()
This method will be called before the minimum period of all datas/indicators have been meet for the strategy to start executing
start()
Called right before the backtesting is about to be started.
stop()
Called right before the backtesting is about to be stopped
notify_order(order)
Receives an order whenever there has been a change in one
notify_trade(trade)
Receives a trade whenever there has been a change in one
notify_cashvalue(cash, value)
Receives the current fund value, value status of the strategy’s broker
notify_fund(cash, value, fundvalue, shares)
Receives the current cash, value, fundvalue and fund shares
notify_store(msg, *args, **kwargs)
Receives a notification from a store provider
buy(data=None, size=None, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs)
Create a buy (long) order and send it to the broker
-
data(default:None)For which data the order has to be created. If
Nonethen the first data in the system,self.datas[0] or self.data0(akaself.data) will be used -
size(default:None)Size to use (positive) of units of data to use for the order.
If
Nonethesizerinstance retrieved viagetsizerwill be used to determine the size. -
price(default:None)Price to use (live brokers may place restrictions on the actual format if it does not comply to minimum tick size requirements)
Noneis valid forMarketandCloseorders (the market determines the price)For
Limit,StopandStopLimitorders this value determines the trigger point (in the case ofLimitthe trigger is obviously at which price the order should be matched) -
plimit(default:None)Only applicable to
StopLimitorders. This is the price at which to set the implicit Limit order, once the Stop has been triggered (for whichpricehas been used) -
trailamount(default:None)If the order type is StopTrail or StopTrailLimit, this is an absolute amount which determines the distance to the price (below for a Sell order and above for a buy order) to keep the trailing stop
-
trailpercent(default:None)If the order type is StopTrail or StopTrailLimit, this is a percentage amount which determines the distance to the price (below for a Sell order and above for a buy order) to keep the trailing stop (if
trailamountis also specified it will be used) -
exectype(default:None)Possible values:
-
Order.MarketorNone. A market order will be executed with the next available price. In backtesting it will be the opening price of the next bar -
Order.Limit. An order which can only be executed at the givenpriceor better -
Order.Stop. An order which is triggered atpriceand executed like anOrder.Marketorder -
Order.StopLimit. An order which is triggered atpriceand executed as an implicit Limit order with price given bypricelimit -
Order.Close. An order which can only be executed with the closing price of the session (usually during a closing auction) -
Order.StopTrail. An order which is triggered atpriceminustrailamount(ortrailpercent) and which is updated if the price moves away from the stop -
Order.StopTrailLimit. An order which is triggered atpriceminustrailamount(ortrailpercent) and which is updated if the price moves away from the stop
-
-
valid(default:None)Possible values:
-
None: this generates an order that will not expire (aka Good till cancel) and remain in the market until matched or canceled. In reality brokers tend to impose a temporal limit, but this is usually so far away in time to consider it as not expiring -
datetime.datetimeordatetime.dateinstance: the date will be used to generate an order valid until the given datetime (aka good till date) -
Order.DAYor0ortimedelta(): a day valid until the End of the Session (aka day order) will be generated -
numeric value: This is assumed to be a value corresponding to a datetime inmatplotlibcoding (the one used bybacktrader) and will used to generate an order valid until that time (good till date)
-
-
tradeid(default:0)This is an internal value applied by
backtraderto keep track of overlapping trades on the same asset. Thistradeidis sent back to the strategy when notifying changes to the status of the orders. -
oco(default:None)Another
orderinstance. This order will become part of an OCO (Order Cancel Others) group. The execution of one of the orders, immediately cancels all others in the same group -
parent(default:None)Controls the relationship of a group of orders, for example a buy which is bracketed by a high-side limit sell and a low side stop sell. The high/low side orders remain inactive until the parent order has been either executed (they become active) or is canceled/expires (the children are also canceled) bracket orders have the same size
-
transmit(default:True)Indicates if the order has to be transmitted, ie: not only placed in the broker but also issued. This is meant for example to control bracket orders, in which one disables the transmission for the parent and 1st set of children and activates it for the last children, which triggers the full placement of all bracket orders.
-
**kwargs: additional broker implementations may support extra parameters.backtraderwill pass the kwargs down to the created order objectsExample: if the 4 order execution types directly supported by
backtraderare not enough, in the case of for example Interactive Brokers the following could be passed as kwargs:orderType='LIT', lmtPrice=10.0, auxPrice=9.8This would override the settings created by
backtraderand generate aLIMIT IF TOUCHEDorder with a touched price of 9.8 and a limit price of 10.0. -
Returns
- the submitted order
sell(data=None, size=None, price=None, plimit=None, exectype=None, valid=None, tradeid=0, oco=None, trailamount=None, trailpercent=None, parent=None, transmit=True, **kwargs)
To create a selll (short) order and send it to the broker
See the documentation for buy for an explanation of the parameters
Returns: the submitted order
close(data=None, size=None, **kwargs)
Counters a long/short position closing it
See the documentation for buy for an explanation of the parameters
Note
size: automatically calculated from the existing position if not provided (default:None) by the caller
Returns: the submitted order
cancel(order)
Cancels the order in the broker
buy_bracket(data=None, size=None, price=None, plimit=None, exectype=2, valid=None, tradeid=0, trailamount=None, trailpercent=None, oargs={}, stopprice=None, stopexec=3, stopargs={}, limitprice=None, limitexec=2, limitargs={}, **kwargs)
Create a bracket order group (low side - buy order - high side). The default behavior is as follows:
-
Issue a buy order with execution
Limit -
Issue a low side bracket sell order with execution
Stop -
Issue a high side bracket sell order with execution
Limit.
See below for the different parameters
-
data(default:None)For which data the order has to be created. If
Nonethen the first data in the system,self.datas[0] or self.data0(akaself.data) will be used -
size(default:None)Size to use (positive) of units of data to use for the order.
If
Nonethesizerinstance retrieved viagetsizerwill be used to determine the size.Note
The same size is applied to all 3 orders of the bracket
-
price(default:None)Price to use (live brokers may place restrictions on the actual format if it does not comply to minimum tick size requirements)
Noneis valid forMarketandCloseorders (the market determines the price)For
Limit,StopandStopLimitorders this value determines the trigger point (in the case ofLimitthe trigger is obviously at which price the order should be matched) -
plimit(default:None)Only applicable to
StopLimitorders. This is the price at which to set the implicit Limit order, once the Stop has been triggered (for whichpricehas been used) -
trailamount(default:None)If the order type is StopTrail or StopTrailLimit, this is an absolute amount which determines the distance to the price (below for a Sell order and above for a buy order) to keep the trailing stop
-
trailpercent(default:None)If the order type is StopTrail or StopTrailLimit, this is a percentage amount which determines the distance to the price (below for a Sell order and above for a buy order) to keep the trailing stop (if
trailamountis also specified it will be used) -
exectype(default:bt.Order.Limit)Possible values: (see the documentation for the method
buy -
valid(default:None)Possible values: (see the documentation for the method
buy -
tradeid(default:0)Possible values: (see the documentation for the method
buy -
oargs(default:{})Specific keyword arguments (in a
dict) to pass to the main side order. Arguments from the default**kwargswill be applied on top of this. -
**kwargs: additional broker implementations may support extra parameters.backtraderwill pass the kwargs down to the created order objectsPossible values: (see the documentation for the method
buyNote
This
kwargswill be applied to the 3 orders of a bracket. See below for specific keyword arguments for the low and high side orders -
stopprice(default:None)Specific price for the low side stop order
-
stopexec(default:bt.Order.Stop)Specific execution type for the low side order
-
stopargs(default:{})Specific keyword arguments (in a
dict) to pass to the low side order. Arguments from the default**kwargswill be applied on top of this. -
limitprice(default:None)Specific price for the high side stop order
-
stopexec(default:bt.Order.Limit)Specific execution type for the high side order
-
limitargs(default:{})Specific keyword arguments (in a
dict) to pass to the high side order. Arguments from the default**kwargswill be applied on top of this.
High/Low Side orders can be suppressed by using:
-
limitexec=Noneto suppress the high side -
stopexec=Noneto suppress the low side -
Returns
-
A list containing the 3 orders [order, stop side, limit side]
-
If high/low orders have been suppressed the return value will still contain 3 orders, but those suppressed will have a value of
None
-
sell_bracket(data=None, size=None, price=None, plimit=None, exectype=2, valid=None, tradeid=0, trailamount=None, trailpercent=None, oargs={}, stopprice=None, stopexec=3, stopargs={}, limitprice=None, limitexec=2, limitargs={}, **kwargs)
Create a bracket order group (low side - buy order - high side). The default behavior is as follows:
-
Issue a sell order with execution
Limit -
Issue a high side bracket buy order with execution
Stop -
Issue a low side bracket buy order with execution
Limit.
See bracket_buy for the meaning of the parameters
High/Low Side orders can be suppressed by using:
-
stopexec=Noneto suppress the high side -
limitexec=Noneto suppress the low side -
Returns
-
A list containing the 3 orders [order, stop side, limit side]
-
If high/low orders have been suppressed the return value will still contain 3 orders, but those suppressed will have a value of
None
-
order_target_size(data=None, target=0, **kwargs)
Place an order to rebalance a position to have final size of target
The current position size is taken into account as the start point
to achieve target
-
If
target>pos.size-> buytarget - pos.size -
If
target<pos.size-> sellpos.size - target
It returns either:
- The generated order
or
Noneif no order has been issued (target == position.size)
order_target_value(data=None, target=0.0, price=None, **kwargs)
Place an order to rebalance a position to have final value of
target
The current value is taken into account as the start point to
achieve target
-
If no
targetthen close postion on data -
If
target>valuethen buy on data -
If
target<valuethen sell on data
It returns either:
- The generated order
or
Noneif no order has been issued
order_target_percent(data=None, target=0.0, **kwargs)
Place an order to rebalance a position to have final value of
target percentage of current portfolio value
target is expressed in decimal: 0.05 -> 5%
It uses order_target_value to execute the order.
Example
-
target=0.05and portfolio value is100 -
The
valueto be reached is0.05 * 100 = 5 -
5is passed as thetargetvalue toorder_target_value
The current value is taken into account as the start point to
achieve target
The position.size is used to determine if a position is long /
short
-
If
target>value- buy if
pos.size >= 0(Increase a long position) - sell if
pos.size < 0(Increase a short position)
- buy if
-
If
target<value- sell if
pos.size >= 0(Decrease a long position) - buy if
pos.size < 0(Decrease a short position)
- sell if
It returns either:
- The generated order
or
Noneif no order has been issued (target == position.size)
getsizer()
Returns the sizer which is in used if automatic statke calculation is used
Also available as sizer
setsizer(sizer)
Replace the default (fixed stake) sizer
getsizing(data=None, isbuy=True)
Return the stake calculated by the sizer instance for the current situation
getposition(data=None, broker=None)
Returns the current position for a given data in a given broker.
If both are None, the main data and the default broker will be used
A property position is also available
getpositionbyname(name=None, broker=None)
Returns the current position for a given name in a given broker.
If both are None, the main data and the default broker will be used
A property positionbyname is also available
getpositionsbyname(broker=None)
Returns the current by name positions directly from the broker
If the given broker is None, the default broker will be used
A property positionsbyname is also available
getdatanames()
Returns a list of the existing data names
getdatabyname(name)
Returns a given data by name using the environment (cerebro)
add_timer(when, offset=datetime.timedelta(0), repeat=datetime.timedelta(0), weekdays=[], weekcarry=False, monthdays=[], monthcarry=True, allow=None, tzdata=None, cheat=False, *args, **kwargs)
Note
Can be called during __init__ or start
Schedules a timer to invoke either a specified callback or the
notify_timer of one or more strategies.
-
Parameters
when (-) – can be
-
datetime.timeinstance (see belowtzdata) -
bt.timer.SESSION_STARTto reference a session start -
bt.timer.SESSION_ENDto reference a session end -
offsetwhich must be adatetime.timedeltainstance
Used to offset the value
when. It has a meaningful use in combination withSESSION_STARTandSESSION_END, to indicated things like a timer being called15 minutesafter the session start.-
repeatwhich must be adatetime.timedeltainstanceIndicates if after a 1st call, further calls will be scheduled within the same session at the scheduled
repeatdeltaOnce the timer goes over the end of the session it is reset to the original value for
when -
weekdays: a sorted iterable with integers indicating on which days (iso codes, Monday is 1, Sunday is 7) the timers can be actually invokedIf not specified, the timer will be active on all days
-
weekcarry(default:False). IfTrueand the weekday was not seen (ex: trading holiday), the timer will be executed on the next day (even if in a new week) -
monthdays: a sorted iterable with integers indicating on which days of the month a timer has to be executed. For example always on day 15 of the monthIf not specified, the timer will be active on all days
-
monthcarry(default:True). If the day was not seen (weekend, trading holiday), the timer will be executed on the next available day. -
allow(default:None). A callback which receives a datetime.date` instance and returnsTrueif the date is allowed for timers or else returnsFalse -
tzdatawhich can be eitherNone(default), apytzinstance or adata feedinstance.None:whenis interpreted at face value (which translates to handling it as if it where UTC even if it’s not)pytzinstance:whenwill be interpreted as being specified in the local time specified by the timezone instance.data feedinstance:whenwill be interpreted as being specified in the local time specified by thetzparameter of the data feed instance.Note
If
whenis eitherSESSION_STARTorSESSION_ENDandtzdataisNone, the 1st data feed in the system (akaself.data0) will be used as the reference to find out the session times. -
cheat(defaultFalse) ifTruethe timer will be called before the broker has a chance to evaluate the orders. This opens the chance to issue orders based on opening price for example right before the session starts -
*args: any extra args will be passed tonotify_timer -
**kwargs: any extra kwargs will be passed tonotify_timer
-
Return Value:
- The created timer
notify_timer(timer, when, *args, **kwargs)
Receives a timer notification where timer is the timer which was
returned by add_timer, and when is the calling time. args
and kwargs are any additional arguments passed to add_timer
The actual when time can be later, but the system may have not be
able to call the timer before. This value is the timer value and no the
system time.