Skip to content

Execution · Intermediate

TWAP, slicing and jitter

A trade’s cost is measured against the price when it was decided; splitting an order keeps that cost down, and an irregular schedule makes it harder for others to trade ahead of it.

20 min read10 referencesIntroduction to the series

Educational material only. Not investment advice.

Contents
  1. 01Parent orders and implementation shortfall
  2. 02Arrival, TWAP and VWAP
  3. 03Market impact and the cost of waiting
  4. 04Schedules
  5. 05Why schedules are randomised
  6. 06An execution laboratory
  7. 07Measuring execution quality
  8. —References

Abstract

The cost that matters is implementation shortfall: the gap between the price when the order was decided and the prices actually paid. Impact grows roughly with the square root of order size relative to daily volume, and the Almgren–Chriss trade-off between impact and timing risk sets how an order should be split. Jitter makes a schedule harder to anticipate, at a small and measurable cost. Execution quality becomes visible only across many orders, and at realistic timing risk a comparison of two algorithms needs well over a thousand of them.

Key takeaways

  • Measure execution against the arrival price; TWAP and VWAP describe how an order was worked, not what it cost.
  • Impact grows roughly with the square root of size relative to volume, so participation matters more than share count.
  • Splitting an order exchanges impact for timing risk; with risk ignored and liquidity even through the window, an even split (TWAP) minimises expected cost, and when volume has a strong shape, following it (VWAP) costs less.
  • Regular schedules are easy to time; jitter makes child times much less predictable at a small expected cost, though it cannot hide a large order that keeps buying, or selling, all day.
  • Execution quality is only visible across many orders, normalised by volatility and participation.

Before you start

  • Bid, ask, mid-quote and spread
  • Volatility and the square root of time
  • The series notation, in the Introduction to the series

A signal decides what to hold; execution decides what it costs to get there. Any order larger than the liquidity resting at the best prices moves the price against the trader if it is sent all at once, so larger orders are split and worked over time. How they are split, and what they are measured against, can decide whether a modest edge survives trading.

Parent orders and implementation shortfall

Call the order the trader wants filled the parent, and the pieces actually sent to the market its children. The cost of a parent order is best measured against the price at the moment the decision was made, the arrival price, usually the mid-quote. For a buy of intended size Q, filled in pieces qi at prices pi, with mend the mid when the order ends:

IS  =  [ Σ qi (pi − marrival) + (Q − Σ qi)(mend − marrival) ] / Q
implementation shortfall of a buy, per unit of the intended size (Perold 1988); the second term is the opportunity cost of any part left unfilled

Perold introduced implementation shortfall as the gap between a paper portfolio, traded instantly at decision prices, and the real one.1 In practice it is split into four parts: the half-spread paid to cross the quote, the market impact of the trader’s own demand, the timing risk of prices moving while the order is worked, and the opportunity cost of any part left unfilled. Splitting an order trades the second against the third: smaller children each pay less impact, but sending them takes time, and the part not yet filled is exposed to the market meanwhile.

Figure 1From parent order to measured cost
Execution chain: parent order, scheduler with slices and jitter, child orders, venue, fills, transaction cost analysiscalibrates the next scheduleParent ordersize Q, arrival midSchedulerN slices, window W, jitterChild ordersq₁ … q_NMarketquotes, volumeFillsprice, size, timeCost analysisIS, vs VWAP, vs TWAP
The scheduler turns one decision into child orders; the fills are measured against the arrival mid, and the measurements feed the next schedule.

Arrival, TWAP and VWAP

Three benchmarks are in common use, and each rewards different behaviour. Choosing one is choosing what the execution is judged on.

BenchmarkDefinitionWhat it rewardsWeakness
Arrival price (implementation shortfall)Mid-quote when the parent order arrivedFinishing fast when impact is low; the true economic costNoisy: dominated by market moves on any single order
TWAPTime-weighted average price over the execution windowTrading evenly through the windowCan be matched exactly by trading evenly, whatever it costs
VWAPVolume-weighted average price over the windowTrading in proportion to market volumeThe trader’s own volume is inside the benchmark; easy to match, easy to game

