backtesting.py
backtesting.py copied to clipboard
Logging Orders
Desired Behavior
To dig into each backtest order, specifically to evaluate target prices which I don't believe are working correctly or I'm not calling properly. Didn't see an example in the docs.
I tried adding self.orders to _broker.log but without success - the idea was use copy.copy(self.orders) in backtesting.py for a PIT (point in time) snapshot.
So 2 points I'd like addressed:
- How to properly set target prices.
- How to enhance the logs with more Order granularity.
Additional Log Attempt
In class _Broker.next(), I called this function when opening or closing a position.
for example in class _Broker.next():
if entry or orders._close:
self._update_order_log(self.orders, i)
where:
def _update_order_log(self, order, i):
self.log.order_info[i] = copy.copy(order)
then in class _Broker:
class _Log:
def __init__(self, length):
...
self.order_info = {k: '' for k in range(length)}
Steps to Reproduce
class SmaCrossTarget(Strategy):
def init(self):
self.sma1 = self.I(SMA, self.data.Close, 2)
self.sma2 = self.I(SMA, self.data.Close, 6)
self.Close = self.data.Close
def next(self):
if (self.sma1[-2] < self.sma2[-2] and self.sma1[-1] > self.sma2[-1]):
self.buy(tp=self.Close[-1]*1.05)
elif (self.sma1[-2] > self.sma2[-2] and self.sma1[-1] < self.sma2[-1]):
self.sell()
GOOG = GOOG.head(40)
bt = Backtest(GOOG, SmaCrossTarget, cash=1000, commission=.001)
result = bt.run()
result._trade_data.dropna(subset=['Entry Price']).head(3)
Equity Exit Entry Exit Position Entry Price Entry Direction Exit Price Exit Comment P/L Returns
2004-08-30 1,030.0300 nan nan 105.2800 -1.0000 nan nan nan
2004-09-09 1,021.8743 7.0000 -9.4890 102.5300 1.0000 102.5300 NaN 25.0957 0.0244
2004-09-28 1,154.8585 14.0000 9.9880 121.3000 -1.0000 121.3000 NaN 186.4511 0.1825
The 3rd line should have been closing the position when target_price was hit.
Additional info
- Backtesting version: 0.1.6
Is the Entry Direction column not longer available ?
This was overhauled in #47 (released in 0.2.0), rendering this issue obsolete.
The new way to access individual trades data is:
stats = bt.run()
stats._equity_curve # equity/drawdown data
stats._trades # trade data
I'm curious about orders though, not trades.
@bscully27 You could always continue to log orders yourself: :grin:
class MyStrategy(Strategy):
def init(self):
self.orders_log = []
...
def buy(self, *args, **kwargs):
super().buy(*args, **kwargs)
self.orders_log.append(self.orders[-1])
def next(self):
...
self.buy(...)
stats = Backtest(...).run()
orders_placed = stats._strategy.orders_log
Is the Entry Direction column not longer available ?
@lkmh In fact, you can infer the Entry Direction
with size column, if size > 0 Entry Direction
is long otherwise is short.
Dear author, the information about accessing individual trades and orders is very useful and even essential. Would you please make it easier to find? I mean, add this information into the manuals and examples.
When I tried the following code
def buy(*args, **kwargs): super().buy(*args, **kwargs) self.orders_log.append(self.orders[-1])
I got an error
RuntimeError: super(): no arguments
I have found the solution here.
This works better:
def buy(self, *args, **kwargs): super().buy(*args, **kwargs) self.orders_log.append(self.orders[-1])
There's some new related discussion in https://github.com/kernc/backtesting.py/issues/197.