← Kembali ke artikel
July 16, 2026
Bacaan 5 minit

Simulasi fill: tangga dari fantasi harga penutup kepada realiti sedar-queue

Simulasi fill: tangga dari fantasi harga penutup kepada realiti sedar-queue
#simulasi fill
#backtest
#limit order
#kedudukan queue
#partial fill
#market making
#eksekusi
#market microstructure

Backtest anda mengandungi dua model: model alpha anda dan model fill anda. Kebanyakan orang menghabiskan 95% usaha mereka pada yang pertama dan mewarisi yang kedua daripada framework apa sahaja yang mereka gunakan. Ini adalah songsang. Signal yang sederhana dengan model fill yang jujur menghasilkan anggaran PnL yang sederhana tetapi sebenar. Signal yang hebat dengan fill_price = candle.close menghasilkan angka yang bukan anggaran bagi apa-apa — ia adalah output daripada andaian yang tidak pernah anda periksa.

Untuk strategi taker pada instrumen liquid, model fill adalah sebutan pembetulan. Untuk apa-apa yang melibatkan resting limit order — market making, kemasukan pasif, post-only rebate harvesting — model fill itulah strategi tersebut. Sama ada anda dapat fill, bila, dalam kuantiti berapa, dan bergantung pada pergerakan harga susulan apa, menentukan tanda PnL, bukan sekadar magnitudnya.

Dalam Backtest-live parity kami memetakan taksonomi penuh percanggahan backtest-live dan menilai percanggahan eksekusi sebagai keterukan 5/5 — kelas paling teruk. Artikel itu memberikan simulasi fill tiga tahap ketepatan kasar dan meneruskan. Artikel ini adalah pendamping mendalam: tangga lengkap, anak tangga demi anak tangga, dengan lifecycle order sebagai state machine, sempadan kebarangkalian fill yang benar-benar boleh anda kira, dan eksperimen terukur yang menunjukkan tepat di mana pada tangga tersebut strategi maker yang "menguntungkan" itu mati.

Tangga itu

Tangga ketepatan simulasi fill lima anak tangga

Setiap anak tangga memerlukan lebih banyak data dan lebih banyak kod, dan setiap anak tangga menghilangkan bias sistematik yang khusus. Anak tangga disusun mengikut apa yang mereka salah faham, bukan sekadar mengikut kos.

Anak tangga 0: fill harga penutup

fill_price = bar.close

Order fill serta-merta, sepenuhnya, pada penutup bar yang menghasilkan signal. Signal dikira daripada penutup yang sama itu, jadi anda berdagang menggunakan data yang belum wujud ketika harga itu dicetak: look-ahead bias yang memakai kostum eksekusi. Mana-mana strategi dengan turnover kelihatan bagus di sini.

Anak tangga 1: pembukaan bar seterusnya

fill_price = next_bar.open

Model minimum yang jujur untuk logik taker pada bar. Signal dikira pada bar tt, fill berlaku pada harga pertama yang boleh diperhatikan pada bar t+1t+1. Ini menghapuskan look-ahead tetapi masih mengandaikan sifar spread, sifar impak, liquidity tanpa had pada cetakan pembukaan, dan kepastian fill 100%. Untuk limit order, ia merosot menjadi logik touch-fill (lebih lanjut tentang mengapa ini racun di bawah).

Anak tangga 2: spread + slippage tetap

half_spread = mid * spread_bps / 2e4
slip        = mid * slippage_bps / 1e4
fill_price  = mid + side * (half_spread + slip)   # side: +1 buy, -1 sell

Sekarang setiap dagangan taker membayar separuh spread ditambah pemalar yang dikalibrasi. Ini adalah anak tangga pertama di mana strategi turnover tinggi boleh mati dalam backtest — itulah intinya. Ralat baki: slippage bukan pemalar. Ia berskala mengikut saiz order berbanding depth yang dipaparkan dan meletup tepat apabila strategi anda paling ingin berdagang. 5 bps tetap adalah purata merentasi regim; strategi anda tidak berdagang pada regim purata.

Anak tangga 3: depth-walk L2 untuk market order

Dengan snapshot order book, anda berhenti meneka slippage dan mengiranya. Market buy bersaiz QQ berjalan menuruni sisi ask peringkat demi peringkat; harga fill adalah purata berwajaran volum merentasi peringkat yang digunakan:

