← Kembali ke artikel
July 20, 2026
Bacaan 5 minit

Implementation shortfall dan DIY TCA: mengukur kos sebenar eksekusi anda

Implementation shortfall dan DIY TCA: mengukur kos sebenar eksekusi anda
#execution
#tca
#implementation-shortfall
#markouts
#kos-transaksi
#algotrading
#backtest
#market-microstructure

Setiap meja dagangan institusi mempunyai saluran paip transaction cost analysis. Hampir tiada sesiapa yang menjalankan bot kripto memilikinya. Persediaan tipikal mencatat fill, menjumlahkan yuran, dan memanggil perbezaan antara PnL backtest dengan PnL live sebagai "slippage" — satu residual tunggal yang tidak dijelaskan, yang menyerap latensi, spread, impact, adverse selection, dan setiap pesanan yang tidak terisi yang telah lari daripada harga. Anda tidak boleh membetulkan kos yang diukur sebagai satu nombor sahaja. Mekanisme untuk mengukurnya dengan betul telah wujud sejak 1988, ia bukan proprietari, dan ke atas log fill anda sendiri ia hanya kira-kira 200 baris Python. Artikel ini membina mekanisme tersebut.

Ganjarannya bukan dashboard yang lebih cantik. Backtest anda mengandungi model kos — pemalar slippage, kebarangkalian fill, pekali impact — dan setiap parameter di dalamnya pada masa ini hanyalah andaian. TCA ke atas fill live adalah satu-satunya ground truth yang boleh digunakan untuk menentukur parameter tersebut. Kami telah membina bahagian simulasi bagi gelung ini dalam Fill simulation: tangga dari fantasi harga penutup kepada realiti sedar-queue; artikel ini membina bahagian pengukuran.

Kertas berbanding realiti: apa yang Perold sebenarnya ukur

Helah asas ini dikaitkan dengan André Perold (1988, "The Implementation Shortfall: Paper Versus Reality," Journal of Portfolio Management 14(3), 4–9). Jalankan dua portfolio secara selari. Portfolio kertas melaksanakan setiap keputusan serta-merta, dalam saiz tanpa had, pada kos sifar, pada harga yang berlaku pada saat keputusan dibuat. Portfolio sebenar ialah apa yang bot anda benar-benar lakukan: fill separa, quote yang dikejar, baki yang dibatalkan, yuran. Implementation shortfall ialah perbezaan dalam pulangan kedua-duanya.

Definisi ini penting kerana apa yang ia enggan sembunyikan. Penyata yuran menunjukkan komisen. Laporan fill-berbanding-limit-price tidak menunjukkan apa-apa langsung (anda tidak pernah fill lebih teruk daripada limit anda — secara struktur memang begitu). Portfolio kertas mengenakan caj untuk segala-galanya: hanyutan antara keputusan dan ketibaan, spread yang anda silangi, impact yang anda cetuskan, dan — yang paling penting — pesanan yang tidak pernah terisi sementara harga terus lari. Wagner dan Edwards (1993, "Best Execution," Financial Analysts Journal 49(1), 65–71) menyebut yuran yang kelihatan sebagai hujung gunung ais; bagi apa-apa dengan turnover, bahagian yang tenggelam lebih mendominasi.

Tetapkan notasi. Satu pesanan induk (parent order): sisi s{+1,1}s \in \{+1, -1\} (beli/jual), saiz XX. Harga keputusan PdP_d ialah mid yang dilihat oleh strategi anda ketika isyarat dicetuskan. Fill tiba sebagai (pj,xj)(p_j, x_j) dengan jumlah kuantiti terisi x=jxjXx = \sum_j x_j \le X. Pada horizon TT (induk selesai, dibatalkan, atau tamat masa), mid ialah PTP_T. Yuran eksplisit ialah FF. Implementation shortfall dari segi matawang:

IS=sjxj(pjPd)kos eksekusi  +  s(Xx)(PTPd)kos peluang  +  F,\mathrm{IS} = \underbrace{s \sum_j x_j\,(p_j - P_d)}_{\text{kos eksekusi}} \;+\; \underbrace{s\,(X - x)(P_T - P_d)}_{\text{kos peluang}} \;+\; F,

