v1.0.0 to v2.0.0

67 added, 24 removed. Audit A to A.

---
name: execution-slippage-attribution-timing-vs-sizing
description: >-
- Quantitative post-trade TCA engine for decomposing Implementation Shortfall (IS) into timing/delay slippage vs sizing/market impact slippage, identifying primary slippage drivers, and recommending execution strategy adjustments.
+ Post-trade TCA engine that splits the executed leg of Implementation Shortfall into timing/delay slippage (decision to arrival) and sizing/market-impact slippage (arrival to completion), names the larger adverse component, and flags partial fills whose opportunity cost is not measured here.
domain: Execution Algorithms
subdomain: Post-Trade Transaction Cost Analysis (TCA)
tags: ["tca", "implementation-shortfall", "slippage-attribution", "timing-slippage", "sizing-slippage", "market-impact", "execution-benchmarking"]
- brokers_frameworks: ["Almgren-Chriss TCA", "IS Decomposition", "Python Dataclasses"]
- version: "1.0.0"
+ brokers_frameworks: ["Perold (1988) Implementation Shortfall", "Delay / Trading Cost Decomposition", "Python Dataclasses"]
+ version: "2.0.0"
author: algo-trading-skills-contributors
license: Apache-2.0
---
## When to Use
- Use this skill in post-trade Transaction Cost Analysis (TCA), algorithmic execution reviews, and portfolio management. Total Implementation Shortfall ($\text{IS}_{\text{total}}$) measures the total cost of executing a trade relative to the decision price ($P_{\text{decision}}$). This module mathematically decomposes total slippage into **Timing/Delay Slippage** (price movement between decision time and order arrival at the venue) and **Sizing/Market Impact Slippage** (impact caused by order size during execution).
+ Use this skill in post-trade Transaction Cost Analysis (TCA) and algorithmic execution reviews, when you already know an order cost money and need to know **which half of the execution stack to fix**: the path between the PM's decision and the order reaching the venue, or the algorithm's behaviour once it was working the order.
+ It splits the executed leg of Implementation Shortfall into two additive components, both expressed as cost-signed basis points of the decision price $P_{\text{decision}}$ (positive = money lost, for buys *and* sells):
+
+ - **Timing / delay slippage** — what the price did between decision and arrival, before the algorithm had any influence.
+ - **Sizing / market-impact slippage** — what the price did between arrival and the final fill, while the order was being worked.
+
+ ## When NOT to Use
+
+ - **As a complete Implementation Shortfall.** Perold (1988) decomposes IS into delay cost + trading cost + **opportunity cost** + **explicit fees**. This engine measures the first two — the price cost on shares that actually filled. It never sees an end-of-horizon price, so it cannot compute opportunity cost on the unfilled residual, and it takes no commissions or taxes. For the full four-component shortfall use `implementation-shortfall-minimization`.
+ - **On a materially underfilled order, as the headline cost number.** At a 40% fill the opportunity cost on the missing 60% can exceed everything reported here. The report sets `is_partial_fill` and excludes that term; do not present the remainder as the cost of the order.
+ - **As proof that the dispatch path is slow.** The timing component is *whatever the price did* during the delay. Over a short delay on a liquid name that is mostly drift and news, not latency. Correlate the bps figure with `delay_seconds` across many trades before re-engineering anything.
+ - **As a market-adjusted measure.** Neither component is decontaminated of index/beta movement, so a timing figure measured during a broad market move is partly beta. Pair with `benchmark-relative-performance-attribution` if you need the stock-specific part.
+ - **As an automatic control input.** `strategy_action_recommendation` is a single-trade triage hint, not a risk control. Retuning a live participation ceiling from one trade's attribution fits noise; see `execution-algo-parameter-optimization-via-backtest`.
+
## Prerequisites
- - Trade execution details (`side`: `'BUY'` or `'SELL'`, `order_qty`, `decision_price`, `arrival_price`, `average_execution_price`).
- - Timestamps (`decision_time`, `arrival_time`, `completion_time`).
+ - Trade execution details: `side` (`'BUY'` or `'SELL'` — nothing else is accepted), `order_qty`, optional `filled_qty` (defaults to a full fill), `decision_price`, `arrival_price`, `average_exec_price` (quantity-weighted).
+ - All three prices finite and strictly positive, on the same quotation basis and currency.
+ - Timestamps `decision_time_iso`, `arrival_time_iso`, `completion_time_iso` as **timezone-aware** ISO-8601 strings, in non-decreasing order. Naive timestamps are rejected.
+ - A materiality threshold in bps (default 1.0) below which a component counts as noise rather than a driver. This is a desk reporting convention, not a standard — set it from your own cost distribution.
## Workflow
- 1. **Total Implementation Shortfall (IS) Calculation**:
- - $\text{IS}_{\text{total}} = \text{Side} \times \frac{\bar{P}_{\text{exec}} - P_{\text{decision}}}{P_{\text{decision}}} \times 10,000 \text{ (bps)}$.
- 2. **Timing / Delay Slippage Calculation**:
- - $\text{IS}_{\text{timing}} = \text{Side} \times \frac{P_{\text{arrival}} - P_{\text{decision}}}{P_{\text{decision}}} \times 10,000 \text{ (bps)}$.
- 3. **Sizing / Market Impact Slippage Calculation**:
- - $\text{IS}_{\text{sizing}} = \text{Side} \times \frac{\bar{P}_{\text{exec}} - P_{\text{arrival}}}{P_{\text{decision}}} \times 10,000 \text{ (bps)}$.
- - Verify identity: $\text{IS}_{\text{total}} \equiv \text{IS}_{\text{timing}} + \text{IS}_{\text{sizing}}$.
- 4. **Primary Driver & Strategy Recommendation**:
- - If $|\text{IS}_{\text{timing}}| > |\text{IS}_{\text{sizing}}| \implies$ Flag `TIMING_DRIVEN_SLIPPAGE` (Recommend `ACCELERATE_ORDER_DISPATCH`).
- - Else $\implies$ Flag `SIZING_DRIVEN_SLIPPAGE` (Recommend `REDUCE_PARTICIPATION_RATE_CEILING`).
- 5. **Audit Report Generation**: Output structured `SlippageAttributionAuditReport`.
+ 1. **Validate before computing.** Reject non-finite or non-positive prices, unrecognised sides, non-positive or over-filled quantities, and naive or out-of-order timestamps.
+ - **Decision point — never attribute unvalidated data.** A NaN price makes every comparison in the classifier false, which lands the trade in the "nothing material" branch and reports corrupt input as `OPTIMAL`. Fail loudly; a TCA engine that cannot compute a cost must not emit a clean bill of health.
+ - **Decision point — an unrecognised `side` is a data error, not a sell.** Defaulting anything that is not `'BUY'` to $-1$ turns a $+70$ bps cost on a mistyped buy into a $-70$ bps gain of identical magnitude.
+ 2. **Decompose, normalising every term on $P_{\text{decision}}$** (with $\text{Side} = +1$ for BUY, $-1$ for SELL):
+ - $\text{IS}_{\text{total}} = \text{Side} \times \frac{\bar{P}_{\text{exec}} - P_{\text{decision}}}{P_{\text{decision}}} \times 10{,}000$
+ - $\text{IS}_{\text{timing}} = \text{Side} \times \frac{P_{\text{arrival}} - P_{\text{decision}}}{P_{\text{decision}}} \times 10{,}000$
+ - $\text{IS}_{\text{sizing}} = \text{Side} \times \frac{\bar{P}_{\text{exec}} - P_{\text{arrival}}}{P_{\text{decision}}} \times 10{,}000$
+ - **Decision point — the sizing term is divided by $P_{\text{decision}}$, not $P_{\text{arrival}}$.** That single choice is what makes the decomposition additive. Normalising the impact leg on the arrival price is defensible in isolation but breaks $\text{IS}_{\text{total}} \equiv \text{IS}_{\text{timing}} + \text{IS}_{\text{sizing}}$.
+ - Verify the identity **in full precision**, then round for reporting — and report the directly computed total, not the sum of the rounded components.
+
+ 3. **Weight to the intended notional if the order underfilled.** Canonical IS divides by $Q_{\text{order}} \times P_{\text{decision}}$, so the per-share cost contributes only $Q_{\text{filled}} / Q_{\text{order}}$ of itself: `executed_is_contribution_bps` $= \text{IS}_{\text{total}} \times \text{fill ratio}$.
+ - **Decision point — if `is_partial_fill` is true, this report is not the order's total cost.** Retrieve the opportunity cost separately before quoting a headline number.
+
+ 4. **Rank by *adverse* cost, never by absolute magnitude.**
+ - A component that made money is never a slippage driver. Ranking by $|\cdot|$ lets a $-50$ bps timing *gain* outrank a $+20$ bps sizing cost and recommend `ACCELERATE_ORDER_DISPATCH` — advice that would forfeit the gain and leave the only real cost untouched.
+ - Neither component materially adverse $\implies$ `FAVORABLE_EXECUTION` (total materially negative) or `ZERO_SLIPPAGE`.
+ - Both materially adverse and within the tie band $\implies$ `BOTH_DRIVERS_MATERIAL` (`REDUCE_DELAY_AND_PARTICIPATION`). An exact tie is *not* zero slippage: $+50/+50$ is 100 bps of real cost.
+ - Otherwise the larger adverse component wins: `TIMING_DRIVEN_SLIPPAGE` (`ACCELERATE_ORDER_DISPATCH`) or `SIZING_DRIVEN_SLIPPAGE` (`REDUCE_PARTICIPATION_RATE_CEILING`), with `secondary_driver_material` set when the loser is *also* adverse — fixing one leg then leaves most of the cost in place.
+
+ 5. **Report contribution shares against gross cost** $|\text{IS}_{\text{timing}}| + |\text{IS}_{\text{sizing}}|$, not against the net total, so offsetting legs cannot produce percentages in the thousands.
+
+ 6. **Audit Report Generation**: output structured `SlippageAttributionAuditReport`, carrying the materiality threshold the verdict was judged against.
+
> Full procedure: see `references/workflows.md`.
> Standards reference: see `references/standards.md`.
> Printable pre-flight checklist: see `assets/checklist.md`.
## Common Pitfalls
- - **Conflating Delay Slippage with Market Impact**: Blaming execution algorithms for high slippage when 80% of the cost occurred during decision-to-routing delays before the order reached the venue.
- - **Failing to Handle Trade Side Multipliers**: Reversing sign conventions for short/sell orders, resulting in negative slippage reported as positive cost.
- - **Ignoring Benchmarks Other Than Arrival Price**: Evaluating IS without isolating broad market beta movement from stock-specific execution impact.
+ - **Reporting corrupt data as `OPTIMAL`**: with NaN prices every bps figure is NaN, and both `abs(nan) > abs(nan)` comparisons evaluate false, so a naive classifier falls through to its "nothing material" branch. The worst input produces the most reassuring output. Validate prices before attributing.
+ - **Treating an exact tie as zero slippage**: a classifier built from two strict `>` comparisons has no branch for $|\text{timing}| = |\text{sizing}|$. A $+50/+50$ split — 100 bps of genuine cost — silently lands in the else-branch labelled "minimal slippage".
+ - **Ranking components by absolute value**: this promotes a favourable leg to "primary slippage driver" and inverts the recommendation. Only adverse components can drive remediation.
+ - **Reversing sign conventions for sell orders**: mapping "anything not BUY" to $-1$ means one typo (`'BUYY'`, `'B'`, `'LONG'`, an empty string) reports a cost as a gain of exactly the same size, and nothing in the output looks wrong.
+ - **Dividing contribution shares by the net total**: when the legs offset, $+500$ bps timing against $-499$ bps sizing yields $50{,}000\%$ and $-49{,}900\%$. Normalise on gross cost.
+ - **Claiming the identity is verified while substituting the sum for the total**: writing `total = timing + sizing` guarantees the printed numbers agree and checks nothing. Verify in full precision and report the independently computed total.
+ - **Conflating delay slippage with market impact**: blaming the execution algorithm when most of the cost accrued before the order ever reached the venue.
+ - **Quoting a partial fill's per-share cost as the order's cost**: it omits opportunity cost on the residual *and* overstates the contribution to IS by $Q_{\text{order}} / Q_{\text{filled}}$.
+ - **Measuring the delay from naive timestamps**: across a DST transition or between venues in different zones the duration is silently wrong, which makes an `ACCELERATE_ORDER_DISPATCH` recommendation unfalsifiable.
+ - **Warning on every trade**: logging each routine attribution at WARNING buries the material ones under thousands of lines in a batch run.
## Verification
- - Instantiate `ExecutionSlippageAttributionEngine`. Input BUY order: $P_{\text{decision}} = \$100.00$, $P_{\text{arrival}} = \$100.50$, $\bar{P}_{\text{exec}} = \$100.70$. Verify engine computes total IS = $+70.0\text{ bps}$, timing slippage = $+50.0\text{ bps}$, sizing slippage = $+20.0\text{ bps}$, classifies primary driver as `TIMING_DRIVEN_SLIPPAGE`, and recommends `ACCELERATE_ORDER_DISPATCH`.
- - Run `python scripts/test_execution_slippage_attribution_timing_vs_sizing.py`.
+ - **Timing-driven BUY**: $P_{\text{decision}} = \$100.00$, $P_{\text{arrival}} = \$100.50$, $\bar{P}_{\text{exec}} = \$100.70$ $\Rightarrow$ total $= +70.0$ bps, timing $= +50.0$ bps, sizing $= +20.0$ bps, shares $71.4\% / 28.6\%$, driver `TIMING_DRIVEN_SLIPPAGE`, recommendation `ACCELERATE_ORDER_DISPATCH`, `secondary_driver_material` true.
+ - **Sign convention**: a SELL at $P_{\text{decision}} = \$100.00$, $P_{\text{arrival}} = \$99.90$, $\bar{P}_{\text{exec}} = \$99.20$ gives $+80.0$ bps of *cost* ($+10.0$ timing, $+70.0$ sizing); the same SELL filled at $\$100.50$ gives $-50.0$ bps and `FAVORABLE_EXECUTION`.
+ - **Tie**: $\$100.00 \to \$100.50 \to \$101.00$ must yield `BOTH_DRIVERS_MATERIAL` / `REDUCE_DELAY_AND_PARTICIPATION` at $+100.0$ bps — never `ZERO_SLIPPAGE`.
+ - **Favourable leg**: $\$100.00 \to \$99.50 \to \$99.70$ (timing $-50.0$, sizing $+20.0$) must yield `SIZING_DRIVEN_SLIPPAGE`, not `TIMING_DRIVEN_SLIPPAGE`.
+ - **Offsetting legs**: $\$100.00 \to \$105.00 \to \$100.01$ must keep both contribution shares within $[-100\%, 100\%]$.
+ - **Partial fill**: 4,000 of 10,000 filled at the timing-driven prices above gives `fill_ratio` $= 0.4$, `is_partial_fill` true, `executed_is_contribution_bps` $= 28.0$ while `total_is_slippage_bps` stays $+70.0$.
+ - **Rounding**: a SELL at $\$1234.56 \to \$1240.01 \to \$1231.77$ reports timing $-44.15$, sizing $+66.74$, total $+22.60$ — the directly computed total, one ulp above the $22.59$ sum of the rounded parts.
+ - **Negative checks**: non-finite or non-positive prices, an unrecognised `side`, `filled_qty` $\le 0$ or $>$ `order_qty`, naive/malformed/out-of-order timestamps, and a negative materiality threshold must each raise.
+ - Run `python scripts/test_execution_slippage_attribution_timing_vs_sizing.py` and confirm all tests pass.
## Related Skills
- - `execution-algo-parameter-optimization-via-backtest`
+ - `implementation-shortfall-minimization` — the full Perold decomposition including opportunity cost and explicit fees.
- `post-trade-execution-quality-scorecard`
- ---
+ - `execution-algo-parameter-optimization-via-backtest`
+ - `arrival-price-benchmark-execution-algo`
+ - `transaction-cost-analysis-tca-integration`