Pfill(Q)=1Qipimin ⁣(qi,  Qj<iqj)P_{\text{fill}}(Q) = \frac{1}{Q}\sum_{i} p_i \cdot \min\!\left(q_i,\; Q - \textstyle\sum_{j<i} q_j\right)

def depth_walk(levels: list[tuple[float, float]], qty: float) -> tuple[float, float]:
    """levels: [(price, size), ...] sorted best-first. Returns (vwap, filled_qty)."""
    remaining, cost = qty, 0.0
    for price, size in levels:
        take = min(size, remaining)
        cost += take * price
        remaining -= take
        if remaining <= 0:
            break
    filled = qty - remaining
    return (cost / filled if filled > 0 else float("nan"), filled)

Dua pembetulan menjadikan ini jauh lebih jujur secara material. Pertama, latency: jalankan buku sebagaimana ia berdiri Δt\Delta t selepas cap masa keputusan anda, di mana Δt\Delta t adalah latency signal-ke-exchange terukur anda — buku yang anda lihat bukanlah buku yang anda kena. Kedua, partial marketable fill: jika depth yang dipaparkan dalam harga limit-through anda kurang daripada QQ, model mesti mengembalikan partial fill dan meninggalkan baki yang resting, yang menyerahkan masalah itu kepada state machine di bawah.

Ralat baki pada anak tangga 3 adalah impak dan refill: anda menggunakan buku sebagai objek statik, tetapi buku sebenar sebahagiannya diisi semula (dan counterparty sebenar bertindak balas). Untuk saiz klip di bawah beberapa peratus depth top-of-book, ralat ini kecil; untuk klip yang lebih besar anda memerlukan model impak (Almgren-Chriss 2001) yang dilapiskan di atasnya.

Anak tangga 4: fill kedudukan queue kebarangkalian untuk limit order

Anak tangga 0-3 menjawab "pada harga berapa order agresif saya fill." Anak tangga 4 menjawab soalan yang lebih sukar: adakah order pasif saya fill langsung — dan ia adalah satu-satunya anak tangga yang boleh menilai harga strategi maker. Resting limit order pada harga pp fill apabila volum dagangan kumulatif pada pp melebihi volum queue yang berada di hadapannya. Itu memerlukan penjejakan kedudukan anda dalam queue FIFO yang anda tidak boleh perhatikan secara langsung.

Mesin anggaran kedudukan queue — kedudukan awal, peraturan kemas kini pada dagangan lawan pembatalan, keluarga kebarangkalian f(x)f(x) untuk mengagihkan pembatalan yang tidak diperhatikan — adalah primitif yang kami bina dalam Queue inside the wall. Saya tidak akan menurunkan semula di sini; simulator menggunakannya. Apa yang anak tangga 4 tambah adalah peraturan keputusan fill di atas anggaran itu, yang dibincangkan dalam bahagian kebarangkalian fill di bawah.

Mengapa anak tangga ini penting dikuantifikasikan dalam literatur: Moallemi dan Yuan (2016), "A Model for Queue Position Valuation in a Limit Order Book," menunjukkan bahawa untuk instrumen large-tick, nilai ekonomi kedudukan front-of-queue berbanding back-of-queue setanding dengan half-spread — magnitud yang sama dengan keseluruhan edge teori strategi market making. Model fill yang mengabaikan kedudukan queue tidak salah anggar PnL maker; ia menganggar PnL strategi yang lain sama sekali.

Terdapat anak tangga 5 — simulasi berasaskan agen penuh di mana pasaran bertindak balas terhadap order anda (model queue-reactive dalam pengertian Huang, Lehalle dan Rosenbaum 2015; framework multi-agen seperti ABIDES, Byrd et al. 2020). Replay historikal, walaupun sedar-queue, mengandaikan order anda tidak mengubah apa-apa tentang tingkah laku orang lain. Andaian itu munasabah pada saiz runcit dan semakin salah apabila kuota anda menjadi pecahan yang boleh dilihat pada suatu peringkat. Anak tangga 5 di luar skop di sini; ketahui bahawa tangga itu tidak berakhir pada 4.

Partial fill sebagai state machine

Anak tangga 0-2 boleh berpura-pura order itu adalah panggilan fungsi: hantar, dapat harga, selesai. Dari anak tangga 3 ke atas, order adalah proses dengan lifecycle, dan simulator mesti memodelkannya sebagai state machine atau ia akan diam-diam salah kendali kes-kes yang paling penting.