dinormalkan kepada basis points dengan membahagikannya dengan notional kertas XPdX \cdot P_d. Positif bermakna anda membayar. Terma pertama ialah kos fill anda berbanding portfolio kertas; yang kedua ialah kos peluang Perold — baki yang tidak terisi ditanda pada harga yang ia terlepas; yang ketiga ialah satu-satunya bahagian yang diakui oleh penyata pertukaran anda.

Satu nota konvensyen: industri menyebut "arrival price," dan dalam kebanyakan TCA ekuiti, arrival bermaksud mid ketika pesanan sampai ke pasaran. Bagi sebuah bot, masa keputusan dan masa ketibaan berbeza disebabkan latensi dalaman anda sendiri ditambah baris gilir rate-limit — satu kos sebenar yang boleh diukur. Jadi kami mengekalkan kedua-dua cap masa dan kedua-dua harga, dan membiarkan penguraian memisahkannya.

Penguraian: delay, impact, timing, peluang, yuran

Satu nombor IS sahaja memberitahu anda bahawa eksekusi itu mahal. Ia tidak memberitahu anda sebabnya, dan pembetulan untuk komponen yang berbeza adalah sama sekali berbeza — anda tidak menyelesaikan kos delay dan kos impact dengan perubahan yang sama. Implementation shortfall yang diperluas oleh Robert Kissell (Kissell, 2006, "The Expanded Implementation Shortfall: Understanding Transaction Cost Components," Journal of Trading 1(3), 6–16; dikembangkan secara mendalam dalam The Science of Algorithmic Trading and Portfolio Management, Academic Press, 2013) menguraikan jumlah keseluruhan kepada komponen, setiap satu boleh dikaitkan dengan peringkat tersendiri dalam kitaran hayat pesanan. Versi praktikal, menggunakan arrival mid P0P_0 (mid pada pengesahan pertukaran pertama):

IS=sX(P0Pd)delay  +  sjxj(pjP0)kos dagangan  +  s(Xx)(PTP0)peluang  +  F.\mathrm{IS} = \underbrace{s\,X\,(P_0 - P_d)}_{\text{delay}} \;+\; \underbrace{s \sum_j x_j\,(p_j - P_0)}_{\text{kos dagangan}} \;+\; \underbrace{s\,(X - x)(P_T - P_0)}_{\text{peluang}} \;+\; F.

Identiti ini kembali tepat kepada definisi Perold — kembangkan terma-terma dan P0P_0 akan bersaling hapus. Setiap bahagian mempunyai pemilik tersendiri:

Kos delay sX(P0Pd)sX(P_0 - P_d): hanyutan harga antara isyarat dicetuskan dan child order pertama anda menjadi live di pertukaran. Ini adalah infrastruktur anda — serialisasi, rangkaian, baris gilir rate-limit, semakan risiko. Jika isyarat anda mempunyai alpha horizon-pendek yang sebenar, kos delay adalah tempat ia bocor terlebih dahulu; min yang secara konsisten positif menunjukkan pasaran bergerak ke arah anda sebelum anda tiba — alpha momentum yang mereput, atau seseorang yang lebih pantas mendagangkan isyarat yang sama.

Kos dagangan sjxj(pjP0)s\sum_j x_j(p_j - P_0): apa yang fill anda bayar berbanding arrival — spread yang disilangi ditambah market impact ditambah hanyutan intra-jadual. Ini adalah kad laporan algoritma eksekusi, dan kuantiti yang sebenarnya dimodelkan oleh penyelidikan eksekusi. Almgren, Thum, Hauptmann dan Li (2005, "Direct Estimation of Equity Market Impact," Risk 18(7), 58–62) mengukurnya ke atas kira-kira 700,000 pesanan ekuiti AS daripada meja dagangan Citigroup (Disember 2001–Jun 2003) dan mendapati kos dagangan berskala mengikut volatiliti harian dan kadar penyertaan — impact sementara mengikut power law dalam kadar dagangan dengan eksponen hampir 3/5, impact kekal hampir linear dengan saiz. Kami akan menggunakan semula bentuk fungsian mereka apabila kami menentukur.

