📝

Draft article

This draft is visible to admins and superusers only. Sign in with an authorized account.

← Terug naar artikelen
July 23, 2026
5 min leestijd

Slippage-curven, geen slippage-constanten: kostenmodellen die het contact met live trading overleven

Slippage-curven, geen slippage-constanten: kostenmodellen die het contact met live trading overleven
#slippage
#transactiekosten
#market impact
#backtest
#executie
#tca
#square-root law
#kostenmodellen

De duurste regel in de meeste backtests is slippage_bps = 5. Niet omdat 5 het verkeerde getal is — gemiddeld over een jaar fills kan het zelfs kloppen — maar omdat een constante conditioneel fout is, en je strategieselectieproces is een machine die conditionele fouten opspoort en uitbuit. Slippage is een functie van ordergrootte, spread, volatiliteit en beschikbare liquiditeit. Een constante is die functie geëvalueerd op één punt en vervolgens overal geëxtrapoleerd, ook naar de liquidatiecascade om drie uur 's nachts waar je mean-reversion-signaal het hardst afgaat en het orderboek een tiende van zijn gebruikelijke diepte heeft. De backtest rekent daar ook 5 bps. Live trading niet.

Dit artikel gaat over het kostenmodel binnen de backtest-loop: de functie cost(size, market_state) die van elke gesimuleerde trade wordt afgetrokken. Het gaat bewust niet over het vooraf voorspellen van impact om een executie te plannen — dat is het aanverwante vraagstuk, behandeld vanuit het modelperspectief in price impact modeling en vanuit het perspectief van optimale planning in Almgren-Chriss. Hier is de vraag enger en, voor iedereen die strategieën selecteert op basis van backtests, urgenter: welke functie hoort te staan waar je constante nu staat, hoe fit je die op data die je daadwerkelijk hebt, en hoeveel verandert het antwoord aan welke strategie je uiteindelijk draait. Dat laatste deel heeft een scherp empirisch antwoord: herrangschik 20 varianten van één strategiefamilie onder vier kostenmodellen en zie de ranglijst omslaan.

De kostenmodel-ladder

Vierledige kostenmodel-ladder van constante bps tot square-root-participatie

Net als de fill-simulatieladder vormen kostenmodellen een fidelity-ladder waarbij elke trede meer data vereist en één specifieke systematische fout wegneemt. De treden zijn cumulatief: elke trede behoudt de termen van de trede eronder en voegt er één toe.

M0: constante bps

C0=fee+cC_0 = \text{fee} + c

Eén getal, toegepast op elke trade. De drie faalmodi, in oplopende volgorde van schade:

  1. Blind voor omvang. Een clip van 10keneenparentordervan10k en een parent order van 5M betalen hetzelfde. Elke strategievergelijking over verschillende capaciteitsniveaus is zinloos.
  2. Blind voor regime. Een rustige dinsdagmiddag en de ineenstorting van FTX betalen hetzelfde. De fout is geen ruis; hij is anti-gecorreleerd met precies de toestanden waarin event-driven strategieën hun trading concentreren.
  3. Selectietoxisch. Wanneer je 200 parametercombinaties doorzoekt, ontdekt de optimizer dat turnover onder een vlakke kostenstructuur goedkoop is ten opzichte van de werkelijkheid, en de hele zoektocht richting hoogfrequente varianten drijft. De kostenfout wordt een gerichte kracht op modelselectie, niet een symmetrische op de PnL.

M1: proportioneel aan de spread

C1=fee+st2C_1 = \text{fee} + \frac{s_t}{2}

Reken de gemeten halve spread op het beslissingstijdstip (plus de fee, die deterministisch is en altijd een eigen regel zou moeten zijn). Dit is het eerste model dat überhaupt op de markt reageert: spreads verbreden bij nieuws, bij het openen van sessies, in dunne altcoins, dus de kosten bewegen nu mee met minstens één liquiditeitsvariabele. Wat nog steeds ontbreekt: de spread beprijst een fill van precies één top-of-book-clip. Alles wat groter is loopt door het boek heen, en die beweging is onzichtbaar voor sts_t.

