Skip to content

Commit 28eca40

Browse files
committed
Replace hand-rolled cache with @cached_property
1 parent 4099372 commit 28eca40

File tree

1 file changed

+19
-25
lines changed

1 file changed

+19
-25
lines changed

backtesting/backtesting.py

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import warnings
1313
from abc import ABCMeta, abstractmethod
1414
from copy import copy
15-
from functools import lru_cache, partial
15+
from functools import cached_property, lru_cache, partial
1616
from itertools import chain, product, repeat
1717
from math import copysign
1818
from numbers import Number
@@ -362,8 +362,6 @@ def __bool__(self):
362362
@property
363363
def size(self) -> float:
364364
"""Position size in units of asset. Negative if position is short."""
365-
if self.__broker._trade_sums_dirty:
366-
self.__broker._recalculate_trade_sums()
367365
return self.__broker._open_trade_size_sum
368366

369367
@property
@@ -374,8 +372,6 @@ def pl(self) -> float:
374372
@property
375373
def pl_pct(self) -> float:
376374
"""Profit (positive) or loss (negative) of the current position in percent."""
377-
if self.__broker._trade_sums_dirty:
378-
self.__broker._recalculate_trade_sums()
379375
total_invested = self.__broker._open_trade_entry_abs_value_sum
380376
return (self.pl / total_invested) * 100 if total_invested else 0
381377

@@ -776,10 +772,6 @@ def __init__(self, *, data, cash, spread, commission, margin,
776772
self.trades: List[Trade] = []
777773
self.position = Position(self)
778774
self.closed_trades: List[Trade] = []
779-
self._trade_sums_dirty = True
780-
self._open_trade_size_sum = 0
781-
self._open_trade_entry_value_sum = 0.0
782-
self._open_trade_entry_abs_value_sum = 0.0
783775

784776
def _commission_func(self, order_size, price):
785777
return self._commission_fixed + abs(order_size) * price * self._commission_relative
@@ -837,23 +829,25 @@ def new_order(self,
837829

838830
return order
839831

840-
def _mark_trade_sums_dirty(self) -> None:
841-
self._trade_sums_dirty = True
832+
@cached_property
833+
def _open_trade_size_sum(self) -> int:
834+
return sum(int(trade.size) for trade in self.trades)
842835

843-
def _recalculate_trade_sums(self) -> None:
844-
self._open_trade_size_sum = sum(int(trade.size) for trade in self.trades)
845-
self._open_trade_entry_value_sum = sum(
846-
trade.size * trade.entry_price for trade in self.trades
847-
)
848-
self._open_trade_entry_abs_value_sum = sum(
849-
abs(trade.size) * trade.entry_price for trade in self.trades
850-
)
851-
self._trade_sums_dirty = False
836+
@cached_property
837+
def _open_trade_entry_value_sum(self) -> float:
838+
return sum(trade.size * trade.entry_price for trade in self.trades)
839+
840+
@cached_property
841+
def _open_trade_entry_abs_value_sum(self) -> float:
842+
return sum(abs(trade.size) * trade.entry_price for trade in self.trades)
843+
844+
def _clear_trade_caches(self) -> None:
845+
self.__dict__.pop('_open_trade_size_sum', None)
846+
self.__dict__.pop('_open_trade_entry_value_sum', None)
847+
self.__dict__.pop('_open_trade_entry_abs_value_sum', None)
852848

853849
@property
854850
def unrealized_pl(self) -> float:
855-
if self._trade_sums_dirty:
856-
self._recalculate_trade_sums()
857851
if not self.trades:
858852
return 0.0
859853
current_price = float(self._data._current_value("Close"))
@@ -1099,7 +1093,7 @@ def _process_orders(self):
10991093
def _reduce_trade(self, trade: Trade, price: float, size: float, time_index: int):
11001094
assert trade.size * size < 0
11011095
assert abs(trade.size) >= abs(size)
1102-
self._mark_trade_sums_dirty()
1096+
self._clear_trade_caches()
11031097

11041098
size_left = trade.size + size
11051099
assert size_left * trade.size >= 0
@@ -1120,7 +1114,7 @@ def _reduce_trade(self, trade: Trade, price: float, size: float, time_index: int
11201114
self._close_trade(close_trade, price, time_index)
11211115

11221116
def _close_trade(self, trade: Trade, price: float, time_index: int):
1123-
self._mark_trade_sums_dirty()
1117+
self._clear_trade_caches()
11241118
self.trades.remove(trade)
11251119
if trade._sl_order:
11261120
self.orders.remove(trade._sl_order)
@@ -1144,7 +1138,7 @@ def _open_trade(self, price: float, size: int,
11441138
self.trades.append(trade)
11451139
# Apply broker commission at trade open
11461140
self._cash -= self._commission(size, price)
1147-
self._mark_trade_sums_dirty()
1141+
self._clear_trade_caches()
11481142
# Create SL/TP (bracket) orders.
11491143
if tp:
11501144
trade.tp = tp

0 commit comments

Comments
 (0)