VWAP was proposed as a cost benchmark by Berkowitz, Logue and Noser (1988).

VWAP became popular because it is simple to compute and hard to miss by much: an algorithm that follows the market’s volume curve will land close to it.2 That is also its weakness. A large order moves VWAP towards its own fills, so beating VWAP says little about whether the trade was cheap. Arrival-price cost measures what the trade actually cost, and it is the measure this note uses; TWAP and VWAP are best treated as descriptions of how an order was worked.

Market impact and the cost of waiting

The square-root law

How much does demand move the price? Kyle’s model gives a linear answer: price moves in proportion to net order flow, with a slope that rises with the uncertainty about the asset’s value and falls with the volume of uninformed trading that hides informed orders.3 Empirically, the total impact of a large order grows more slowly than its size. Across markets and decades, a good approximation is

impact  ≈  Y · σ · √( Q / V )
the square-root law of market impact

where σ is volatility (daily here, unlike the annualised σ of the series notation), V daily volume and Y a constant of order one. Almgren, Thum, Hauptmann and Li estimated impact from large US equity orders and found temporary impact growing with the rate of trading raised to a power of about 0.6, close to the square root;4 Tóth and co-authors found the square root across many markets and argued that it reflects how thin liquidity is close to the current price.5,6 Two consequences follow: the cost of an order depends on its size relative to volume more than on its size in shares, and doubling an order raises its cost per share by about 41%, where a linear model would say 100%.

The cost of waiting

Spreading an order over time lowers impact but leaves the unfilled part exposed to price moves. Bertsimas and Lo showed that, with linear impact and no concern for risk, splitting the order evenly over the available time minimises expected cost: that even split is a TWAP.7 Almgren and Chriss added the variance of cost: a risk-averse trader trades faster at the start, and the set of schedules that minimise variance for each level of expected cost forms an efficient frontier, from TWAP at one end to immediate execution at the other.8 Obizhaeva and Wang showed that when the order book refills gradually after each trade, the optimal schedule combines discrete trades at the start and end with continuous trading in between.9

Schedules

A TWAP schedule divides a parent of size Q into N children of size Q/N, one every W/N minutes across a window W. Three numbers describe it. The participation rate, the child’s share of the market volume trading while it works, drives impact. The window drives timing risk. The child size relative to the quoted size decides whether a child can cross the spread without walking the book.

ScheduleChild sizes followBest when
TWAPEqual slices in timeVolume is fairly even, or predictability of volume is poor
VWAPThe expected intraday volume curveVolume has a strong, stable shape (heavy at the open and close)
Participation (POV)A fixed share of volume as it printsSize is uncertain relative to the day’s volume; the order must never dominate
Implementation shortfallFront-loaded, per Almgren–ChrissTiming risk is large relative to impact

Why schedules are randomised

A perfectly regular schedule, the same size at the same interval, is a signal. Anyone watching the tape who sees clips of the same size print every few minutes can infer that a larger order is being worked, estimate its direction and remaining size, and trade ahead of it. Brunnermeier and Pedersen formalised the incentive: when a trader is known to need to buy or sell, others profit by trading in the same direction first and reversing later.10 The defence is to make the schedule harder to read. Jitter randomises each child’s time within its slot and scales its size by a random factor, while still completing the parent within the window.

site_research/fieldnotes/twap.py
def schedule(slices: int, window: int, jitter: float, rng: np.random.Generator):
    """Child times (minutes after the window opens) and sizes (fractions of the parent).

    jitter = 0 is a plain TWAP: equal sizes at the start of equal intervals, so one slice is an
    immediate order. jitter in (0, 1] delays each child by up to jitter x its interval and scales
    each size by 1 + jitter * U(-0.5, 0.5), renormalised so the parent is filled exactly.
    """
    dt = window / slices
    times = (np.arange(slices) + jitter * rng.uniform(0.0, 1.0, slices)) * dt
    sizes = 1.0 + jitter * rng.uniform(-0.5, 0.5, slices)
    return np.sort(times), sizes / sizes.sum()