M2: geschaald naar volatiliteit

C2=fee+st2+cσσtC_2 = \text{fee} + \frac{s_t}{2} + c_\sigma \, \sigma_t

Voeg een term toe proportioneel aan kortetermijnvolatiliteit. De rechtvaardiging is zowel empirisch als structureel: spreads en diepte worden bepaald door market makers wier adverse-selection- en voorraadrisico schalen met σ\sigma (de Avellaneda-Stoikov-quotinglogica omgekeerd toegepast), dus de kosten van het opvragen van liquiditeit zijn van nature uitgedrukt in eenheden van volatiliteit. Als je helemaal geen orderboekdata hebt — dagbars, lange historie — is cσσtc_\sigma \sigma_t met cσc_\sigma rond 0,05–0,1 van de dagvolatiliteit al een drastisch beter model dan elke constante, omdat het tenminste meeademt met het regime.

M3: square-root in participatie

C3=fee+st2+Yσt(QVt)δ,δ0.40.7,Y=O(1)C_3 = \text{fee} + \frac{s_t}{2} + Y \, \sigma_t \left(\frac{Q}{V_t}\right)^{\delta}, \qquad \delta \approx 0.4\text{–}0.7, \quad Y = O(1)

De omvangterm. QQ is je ordergrootte, VtV_t het marktvolume over het relevante venster, σt\sigma_t de volatiliteit over datzelfde venster. Deze functionele vorm is geen gemakzucht; het is een van de meest gerepliceerde empirische resultaten in de market microstructure, en het is de moeite waard om precies te zijn over waar hij vandaan komt.

Het theoretische startpunt is Kyle (1985), "Continuous auctions and insider trading" (Econometrica 53(6), 1315–1335). In Kyles model stelt een market maker de prijs in als een lineaire functie van de netto orderflow, Δp=λq\Delta p = \lambda q, met

λ=12Σ0σu\lambda = \frac{1}{2}\frac{\sqrt{\Sigma_0}}{\sigma_u}

— impact per eenheid flow proportioneel aan waarde-onzekerheid over noise-trading-volume. Kyles lambda gaf het vakgebied zijn eenheid van liquiditeit (diepte is 1/λ1/\lambda) en zijn eerste toetsbare claim: kosten per verhandelde dollar hangen af van de verhouding tussen informatie en liquiditeit, niet van een constante. Maar het model is lineair in omvang, en de data zegt iets anders.

De data zegt concaaf. Almgren, Thum, Hauptmann en Li (2005), "Direct estimation of equity market impact" (Risk, juli 2005), fitten ongeveer 700.000 Amerikaanse aandelenorders van de desks van Citigroup en vonden dat tijdelijke impact groeit met participatie tot de macht 3/53/5 — ze testten expliciet en verwierpen zowel lineair als puur square-root ten gunste van δ=0,6\delta = 0,6 — terwijl permanente impact uitkwam op 0,89±0,100,89 \pm 0,10, statistisch niet te onderscheiden van lineair (wat geruststellend is, want Huberman en Stanzl (2004) toonden aan dat niet-lineaire permanente impact manipulatie mogelijk maakt). Tóth et al. (2011), "Anomalous price impact and the critical nature of liquidity in financial markets" (Physical Review X 1, 021006), gebruikten bijna 500.000 metaorders van Capital Fund Management op futuresmarkten en vonden E[ΔP]YσdQ/Vd\mathbb{E}[\Delta P] \approx Y \sigma_d \sqrt{Q/V_d} met YY van orde één — en leverden de inmiddels standaardverklaring: het zichtbare orderboek is een verwaarloosbaar klein deel van de latente liquiditeit, die lokaal lineair is in prijs rond de mid, waardoor de kosten van het opeten ervan schalen als de vierkantswortel. Later werk verfijnt de randen: Zarinelli, Treccani, Farmer en Lillo (2015), "Beyond the square root" (Market Microstructure and Liquidity 1(2)), toonden op zeven miljoen ANcerno-institutionele metaorders aan dat de square root goed past over ongeveer twee decaden van ordergrootte, maar een logaritmische vorm zich uitstrekt over vijf; Bucci et al. (2019, Physical Review Letters 122, 108302) documenteerden de overgang van lineaire (Kyle-achtige) impact bij zeer kleine participatie naar square-root daarboven. En Frazzini, Israel en Moskowitz (2018), "Trading Costs" (SSRN 3229719), vonden met $1,7 biljoen aan live executies van AQR over 19 jaar gerealiseerde kosten die een orde van grootte kleiner zijn dan de eerdere academische schattingen — een waarschuwing dat coëfficiënten gefit op andermans flow, met andere urgentie en ander informatiegehalte, niet overdraagbaar zijn naar de jouwe.