State machine lifecycle order dengan anotasi kedudukan queue

enum OrderState {
    PendingNew,                                  // sent, not yet acked (latency window)
    Resting     { remaining: f64, q_ahead: f64 }, // in book, queue position estimated
    PartialFill { remaining: f64, q_ahead: f64 }, // some qty done, rest still queued
    PendingAmend,                                 // amend in flight
    PendingCancel,                                // cancel in flight
    Filled,
    Canceled    { filled_qty: f64 },              // may be partially filled at cancel time
    Rejected,
}

Peralihan tersebut membawa ekonominya:

  • PendingNewResting: order menyertai queue di belakang segala yang sudah wujud pada masa ack, bukan pada masa keputusan. Kedudukan queue anda disemai dengan volum peringkat pada t+Δtackt + \Delta t_{\text{ack}}. Simulator yang menyemai pada masa keputusan secara sistematik terlebih anggar keutamaan queue — tepat sebanyak volum yang tiba semasa tetingkap latency anda, iaitu kebanyakan volum semasa lonjakan.
  • RestingPartialFill: dagangan pada peringkat anda yang lebih besar daripada queue di hadapan mengisi anda secara separa. Baki mengekalkan kedudukannya (kini di hadapan queue). Partial fill bukan bunyi bising — ia adalah maklumat: mendapat fill 0.3 daripada 1.0 dan melihat harga terpantul pergi adalah peristiwa PnL yang berbeza daripada fill penuh, dan proses inventori maker dibina daripada serpihan-serpihan ini.
  • RestingPendingAmendResting: perangkap tersebut. Pada hampir semua venue kripto, amend adalah cancel/replace — cancelReplace Binance atomik terhadap pelaksanaan berganda tetapi mengembalikan ID order baharu di belakang queue. Malah venue dengan semantik modify asli (CME Globex) hanya mengekalkan keutamaan masa untuk pengurangan kuantiti; perubahan harga atau peningkatan kuantiti menggugurkannya. Jadi dalam simulator: mana-mana amend harga menetapkan semula q_ahead kepada keseluruhan volum peringkat semasa. Enjin quoting yang re-peg setiap 500ms bukan "mengekalkan quote" — ia sentiasa memasuki semula di belakang queue, dan profil fill realistiknya adalah hampir semata-mata adverse selection. Digabungkan dengan hasil Moallemi-Yuan: re-quoting mempunyai harga, dan harga itu adalah kedudukan queue anda.
  • PendingCancelPartialFillCanceled: pembatalan juga mengambil latency. Dalam tetingkap antara membuat keputusan menarik quote dan cancel sampai ke matching engine, anda masih boleh mendapat fill — dan fill-fill itu adalah fill paling teruk yang akan anda terima, kerana sebab anda menarik quote itu adalah kerana pasaran hampir melanggar anda. Simulator tanpa cancel latency memadamkan tepat fill-fill paling toksik daripada sejarah anda.

State machine juga adalah apa yang menjadikan perakaunan simulator jujur: fi terkumpul setiap peristiwa fill, inventori dikemas kini setiap peristiwa fill, dan statistik time-in-state (berapa lama order resting sebelum fill berbanding dibatalkan) menjadi boleh dibandingkan secara langsung dengan log live — yang menjadi input kepada gelung kalibrasi pada akhir artikel.

Kebarangkalian fill limit: tiga model dan satu bracket

Diberi order resting pada harga pp (katakan satu bid), bila simulator mengisytiharkan fill? Tiga peraturan keputusan, dengan tahap kejujuran meningkat:

1. Touch-fill (naif). Fill jika harga menyentuh peringkat anda: lowtp\text{low}_t \le p. Ini adalah peraturan first-passage-time, dan kegagalannya telah diukur suku abad lalu: Lo, MacKinlay dan Zhang (2002), "Econometric Models of Limit-Order Executions" (Journal of Financial Economics 65), memuatkan model survival kepada data limit order sebenar dan menyimpulkan bahawa pelaksanaan hipotesis yang dibina daripada first-passage time "adalah proksi yang sangat lemah bagi pelaksanaan limit-order sebenar." Mod kegagalan itu berstruktur: apabila harga menyentuh peringkat anda dan terpantul, sentuhan itu telah menghabiskan hadapan queue — peniaga yang quote sebelum anda. Touch-fill menganugerahkan anda fill mereka. Lebih teruk, ia menganugerahkan tepat fill yang baik (touch-and-bounce adalah senario menguntungkan bagi maker), sedangkan set fill sebenar anda lebih cenderung kepada touch-and-run-through — yang mengalami adverse selection.

