"Execution costs are too high" is not a finding. It is the absence of one. It appears in quarterly packs because the underlying work stopped at a total, and a total gives nobody an action. The desk cannot attack a total. It can attack a bucket.
The version that produces action has four buckets and one property that most attribution work quietly lacks: it reconciles. If your delay, spread, impact and fee figures do not sum to a number that ties to the profit and loss the fund actually booked, you have not measured anything. You have produced four plausible estimates and left the difference in the dark, and the difference is usually where the interesting cost was hiding.
The identity the report has to satisfy
Start from the paper portfolio. Strike every position at the decision price, mark it to the same exit you actually got, and you have the money a frictionless version of your process would have made. Subtract the money the fund actually made. That gap is total execution cost, and it is a single unarguable number because both of its inputs are recorded facts.
The whole job is to explain that gap. So the identity is:
Total gap equals delay plus spread plus impact plus fees plus residual.
The residual term is the part that makes this an identity rather than an approximation, and it is the part most desks delete because it looks like an admission. It is the opposite. A report with a named residual is a report where the four buckets are honest estimates and the unexplained remainder is visible. A report without one has silently smeared the unexplained portion across whichever bucket the model happened to be least constrained on, and that bucket is now wrong by an unknown amount in an unknown direction.
Where each bucket's data actually comes from
Before you design the buckets, look at what the feed hands you and what it does not, because the gaps determine which buckets can be measured and which have to be estimated.

At capture the table carried Asset, Type, Direction, Status, Timeframe, Period, Order, Time, Entry, Exit, TP, SL, PnL, Run-Up, Draw and Action, with source chips above it for MTE, MANUAL, AOE, MRS and MRE and filters for side, asset, status, timeframe and exchange.
Delay comes from the Time column against your venue-side arrival stamp. The feed rendered times to the minute at capture, shown as 08/20 08:00 AM and 07/17 08:00 AM, so if that is your only stamp then delay is quantised to the minute and you must say so in the footnote rather than quote a figure to one decimal place of a basis point.
Spread comes from quote data at arrival, which is not in the feed and has to come from the venue. If you do not have contemporaneous quotes, you cannot measure this bucket, only bound it.
Impact comes from the price path around your fills, again from venue data. Run-Up and Draw give you the position's path after entry, which is useful for the counterfactual question but is not an impact measurement, because the path includes everything the market did for reasons unrelated to you.
Fees come from broker statements and nowhere else. There is no fee column on this table and there should not be, but that means the fee bucket is an accounting join rather than an analytics one. Financing on perpetuals and borrow on shorts belong in this bucket too, and on a book that holds for weeks they can dominate the other three combined. The capture shows entries running from 07/17 through 08/20 on mid-term rows, which is exactly the horizon where carry stops being a rounding error.
Sign conventions, and the residual you are not allowed to hide
Two conventions decide whether the report survives contact with a sceptical reader.
Every bucket is signed. Delay in particular is signed, because delay is favourable roughly as often as it is not, and a desk that reports absolute delay cost is reporting a number that can only grow. Signed delay also protects you from the opposite abuse, which is a quarter where the market happened to drift your way and the desk claims credit for negative execution cost. Signed and reconciled, both of those are visible for what they are.
Every bucket is per-order and then aggregated, never computed on aggregates. Computing spread cost on a quarterly average order size produces a number with no relationship to the money, because cost is convex in size and your size distribution has a tail.
Set a tolerance for the residual in advance and enforce it. Something like: if unexplained exceeds a fifth of the total gap, the report is not published until it is chased. Then chase it in the usual places. Currency conversion applied at a different rate than the analytics assumed. Corporate actions. Partial fills that never made it into the analytics extract. Financing accrued between the analytics cut and the accounting cut. In my experience the residual is almost never a modelling failure, it is a plumbing failure, and finding it improves every future report rather than only this one.
The MARKET column, and the two buckets it fuses
Here is the constraint that will shape your first version of this report more than any modelling choice.
At capture, every visible row in the Order column read MARKET. When an order crosses the spread and moves the book in the same action, spread and impact are not separately identifiable from fill data alone. You can compute their sum. You cannot split it without either quote-level data at the moment of each child fill or an order mix that includes passive orders to compare against.
The correct response is to report them as one line, labelled honestly as combined crossing cost, and to make the separation a project with an owner and a date rather than an assumption. The incorrect response, which I have watched a desk defend for two quarters, is to assume half the spread on every order and call the remainder impact. That produces a spread bucket that is a constant times volume, which is to say a number that tells you nothing you did not already know from your own volume.
There is a second product behaviour worth writing into the methodology note. The platform describes signals as confidence scored and deduped across sources on a ninety second window. That is sensible feed design and it means row counts are not source counts. Attribute cost to the source label on the row and do not build any metric where the number of rows stands in for how many engines agreed, because the feed is built to collapse exactly that.
Ranking the buckets by what the fix would cost
Once the four buckets reconcile, the report has one more job, and it is the one that actually changes behaviour: say which bucket to attack first. The answer is not the largest bucket. It is the bucket with the best ratio of size to the cost of fixing it.
| Bucket | What the fix is | What the fix costs |
|---|---|---|
| Fees | Renegotiate schedules, move tiers, review financing terms | Meetings, and a willingness to move flow |
| Spread | Order type policy, passive tolerance by liquidity tier | Policy work, plus accepting some unfilled orders |
| Delay | Plumbing between signal and staged order | Engineering time, one off, potentially large |
| Impact | Sizing, scheduling, capacity limits | Strategy capacity, which is the expensive one |
Work down that table rather than down the size ranking. Fees are almost always the first move because the fix is commercial rather than technical and the effect is immediate and permanent. Spread is second because an order type policy is a document, not a build. Delay is third and it is where most desks start, which is backwards: it is the most engineering-intensive fix and on a book whose rows read Mid-Term with periods of 1day and 4h, as the capture showed, ninety seconds of delay is close to irrelevant to the outcome.
Impact is last on the list to attack and first on the list to respect, because the only real fixes for it reduce the size of the strategy. That is a conversation for the investment committee rather than the trading desk, and the value of the reconciled report is that it lets you have that conversation with a number attached instead of an argument about whether execution is doing its job.