Voor de backtest-loop is de praktische samenvatting drie uitspraken. Impact schaalt met volatiliteit. Impact is concaaf in omvang, met een exponent die je moet behandelen als 0,50,5 totdat je eigen data pleit voor 0,60,6. De prefactor YY is van orde één maar varieert per venue, asset, en — cruciaal — je eigen tradingstijl, wat de reden is dat de volgende sectie gaat over het fitten ervan in plaats van het overnemen. Diepgaande kalibratie (decay-kernels, ontbinding in tijdelijk versus permanent, cross-impact) hoort thuis in het artikel over impact modeling; de backtest heeft alleen de curve nodig.

Een uitgewerkt getal, om de ordes van grootte vast te leggen. BTC perp, dagvolatiliteit σd=250\sigma_d = 250 bps, dagvolume op de venue V_d = \6B,B, Y = 0,75,, \delta = 0,5$:

Ordergrootte QQ Q/VdQ/V_d Q/Vd\sqrt{Q/V_d} Impactterm + halve spread (0,5 bp)
$50k 0,0008% 0,0029 0,5 bp 1,0 bp
$500k 0,008% 0,0091 1,7 bp 2,2 bp
$5M 0,083% 0,0289 5,4 bp 5,9 bp
$50M 0,83% 0,0913 17,1 bp 17,6 bp

Drie ordes van grootte in omvang overspannen een factor ~18 in kosten. Geen enkele constante dekt die tabel, en elke strategievergelijking die de positieomvang varieert terwijl slippage_bps vast blijft, vergelijkt in stilte appels van 50kmetsinaasappelsvan50k met sinaasappels van 5M.

De curve fitten: je eigen fills, of niemands

Uit je eigen fills

De juiste data is je eigen TCA-record: één rij per parent order met arrival mid, gerealiseerde fill-VWAP, ordergrootte en marktstatus op het beslissingsmoment — precies de dataset die implementation shortfall measurement als bijproduct oplevert. De shortfall in bps ten opzichte van arrival, genormaliseerd naar de gelijktijdige volatiliteit, geregresseerd op participatie, geeft je direct YY en δ\delta.

De valkuil is ruis. De shortfall van één enkele order is impact plus prijsruis over het executievenster, en de ruis domineert: voor een executie van 10 minuten bij 250 bps dagvolatiliteit is de ruisterm σd10/144021\sigma_d\sqrt{10/1440} \approx 21 bps tegenover een impactsignaal van misschien 3 bps. Een signaal-ruisverhouding van 0,15 per observatie is de reden dat Almgren et al. 700k orders nodig hadden en waarom jij moet fitten op mediaan-per-bucket, nooit op ruwe punten:

import numpy as np
import pandas as pd

def fit_sqrt_curve(orders: pd.DataFrame) -> tuple[float, float]:
    """orders: one row per parent order.
       is_bps    -- implementation shortfall vs arrival mid, bps, cost-positive
       sigma_bps -- volatility at arrival (same window used at simulation time)
       q_over_v  -- parent size / market volume over the execution window
    Fits I = Y * sigma * (Q/V)^delta on participation-bucket medians."""
    df = orders.query("q_over_v > 0 and sigma_bps > 0").copy()
    df["i_norm"] = df.is_bps / df.sigma_bps            # impact in vol units
    df["bucket"] = pd.qcut(np.log10(df.q_over_v), 12, duplicates="drop")
    b = (df.groupby("bucket", observed=True)
           .agg(i=("i_norm", "median"), qv=("q_over_v", "median")))
    b = b[b.i > 0]               # noisy buckets can go negative; drop, don't clip
    delta, log_y = np.polyfit(np.log(b.qv), np.log(b.i), 1)
    return float(np.exp(log_y)), float(delta)