2. Trade-through (sempadan konservatif). Fill hanya jika harga berdagang menembusi peringkat anda dengan tegas: lowt<pϵ\text{low}_t < p - \epsilon, atau pada data tick, volum dagangan kumulatif pada pp melebihi keseluruhan peringkat. Jika harga berdagang menembusi, keseluruhan queue pada pp telah dihabiskan, jadi anda pasti fill tanpa mengira kedudukan. Ini tidak pernah menganugerahkan fill yang anda tidak akan dapat. Biasnya adalah bayangan cermin touch-fill: ia menafikan anda setiap fill di mana queue habis kepada kedudukan anda tanpa penembusan penuh, dan fill yang ia berikan sangat berat sebelah kepada yang run-through (mengalami adverse selection). Backtest maker di bawah trade-through adalah stress test, bukan anggaran.

3. Anggaran queue-depletion. Jejaki volum dagangan kumulatif MtM_t pada harga anda daripada trade tape dan volum dibatalkan CtC_t yang disimpulkan daripada delta L2. Anggaran queue di hadapan anda:

Q^ahead(t)=max ⁣(Q0MtϕCt,  0)\hat{Q}_{\text{ahead}}(t) = \max\!\Big(Q_0 - M_t - \phi \cdot C_t,\; 0\Big)

di mana Q0Q_0 adalah volum peringkat pada kemasukan order (masa ack) dan ϕ[0,1]\phi \in [0,1] adalah pecahan pembatalan yang diandaikan datang daripada di hadapan anda — knob yang bentuk berprinsipnya (keluarga f(x)f(x)) diturunkan dalam artikel kedudukan queue. Fill bermula apabila Q^ahead=0\hat{Q}_{\text{ahead}} = 0; kuantiti anda yang fill adalah volum dagangan melebihi itu, yang menghasilkan partial fill secara semula jadi:

filled(t)=min ⁣(S,  max(MtQ0+ϕCt,0))\text{filled}(t) = \min\!\Big(S,\; \max(M_t - Q_0 + \phi\, C_t,\, 0)\Big)

Menetapkan ϕ=1\phi = 1 (semua pembatalan di hadapan anda) memberikan edge optimistik model ini; ϕ=0\phi = 0 edge pesimistiknya. Apabila anda hanya mempunyai snapshot L2 yang jarang dan tiada trade tape pada peringkat itu — biasa dengan feed kripto yang throttle 100ms — anda boleh berundur kepada prior berasaskan model: Cont, Stoikov dan Talreja (2010), "A Stochastic Model for Order Book Dynamics" (Operations Research 58), memodelkan setiap peringkat harga sebagai queue birth-death dan mengira, melalui transformasi Laplace, kebarangkalian bahawa order pada bid dilaksanakan sebelum mid bergerak, bersyarat pada saiz queue semasa. Ia adalah oracle kebarangkalian fill analitik: kasar berbanding replay tape, jauh lebih baik daripada touch-fill, dan cukup murah untuk dinilai dalam gelung backtest yang panas.

Disiplin bracket

Ketiga-tiga peraturan itu bukan pesaing — mereka adalah satu susunan:

fillstrade-through    fillsqueue    fillstouch\text{fills}_{\text{trade-through}} \;\subseteq\; \text{fills}_{\text{queue}} \;\subseteq\; \text{fills}_{\text{touch}}

yang mendorong bracket PnL. Jalankan setiap backtest maker tiga kali dan laporkan selangnya:

PnLtrade-through    PnLlivePnLtouch\text{PnL}_{\text{trade-through}} \;\le\; \text{PnL}_{\text{live}} \lesssim \text{PnL}_{\text{touch}}

