Quantitative Finance · Book 10 · Execution

Microstructure and Execution

Microstructure and Execution · Execution

27Build: an Agent-Based Market

An exchange simulator with nobody on it is an empty room. Put a few kinds of simple traders in it, some who know nothing, some who know the value, some who follow trends and one who makes markets, and it starts to look like a market; which of them it needs in order to look like one is itself a finding. This chapter describes the agent library this book has used since chapter 11, firm.agentmkt, adds the two agent types it lacked (chartists and an inventory-skewing market maker), calibrates the population to a target market by the method of simulated moments, and then takes it apart one agent type at a time to see which fact each one carries.

27.1 Agents and their information

Definition 27.1 (Agent-based model)

An agent-based model of a market is a simulation in which prices and volumes are not specified but emerge from the orders of many simulated traders (agents), each following its own rule with its own information, through a trading mechanism such as a limit order book.

Definition 27.2 (Fundamentalist agent, chartist agent)

A fundamentalist agent trades toward a value it believes the asset is worth: it buys when the price is below that value and sells when it is above, more often the larger the gap. A chartist agent trades on the price’s own recent history, typically in the direction of its recent trend.

Agent-based markets come in two traditions. The first gives agents strategies and asks what dynamics follow: Lux and Marchesi (1999) built a market of fundamentalists and chartists whose news process had neither fat tails nor any time dependence in volatility, and found that the interactions of the agents produced both. The second removes strategy almost entirely: Farmer, Patelli and Zovko (2005) let agents place and cancel orders at random (chapter 1’s zero-intelligence model) and, on eleven London Stock Exchange stocks, explained 96% of the cross-sectional variance of the spread and 76% of that of the price diffusion rate with one free parameter. Chiarella and Iori (2002) put heterogeneous rule-based traders into an order-driven market with a central matching mechanism and studied how their strategies, the tick and the lifetime of orders shape spreads, volume and volatility. The population here takes a little from each: most of its order flow is random, and a few rules give it direction.

The population. The three types on the left run as one agent, Population, on independent Poisson clocks; the chartists belong to it too, but are new in this chapter; the market maker and the execution agents are separate agents with their own sessions and a 20-microsecond latency.
Figure 27.1. The population. The three types on the left run as one agent, Population, on independent Poisson clocks; the chartists belong to it too, but are new in this chapter; the market maker and the execution agents are separate agents with their own sessions and a 20-microsecond latency.

Population runs its traders as clocks whose rates are recomputed after every event (Figure 27.1). Liquidity providers add one-lot limit orders on each side, half of them one tick from the opposite best quote and the rest up to ten ticks behind it, and every resting order is cancelled at a constant rate. Noise takers send market orders whose signs come in runs (next section). Fundamentalists send market orders toward a hidden value VV, a random walk of one-tick jumps, at a rate proportional to the distance between VV and the mid: they are also this market’s informed traders (chapter 4), since nobody else sees VV. Chartists send market orders in the direction of the mid’s change over the last 30 seconds, at a rate proportional to its size. The noise orders and the jumps of VV are drawn in advance from the seed, so two runs that differ by one agent share them (common random numbers).

    def on_timer(self, ctx, tag):
        c = self.cfg
        if tag != "tick":
            _, kind, x = self.exo[tag[1]]
            if kind == "noise":
                ctx.send(Order(side="B" if x > 0 else "S", qty=abs(x), price=0, tif="I"))
            else:
                self.v += x * c.tick
                self.v_path.append((ctx.now_ns, self.v))
            return
        r = self._r
        k = int(self.rng.choice(len(r), p=r / r.sum()))
        if k == 0:
            side = "B" if self.rng.random() < 0.5 else "S"
            b, _, a, _ = ctx.top(1)
            ref = a if side == "B" else b
            if ref is None:
                ref = int(round(self._mid(ctx) / c.tick)) * c.tick + (c.tick if side == "B" else -c.tick)
            d = 1 if self.rng.random() < c.near else 1 + int(self.rng.choice(c.depth, p=self.w))
            self._add(ctx, side, ref - d * c.tick if side == "B" else ref + d * c.tick)
        elif k == 1 and self.live:
            cl = self.live[int(self.rng.integers(len(self.live)))]
            ctx.cancel(cl)
            self._drop(cl)
        elif k == 2:
            ctx.send(Order(side="B" if self.v > self._mid(ctx) else "S", qty=100, price=0, tif="I"))
        elif k == 3:                                                  # a chartist follows the trend
            ctx.send(Order(side="B" if self.trend > 0 else "S", qty=100, price=0, tif="I"))
        self._next(ctx)