Risiko timing: bukan terma dalam penguraian min tetapi varians di sekelilingnya. Menyebarkan induk sepanjang masa mengurangkan impact jangkaan dan mendedahkan anda kepada volatiliti; bagi jadual dengan kedudukan baki q(t)q(t), sisihan piawai kos berskala sebagai σ0Tq(t)2dt\sigma \sqrt{\int_0^T q(t)^2\,dt}. Ini tepat sekali pertukaran (trade-off) yang dioptimumkan oleh kerangka kerja Almgren–Chriss. Dalam laporan TCA anda, ia muncul sebagai dispersi IS merentasi induk-induk — laporkan sisihan piawai di sebelah setiap min, atau min akan mengambil semua perhatian dan ekor (tails) akan mengambil semua wang anda.

Kos peluang s(Xx)(PTP0)s(X - x)(P_T - P_0): kuantiti yang tidak terisi ditanda pada harga terminal. Bagi strategi pasif, ini sering menjadi komponen terbesar dan paling kurang diperiksa, dan ia adalah terma yang menjadikan keseluruhan kerangka kerja ini jujur — lebih lanjut mengenai ini dalam bahagian perangkap, kerana mengabaikannya adalah cara paling biasa orang menipu diri sendiri dengan TCA.

Yuran FF: bahagian eksplisit. Dalam kripto, catat yuran selepas diskaun (tahap VIP, rebat token yang ditukar pada harga masa-fill) dan kekalkan rebat maker bertanda — yuran negatif adalah data, bukan bunyi bising.

Contoh berangka

Beli X=10X = 10 BTC. Isyarat dicetuskan dengan Pd=60,000P_d = 60{,}000; notional kertas $600,000. Child order pertama diakukan dengan mid P0=60,012P_0 = 60{,}012. Sepanjang dua minit berikutnya, 8 BTC terisi pada VWAP 60,072; harga sedang trending menjauh, algo menghormati limitnya, dan baki 2 BTC dibatalkan dengan mid pada PT=60,240P_T = 60{,}240. Yuran gabungan 2.5 bps ke atas notional terisi.

Komponen Formula USD bps daripada kertas
Delay 10×(60,01260,000)10 \times (60{,}012 - 60{,}000) 120 2.0
Kos dagangan 8×(60,07260,012)8 \times (60{,}072 - 60{,}012) 480 8.0
Peluang 2×(60,24060,012)2 \times (60{,}240 - 60{,}012) 456 7.6
Yuran 8×60,072×2.5e-48 \times 60{,}072 \times 2.5\text{e-}4 120 2.0
Jumlah IS 1,176 19.6

Penyata pertukaran menunjukkan $120. Kos sebenar untuk melaksanakan keputusan itu ialah $1,176 — faktor sepuluh, dengan dua komponen terbesar tidak kelihatan kepada perakaunan berasaskan yuran. Kira-kira 40% daripadanya datang daripada kuantiti yang tidak pernah didagangkan. Laporan TCA yang hanya menganalisis fill akan menilai induk ini sebagai 8 bps dan menganggapnya baik-baik sahaja.

Penguraian air terjun (waterfall) implementation shortfall daripada portfolio kertas kepada portfolio sebenar

Markouts: menilai adverse selection

Implementation shortfall menilai pesanan induk. Ia tidak memberitahu apa-apa tentang kualiti fill individu — khususnya, sama ada anda secara sistematik berdagang dengan pihak lawan yang mengetahui sesuatu yang anda tidak tahu. Itu diukur melalui markouts: tanda setiap fill kepada mid pada horizon tetap selepas ia berlaku.

πτ=s(mtf+τpf)mtf×104 bps,\pi_\tau = \frac{s\,(m_{t_f + \tau} - p_f)}{m_{t_f}} \times 10^4 \ \text{bps},

