Skip to main content
A Trade is created when an Order is filled. Access active trades through Strategy.trades and settled (closed) trades through Strategy.closed_trades.
from backtesting import Strategy

class MyStrategy(Strategy):
    def next(self):
        for trade in self.trades:
            print(trade.pl, trade.entry_price)

Properties

Entry and exit

size
int
Trade size in units. Negative for short trades.
for trade in self.trades:
    direction = 'long' if trade.is_long else 'short'
    print(f"{direction} trade with {abs(trade.size)} units")
entry_price
float
Price at which the trade was opened.
exit_price
float | None
Price at which the trade was closed. None if the trade is still active.
entry_bar
int
Candlestick bar index at the time of entry.
exit_bar
int | None
Candlestick bar index at the time of exit. None if the trade is still active.
entry_time
pd.Timestamp | int
Datetime (or integer period) of the bar at entry. The type matches the index type of the data passed to Backtest.
exit_time
pd.Timestamp | int | None
Datetime (or integer period) of the bar at exit. None if the trade is still active.

Profit and loss

pl
float
Profit (positive) or loss (negative) in cash units.For active trades, this is the current unrealized P&L based on the last close price. Commissions are reflected only once the trade is closed.
total_pl = sum(t.pl for t in self.trades)
pl_pct
float
P&L as a percentage relative to the entry price, adjusted for commissions after close.
value
float
Total trade value in cash: abs(size) × current price.

Direction

is_long
bool
True if the trade is long (i.e. size > 0).
is_short
bool
True if the trade is short (i.e. size < 0).

SL/TP management

sl
float | None
Stop-loss price for this trade. Writable.
  • Assigning a price creates or replaces the existing contingent stop-market order.
  • Assigning None cancels the current SL order.
trade.sl = 98.50   # set or update stop-loss
trade.sl = None    # cancel stop-loss
For long trades, sl must be below the current price. For short trades, it must be above.
tp
float | None
Take-profit price for this trade. Writable.
  • Assigning a price creates or replaces the existing contingent limit order.
  • Assigning None cancels the current TP order.
trade.tp = 115.00  # set or update take-profit
trade.tp = None    # cancel take-profit

Tracking

tag
any
Arbitrary value inherited from the Order that opened this trade. Use for grouping, conditional logic, or post-run analysis.
# Tag an order
self.buy(size=5, tag='momentum')

# Analyze closed trades by tag
momentum_trades = [t for t in self.closed_trades if t.tag == 'momentum']
See also Order.tag.

Methods

Trade.close()

def close(portion: float = 1.0) -> None
Place a new market order to close portion of this trade at the next available price.
portion
float
default:"1.0"
Fraction of the trade to close. Must satisfy 0 < portion <= 1.
  • 1.0 (default) closes the entire trade.
  • 0.5 closes half the position; the remaining half stays open.
trade.close()      # close entirely
trade.close(0.5)   # close 50%
trade.close(0.25)  # close 25%
portion must be strictly greater than 0 and at most 1. Passing 0 or a negative value raises an AssertionError.

Examples

Accessing trade information

def next(self):
    for trade in self.trades:
        print(
            f"size={trade.size}, "
            f"entry={trade.entry_price:.2f}, "
            f"pl={trade.pl:.2f}, "
            f"pl_pct={trade.pl_pct:.2%}, "
            f"value={trade.value:.2f}"
        )

Dynamic SL/TP adjustment (trailing stop)

def next(self):
    atr = self.atr[-1]
    for trade in self.trades:
        if trade.is_long:
            # Trail stop-loss upward as price rises
            new_sl = self.data.Close[-1] - 2 * atr
            if trade.sl is None or new_sl > trade.sl:
                trade.sl = new_sl

        elif trade.is_short:
            # Trail stop-loss downward as price falls
            new_sl = self.data.Close[-1] + 2 * atr
            if trade.sl is None or new_sl < trade.sl:
                trade.sl = new_sl

Partial closes

def next(self):
    for trade in self.trades:
        # Take partial profit at a fixed return threshold
        if trade.pl_pct >= 0.03 and trade.size > 1:
            trade.close(0.5)   # close half the trade

Tagging and post-run analysis

class TaggedStrategy(Strategy):
    def init(self):
        pass

    def next(self):
        if some_signal:
            self.buy(size=10, tag='signal-A')
        elif other_signal:
            self.sell(size=10, tag='signal-B')

bt = Backtest(data, TaggedStrategy, cash=10_000)
stats = bt.run()

trades_df = stats['_trades']
print(trades_df[trades_df['Tag'] == 'signal-A'])

Build docs developers (and LLMs) love