(ketaksamaan atas adalah anggaran — touch-fill boleh mensalah-susun strategi, bukan sekadar menggembungkannya, kerana ia memberikan anda fill baik yang counterfactual). Peraturan keputusan yang mengikutinya: strategi maker hanya boleh digunakan (deployable) jika ia bertahan pada edge konservatif bracket, dan bracket itu cukup sempit sehingga anggaran titik itu bermakna. Strategi yang menunjukkan +9ktouch/9k touch / -3k trade-through mempunyai bracket lebar 12k;andatidaktahuapaapakecualibahawaandaiansimulatorandamendominasialphaanda.Strategiyangmenunjukkan+12k; anda tidak tahu apa-apa kecuali bahawa andaian simulator anda mendominasi alpha anda. Strategi yang menunjukkan +2.1k / +$0.4k memberitahu anda sesuatu yang sebenar.

Eksperimen: menuruni satu strategi maker melalui tangga

PnL strategi maker runtuh anak tangga demi anak tangga menuruni tangga model fill

Ambil satu maker yang sengaja mudah — quote simetri pada best bid/ask, klip tetap 0.05 BTC, inventori dihadkan pada ±0.5 BTC dengan taker flattening pada had. Satu bulan data perpetual BTCUSDT: bar 1m untuk anak tangga rendah, diff L2 100ms ditambah trade tape untuk anak tangga tinggi; fi maker 1.0 bps, taker 4.0 bps. Kod signal yang sama pada setiap anak tangga (teras dikongsi, jadi satu-satunya pemboleh ubah adalah model fill). Angka di bawah adalah satu larian mewakili milik kami — magnitud anda akan berbeza mengikut venue, bulan, dan saiz; bentuknya tidak akan berbeza:

Anak tangga Model fill Kadar fill quote Fill PnL Bulanan Verdict
0 close-fill 98% 41,200 +$14,800 fantasi
1 next-bar-open / touch pada bar 1m 89% 37,400 +$9,600 fantasi dengan latency
2 touch + spread & slippage tetap pada taker flatten 89% 37,400 +$7,100 kos dimodelkan, fill masih fiksyen
3 + depth-walk L2 pada taker flatten 89% 37,400 +$6,400 exit jujur, entry masih fiksyen
4a trade-through (konservatif) 21% 8,900 -$3,900 sempadan stress
4b queue-depletion, ϕ\phi dikalibrasi 37% 15,600 -$700 anggaran terbaik
4c queue-depletion, ϕ=1\phi = 1 (optimistik) 44% 18,700 +$1,900 edge atas
larian shadow live, bulan yang sama 35% 14,100 -$1,150 realiti

Baca jadual dari atas ke bawah dan perhatikan di mana strategi itu mati. Ia bukan anak tangga 2 — fi dan slippage mengurangkan 26% dan strategi masih kelihatan menguntungkan secara mantap. Ia mati antara anak tangga 3 dan anak tangga 4, dan ia mati atas sebab yang tiada model kos boleh tangkap: pemilihan fill. Touch-fill memberikan 37,400 fill di mana majoritinya adalah touch-and-bounce — penangkapan spread tulen. Model sedar-queue memadamkan 58% daripada fill tersebut, dan fill yang ia padamkan adalah secara berat sebelah yang menguntungkan: apabila peringkat itu disentuh ringan, queue di hadapan maker re-quoting berlatency-runcit menyerap segala-galanya. Fill yang terus wujud ke anak tangga 4 lebih cenderung kepada sapuan yang menghabiskan peringkat — fill di mana harga sudah bergerak melalui anda. Kadar fill jatuh 2.4x; PnL bertukar tanda. Ketidaksimetrian itu — kehilangan fill yang baik, mengekalkan yang buruk — adalah adverse selection yang dijadikan eksplisit secara mekanikal, dan ia tidak boleh dilihat pada setiap anak tangga di bawah 4.

Perhatikan juga apa yang bracket itu lakukan: [-3,900,+3,900, +1,900] merangkumi sifar dengan anggaran terkalibrasi pada -700danlivepada700 dan live pada -1,150. Simulator itu tidak menepati PnL live kepada dolar terdekat — ia mendapat tanda, magnitud, dan kadar fill dalam lingkungan 2 mata. Itulah tujuan model fill. Backtest anak tangga 1 tersasar PnL live sebanyak $10,750 pada strategi yang keseluruhan edge kasar bulanannya hanya beberapa ribu dolar: ralat model fill kira-kira 3x saiz alpha itu sendiri. Maka tesisnya: model fill anda adalah andaian yang lebih besar daripada alpha anda.