In the simulator, an observer who predicts each child’s time as the previous child’s time plus the median gap seen so far gets 100% of an unjittered TWAP’s children after the second (20 children over two hours) right to within 30 seconds; at 50% jitter the figure falls to 27%, and at full jitter to 14%. The price is small but not zero: 0.36 bp of expected cost at full jitter in this model, against a timing risk of 46 bp. It arises because a child’s total impact cost grows with its size to the power 1.5, so uneven sizes cost more than even ones, and because delayed children move along the intraday volume curve. The measure is deliberately narrow: it only watches the clock. Jitter does not hide one-sided flow, which a careful observer sees in the tape whatever the timing, and it helps little when children are about a minute apart. Randomising order types and venues, and never trading the same size at the same second of the minute, follow from the same logic.

site_research/fieldnotes/twap.py
def detectability(slices: int, window: int, jitter: float, rng: np.random.Generator,
                  tolerance: float = 0.5) -> float:
    """Share of child orders whose time an observer predicts to within `tolerance` minutes by
    adding the median of the gaps seen SO FAR to the previous child's time. 1.0 for an exact
    TWAP. The observer only watches the clock; size and direction are other giveaways."""
    t, _ = schedule(slices, window, jitter, rng)
    gaps = np.diff(t)
    if len(gaps) < 2:
        return 0.0
    guess = np.array([t[i - 1] + np.median(gaps[: i - 1]) for i in range(2, len(t))])
    return float(np.mean(np.abs(guess - t[2:]) <= tolerance))

An execution laboratory

The laboratory below simulates a buy order under the model in the code listing: a random-walk mid with the chosen daily volatility, a half-spread of 1 bp, temporary impact following the square-root law in each child’s share of the volume while it works (one minute, or its slot if shorter), linear permanent impact (small at this size, under 1 bp), and a U-shaped intraday volume curve. Each child starts its slot, so a single child is an immediate order; jitter delays children within their slots. The impact coefficient η = 0.15 applies to one minute’s participation. With it, a full-day order worked as 390 one-minute children pays 3.55 bp in all, a temporary impact of about 0.15 · σ√(Q/V): roughly a sixth of the square-root law’s constant of order one, so the model sits at the cheap end of published estimates. The permanent-impact coefficient γ is 0.3. The two are close to the values Almgren and co-authors fitted, though their temporary impact grows with the trading rate to the power 0.6.4 They are illustrative: the shapes of the results matter here, and their levels do not. Expected costs and timing risks below are exact under the model (the random-walk mid is integrated out); only the spread of outcomes comes from simulated days.

Figure 2An execution laboratory
Expected cost
10.6 bp
impact and half the spread; the mid’s own move averages zero
Timing risk (standard deviation)
46.9 bp
simulated days, 5th to 95th percentile: −73 to 96 bp
Participation while working
17%
each child’s share of the volume trading while it works (U-shaped day)
Predictable child times
27%
guessed to within 30 s from the gaps seen so far
One sample schedule: child orders over the window (height = size)0 min60 min120 minImplementation shortfall against the arrival mid, 800 simulated daysmean of these days 11.7−200−150−100−50050100150200shortfall, bp (positive is a cost)
Expected cost against timing risk, by window010203040020406080100timing risk, bpexpected cost, bp5m15m30m60m120m240m390m

Each point keeps the current pace, one child every 6.0 minutes, and stretches the window. Longer windows at this pace split the order into more, smaller children, so expected cost falls; they also leave it exposed for longer, so timing risk rises. Both axes are exact expectations under the model, not simulation averages.