Listing 27.1. The population’s event: an exogenous noise order or jump of the hidden value, or else one of its clocks chosen in proportion to its rate, a provider’s limit order, a cancellation, a fundamentalist’s or a chartist’s market order. code/firm/agentmkt/firm_agentmkt.py

27.2 Liquidity providers and their inventory

Definition 27.3 (Market-making agent)

A market-making agent quotes on both sides continuously and manages the inventory its fills leave it with, usually by moving its quotes against that inventory so as to attract the trades that reduce it (inventory skew).

The population’s providers never hold anything: their orders are independent of what they have filled. The new MarketMaker does: every half second it quotes two lots at the other traders’ best bid and ask (one tick inside when their spread is wider than two ticks), both moved against its inventory by a skew in ticks per lot held, and it stops adding to a position beyond 20 lots. Its reference excludes its own quotes; an early version that did not walked its own bid down, refresh after refresh, whenever it was long, since each new quote was set below the previous one.

    def on_timer(self, ctx, tag):
        live = ctx.working()
        mine = {o["ref"] for o in live}
        bk = ctx.book(1).book
        b, a = self._best(bk, 1, mine), self._best(bk, -1, mine)
        want = {}
        if b is not None and a is not None:
            inside = self.tick if a - b > 2 * self.tick else 0
            inv = ctx.position(1) / 100
            shift = int(round(self.skew * inv)) * self.tick
            if inv < self.max:
                want["B"] = min(b + inside - shift, a - self.tick)
            if inv > -self.max:
                want["S"] = max(a - inside - shift, b + self.tick)
        for o in live:
            if want.get(o["side"]) == o["price"]:
                del want[o["side"]]
            else:
                ctx.cancel(o["cl"])
        for side, px in want.items():
            ctx.send(Order(side=side, qty=100 * self.lots, price=int(px)))
        ctx.set_timer(int(self.refresh * SEC), 0)
Listing 27.2. The market maker’s refresh: the others’ best quotes, a shift of the skew times the inventory in lots, a quote kept if it is already at the right price and replaced otherwise. code/firm/agentmkt/firm_agentmkt.py
skew (ticks per lot)inventory (lots, root mean square)profit per hour (USD)spread (ticks)
014.5−116-116 (203)1.031
0.14.2448 (98)1.023
0.31.6545 (67)1.024
Table 27.1. The market maker in the calibrated market at three inventory skews, three hours each: the time-weighted root mean square of its inventory, its profit (cash after fees plus the inventory at the last mid) with the standard deviation across hours, and the market’s mean spread. Data: mx_agents.maker_study.

Without skew the maker’s inventory wanders (Figure 27.2) and it loses money: its fills follow the fundamentalists, who know the value, so the inventory it accumulates is the wrong way round when VV moves (chapter 4’s adverse selection). With a skew of 0.3 ticks per lot its inventory stays within a few lots and its hourly profit is positive and steadier (Table 27.1); the skew is the practical form of the inventory models of chapter 4 (and of Book 2, chapter 30). The market’s spread hardly changes: the providers keep it near one tick whatever the maker does.

The market maker’s inventory through one hour of the calibrated market, with the same order flow, without skew and with a skew of 0.3 ticks per lot. Without skew it swings from one 20-lot limit to the other. Data: mx_agents.maker_study.
Figure 27.2. The market maker’s inventory through one hour of the calibrated market, with the same order flow, without skew and with a skew of 0.3 ticks per lot. Without skew it swings from one 20-lot limit to the other. Data: mx_agents.maker_study.