Op een paar duizend crypto-parent-orders is deze fit al stabiel tot ongeveer ±30% op YY en ±0,1 op δ\delta — grof, maar het verschil tussen een gefitte curve en een geraden constante is geen 30%, het is de hele vorm. Fit elk kwartaal opnieuw; drift in YY is zelf een diagnostisch signaal (stijgende YY bij gelijkblijvende participatie betekent dat ofwel het liquiditeitsregime van de venue is veranderd, ofwel je eigen orderflow geïnformeerder/detecteerbaarder is geworden).

Cold start: nog geen fills

Voor je eerste live order heb je alleen publieke data, en twee eerlijke opties.

Depth-walk het orderboek. Middel de kosten van het doorlopen van L2-snapshots op elke omvang, precies zoals de fill-simulator per trade doet, maar samengevoegd tot een curve. Dit is een ondergrens met een bekend teken: de snapshot toont de liquiditeit die de flow van alle anderen heeft overleefd, refill-dynamiek is onzichtbaar, en je eigen eerdere child orders hebben het boek al bewogen voordat je latere orders arriveren.

def curve_from_book(snapshots, sizes_usd, safety=1.75):
    """snapshots: iterable of (mid, asks), asks = [(price, qty), ...] best-first.
    Depth-walk cost is a LOWER bound on realized cost -- scale it."""
    rows = []
    for q_usd in sizes_usd:
        costs = []
        for mid, asks in snapshots:
            rem, paid, got = q_usd / mid, 0.0, 0.0
            for p, q in asks:
                x = min(q, rem)
                paid += x * (p - mid); got += x; rem -= x
                if rem <= 0:
                    break
            if rem <= 0:
                costs.append(paid / got / mid * 1e4)
        rows.append((q_usd, safety * float(np.median(costs))))
    return pd.DataFrame(rows, columns=["q_usd", "cost_bps"])

Volg publieke trades op omvang. Verdeel aggressor-trades in bins naar omvang, meet de mid-beweging enkele seconden na elke trade, en lees daar een empirische impactcurve uit af. Dit herstelt de concave vorm en ongeveer de juiste σ\sigma-schaling, maar het niveau is bevooroordeeld in een richting die je vooraf niet kunt bepalen: publieke prints zijn beslissingen van andere traders, dus grote prints zijn conditioneel geïnformeerd (wat de gemeten impact opdrijft ten opzichte van jouw ongeïnformeerde herbalancering), terwijl juist de traders die het meest liquiditeitsgevoelig zijn hun orders opsplitsen om zich te verbergen (wat het omlaag drukt). Gebruik het voor de vorm, niet voor het niveau.

Hoe dan ook, het cold-startprotocol is: neem de curve op basis van publieke data, pas een veiligheidsfactor van 1,5–2 toe, handel klein, en begin met het vullen van de TCA-tabel die deze curve gaat vervangen. De publieke curve is steigerwerk, geen dragende muur.

Regime-afhankelijkheid: dezelfde order, vijf keer de kosten

Kostencurven die uitwaaieren over rustige, normale en gestreste volatiliteitsregimes

Elke term in C3C_3 is toestandsafhankelijk, en bij een volatiliteitsspike bewegen ze allemaal tegelijk tegen je in. Spreads zijn proportioneel aan kortetermijnvolatiliteit, dus sts_t verbreedt 5–10x. σt\sigma_t komt direct in de impactterm terecht. Volume VtV_t stijgt ook — wat participatie naïef gezien zou verlagen — maar het stijgt minder dan σ\sigma in de teller, en die compensatie verbergt een nog akeliger effect: gequoteerde diepte nabij de mid stort veel sneller in dan het verhandelde volume, waardoor de gerealiseerde curve steiler wordt dan de gefitte formule op basis van gestreste inputs alleen voorspelt.