di mana pfp_f ialah harga fill pada masa tft_f dan mtm_t ialah mid pada masa tt. Ini adalah PnL mark-to-market per unit bagi fill pada horizon τ\tau, dan ia mempunyai anatomi yang bersih pada τ=0\tau = 0: fill maker bermula pada ++separuh-spread (anda membeli pada bid, mid berada di atas anda); fill taker bermula pada -separuh-spread. Apa yang berlaku apabila τ\tau berkembang ialah kandungan maklumat dagangan tersebut:

  • τ=1\tau = 1s mengasingkan sniping dan pickoff quote-basi. Jika fill maker anda sudah berada dalam kerugian satu saat selepas terisi, peserta yang lebih pantas sedang memukul quote anda pada saat ia menjadi salah harga — gelung kemas kini quote anda lebih perlahan daripada gelung trigger mereka. Markout ini adalah diagnostik latensi, bukan diagnostik strategi.
  • τ=10\tau = 10s mengukur adverse selection klasik: fill diikuti oleh pergerakan berterusan melalui harga anda. Bagi seorang market maker, ini adalah kos yang mesti diatasi oleh spread capture; mikrostruktur ekuiti memanggil kuantiti berkaitan ini realized spread, diinstitusikan dalam laporan SEC Rule 605 pada horizon 5 minit. Kripto bergerak lebih pantas; 10–60s adalah jalur yang setara.
  • τ=60\tau = 60s memberitahu anda sama ada fill membawa momentum yang menentang anda melebihi horizon mikrostruktur — bagi strategi taker, sama ada alpha isyarat anda pada 60s melebihi spread-tambah-impact yang anda bayar untuk masuk. Lengkung markout taker yang bermula pada 4-4 bps dan tidak pernah menyeberangi sifar adalah strategi yang membayar untuk kemasukan yang alpha-nya tidak mampu membiayai.

Ketidaksimetrian maker/taker adalah keseluruhan ekonomi dagangan pasif dalam dua lengkung. Lengkung maker yang bermula pada +2+2 bps (separuh-spread) dan mereput kepada 1-1 bps menjelang 60s bermakna: anda menangkap spread dan memberi balik lebih banyak, dan tiada tahap rebat yang membetulkan itu. Lengkung yang sama tetapi mendatar pada +0.7+0.7 bps menunjukkan enjin quoting itu berbaloi. Ini juga tepat apa yang diandaikan oleh backtest touch-fill naif — sebuah simulator yang mengisi anda apabila harga menyentuh limit anda mengabaikan hakikat bahawa terisi berkorelasi dengan tersalah, itulah sebabnya anak tangga sedar-queue dalam tangga fill-simulation memerlukan markout terukur sebagai input dan bukan sebagai andaian.

Lengkung markout berbanding horizon untuk fill maker dan taker menunjukkan reputan adverse selection

Pengiraan adalah merge_asof ke atas strim mid anda sendiri:

import pandas as pd

def markouts(fills: pd.DataFrame, mids: pd.DataFrame,
             horizons=("1s", "10s", "60s")) -> pd.DataFrame:
    """fills: [ts, price, qty, side, liquidity]; mids: [ts, mid].
    Both UTC-indexed and sorted. Mid stream must be from YOUR captured
    feed, not candles reconstructed later."""
    fills = fills.sort_values("ts").reset_index(drop=True)
    mids  = mids.sort_values("ts")
    out = fills.copy()
    for h in horizons:
        probe = fills[["ts"]].copy()
        probe["ts"] = probe["ts"] + pd.Timedelta(h)
        m = pd.merge_asof(probe, mids, on="ts", direction="backward")
        out[f"mo_{h}"] = (fills["side"] * (m["mid"].values - fills["price"])
                          / fills["price"] * 1e4)
    return out