Child orders / simulated daysMean of the simulated days; current settingZero (the arrival price)

Toy model: random-walk mid, half-spread 1 bp, square-root temporary impact on each child’s share of the volume while it works (one minute, or its slot if shorter), small linear permanent impact, U-shaped intraday volume. Children start their slots and jitter delays them. Coefficients are illustrative, not a calibration.

Synthetic. Top: one sample schedule. Middle: implementation shortfall against the arrival mid over 800 simulated days (positive is a cost); its mean is a noisy estimate of the expected cost in the first tile. Bottom: expected cost against timing risk as the window stretches at the current pace between children, the current setting marked (so the child count grows with the window). Try one slice against twenty at a 120-minute window, then stretch the window to the whole day and watch both axes.

The reference grid computed by the Python model (an order of 1% of daily volume, 1.5% daily volatility) shows the two forces separately. Holding the window fixed, more children cut the cost; the timing risk depends mainly on the window:

Window1 slice5 slices20 slices100 slicesTiming risk (standard deviation)
30 min35 bp17 bp9 bp8 bp23 bp
120 min35 bp19 bp10 bp5 bp46 bp
390 min35 bp22 bp11 bp6 bp83 bp

Expected implementation shortfall, in bp of the arrival mid, exact under the toy model. Timing risk shown for 20 slices; it varies little with the slice count beyond a few children.

One immediate child
35 bp
all impact, no timing risk
20 children, 2 hours
10 bp
timing risk 46 bp
100 children, full day
6 bp
timing risk 86 bp
Expected cost of full jitter
+0.36 bp
predictable children 100% to 14%

The trade-off appears when the pace is held and the window stretched. At one child every six minutes, the Python model gives:

WindowChildrenExpected costTiming risk (standard deviation)
6 min135 bp0 bp
30 min517 bp20 bp
60 min1013 bp31 bp
120 min2010 bp46 bp
240 min409 bp67 bp
390 min657 bp86 bp

Same model and assumptions as the grid above; one child every six minutes.

Stretching the window from 6 minutes to the full day cuts the expected cost from 35 bp to 7 bp and raises the timing risk from 0 bp to 86 bp, the risk growing roughly with the square root of the window. In this toy the saving comes from the number of children, not from the time: each child’s impact is gone within its minute, so the same 65 children sent one a minute would cost 6 bp with a timing risk of 35 bp, better on both axes than spreading them over the day. In real markets impact decays over minutes to hours, so trading the same amount faster costs more; that is the trade-off the Almgren–Chriss frontier prices, and choosing a point on it is a statement about how much price risk a strategy is willing to carry to save impact. The toy has no such memory, so this table shows what more children buy, and the frontier itself needs a model in which impact decays.

site_research/fieldnotes/twap.py
def volume_profile(minutes: int = MINUTES) -> np.ndarray:
    """A U-shaped intraday volume profile: busier at the open and the close. Sums to one."""
    t = np.arange(minutes) + 0.5
    f = 1.0 + 1.5 * ((t - minutes / 2) / (minutes / 2)) ** 2
    return f / f.sum()


def _volume(prof: np.ndarray, a: float, b: float) -> float:
    """Market volume (fraction of the day) between minutes a and b, pro rata within a minute."""
    i, j = int(np.floor(a)), int(np.floor(b))
    if i == j:
        return prof[min(i, MINUTES - 1)] * (b - a)
    total = prof[i] * (i + 1 - a) + prof[i + 1:j].sum()
    return total + (prof[j] * (b - j) if j < MINUTES else 0.0)