Satu amaran untuk anak tangga rendah: jika anda mesti hidup dengan data bar (anak tangga 0-2), sekurang-kurangnya selesaikan kesamaran intrabar dengan adaptive drill-down — mengorek dari 1m ke 1s/100ms/trade di mana SL, TP, atau peringkat quote jatuh dalam julat bar. Drill-down membetulkan ralat penjujukan (peringkat mana yang tersentuh dahulu) tetapi tidak boleh membetulkan ralat queue; ia adalah pendamping resolusi-data kepada artikel ini, bukan pengganti anak tangga 4.

Gelung kalibrasi: menutup jurang terhadap fill live

Simulator anak tangga 4 mempunyai parameter bebas — ϕ\phi, latency Δt\Delta t, cancel-latency, andaian refill peringkat. Tanpa kalibrasi, ia sekadar tekaan berbentuk berbeza. Gelung yang menjadikannya instrumen:

1. Log segala-galanya secara live. Setiap peristiwa order dengan cap masa exchange: submit, ack, setiap partial fill, ack amend, ack cancel. Ditambah keadaan L2 pada masa submit. Ini adalah disiplin logging yang sama yang backtest-live parity tuntut untuk DivergenceMonitornya — kalibrasi model fill adalah lapisan paling mendalam monitor itu.

2. Replay order yang sama melalui simulator. Suapkan data pasaran yang direkod dan arahan order yang direkod (bukan fill) ke dalam simulator. Kini anda mempunyai hasil berpasangan: bagi setiap order live, satu nasib simulasi.

3. Bandingkan taburan, bukan purata, dalam baldi (bucket). Satu padanan kadar fill global tunggal boleh menyembunyikan ralat yang saling mengimbangi (terlalu optimistik dalam regim tenang, terlalu pesimistik dalam lonjakan — bersih kepada "terkalibrasi"). Baldikan mengikut pemacu:

import numpy as np
from scipy.stats import ks_2samp

def calibration_report(pairs, bucket_key):
    """pairs: [{'bucket':…, 'live_filled':bool, 'sim_filled':bool,
                'live_ttf':float|None, 'sim_ttf':float|None}, …]"""
    out = {}
    for b in sorted({p['bucket'] for p in pairs}):
        grp = [p for p in pairs if p['bucket'] == b]
        live_fr = np.mean([p['live_filled'] for p in grp])
        sim_fr  = np.mean([p['sim_filled']  for p in grp])
        live_ttf = [p['live_ttf'] for p in grp if p['live_ttf'] is not None]
        sim_ttf  = [p['sim_ttf']  for p in grp if p['sim_ttf']  is not None]
        ks = ks_2samp(live_ttf, sim_ttf) if len(live_ttf) > 20 and len(sim_ttf) > 20 else None
        out[b] = {
            'n': len(grp),
            'fill_rate_live': live_fr,
            'fill_rate_sim':  sim_fr,
            'fill_rate_gap':  sim_fr - live_fr,      # signed: + means sim optimistic
            'ttf_ks_pvalue':  ks.pvalue if ks else None,
        }
    return out

Dua statistik setiap baldi: jurang kadar fill bertanda (simulator tolak live) dan ujian KS pada taburan time-to-fill di kalangan order yang fill. Perbandingan time-to-fill itulah yang tajam — simulator boleh memadankan kadar fill tetapi mengisi pada masa yang secara sistematik salah, yang merosakkan setiap statistik inventori dan adverse-selection hiliran. Ini tepat pelajaran daripada penjelasan survival-analysis Lo-MacKinlay-Zhang: eksekusi adalah masalah time-to-event, jadi sahkan ia sebagai satu.

4. Muatkan knob-knob itu, mengikut susunan kebolehcamalan. Latency dahulu (diukur secara langsung daripada cap masa ack — bukan dimuatkan). Kemudian ϕ\phi dengan meminimumkan jurang kadar fill merentasi baldi kedalaman queue. Kemudian periksa baldi regim volatiliti: jurang optimistik yang berterusan tertumpu pada baldi lonjakan biasanya bermakna simulator anda kurang memodelkan fill toksik cancel-latency atau refill peringkat, bukan ϕ\phi.

5. Jalankan semula bracket. Selepas kalibrasi, anggaran queue-depletion sepatutnya duduk dalam bracket berhampiran live, dan — ujian penerimaan sebenar — susunan varian strategi di bawah simulator sepatutnya sepadan dengan susunan mereka dalam mod shadow. Kemudian bekukan parameter dan kalibrasi semula mengikut jadual; dinamik fill hanyut mengikut tier fi venue, perubahan saiz tick, dan populasi HFT, dan ϕ\phi yang dikalibrasi pada Mac adalah hanya hipotesis menjelang Julai.