27.3 Execution agents and metaorders

A metaorder (Book 7, chapter 9) cut into children sends many market orders of one sign; this is the mechanism Lillo, Mike and Farmer (2005) proposed for the long memory of order signs: if the sizes of large orders have a power-law tail, P(V>v)∝v−αP(V > v) \propto v^{-\alpha}, and they are executed in children of constant size, the autocorrelation of order signs decays as τ−(α−1)\tau^{-(\alpha - 1)}, which is long memory (not summable) when α<2\alpha < 2. The noise takers of firm.agentmkt are that mechanism in a line: their signs come in runs whose lengths are Pareto with tail α\alpha (the parameter run_tail), each run a metaorder. Execution agents proper, Metaorder for a schedule of market-order children and the algorithms of chapters 16 to 22, are added to the same simulator as separate agents; chapter 11 measured their impact against the same session without them.

Autocorrelation of the signs of aggressive orders in the calibrated market (run tail = 2.5), with and without the noise takers’ sign runs, three hours each; the excess the runs add, with the power law their tail implies. The excess is drawn out to lag 20, where it is lost in noise. Data: mx_agents.sign_curves.
Figure 27.3. Autocorrelation of the signs of aggressive orders in the calibrated market (run tail α=2.5\alpha = 2.5), with and without the noise takers’ sign runs, three hours each; the excess the runs add, with the power law their tail implies. The excess is drawn out to lag 20, where it is lost in noise. Data: mx_agents.sign_curves.

The calibrated market has α=2.5\alpha = 2.5, so its runs predict an excess autocorrelation falling as τ−1.5\tau^{-1.5}: short memory. Measured over lags 1 to 7 the excess falls with a log-log slope of −1.15-1.15 (Figure 27.3), a little flatter than the asymptotic law, and is gone by lag 10. What remains without the runs, about 0.07 to 0.09 out to lag 20, is the fundamentalists’ doing: while VV is away from the mid they send order after order in the same direction.

27.4 Calibrating to stylised facts

Definition 27.4 (Method of simulated moments)

The method of simulated moments estimates the parameters of a model that can be simulated but whose moments have no closed form: it chooses the parameters that minimise a weighted distance between moments computed from the data and the same moments averaged over simulations of the model, the simulations using the same random draws at every candidate parameter.

Franke and Westerhoff (2012) estimated small fundamentalist-chartist models this way, with moments chosen from the stylised facts (Book 7, chapter 5) of daily index returns. Here the target is one hour of Book 7’s synthetic market, firm.tape without its news window, measured on eight hours: it has Hawkes-clustered noise flow, metaorders, informed traders and a random activity level, none of which the agent population has as such. The seven facts are the excess kurtosis of 30-second mid returns, their lag-1 autocorrelation, volatility clustering (the mean autocorrelation of absolute returns at lags 1 to 5), the autocorrelation of the signs of aggressive orders at lags 1 and 10 (the prints of one order counted once), the time-weighted mean spread and the mean depth at the best. The distance is the sum of squared differences between simulated and target means, each scaled by the target’s standard deviation across its eight hours.

def distance(sim: dict, target: dict, scale: dict) -> float:
    """Sum over facts of ((simulated - target) / scale)^2."""
    return float(sum(((sim[k] - target[k]) / scale[k]) ** 2 for k in target))


def msm(run, grid, target: dict, scale: dict, seeds) -> dict:
    """The method of simulated moments on a grid: run(params, seed) -> facts; the average over seeds (the same seeds
    at every point: common random numbers) is compared with the target; returns the best point, its facts and every
    point's distance."""
    rows = []
    for params in grid:
        sims = [run(params, s) for s in seeds]
        mean = {k: float(np.mean([x[k] for x in sims])) for k in target}
        rows.append((distance(mean, target, scale), params, mean))
    rows.sort(key=lambda x: x[0])
    return {"best": rows[0][1], "distance": rows[0][0], "facts": rows[0][2], "all": rows}
Listing 27.3. The method of simulated moments on a grid: the distance in target standard deviations, and the average of the same seeds’ facts at every grid point. code/firm/agentmkt/firm_agentmkt.py