def markout_report(mo: pd.DataFrame) -> pd.DataFrame:
    """Qty-weighted markouts by liquidity flag. Weighting matters:
    a 0.001 BTC fill and a 2 BTC fill are not equal evidence."""
    cols = [c for c in mo.columns if c.startswith("mo_")]
    def agg(g):
        w = g["qty"] / g["qty"].sum()
        return pd.Series({c: (g[c] * w).sum() for c in cols}
                         | {"n": len(g), "qty": g["qty"].sum()})
    return mo.groupby("liquidity").apply(agg)

Hiris laporan ini lebih lanjut mengikut simbol, jam dalam sehari, dan jarak quote daripada mid. Hirisan paling boleh diambil tindakan bagi strategi maker ialah markout-mengikut-kedudukan-queue-semasa-fill: fill di hadapan queue-segar mempunyai harga yang sangat berbeza daripada fill di mana tahap tersebut telah disapu melalui anda.

Saluran paip: apa yang perlu dicatat

TCA mati pada lapisan pencatatan, bukan lapisan matematik. Matematik di atas memerlukan nombor-nombor yang dibuang oleh kebanyakan bot, dan tiada satu pun daripadanya boleh dibina semula kemudian daripada sejarah pertukaran. Perkara yang tidak boleh dinegosiasi:

  • Decision mid, daripada feed anda sendiri, pada masa keputusan. Bukan candle close pertukaran, bukan pembinaan semula kemudian. Penanda aras ialah "harga yang dipercayai oleh strategi saya ketika ia membuat keputusan" — hanya proses anda pada saat itu yang mengetahuinya.
  • Kedua-dua cap masa: masa keputusan dan masa ack pertama, jika tidak kos delay tidak dapat diukur dan secara senyap bercampur dengan kos dagangan.
  • Setiap fill dengan cap masa pertukaran, yuran, dan penanda maker/taker — masa terima tempatan anda tercemar oleh latensi masuk anda sendiri.
  • Induk yang dibatalkan dan tamat tempoh, dicatat seperti segala-galanya yang lain. Induk dengan sifar fill adalah baris paling mahal dalam jadual.
  • Strim mid berterusan (atau strim L1) pada kehalusan 100–250ms, disimpan cukup lama untuk mengira markout. Jika anda sudah merekod buku pesanan untuk simulator fill, ini adalah percuma.

Dua jadual rata sudah mencukupi:

PARENTS = {
    "parent_id":    "str",
    "strategy":     "str",
    "symbol":       "str",
    "venue":        "str",
    "algo":         "str",        # twap | pov | sniper | quote | ...
    "side":         "int8",       # +1 buy, -1 sell
    "qty":          "float64",    # parent size, base units
    "limit_px":     "float64",    # NaN for unconstrained
    "decision_ts":  "datetime64[ns, UTC]",
    "decision_mid": "float64",    # mid your feed showed at decision_ts
    "arrival_ts":   "datetime64[ns, UTC]",   # first exchange ack
    "arrival_mid":  "float64",
    "end_ts":       "datetime64[ns, UTC]",   # filled / cancelled / expired
    "terminal_mid": "float64",
    "mkt_volume":   "float64",    # market volume over [arrival_ts, end_ts]
    "sigma_bps":    "float64",    # realized vol estimate at decision time
}

FILLS = {
    "parent_id": "str",
    "ts":        "datetime64[ns, UTC]",  # exchange timestamp
    "price":     "float64",
    "qty":       "float64",
    "fee":       "float64",      # quote ccy, post-discount, signed
    "liquidity": "str",          # maker | taker
    "venue":     "str",
}

Fungsi atribusi adalah transkripsi langsung daripada penguraian:

import numpy as np

def is_decomposition(p: pd.Series, fills: pd.DataFrame) -> dict:
    """Expanded implementation shortfall for one parent, bps of paper
    notional. Sign convention: positive = cost."""
    s, X = p["side"], p["qty"]
    paper = X * p["decision_mid"]
    x = fills["qty"].sum()
    delay = s * X * (p["arrival_mid"] - p["decision_mid"])
    trade = s * ((fills["price"] - p["arrival_mid"]) * fills["qty"]).sum()
    oppty = s * (X - x) * (p["terminal_mid"] - p["arrival_mid"])
    fees  = fills["fee"].sum()
    bps   = lambda v: 1e4 * v / paper
    return {
        "parent_id": p["parent_id"],
        "delay_bps": bps(delay), "trade_bps": bps(trade),
        "oppty_bps": bps(oppty), "fees_bps":  bps(fees),
        "is_bps":    bps(delay + trade + oppty + fees),
        "fill_ratio": x / X,
        "participation": x / max(p["mkt_volume"], x),
    }