Jangkaan penumpuan daripada larian kami: simulator anak tangga 4 yang tidak dikalibrasi biasanya berada dalam ±10-15 mata daripada kadar fill live; selepas satu pusingan kalibrasi, ±3-5 mata, dengan nilai-p KS time-to-fill tidak lagi seragam ditolak. Anda tidak akan mendapat lebih baik daripada itu dengan replay historikal — baki itu adalah reaksi pasaran terhadap anda, masalah anak tangga 5.

Apa yang perlu dibawa pulang

  1. Namakan anak tangga anda. Setiap backtest berada pada tangga ini sama ada anda memilih anak tangga itu atau framework anda yang memilihnya untuk anda. Jika anda tidak boleh namakan anak tangga model fill anda dan bias yang diketahuinya, angka PnL anda mempunyai bar ralat yang belum pernah anda lihat.
  2. Taker boleh berhenti pada anak tangga 3. Depth-walk ditambah latency terukur memberi harga eksekusi agresif secara jujur pada saiz runcit. Belanjakan usaha yang dijimatkan untuk kualiti data.
  3. Maker bermula pada anak tangga 4. Di bawahnya, logik fill limit order bukan sekadar anggaran — ia memilih set fill counterfactual dengan skew adverse-selection yang bertentangan. Backtest touch-fill bagi strategi maker adalah penjana paling boleh dipercayai bagi strategi yang mati sebaik sahaja bersentuh dengan produksi.
  4. Modelkan lifecycle, bukan sekadar fill. Partial fill, amend-menetapkan-semula-queue, cancel latency — state machine adalah tempat fill toksik itu hidup, dan fill toksik adalah tempat PnL maker mati.
  5. Laporkan bracket itu. Sempadan konservatif dan optimistik hanya kos dua larian backtest tambahan dan menukar "backtest saya kata +7k"kepada"realitiberadadisuatutempatdalam[7k" kepada "realiti berada di suatu tempat dalam [-3.9k, +$1.9k]" — yang merupakan keputusan yang berbeza, dan lebih baik.
  6. Kalibrasi terhadap fill live dalam baldi. Model fill yang hanya disahkan secara agregat adalah model fill dengan ralat tersembunyi yang saling mengimbangi. Jurang kadar fill berbaldi ditambah ujian KS time-to-fill, dikalibrasi semula setiap suku tahun.

Anak tangga pada tangga ini bukan gradasi akademik — setiap satu adalah pembohongan khusus yang backtest anda berhenti sampaikan kepada anda. Panjat sehingga pembohongan itu lebih kecil daripada edge anda.

Pautan berguna

  1. Moallemi, C., Yuan, K. — A Model for Queue Position Valuation in a Limit Order Book (2016)
  2. Cont, R., Stoikov, S., Talreja, R. — A Stochastic Model for Order Book Dynamics, Operations Research 58(3), 549-563 (2010)
  3. Lo, A., MacKinlay, C., Zhang, J. — Econometric Models of Limit-Order Executions, Journal of Financial Economics 65(1), 31-71 (2002)
  4. Huang, W., Lehalle, C.-A., Rosenbaum, M. — Simulating and Analyzing Order Book Data: The Queue-Reactive Model, JASA 110(509), 107-122 (2015)
  5. Almgren, R., Chriss, N. — Optimal Execution of Portfolio Transactions (2001)
  6. Byrd, D., Hybinette, M., Balch, T. — ABIDES: Towards High-Fidelity Multi-Agent Market Simulation (2020)
  7. Binance API — Cancel-Replace order semantics
  8. CME Globex — Order modification and time priority rules

Citation

@article{soloviov2026fillsimulation,
  author = {Soloviov, Eugen},
  title = {Fill simulation: the ladder from close-price fantasy to queue-aware reality},
  year = {2026},
  url = {https://marketmaker.cc/blog/fill-simulation-partial-fills-backtest},
  description = {Five rungs of fill simulation fidelity — from close-price fills to probabilistic queue-position models. Partial fills as a state machine, limit-fill probability bounds as a PnL bracket, and a calibration loop against live fills.}
}
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.