Three parameters are calibrated, on a grid of three values each: the noise takers’ rate (0.9, 1.2, 1.5 a second), their run tail (none, 1.5, 2.5) and the chartists’ rate (0, 0.05, 0.1 a second per tick of trend); the providers, fundamentalists and market maker (skew 0.1) are fixed. Each point is run for three hours with the same three seeds.

The distance between simulated and target facts at a noise rate of 1.2 orders a second, by the chartists’ rate and the run tail, three hours per point with the same seeds. Data: mx_agents.calibration.
Figure 27.4. The distance between simulated and target facts at a noise rate of 1.2 orders a second, by the chartists’ rate and the run tail, three hours per point with the same seeds. Data: mx_agents.calibration.

The best point is a noise rate of 1.2, a run tail of 2.5 and a chartists’ rate of 0.05, at a distance of 10.1 over its three calibration hours; the starting point (noise 0.9, no runs, no chartists) was at 27.9 (Figure 27.4). On six fresh hours the calibrated population is at 5.4, and six fresh hours of the target market itself are at 1.7 from the target’s mean: what sampling noise alone gives. Figure 27.5 shows where the rest comes from: the calibrated market has too little volatility clustering and too little depth, and a little too much sign memory at lag 1.

Each fact’s gap to the target in target standard deviations, for the starting point and for the calibrated population. The squares of the calibrated bars sum to the distance on fresh hours. Data: mx_agents.calibration.
Figure 27.5. Each fact’s gap to the target in target standard deviations, for the starting point and for the calibrated population. The squares of the calibrated bars sum to the distance on fresh hours. Data: mx_agents.calibration.

The ablation takes the calibrated population and removes one agent type at a time on the six fresh hours, with the same seeds: the sign runs (the noise takers keep their rate but their signs become independent), the chartists, the fundamentalists, the market maker. Table 27.2 gives each fact’s move in target standard deviations.

removedkurtosisreturnclusteringsignsignspreaddepth
acfacf 1acf 10
sign runs+1.32+1.32+0.02+0.02−0.63-0.63−2.77\mathbf{-2.77}−0.35-0.35−0.38-0.38+0.10+0.10
(0.79)(0.29)(1.12)(0.15)(0.25)(0.19)(0.06)
[2pt] chartists+1.11\mathbf{+1.11}−0.10-0.10−0.72-0.72+0.02+0.02−0.18-0.18−0.29-0.29+0.09+0.09
(0.55)(0.20)(0.67)(0.10)(0.27)(0.11)(0.02)
[2pt] fundamentalists+8.55\mathbf{+8.55}−0.47-0.47−0.73-0.73+0.87+0.87−2.42-2.42−1.29-1.29+0.96+0.96
(2.65)(0.25)(0.88)(0.14)(0.40)(0.15)(0.05)
[2pt] market maker−0.79-0.79−1.77-1.77+0.31+0.31−0.69-0.69−1.00-1.00+9.44\mathbf{+9.44}−0.75-0.75
(0.29)(0.25)(0.57)(0.10)(0.19)(0.37)(0.04)
[2pt]
Table 27.2. Ablation: the change in each fact when one agent type is removed from the calibrated population, in target standard deviations, the mean of six hours with the same seeds (paired standard errors in brackets below; the largest move of each type in bold). Data: mx_agents.ablation.

Each type carries something (Table 27.2). The sign runs carry the lag-1 sign memory (−2.77-2.77, standard error 0.15 standard deviations). The fundamentalists carry the price’s movement: without them the mid is pinned between rare jumps, so the kurtosis of returns explodes (+8.6+8.6) and the long-lag sign memory falls (−2.42-2.42). The market maker carries the spread (+9.4+9.4): without it, the spread widens by 0.15 ticks. The chartists carry nothing this test can see: their largest move, on kurtosis, is +1.11+1.11 with a standard error of 0.55, two standard errors. Removing the noise takers altogether leaves a market in which only fundamentalists trade, with a sign autocorrelation near one; it is not in the table because every fact moves.