def expected_cost(size=0.01, sigma=150.0, slices=10, window=120, jitter=0.0, spread=2.0,
                  eta=0.15, gamma=0.3, child_minutes=1.0, start=0, schedules=400, seed=7) -> dict:
    """Expected implementation shortfall and timing risk, with the price path integrated out.

    The mid is a driftless random walk, so its expected contribution to the cost is zero and
    the expected shortfall is the expected impact plus half the spread. The timing risk is
    exact too: child i fills after m_i one-minute steps, so the price part of the cost has
    variance  vol_min^2 * sum_ij q_i q_j min(m_i, m_j). Only the schedule is random (jitter),
    and it is averaged over `schedules` draws from a fixed seed, so neighbouring settings share
    their draws and the numbers move smoothly. With no jitter one schedule is exact.
    """
    window = min(window, MINUTES - start)
    rng = np.random.default_rng(seed)
    prof = volume_profile()
    vol_min = sigma / np.sqrt(MINUTES)
    work = min(child_minutes, window / slices)
    n = 1 if jitter == 0 else schedules
    impact, var_price = np.empty(n), np.empty(n)
    for k in range(n):
        t, q = schedule(slices, window, jitter, rng)
        m = np.minimum(start + t.astype(int), MINUTES - 1) - start    # price steps before each fill
        v = np.array([_volume(prof, *_working(x, work)) for x in start + t])
        child = q * size
        temp = eta * sigma * np.sqrt(child / v)
        perm = gamma * sigma * np.concatenate([[0.0], np.cumsum(child)[:-1]])
        impact[k] = (q * (perm + temp + spread / 2)).sum()
        later = q[::-1].cumsum()[::-1] - q                         # weight filled after child i
        var_price[k] = vol_min ** 2 * (m * (q * q + 2 * q * later)).sum()
    sd = np.sqrt(var_price.mean() + (impact.var() if n > 1 else 0.0))
    return {"expected": impact.mean(), "sd": sd}


def simulate(size=0.01, sigma=150.0, slices=10, window=120, jitter=0.0, spread=2.0,
             eta=0.15, gamma=0.3, child_minutes=1.0, start=0, paths=2000, seed=7) -> dict:
    """Implementation shortfall (vs the arrival mid) of many paths, and its parts."""
    window = min(window, MINUTES - start)
    rng = np.random.default_rng(seed)
    prof = volume_profile()
    vol_min = sigma / np.sqrt(MINUTES)
    cost = np.empty(paths)
    impact = np.empty(paths)
    for k in range(paths):
        t, q = schedule(slices, window, jitter, rng)
        minute = np.minimum(start + t.astype(int), MINUTES - 1)
        steps = rng.normal(0.0, vol_min, MINUTES)
        path = np.concatenate([[0.0], np.cumsum(steps)])
        mid = path[minute] - path[start]                              # random walk from arrival
        work = min(child_minutes, window / slices)
        a = start + t
        v = np.array([_volume(prof, *_working(x, work)) for x in a])
        child = q * size
        temp = eta * sigma * np.sqrt(child / v)
        perm = gamma * sigma * np.concatenate([[0.0], np.cumsum(child)[:-1]])
        fills = mid + perm + temp + spread / 2
        cost[k] = implementation_shortfall(fills, q, 0.0)
        impact[k] = (q * (perm + temp + spread / 2)).sum()
    return {"mean": cost.mean(), "sd": cost.std(ddof=1), "p05": np.percentile(cost, 5),
            "p95": np.percentile(cost, 95), "expected_impact": impact.mean()}
The model behind the tables: the volume curve, the exact expected cost and timing risk, and the day-by-day simulator that gives the spread of outcomes (it uses schedule and implementation_shortfall, listed above and below). The laboratory runs a TypeScript port of the same model.

Measuring execution quality

The tables give each schedule’s expected cost and its timing risk. A single order delivers one number, its measured shortfall, and that number mixes the two, as one simulated order from the reference case shows.