def tca_table(parents: pd.DataFrame, fills: pd.DataFrame) -> pd.DataFrame:
    fg = dict(tuple(fills.groupby("parent_id")))
    empty = fills.iloc[0:0]
    rows = [is_decomposition(p, fg.get(p["parent_id"], empty))
            for _, p in parents.iterrows()]
    return parents.merge(pd.DataFrame(rows), on="parent_id")

Dan pertanyaan atribusi, iaitu tempat TCA berhenti menjadi perakaunan dan mula menjadi penyelidikan:

tca = tca_table(parents, fills)

def wavg(g: pd.DataFrame, col: str) -> float:
    w = g["qty"] * g["decision_mid"]          # notional weights
    return (g[col] * w).sum() / w.sum()

comp = ["delay_bps", "trade_bps", "oppty_bps", "fees_bps", "is_bps"]
by_strat = tca.groupby("strategy").apply(
    lambda g: pd.Series({c: wavg(g, c) for c in comp}
                        | {"is_std": g["is_bps"].std(), "n": len(g)}))

done = tca[tca["fill_ratio"] > 0.99]
done["pov_bin"] = pd.qcut(done["participation"], 6)
impact_curve = done.groupby("pov_bin").apply(lambda g: wavg(g, "trade_bps"))

tca["hour"] = tca["arrival_ts"].dt.hour
by_hour = tca.groupby("hour").apply(lambda g: wavg(g, "is_bps"))

by_venue = tca.groupby("venue").apply(
    lambda g: pd.Series({"is_bps": wavg(g, "is_bps"),
                         "is_std": g["is_bps"].std(),
                         "fill_ratio": g["fill_ratio"].mean(), "n": len(g)}))

Pertanyaan 4 ialah jadual input yang dioptimumkan oleh smart order router — routing tanpa TCA per-venue adalah routing mengikut jadual yuran, iaitu mengikut komponen kos yang paling kecil (Smart order routing dalam kripto mengambil jadual ini sebagai titik permulaannya). Bersama modul markout, ini adalah ~200 baris yang dijanjikan.

Menutup gelung: menentukur model kos backtest

Di sinilah saluran paip ini membuahkan hasil. Backtest anda menegaskan nombor-nombor: slippage_bps = 5, lengkung kebarangkalian fill, pekali impact. Setiap satu daripadanya adalah dakwaan tentang eksekusi live, dan jadual TCA adalah eksekusi live. Gelungnya: ukur dengan TCA, sesuaikan model kos, jalankan backtest dengan model yang disesuaikan, berdagang, ukur semula.

Gelung penentukuran tertutup daripada fill live melalui atribusi TCA kepada model kos backtest

Bagi kos taker, pinjam bentuk fungsian daripada Almgren et al. (2005) dan bukannya mencipta yang baru. Hasil kajian mereka — kos berkadar dengan volatiliti harian didarab dengan kuasa kadar penyertaan — memberikan model dua-parameter:

trade_bpsσbps=a(xV)b,\frac{\text{trade\_bps}}{\sigma_{\text{bps}}} = a \cdot \left(\frac{x}{V}\right)^{b},

dengan anggaran ekuiti b0.6b \approx 0.6 sebagai prior. Sesuaikan pada min terbin, bukan induk mentah — kos induk individu didominasi oleh bunyi bising (itu adalah terma risiko-timing), dan regresi log-log ke atas data mentah akan dengan senang hati menyesuaikan bunyi bising tersebut:

done = tca[(tca["fill_ratio"] > 0.99) & (tca["participation"] > 0)]
done["norm_cost"] = done["trade_bps"] / done["sigma_bps"]
bins = done.groupby(pd.qcut(done["participation"], 8)).agg(
    pov=("participation", "mean"), cost=("norm_cost", "mean"))
bins = bins[bins["cost"] > 0]                # can't log a negative bin
b, log_a = np.polyfit(np.log(bins["pov"]), np.log(bins["cost"]), 1)

def taker_cost_bps(participation, sigma_bps, a=np.exp(log_a), b=b):
    return a * sigma_bps * participation ** b

Kemudian bersikap jujur tentang jidar ralat (error bars). Pasukan Almgren mempunyai 700,000 pesanan dan masih melaporkan eksponen temporary-impact sebagai 0.600±0.0380.600 \pm 0.038; sebuah bot dengan 2,000 induk tidak layak menganggarkan bb secara bebas bagi setiap simbol. Rejim praktikal: kumpulkan merentasi simbol selepas menormalkan dengan σ\sigma, mengecutkan bb secara kuat ke arah 0.6 (atau hanya tetapkannya dan hanya sesuaikan aa), dan sesuaikan semula setiap bulan. Jika aa yang disesuaikan anda hanyut ke atas, jejak (footprint) anda telah membesar atau pasaran telah menipis — dalam kedua-dua kes backtest perlu mengetahuinya.

Bagi strategi maker, sasaran penentukuran adalah berbeza dan datang daripada dua modul yang lain:

  • Kebarangkalian fill: model queue simulator fill meramalkan P(fill)P(\text{fill}) bagi setiap sel (jarak-spread, kedudukan-queue); log induk anda menyediakan nisbah fill sebenar bagi setiap sel. Ketidaksepakatan adalah pepijat simulator dengan rujukan grid yang disertakan.
  • Adverse selection: gantikan andaian tersirat simulator bahawa "fill boleh saling ditukar" dengan jadual markout yang diukur — fill maker simulasi pada jarak dd pada jam hh membawa π10s(d,h)\pi_{10s}(d, h) yang diukur sebagai potongan mark-to-market segera. Satu perubahan ini adalah perbezaan antara backtest maker yang berhalusinasi dengan yang menjejaki realiti; ia adalah input penentukuran yang hilang yang dikenal pasti dalam artikel fill-simulation.
  • Dispersi kos: masukkan taburan IS, bukan minnya, ke dalam backtest. Model kos yang hanya menganjak min tidak dapat menghasilkan semula drawdown yang dicipta oleh risiko timing; malah lognormal yang disesuaikan kepada IS per-induk mengatasi pemalar tetap.

Rawatan penuh lengkung slippage — bentuk fungsian, pelarasan mengikut rejim, bila power law itu gagal — adalah artikel tersendiri: Lengkung slippage dan model kos untuk backtest. Intinya di sini adalah seni bina: model dalam artikel tersebut tidak dapat disesuaikan tanpa jadual daripada artikel ini.

Perangkap

Literatur TCA telah berusia berdekad-dekad, begitu juga cara-cara untuk memanipulasinya. Tiga mod kegagalan menyumbang kepada kebanyakan penipuan diri sendiri.

Manipulasi penanda aras (benchmark gaming). Sebarang penanda aras selain harga arrival boleh "dipeluk" (hugged). Contoh klasik ialah VWAP: algoritma yang dinilai berbanding VWAP selang boleh menjejakinya dalam lingkungan satu basis point sementara kedudukan berdarah dua puluh berbanding arrival, kerana penanda aras itu hanyut bersama harga yang anda sendiri sedang tolak — dan pada penyertaan yang bermakna, cetakan (prints) anda sendiri adalah VWAP tersebut, jadi menjejakinya adalah kerja rumah yang menilai diri sendiri. Kami telah membedah politik penanda aras dalam TWAP vs VWAP vs POV; peraturan di sisi TCA lebih ringkas: penanda aras dipilih sebelum berdagang, dan IS-berbanding-arrival sentiasa dikira walaupun scheduler dinilai berbanding penanda aras penjadualannya sendiri. Variasi yang lebih halus ialah manipulasi arrival: jika komponen yang menetapkan decision_ts dapat melihat momentum jangka-pendek, ia boleh mengatur masa "keputusan" untuk mempercantikkan terma delay. Cap masa keputusan adalah milik lapisan isyarat, dicatat sebelum sebarang logik eksekusi dijalankan.