27.5 What agent-based markets can and cannot tell you

An agent-based market is a tool for questions about mechanisms: what happens to spreads if the tick halves (chapter 6), whether a band attracts the price (chapter 25), how an algorithm’s shortfall depends on the other traders’ reaction (chapter 28). Replaying a historical tape cannot answer them, because a replayed market does not react; Vyetrenko and coauthors (2020) compared market replay with interactive agent-based configurations on a list of realism metrics taken from the stylised facts, and found the interactive ones more realistic, and more so when the agents’ fundamental value came from historical data rather than a mean-reverting random walk. ABIDES (Byrd, Hybinette and Balch 2020), an open-source simulator of tens of thousands of agents with an exchange agent whose messages follow Nasdaq’s ITCH and OUCH, is built for exactly this.

What it cannot tell you is why real traders do what they do. Matching seven facts to within 5.4 does not identify the agents: other populations, with other rules, would match them as well (here the chartists could be removed at little cost), and the facts left unmatched, volatility clustering first, say that something in the target (its random activity level) is missing from the population. The calibration answers “is this population good enough for the question?”, not “is this how the market works?”; and the answer depends on the facts chosen and their weights. The fair use is comparative: the same population, with and without an algorithm, a rule or a trader, and the same seeds.

27.6 Tutorial: a market that looks like a market

Goal. Populate firm.exchsim with agents, calibrate them to a target market’s stylised facts, and find which fact each agent type carries. End state: Tables 27.1 and 27.2, Figures 27.2, 27.3, 27.4 and 27.5.

  1. Populate. PopulationConfig(lo_rate, near, cancel, depth, noise, run_tail, fund, v_rate, chart, chart_window); session(cfg, seconds, seed, agents=[MarketMaker(skew=0.1)]); the Result’s tape() is in firm.tape’s format.
  2. Measure. facts(tape, 30.0); chapter 3’s firm_lobstats.report(tape) for the book’s own facts (depth profile, lifetimes, fleeting orders, resilience).
  3. Calibrate. mx_agents.target(), calibration() (msm over the grid with common seeds).
  4. Take apart. ablation(), sign_curves(), maker_study(); draw with fig_agents.py.

What to change next. Add a switching rule between fundamentalists and chartists (Lux and Marchesi’s mechanism) and see whether the clustering gap closes; target a real tape’s facts; weight the moments by their simulated covariance instead of the target’s variances.

27.7 Build: agentmkt

Purpose. The agent library and population runner on firm.exchsim, used since chapter 11 and by the tutorials of Books 11 and 12: a reacting market with known ingredients.

Interface. PopulationConfig, Population(cfg, seed, seconds) (.exo, .v_path), Metaorder(plan), MarketMaker(lots, skew, max_lots, refresh_s), session(cfg, seconds, seed, agents, venue); facts(tape, sample_s), FACTS, distance(sim, target, scale), msm(run, grid, target, scale, seeds).

Rules. Deterministic and seeded per agent; exogenous flow drawn in advance so that runs share it; output in firm.tape’s format; the default population unchanged by later additions (the chartists and the activity curve are off by default).

Acceptance tests. code/firm/agentmkt/tests/: the same seed gives the same tape and the exogenous flow is shared; a metaorder trades its plan; the activity curve shapes the flow; the market maker only rests and bounds its inventory; one sign per aggressive order; msm finds the minimum of a known function.

Stretch. Strategy switching; agents with learning rules; several instruments and venues in one population.

