extract_trades¶
Defined in fynance.metrics
- extract_trades(positions, returns)[source]
Extract round-trip trades from a position series.
A trade is a maximal run of bars over which
sign(positions)is constant and nonzero – flat (0) bars are never part of a trade and always close any open run. Its realized return is the compounded net return of holding the (possibly sized, not just signed) position over the run:\[ret = \prod_{t=t_{in}}^{t_{out}} \left(1 + positions_t \cdot returns_t\right) - 1\]positionsandreturnsare assumed already aligned index-for-index (positions[t]earnsreturns[t]) – the conventionBacktestResultstores them in, soextract_trades(result.positions, result.returns)andtradesagree exactly (see that class for how the causal shift is folded intoreturnsupstream, in the engine).- Parameters:
- positionsnp.ndarray[dtype, ndim=1 or 2]
Position / weight series, shape
(T,)for a single asset or(T, n_assets)for a book (column-wise, one independent scan per column).- returnsnp.ndarray[dtype, ndim=1 or 2]
Realized return series aligned with
positions. Either the same shape aspositions, or, for a 2-Dpositions, a 1-D array of shape(T,)broadcast to every column (theBacktestResultcase: a single net return path shared by every asset’s own position run).
- Returns:
- np.ndarray[TRADE_DTYPE, ndim=1]
One row per trade, ordered by asset then by time within each asset, with fields:
asset(int16) – column index (0for a 1-Dpositions).t_in(int64) – first bar of the run.t_out(int64) – last bar of the run, inclusive. A run still open at the last observation is included with its current (unrealized) mark rather than dropped.side(int8) –+1long,-1short.ret(float64) – compounded net return over the run.bars(int64) –t_out - t_in + 1.
- Raises:
- ValueError
If
positionsorreturnsis not 1-D or 2-D, or their shapes are incompatible (see above).
See also
trade_summaryfynance.metrics.trading.sign_changes,fynance.metrics.trading.trades_per_yearfynance.backtest.result.BacktestResult.trades
Examples
A long run of two bars, a direct flip to a short run of two bars (no flat gap – two adjacent trades, not one), a flat bar, then an open long trade at the end:
>>> import numpy as np >>> positions = np.array([1.0, 1.0, -1.0, -1.0, 0.0, 1.0]) >>> returns = np.array([0.5, 0.5, 0.5, -0.5, 0.0, 0.25]) >>> trades = extract_trades(positions, returns) >>> trades['t_in'], trades['t_out'], trades['side'] (array([0, 2, 5]), array([1, 3, 5]), array([ 1, -1, 1], dtype=int8)) >>> trades['ret'] array([ 1.25, -0.25, 0.25]) >>> trades['bars'] array([2, 2, 1])
A two-asset book: each column is scanned independently and tagged with its own
assetindex:>>> pos2 = np.array([[1.0, -1.0], [1.0, -1.0], [0.0, -1.0]]) >>> ret2 = np.array([[0.1, 0.1], [0.1, -0.1], [0.0, 0.2]]) >>> trades2 = extract_trades(pos2, ret2) >>> trades2['asset'] array([0, 1], dtype=int16) >>> trades2['t_in'], trades2['t_out'] (array([0, 0]), array([1, 2]))