BacktestTradesTarget#

Description#

BacktestTradesTarget is a lean directional backtest on the raw trade tape. It is immediate: the target_position you pass on event t executes on the same print, unlike BacktestOHLCTarget which defers to the next bar's open.

Each print the engine computes the desired trade as clamp(target, min_position, max_position) - current_position and takes it against the current print as a marketable (taker) order. The fill pays taker_fee on the traded notional and the position marks to the print price. If the target equals the current position, no order is placed and the event is a mark-only step.

Inputs are (target_position, trade_price, trade_size). Outputs are the four standard backtest columns: 0 = equity (cumulative dollar PnL), 1 = pnl (per event), 2 = position, and 3 = cost (per event). A NaN trade_price or trade_size skips the event and returns all-NaN (nan_policy: ignore). backtest_report summarizes the resulting equity curve.

The optional min_position and max_position parameters cap the inventory. The target is clamped before the order size is computed, so the engine never carries a position outside that range.

Limitations#

The fill model is optimistic: the full order size executes at the print price with no market impact or slippage beyond taker_fee. Orders are counterfactual (zero market impact), so the tape is unaffected by the strategy's activity.

Examples#

Usage plot#

import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from screamer import BacktestTradesTarget

rng = np.random.default_rng(5)
n = 400
t = np.arange(n)
price = 100 + 2 * np.sin(2 * np.pi * t / n * 4) + np.cumsum(rng.standard_normal(n) * 0.1)
size = np.ones(n)

# a simple mean-reversion signal: go long when cheap, short when rich
signal = np.sign(100 - price)

out = BacktestTradesTarget(taker_fee=0.0002, max_position=3.0, min_position=-3.0)(
    signal, price, size)
eq, pos = out[:, 0], out[:, 2]

fig = make_subplots(rows=3, cols=1, shared_xaxes=True, row_heights=[0.4, 0.3, 0.3],
                    vertical_spacing=0.06)
fig.add_trace(go.Scatter(y=price, name='price', line=dict(color='gray')), row=1, col=1)
fig.add_trace(go.Scatter(y=eq, name='equity', line=dict(color='steelblue')), row=2, col=1)
fig.add_trace(go.Scatter(y=pos, name='position', line=dict(color='darkorange', shape='hv')),
              row=3, col=1)
fig.update_layout(title='BacktestTradesTarget: immediate taker fills on each print',
                  yaxis=dict(title='price'), yaxis2=dict(title='equity ($)'),
                  yaxis3=dict(title='position'),
                  margin=dict(l=20, r=20, t=60, b=20),
                  legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1))
fig.show()