Sources and further reading

  • T. Lux and M. Marchesi, “Scaling and criticality in a stochastic multi-agent model of a financial market”, Nature 397, 1999.
  • J. D. Farmer, P. Patelli and I. I. Zovko, “The predictive power of zero intelligence in financial markets”, Proceedings of the National Academy of Sciences 102(6), 2005.
  • C. Chiarella and G. Iori, “A simulation analysis of the microstructure of double auction markets”, Quantitative Finance 2(5), 2002.
  • F. Lillo, S. Mike and J. D. Farmer, “Theory for long memory in supply and demand”, Physical Review E 71, 066122, 2005.
  • R. Franke and F. Westerhoff, “Structural stochastic volatility in asset pricing dynamics: estimation and model contest”, Journal of Economic Dynamics and Control 36(8), 2012.
  • D. Byrd, M. Hybinette and T. H. Balch, “ABIDES: towards high-fidelity multi-agent market simulation”, Proceedings of the 2020 ACM SIGSIM Conference on Principles of Advanced Discrete Simulation.
  • S. Vyetrenko, D. Byrd, N. Petosa, M. Mahfouz, D. Dervovic, M. Veloso and T. H. Balch, “Get real: realism metrics for robust limit order book market simulations”, Proceedings of the First ACM International Conference on AI in Finance, 2020.

27.8 Exercises

Exercise 27.1 ★

The target’s lag-1 sign autocorrelation is 0.158 with a standard deviation of 0.046 across its hours; the calibrated population gives 0.212 on fresh hours. How many target standard deviations is the gap, and what does it add to the distance?

Solution

Solution of Exercise 27.1.

(0.212−0.158)/0.046=1.17(0.212-0.158)/0.046=1.17 standard deviations, which adds 1.172=1.41.17^2=1.4 to the distance (a quarter of the fresh distance of 5.4).

Exercise 27.2 ★

By Lillo, Mike and Farmer’s result, at what rate does the sign autocorrelation decay for run tails of 1.5 and 2.5? Which is long memory?

Solution

Solution of Exercise 27.2.

As τ−(α−1)\tau^{-(\alpha-1)}: τ−0.5\tau^{-0.5} for a tail of 1.5 and τ−1.5\tau^{-1.5} for 2.5. Only the first is long memory (α<2\alpha<2: the autocorrelations are not summable); the calibrated tail of 2.5 gives short memory.

Exercise 27.3 ★

If the population were exactly right and the facts’ simulated variances equal to the target’s, what distance would you expect from the mean of six simulated hours against the mean of eight target hours, with seven facts? Compare with the fresh distance and the floor.

Solution

Solution of Exercise 27.3.

Each fact’s scaled gap has variance 1/6+1/8=0.291/6+1/8=0.29, so the expected distance is 7×0.29=2.07\times0.29=2.0. The floor, 6 fresh target hours against the 8-hour mean, is 1.7, close to the same expectation; the calibrated population’s 5.4 is about 2.7 times that: a misfit beyond sampling noise, mostly in clustering, depth and lag-1 sign memory.

Exercise 27.4 ★★

Why is the calibrated point’s distance on its three calibration hours larger than on six fresh hours?

Solution

Solution of Exercise 27.4.

Two reasons. The mean of three hours carries more simulation noise than the mean of six (7×(1/3+1/8)=3.27\times(1/3+1/8)=3.2 expected against 2.0), and the point was chosen because its three hours happened to land closest among 27, so its in-sample distance also reflects which hours they were: in the calibration hours its kurtosis was 3.11, on fresh hours 1.90. The fresh distance is the honest one.

Exercise 27.5 ★★

Why does removing the fundamentalists make the kurtosis of returns explode?

Solution

Solution of Exercise 27.5.

Without them nothing pushes the price between the noise orders, which the providers’ deep book absorbs: the mid sits still for most 30-second intervals and moves only when a run of noise orders or a chartist burst empties a level. Returns that are mostly zero with rare jumps have a very large kurtosis. The fundamentalists are what makes the price follow VV in small steps.

Exercise 27.6 ★★

Why does the market maker lose money without inventory skew and make money with it, when its quotes are otherwise the same?

Solution

Solution of Exercise 27.6.

Its fills are adversely selected: the fundamentalists trade against it when VV has moved, so without skew its inventory grows the wrong way and stays there while the price keeps moving against it. Skew makes its quotes attract the trades that reduce the inventory, so it holds less (1.6 lots root mean square at a skew of 0.3, against 14.5) for less time and earns the spread on flow that turns over.

Exercise 27.7 ★★★

Coding. Recalibrate on the five return and order-flow facts only (drop spread and depth), from the grid’s stored facts. Does the best point change, and what is its distance?