Step by stepOne order’s shortfall, from the arrival price to the measured cost
The mid and the fills, bp from the arrival mid−100−80−60−40−200200 min30 min60 min90 min120 minarrival midaverage fill −35.9 bpThe market’s volume per minute (shaded) and the children (bars), same minutesWhat each child paid above the mid it met, bp051015temporary 7.710.9grey: half-spread; dark: permanent impact; aqua: temporary impactThe same order’s shortfall over many days, bp−100−50050100150+10.5 spread and impact−46.4 the market’s move−35.9 measuredexpected +10.5this day41% below zero
  1. Step 1 of 4

    The arrival price

    The order is the reference case of the tables above: a buy of 1% of the day’s volume, worked as 20 children over the first 120 minutes. The decision fixes the arrival mid, the zero line. On this simulated day the market fell while the order was worked: when the last child traded, the mid stood at −63.4 bp.

  2. Step 2 of 4

    What each child pays

    Each child crosses half the spread, 1 bp, and pays a temporary impact for its share of the volume trading while it works: 7.7 bp for the first child, rising to 10.9 bp for the last as the morning’s volume thins. The children before it have also left a small permanent impact. Every fill sits that far above the mid it met.

  3. Step 3 of 4

    The shortfall, taken apart

    Averaged over the children, spread and impact came to 10.5 bp: the expected cost the grid gives for 20 children over two hours, and the part the schedule controls. The market’s own move while the order was worked contributed −46.4 bp. The measured shortfall, average fill minus arrival mid, was −35.9 bp: on paper, the order made money.

  4. Step 4 of 4

    One day among many

    Repeated over many days, the shortfall scatters around its expected 10.5 bp with a standard deviation of 46.2 bp, and 41% of days come out below zero. Sent as one immediate child, the same order would cost 35.5 bp every day, with no timing risk. A single order’s measured cost says little about its schedule; telling two schedules apart takes many orders.

Synthetic: one simulated day of the note’s execution model with the reference grid’s settings (a buy of 1% of daily volume, 1.5% daily volatility, a half-spread of 1 bp, 20 children over 120 minutes, no jitter). The day shown is the one, of the first two hundred simulated, whose market move is closest to one standard deviation in the buyer’s favour. Without script, or with reduced motion, the figure shows its final state.

Execution quality can only be judged in aggregate. With a timing risk of about 46 bp per order in the example above, telling apart two algorithms whose true costs differ by 5 bp needs roughly 1,300 orders for each algorithm to detect the difference reliably (a two-sided 5% test with 80% power). Removing the market’s move from each order’s cost, or splitting the same parent orders between the two algorithms, so that both face the same market move, cuts that number considerably.

Figure 3How many orders it takes to see a cost difference
Order worked over (20 children)
Share of the variance a benchmark explains (R²)
Timing risk per order
46.2 bp
standard deviation of one order’s shortfall
Standard error of the difference
6.5 bp
95% of experiments land within 12.8 bp of the truth
Chance of detecting it
12%
a 95% interval that excludes zero, with 100 orders each
Orders needed for 80%
1,341
per algorithm, two-sided 5% test
Predict first: how many of the 20 will find it?
Measured difference between the two algorithms, bp: where 95% of experiments land−40−2002040101001,00010,000orders per algorithm (log scale)no differencetrue difference 5.0 bp80% power, 1,341
Where 95% of measured differences landOrders now; experiments (filled: interval above zero)No difference
Synthetic, the note’s execution model: the timing risk per order is the reference grid’s, for 20 children over 30 minutes, two hours or the whole day. With no jitter each order’s shortfall is normally distributed under the model, so the band and the simulated experiments are exact rather than approximations. Suggested experiments: at the defaults, predict how many of the 20 experiments of 100 orders each will find a 5 bp difference, then run them; move to the 80% line; then let a benchmark explain 75% of the variance of each order’s cost (R² = 0.75, halving the timing risk) and watch the orders needed fall by a factor of four.

