Skip to content

Commit 9eba337

Browse files
committed
ENH: Add the possibility to let unclose trades at end of bt.run (#273)
1 parent 73e1534 commit 9eba337

File tree

2 files changed

+37
-10
lines changed

2 files changed

+37
-10
lines changed

backtesting/backtesting.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,8 @@ def __init__(self,
984984
margin: float = 1.,
985985
trade_on_close=False,
986986
hedging=False,
987-
exclusive_orders=False
987+
exclusive_orders=False,
988+
close_all_at_end=True
988989
):
989990
"""
990991
Initialize a backtest. Requires data and a strategy to test.
@@ -1078,7 +1079,7 @@ def __init__(self,
10781079
warnings.warn('Data index is not datetime. Assuming simple periods, '
10791080
'but `pd.DateTimeIndex` is advised.',
10801081
stacklevel=2)
1081-
1082+
self._close_all_at_end = close_all_at_end
10821083
self._data: pd.DataFrame = data
10831084
self._broker = partial(
10841085
_Broker, cash=cash, commission=commission, margin=margin,
@@ -1164,14 +1165,15 @@ def run(self, **kwargs) -> pd.Series:
11641165
# Next tick, a moment before bar close
11651166
strategy.next()
11661167
else:
1167-
# Close any remaining open trades so they produce some stats
1168-
for trade in broker.trades:
1169-
trade.close()
1170-
1171-
# Re-run broker one last time to handle orders placed in the last strategy
1172-
# iteration. Use the same OHLC values as in the last broker iteration.
1173-
if start < len(self._data):
1174-
try_(broker.next, exception=_OutOfMoneyError)
1168+
if self._close_all_at_end is True:
1169+
# Close any remaining open trades so they produce some stats
1170+
for trade in broker.trades:
1171+
trade.close()
1172+
1173+
# Re-run broker one last time to handle orders placed in the last strategy
1174+
# iteration. Use the same OHLC values as in the last broker iteration.
1175+
if start < len(self._data):
1176+
try_(broker.next, exception=_OutOfMoneyError)
11751177

11761178
# Set data back to full length
11771179
# for future `indicator._opts['data'].index` calls to work

backtesting/test/_test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,31 @@ def next(self):
398398

399399
self.assertFalse(Backtest(SHORT_DATA, S).run()._trades.empty)
400400

401+
def test_dont_close_orders_from_last_strategy_iteration(self):
402+
class S(Strategy):
403+
def init(self): pass
404+
405+
def next(self):
406+
if not self.position:
407+
self.buy()
408+
elif len(self.data) == len(SHORT_DATA):
409+
self.position.close()
410+
self.assertEqual(len(
411+
Backtest(SHORT_DATA, S, close_all_at_end=False).run()._strategy.closed_trades), 0)
412+
self.assertEqual(len(
413+
Backtest(SHORT_DATA, S, close_all_at_end=False).run()._strategy.trades), 1)
414+
415+
def test_dont_close_orders_trades_from_last_strategy_iteration(self):
416+
class S(Strategy):
417+
def init(self): pass
418+
419+
def next(self):
420+
if not self.position:
421+
self.buy()
422+
423+
self.assertGreater(len(
424+
Backtest(SHORT_DATA, S, close_all_at_end=False).run()._strategy.trades), 0)
425+
401426
def test_check_adjusted_price_when_placing_order(self):
402427
class S(Strategy):
403428
def init(self): pass

0 commit comments

Comments
 (0)