Solution

Solution of Exercise 27.7.

Yes. On the five facts the best grid point becomes a noise rate of 1.5, a run tail of 2.5 and a chartists’ rate of 0.1, at a distance of 5.1 on the calibration hours; the chapter’s point comes second at 7.7. The faster noise flow thins the book (depth about 9 lots against the target’s 24) and widens the spread (about 1.08 ticks against 1.04, more than two target standard deviations): the full calibration rejected it for its book, which the five facts no longer see. The facts chosen decide the answer.

Exercise 27.8 ★★★

Find the flaw. “Our calibrated agent-based market reproduces the stylised facts, so real traders are fundamentalists, chartists and noise traders in these proportions.”

Solution

Solution of Exercise 27.8.

Matching facts does not identify mechanisms: different populations can produce the same seven moments (here removing the chartists moved no fact significantly, so any chartist share near the calibrated one fits as well), the facts left unmatched show the population lacks something the target has, and the target is itself a model. The calibration says the population is good enough for some questions, not what real traders are.

27.9 Problem: A Market That Looks Like a Market

Problem 27.1

Weekend problem — a market that looks like a market

A research lead wants a simulated market to test execution algorithms in, and asks how realistic it is and what makes it so.

Part I — Agents.

  1. Define an agent-based model, a fundamentalist agent and a chartist agent.
  2. What did Lux and Marchesi find, and what did Farmer, Patelli and Zovko find?
  3. Describe the population’s liquidity providers, noise takers, fundamentalists and chartists.
  4. Why are the fundamentalists also the informed traders here?
  5. Why are the noise orders drawn in advance from the seed?

Part II — Inventory and metaorders.

  1. Define a market-making agent and describe MarketMaker’s quotes.
  2. What went wrong when the maker’s reference included its own quotes?
  3. Give the maker’s inventory and profit at the three skews.
  4. State Lillo, Mike and Farmer’s result, and how the noise takers implement it.
  5. What does the sign-autocorrelation figure show about the calibrated tail?

Part III — Calibration.

  1. Define the method of simulated moments, and say why the same seeds are used at every grid point.
  2. What is the target, and what are the seven facts?
  3. Give the grid and the best point.
  4. State the named result: the distance between simulated and target facts after calibration, in and out of sample, against the starting point and the floor, and the fact each agent type carries.
  5. Which facts does the calibrated population miss, and why?

Part IV — Judgement.

  1. What did Vyetrenko and coauthors find about replay and agent-based markets?
  2. Why can a replayed tape not answer an execution question that an agent market can?
  3. Why does matching the facts not identify the agents?
  4. What would you tell the research lead about using this market to compare algorithms?
  5. In one sentence: what is an agent-based market for?
Solution

Solution of Problem 27.1.