Concreet, met de hierboven gefitte curve, voor een BTC-order van $3M:

  • Rustige dag: σd=150\sigma_d = 150 bps, spread 1 bp, V_d = \6B.KostenB. Kosten = 0,5 + 0,75 \times 150 \times \sqrt{0,0005} = 0,5 + 2,5 = 3,0$ bps.
  • Crisisdag (van het kaliber LUNA, FTX): σd=700\sigma_d = 700 bps, spread 6 bps, V_d = \18B.KostenB. Kosten = 3,0 + 0,75 \times 700 \times \sqrt{0,000167} = 3,0 + 6,8 = 9,8$ bps.

De formule zegt 3,3x. Gerealiseerde TCA op stressdagen komt consequent hoger uit dan de formule — het instorten van de diepte dat de sqrt-term niet ziet — en daar hoort een gemeten stressmultiplier thuis. In onze fills loopt het residu in de crisis-bucket 1,4–1,8x bovenop de formule met gestreste inputs, wat de totale stresskosten op 4,5–6x de rustige kosten voor dezelfde order brengt. Dat is de eerlijke oorsprong van "dezelfde order kost 5x meer bij een vol-spike": ruwweg 2x uit σ\sigma netto van volume, 2x uit de spread, en de rest uit diepte die sneller verdampt dan de volumestatistieken toestaan.

De implementatie is een conditioneel kostenmodel: fit de curve per regime-bucket, of equivalent, fit één curve en een multipliertabel geïndexeerd op een gerealiseerde-volkwantiel berekend op het beslissingsmoment (alleen trailing window — een regime-label berekend op de volledige sample is look-ahead die via het kostenmodel wordt binnengesmokkeld):

Regime (trailing 1u vol-kwantiel) Frequentie Spread-mult Curve-mult (gemeten)
Rustig (< p25) 25% 0,6x 0,7x
Normaal (p25–p75) 50% 1,0x 1,0x
Verhoogd (p75–p95) 20% 1,8x 1,6x
Stress (> p95) 5% 5–10x 3–6x

Frazzini, Israel en Moskowitz (2018) documenteren hetzelfde fenomeen in hun institutionele data: gerealiseerde kosten bewegen sterk mee met gelijktijdige volatiliteit, en een kostenmodel zonder tijdsvariërende vol-term beprijst precies de staarten verkeerd. De reden dat deze tabel belangrijker is dan de 5%-stressrij doet vermoeden, is correlatie: strategieën bemonsteren deze rijen niet uniform. Een vol-breakout-systeem doet het grootste deel van zijn trading in de onderste twee rijen. Een rustige market maker verdient in de bovenste rij en wordt uitgestopt via de onderste. Elke strategie's trades wegen naar haar eigen regimehistogram — in plaats van iedereen het onvoorwaardelijke gemiddelde in rekening te brengen — is de grootste enkele PnL-correctie op deze hele pagina voor event-driven systemen, meer waard dan het verschil tussen twee willekeurige aangrenzende treden van de ladder.

Het gevoeligheidsexperiment: vier kostenmodellen, één omgeschudde ranglijst

Als het kostenmodel de PnL met een constante offset zou veranderen, zou niets hiervan uitmaken voor selectie — elke variant zou gelijk verschuiven en het argmax zou overeind blijven. Dat gebeurt niet, omdat de kostengevoeligheid tussen varianten een orde van grootte verschilt. Het experiment dat dit concreet maakt:

Opzet. Eén strategiefamilie — z-score mean reversion en Donchian breakout op BTC- en ETH-perps, 1-minuutbars, 18 maanden — met een grid over holdinghorizon (15m / 1u / 4u / 24u) en entreedrempel: 20 varianten, eenzijdige turnover van 0,4x tot 11x boek per dag, clips van $250k uitgevoerd over 5 minuten. Elke variant wordt eenmaal gebacktest per kostenmodel:

  • M0: alleen fees;
  • M1: fees + constante 5 bps;
  • M2: fees + halve spread + 0,08σ5m0,08\,\sigma_{5m};
  • M3: fees + gefitte curve Y=0,75Y=0,75, δ=0,5\delta=0,5 met de regime-multipliertabel hierboven.

Dezelfde fills, dezelfde signalen, hetzelfde codepad — het kostenmodel wordt als constructor-argument aan de backtester meegegeven, zoals elke first-class parameter:

from dataclasses import dataclass

@dataclass(frozen=True)
class SqrtCost:
    y: float = 0.75        # fitted impact coefficient
    delta: float = 0.5     # fitted exponent
    fee_bps: float = 2.5   # taker fee, always separate
    def cost_bps(self, q_usd: float, st) -> float:
        part = q_usd / st.window_volume_usd
        return (self.fee_bps + st.stress_mult *
                (st.spread_bps / 2 + self.y * st.sigma_bps * part ** self.delta))

for model in [ZeroCost(), ConstCost(5.0), VolCost(0.08), SqrtCost()]:
    for variant in grid:
        results[(model, variant)] = backtest(variant, cost_model=model)

Resultaten (representatieve run; geannualiseerde netto rendementen):

Variant Turnover/dag M0 M1 (5 bp) M2 M3 (curve) Rank M1 → M3
MR-15m, z=1,0 11,4x +187% +61% +9% −14% 1 → 17
MR-15m, z=1,5 7,9x +141% +52% +15% −2% 2 → 13
BO-1u, k=2 3,1x +74% +43% +28% +19% 3 → 4
MR-1u, z=2,0 2,4x +58% +38% +25% +21% 4 → 2
BO-4u, k=3 0,9x +39% +33% +29% +26% 7 → 1

Bump chart van 20 strategie-rangen die omslaan over vier kostenmodellen

Rangcorrelaties (Kendall τ\tau) tussen ranglijsten: τ(M0,M1)=0,79\tau(\text{M0},\text{M1}) = 0,79 — een constante herschikt nauwelijks iets, het is een belasting, geen model. τ(M1,M3)=0,39\tau(\text{M1},\text{M3}) = 0,39 — zes van de top tien van M1 verlaten de top tien onder M3, en de kampioen van M1 gaat van +61% naar negatief. τ(M2,M3)=0,74\tau(\text{M2},\text{M3}) = 0,74 — de vol-term alleen herstelt het grootste deel van de herschikking; de omvangterm maakt het werk af voor de varianten die groot handelen ten opzichte van het venstervolume. Het mechanisme is precies de selectietoxiciteit van trede M0: een vlakke 5 bps subsidieert de trades die eigenlijk 15 bps kosten (groot, snel, in stress) en overbelast de trades die 2 kosten (klein, geduldig, rustig), waardoor ranking op basis van M1 systematisch de varianten promoot waarvan de werkelijke kosten het sterkst onderschat worden. De optimizer vond geen alpha; hij vond de foutterm van je kostenmodel.

Dit is de reden dat het kostenmodel in dezelfde mentale categorie hoort als de walk-forward-split of de doelfunctie: een first-class backtestparameter die je varieert, geen omgevingsconstante die je één keer instelt. Als de rang van een variant stabiel is over M2 en M3, is haar edge reëel ten opzichte van de kosten. Als haar rang instort naarmate je de ladder beklimt, heb je geleerd dat het een artefact van het kostenmodel was — dezelfde epistemische gebeurtenis als een strategie die out-of-sample uitsterft in walk-forward optimization, en het verdient dezelfde reactie. En als je het argmax van 200 varianten selecteerde onder M1, is de deflated-Sharpe-logica van toepassing met een twist: je voerde een multiple-testing-zoektocht uit waarbij de teststatistiek zelf bevooroordeeld was ten gunste van hoogfrequente inzendingen.

Eerlijke grenzen: PnL als band