The practical consequences:

  1. Record everything at the child level: decision time, arrival mid, each child’s send time, fill price, size and venue, and the quote at the time.
  2. Measure against arrival first, then decompose: spread paid, temporary impact (the drift during the order that reverses afterwards), permanent impact (the part that persists), and timing (the market’s own moves while the order was worked, which a benchmark such as the index or the sector over the same minutes estimates).
  3. Normalise by volatility and participation before comparing orders: cost divided by σ√(Q/V) is comparable across days and instruments; raw basis points are not.
  4. Reconcile against the backtest. The backtest’s cost assumption is a hypothesis; live fills test it. QuantConnect and LEAN describes how a backtesting engine models fills; the gap between modelled and live fills is a common source of live underperformance, and Live versus backtest reconciliation measures it fill by fill against the cost model.
site_research/fieldnotes/twap.py
def implementation_shortfall(fill_prices, fill_sizes, arrival_mid, side=1, intended=None, end_mid=None):
    """Cost of a parent order against the mid at the moment it arrived, per unit of the size the
    trader intended, in the price's units.

    side = +1 for a buy, -1 for a sell; positive is a cost. `intended` is the parent's size Q
    (default: everything filled). If less than Q was filled, the unfilled part is charged its
    opportunity cost, the move from the arrival mid to `end_mid`, the mid when the order ended:

        IS = [ sum q_i (p_i - m_arrival) + (Q - sum q_i) (m_end - m_arrival) ] / Q

    Divide by the arrival mid (and multiply by 1e4) for basis points when prices are levels
    rather than bp offsets.
    """
    fill_prices, fill_sizes = np.asarray(fill_prices, float), np.asarray(fill_sizes, float)
    filled = fill_sizes.sum()
    q = filled if intended is None else float(intended)
    paid = (fill_sizes * (fill_prices - arrival_mid)).sum()
    missed = q - filled
    if missed > 1e-12 * q:
        if end_mid is None:
            raise ValueError("a partly filled order needs end_mid to price what was not filled")
        paid += missed * (end_mid - arrival_mid)
    return side * paid / q

References

  1. Perold, A. F. (1988). The implementation shortfall: Paper versus reality. Journal of Portfolio Management, 14(3), 4–9. https://doi.org/10.3905/jpm.1988.409150
  2. Berkowitz, S. A., Logue, D. E., & Noser, E. A. (1988). The total cost of transactions on the NYSE. Journal of Finance, 43(1), 97–112. https://doi.org/10.1111/j.1540-6261.1988.tb02591.x
  3. Kyle, A. S. (1985). Continuous auctions and insider trading. Econometrica, 53(6), 1315–1335. https://doi.org/10.2307/1913210
  4. Almgren, R., Thum, C., Hauptmann, E., & Li, H. (2005). Direct estimation of equity market impact. Risk, 18(7), 58–62.
  5. Tóth, B., Lempérière, Y., Deremble, C., de Lataillade, J., Kockelkoren, J., & Bouchaud, J.-P. (2011). Anomalous price impact and the critical nature of liquidity in financial markets. Physical Review X, 1(2), 021006. https://doi.org/10.1103/physrevx.1.021006
  6. Bouchaud, J.-P., Bonart, J., Donier, J., & Gould, M. (2018). Trades, quotes and prices: Financial markets under the microscope. Cambridge University Press. https://doi.org/10.1017/9781316659335
  7. Bertsimas, D., & Lo, A. W. (1998). Optimal control of execution costs. Journal of Financial Markets, 1(1), 1–50. https://doi.org/10.1016/s1386-4181(97)00012-8
  8. Almgren, R., & Chriss, N. (2000/2001). Optimal execution of portfolio transactions. Journal of Risk, 3(2), 5–39. https://doi.org/10.21314/jor.2001.041
  9. Obizhaeva, A. A., & Wang, J. (2013). Optimal trading strategy and supply/demand dynamics. Journal of Financial Markets, 16(1), 1–32. https://doi.org/10.1016/j.finmar.2012.09.001
  10. Brunnermeier, M. K., & Pedersen, L. H. (2005). Predatory trading. Journal of Finance, 60(4), 1825–1863. https://doi.org/10.1111/j.1540-6261.2005.00781.x