1. See the definitions. 2. Lux and Marchesi: interactions of fundamentalists and chartists produce fat tails and clustered volatility from news that has neither. Farmer, Patelli and Zovko: random order placement explains 96% of the cross-sectional variance of spreads and 76% of that of price diffusion on 11 London stocks with one free parameter. 3. One-lot limit orders on both sides, half one tick from the opposite best and the rest up to ten ticks behind it, each cancelled at a constant rate; market orders at a constant rate with signs in Pareto runs; market orders toward the hidden value at a rate proportional to the gap; market orders along the 30-second trend at a rate proportional to its size. 4. They alone see VV. 5. So that runs that differ by one agent share them (common random numbers). 6. See the definition; two lots at the others’ best quotes (one tick inside when their spread exceeds two ticks), shifted by the skew times the inventory, and no bid (offer) beyond 20 lots long (short). 7. Each new bid was set below its own previous bid when long, so the bid walked down refresh after refresh. 8. 14.5, 4.2 and 1.6 lots; −116-116, 448 and 545 USD an hour for skews 0, 0.1 and 0.3. 9. Power-law large orders split into constant children give sign autocorrelation decaying as τ−(α−1)\tau^{-(\alpha-1)}; the noise takers’ sign runs have Pareto lengths with tail α\alpha. 10. An excess from the runs falling with slope −1.15-1.15 over lags 1 to 7 (the law says −1.5-1.5), gone by lag 10; the rest comes from the fundamentalists. 11. See the definition; so that differences between grid points are not differences of luck. 12. Eight hours of firm.tape without news; kurtosis and lag-1 autocorrelation of 30-second returns, clustering, sign autocorrelation at lags 1 and 10, spread, depth. 13. Noise 0.9, 1.2, 1.5; run tail none, 1.5, 2.5; chartists 0, 0.05, 0.1; best 1.2, 2.5, 0.05. 14. Named result: after calibration the distance is 10.1 on the three calibration hours and 5.4 on six fresh hours, against 27.9 for the starting point and a floor of 1.7 for the target market itself; the sign runs carry the lag-1 sign memory (−2.77-2.77, standard error 0.15), the fundamentalists the price’s movement (kurtosis +8.6+8.6 without them), the market maker the spread (+9.4+9.4), and the chartists nothing significant (+1.11+1.11 with a standard error of 0.55). 15. Volatility clustering, depth and lag-1 sign memory: the target has a random activity level and Hawkes-clustered flow the population lacks. 16. Interactive agent configurations were more realistic than replay, and more so with a fundamental from historical data. 17. A replayed tape does not react to the algorithm’s orders, so impact and the others’ response are missing. 18. Several populations match the same facts; an agent type can be removed with little change. 19. Use it comparatively, algorithm against algorithm with the same seeds, and check the conclusions do not hinge on the facts it misses. 20. To answer “what if” questions about mechanisms in a market that reacts.

27.10 Interview questions

Interview question 27.1 ★ researcher

What is a zero-intelligence market, and what can it explain?

Solution

Solution of Interview question 27.1.

Agents that place and cancel limit and market orders at random rates, with no strategy; with the order-flow rates as inputs it predicts spreads and price diffusion across stocks well (Farmer, Patelli and Zovko), showing how much the mechanism alone explains.

Interview question 27.2 ★★ researcher

How would you calibrate an agent-based market to a stock, and how would you know you had overfitted?

Solution

Solution of Interview question 27.2.

Choose the facts that matter for the question (returns, order flow, book), measure them on the stock with their sampling variability, and minimise a weighted distance over the population’s parameters by simulated moments with common random numbers; check the fit on fresh simulated days and on facts not used in the fit, and compare the distance with what sampling noise alone gives.

Interview question 27.3 ★★ developer

How do you make an agent-based simulation deterministic, and why does it matter for comparing two algorithms?

Solution

Solution of Interview question 27.3.

One event queue ordered by time and a tie-breaking sequence, every random stream seeded per agent and per purpose, no wall clock or thread timing in the logic; then the two algorithms face the same exogenous flow and their difference is not noise.

Interview question 27.4 ★★ trader

Why should a market maker skew its quotes on inventory, and by how much?

Solution

Solution of Interview question 27.4.

To make the fills that reduce inventory more likely and those that add to it less, which cuts inventory risk and adverse selection; enough that the inventory mean-reverts within the holding time the desk accepts, which in the chapter’s market meant 0.1 to 0.3 ticks per lot.

Interview question 27.5 ★★ mle

You train an execution policy by reinforcement learning in an agent-based market. What can go wrong when it meets the real one?

Solution

Solution of Interview question 27.5.

It learns the simulator’s quirks: agents that do not adapt to it, liquidity that refills by fixed rules, missing facts such as clustering; it may exploit patterns absent in reality. Randomise the population, test on held-out configurations and on real data before trading.

Interview question 27.6 ★★★ risk

A desk validates a new algorithm only in an agent-based simulator. What would you ask before approving it?

Solution

Solution of Interview question 27.6.

Which facts the simulator matches and misses, whether the algorithm’s advantage survives other plausible populations and seeds, whether its behaviour in stressed scenarios (halts, gaps, one-sided flow) was tested, and a plan for a limited live trial with controls.

Terms defined in this chapter

See all 2333 terms in the glossary