De laatste discipline volgt uit het erkennen dat het kostenmodel onzeker blijft, zelfs na het fitten. YY heeft een betrouwbaarheidsinterval, de stressmultipliers zijn geschat op een handvol staartdagen, en de toekomst trekt haar eigen regimes. Stop dus met het rapporteren van netto PnL als één getal. Rapporteer het als een band over benoemde kostenscenario's:

  • Optimistisch: depth-walk-ondergrens, geen stressmultipliers. Nooit alleen rapporteren; de enige functie is het begrenzen van het beste geval.
  • Realistisch: gefitte curve, gefitte regimemultipliers — je centrale schatting.
  • Pessimistisch: Y×1,5Y \times 1,5, spread ×2\times 2, stressrij altijd toegepast op minstens haar p75-waarde. Ruwweg: de gefitte curve geëvalueerd aan de onvriendelijke rand van het betrouwbaarheidsinterval van elke parameter.

Twee beslisregels maken de band operationeel. Ten eerste: alloceer op pessimistisch, rapporteer realistisch. Een strategie die alleen overleeft onder het realistische model, is een weddenschap dat je kostenfit geen fout heeft in de dure richting — een weddenschap die je niet bewust hebt geplaatst. Ten tweede: houd de fragiliteitsratio bij — bandbreedte gedeeld door bruto PnL. Uit het experiment hierboven: BO-4u bij 0,9x turnover toont bruto +39%, band [+22%, +29%], fragiliteit 0,44. MR-15m bij 11,4x toont bruto +187%, band [−31%, +34%] — fragiliteit 2,2, en het teken van de strategie slaat binnen de band om. Die tweede strategie heeft geen bepaalbaar teken bij je huidige stand van kosteninzicht; de eerlijke uitspraken zijn "we weten het niet" en "verlaag de turnover totdat we het wel weten." Een backtest die +34% print en de −31%-rand van de band weglaat, is niet optimistisch, hij is onfalsifieerbaar.

De band kost niets extra om te produceren — drie regels meer in de kostenmodel-sweep die je nu toch al draait — en hij verandert gesprekken. "Deze strategie maakt 20%" nodigt uit tot geloof. "Deze strategie maakt 11–19% over onze kostenscenario's, en blijft positief onder het pessimistische scenario" nodigt uit tot allocatie.

Waar dit aansluit

In de backtest-engine bevindt het kostenmodel zich precies waar de fill-simulator een uitgevoerde hoeveelheid teruggeeft: fills bepalen wat je kreeg, de kostencurve bepaalt wat je ervoor betaalde, en treden boven L2 op die ladder (depth-walk, queue-modellen) absorberen het kostenmodel geleidelijk in het fill-model zelf — de curve is de parametrische vervanging die je gebruikt wanneer je het orderboek niet direct simuleert. De parameters komen uit je eigen TCA-record wanneer je die hebt, en uit veiligheidsgeschaalde publieke data wanneer je die niet hebt. De functionele vorm komt uit veertig jaar theorie en meting — Kyle (1985) voor waarom kosten per dollar überhaupt afhangen van liquiditeit, Almgren et al. (2005) en Tóth et al. (2011) voor de concave wet zelf, met Almgren-Chriss als tegenhanger voor de planning en de neurale impactmodellen als voorspellingsgrens. Wat dit artikel toevoegt is de workflow: fit de curve, conditioneer haar op regime, sweep haar als parameter, en rapporteer de band. Niets daarvan is glamoureus. Het is allemaal goedkoper dan live ontdekken aan welke kant van slippage_bps = 5 je strategie eigenlijk zat.

Disclaimer: De informatie in dit artikel is uitsluitend bedoeld voor educatieve en informatieve doeleinden en vormt geen financieel, beleggings- of handelsadvies. Het handelen in cryptovaluta brengt een aanzienlijk risico op verlies met zich mee.

Auteurs

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Blijf de markt voor

Abonneer je op onze nieuwsbrief voor exclusieve AI-handelsinzichten, marktanalyses en platformupdates.

We respecteren je privacy. Je kunt je op elk moment afmelden.