Survivorship bias dalam analisis fill-sahaja. Kondisikan analisis kos anda ke atas fill dan eksekusi pasif akan kelihatan percuma. Secara konkrit: 100 induk beli pasif, satu tick di bawah mid. Enam puluh terisi, dan — kerana pasif — terisi pada harga purata 3 bps lebih baik daripada arrival: "kos" terukur 3-3 bps, sebuah laporan yang membanggakan. Empat puluh yang tidak pernah terisi adalah tepat yang mana harga naik menjauh; tandakan mereka 25 bps merugikan (adverse) pada pembatalan dan nombor jujurnya ialah 0.6×(3)+0.4×25=+8.20.6 \times (-3) + 0.4 \times 25 = +8.2 bps. Laporan fill-sahaja dan laporan sebenar berbeza sebanyak 11 bps dan dari segi tanda. Ini bukan kes tepi — ia adalah mekanisme dagangan pasif itu sendiri: mendapat fill berkorelasi dengan harga melalui anda, iaitu pengkondisian yang sama yang menjadikan backtest touch-fill sebagai fantasi. Kos peluang bukan penambahbaikan pilihan bagi IS; ia adalah terma yang mempertahankan keseluruhan pengukuran daripada bias pemilihan. Bias yang sama mempunyai variasi taker: pesanan IOC yang terlepas, pesanan yang ditolak oleh rate limit atau semakan risiko — jika kegagalan tidak dicatat, kos daripada kegagalan tersebut tidak diukur, dan ia paling besar tepat dalam pasaran pantas di mana strategi anda paling mahukan dagangan tersebut.

Pelbagai jerat (foot-guns), secara ringkas: arrival mid yang dibina semula daripada candle pertukaran (feed anda dan candle tersebut tidak sepakat tepat pada saat ia penting); purata bps per-induk tanpa pemberat notional (seribu fill habuk mengatasi undi satu pesanan sebenar); yuran dicatat sebelum diskaun; markout mid diambil daripada venue yang berbeza daripada fill (asas silang-venue menyamar sebagai adverse selection); dan pada perps, membiarkan akruan funding bocor ke dalam tetingkap eksekusi — funding adalah satu kos, tetapi bukan kos eksekusi, dan mencampurkannya meracuni kedua-dua analisis.

Apa yang perlu dilakukan minggu ini

Tambah dua jadual log kepada bot anda — skema di atas adalah senarai lajur, bukan projek. Jangan backfill apa-apa; dua minggu log jujur mengatasi setahun pembinaan semula. Jalankan penguraian dan tiga horizon markout. Anda akan mempelajari komponen mana yang mendominasi (hampir tidak pernah yuran), sama ada fill pasif anda dipilih secara merugikan (adversely selected) melebihi spread capture-nya, dan sejauh mana pemalar kos backtest anda tersasar daripada lengkung terukur. Kemudian masukkan semula lengkung yang disesuaikan ke dalam simulator dan jalankan semula backtest yang mula-mula menyuruh anda menjalankan strategi ini. Portfolio kertas Perold, tiga puluh lapan tahun kemudian, masih menjadi satu-satunya lawan jujur yang dimiliki oleh portfolio sebenar anda.

Penafian: Maklumat yang disediakan dalam artikel ini adalah untuk tujuan pendidikan dan maklumat sahaja dan bukan merupakan nasihat kewangan, pelaburan, atau dagangan. Dagangan mata wang kripto melibatkan risiko kerugian yang ketara.

Pengarang

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

Kekal Mendahului Pasaran

Langgan surat berita kami untuk pandangan dagangan AI eksklusif, analisis pasaran, dan kemas kini platform.

Kami menghormati privasi anda. Berhenti melanggan pada bila-bila masa.