Sistem backtest frekuensi tinggi berdasarkan setiap transaksi dan cacat backtest K-line

Penulis:Kebaikan, Dibuat: 2020-06-16 10:30:19, Diperbarui: 2023-11-01 20:26:21

img

Ketika aku menulisPenelitian tentang Strategi Hedging Multi-Valuta Binance Futures, Saya juga merilis mesin backtest. Dan laporan pertama didasarkan pada backtest K-line satu jam, yang memverifikasi efektivitas strategi. Tapi waktu tidur dari strategi sumber terbuka sebenarnya adalah 1 detik, yang merupakan strategi yang cukup frekuensi tinggi. Jelas, menggunakan backtest K-line per jam tidak dapat menghasilkan hasil yang akurat. Kemudian, hasil backtest tingkat menit K line ditambahkan, dan pendapatan backtest telah meningkat banyak, tetapi masih tidak mungkin untuk menentukan parameter apa yang harus digunakan dalam kasus seconds level, dan pemahaman keseluruhan strategi tidak sangat jelas. Alasan utama adalah kelemahan penting dari backtest berdasarkan K-line.

Masalah berdasarkan backtest K-line

Pertama-tama, apa itu garis K historis? Data garis K berisi empat harga tinggi, terbuka, rendah, dekat, dua kali pertama dan volume interval. Sebagian besar platform dan kerangka kerja kuantisasi didasarkan pada backtest garis K, dan platform FMZ juga menyediakan backtest tingkat tik. Kecepatan backtest garis K sangat cepat, dan dalam kebanyakan kasus memiliki sangat sedikit masalah, tetapi juga memiliki cacat yang sangat serius, terutama strategi backtest multi-varietas dan strategi frekuensi tinggi, hampir tidak mungkin untuk menarik kesimpulan yang benar.

Yang pertama adalah masalah waktu. Waktu harga tertinggi dan harga terendah dari data K-line tidak diberikan dan tidak perlu dipertimbangkan, tetapi harga pembukaan dan penutupan yang paling penting bukanlah waktu pembukaan dan penutupan. Bahkan varietas perdagangan yang kurang populer sering tidak memiliki perdagangan selama lebih dari sepuluh detik, dan ketika kita backtest strategi multi-varietas, kita sering berasumsi bahwa harga pembukaan dan harga penutupan mereka sama, yang juga didasarkan pada backtest harga penutupan.

Bayangkan menggunakan garis tingkat menit K untuk backtest arbitrase dua varietas. Perbedaan antara mereka biasanya 10 yuan ((atau dolar). Sekarang, pada pukul 10:01, harga penutupan kontrak A adalah 100, kontrak B adalah 112, dan perbedaannya adalah 12 yuan. Jadi strategi mulai lindung nilai. Pada saat tertentu, perbedaan harga kembali, dan strategi menghasilkan laba laba 2 yuan.

Tapi situasi sebenarnya mungkin adalah bahwa pada pukul 10:00:45, kontrak A menghasilkan transaksi 100 yuan, setelah itu tidak ada transaksi, kontrak B memiliki transaksi 112 yuan pada pukul 10:00:58, pada pukul 10:01:00 Kedua harga tidak ada.101.9untuk102.1, dan tidak ada perbedaan 2 yuan sama sekali.

Masalah kedua adalah masalah pencocokan. Pencocokan yang sebenarnya adalah prioritas harga dan prioritas waktu. Jika pembeli melebihi harga Jual 1, mereka biasanya akan langsung berurusan dengan harga Jual 1, jika tidak mereka akan masuk ke buku pesanan yang tertunda dan menunggu. Data garis K jelas tidak memiliki harga Beli 1 dan Jual 1, tidak mungkin untuk mensimulasikan tingkat pencocokan harga detail.

Yang terakhir adalah dampak dari strategi itu sendiri pada pasar. Jika itu adalah backtest dana jumlah kecil, dampaknya tidak besar. Tapi jika volume transaksi besar, itu akan berdampak pada pasar. Tidak hanya akan tergelincir harga besar ketika Anda menempatkan pesanan volume besar, jika Anda membeli pesanan panjang yang dilaksanakan, tindakan semacam ini benar-benar merebut pesanan dari pedagang lain yang awalnya ingin membeli, efek butterfly akan berdampak pada pasar. Efek ini tidak dapat diukur. Kita hanya dapat mengatakan dari pengalaman bahwa perdagangan frekuensi tinggi hanya dapat mengakomodasi dana kecil.

Backtest berdasarkan kedalaman waktu nyata dan tick

FMZ menyediakan backtest tingkat nyata, yang dapat memperoleh sejarah nyata20 layer depth price, real-time tingkat keduaTicks, Each Individual TransactionBerdasarkan fitur ini, FMZ membuat fungsi pemutaran transaksi real-time.

Jumlah data backtest ini sangat besar, dan kecepatan backtest juga sangat lambat, umumnya hanya dapat backtest selama dua hari. Untuk strategi yang relatif frekuensi tinggi atau waktu kritis, backtest tingkat pasar nyata diperlukan. Pasangan perdagangan dan waktu perdagangan yang dikumpulkan oleh FMZ tidak terlalu lama, tetapi masih ada lebih dari 70 miliar data historis.

Mekanisme pencocokan saat ini adalah bahwa jika pesanan pembelian lebih besar dari Sell 1, itu akan sepenuhnya dicocokkan segera tanpa melihat jumlahnya, dan jika kurang dari Sell 1, itu akan masuk ke antrian pencocokan untuk menunggu. Mekanisme backtest semacam itu memecahkan dua masalah pertama dari backtest K-line, tetapi masih tidak dapat memecahkan masalah terakhir. Dan karena jumlah data terlalu besar, kecepatan backtest dan rentang waktu terbatas.

img

Mekanisme backtest berdasarkan aliran transaksi order per order

Ada terlalu sedikit informasi di garis K, dan kedalaman harga juga bisa menjadi kedalaman palsu, tapi ada jenis data yang merupakan pasar s bersedia transaksi nyata, yang mencerminkan sejarah transaksi yang paling nyata, yaitu,Each Individual TransactionArtikel ini akan mengusulkan sistem backtest frekuensi tinggi berdasarkan aliran pesanan, yang akan sangat mengurangi volume data backtest tingkat pasar riil, dan sampai batas tertentu mensimulasikan dampak volume perdagangan di pasar.

Saya mengunduh transaksi 5 hari terakhir Binance XTZ kontrak abadi (Alamat download:https://www.fmz.com/upload/asset/1ff487b007e1a848ead.csv), sebagai varietas yang tidak populer, memiliki total 213000 data transaksi, pertama-tama mari kita lihat komposisi data:

[['XTZ', 1590981301905, 2.905, 0.4, 'False\n'],
 ['XTZ', 1590981303044, 2.903, 3.6, 'True\n'],
 ['XTZ', 1590981303309, 2.903, 3.7, 'True\n'],
 ['XTZ', 1590981303738, 2.903, 238.1, 'True\n'],
 ['XTZ', 1590981303892, 2.904, 0.1, 'False\n'],
 ['XTZ', 1590981305250, 2.904, 0.1, 'False\n'],
 ['XTZ', 1590981305643, 2.903, 197.3, 'True\n'],

Data adalah daftar dua dimensi, disortir dalam urutan kronologis. Makna spesifiknya adalah sebagai berikut: nama varietas, harga transaksi, timestamp transaksi, jumlah transaksi, apakah itu adalah transaksi aktif pesanan penjualan. Ada sisi membeli dan menjual, dan setiap transaksi mencakup pembeli dan penjual. Jika pembeli adalah pasarMakerdan penjual adalah aktifTaker, data terakhir adalahTrue.

Pertama-tama, sesuai dengan arah transaksi, Anda dapat dengan cukup akurat berspekulasi tentang Buy 1 dan Sell 1 di pasar. Jika itu adalah order jual aktif, maka harga Buy 1 pada saat ini adalah harga transaksi, jika itu adalah order pembelian aktif, maka harga Sell 1 akan menjadi harga transaksi. Jika ada transaksi baru, maka semua harga akan diperbarui dan diperbarui. Hasil terakhir akan dipertahankan jika tidak ada pembaruan dan pembaruan. Mudah untuk memperkenalkan momen terakhir data di atas, harga Buy 1 adalah 2.903, dan Sell 1 adalah 2.904.

Menurut aliran pesanan, dapat disesuaikan dengan cara ini: mengambil pesanan pembelian sebagai contoh, harga adalahprice, jumlah pesanan adalahamount, maka beli dan jual 1 pada saat ini adalahbiddanaskJikapricelebih rendah dariaskdan lebih tinggi daribid, maka dinilai sebagaimakerpertama, dan prioritas dapat dicocokkan untuk membuat kesepakatan, maka semua transaksi dengan harga transaksi lebih rendah dari atau sama denganpriceselama waktu keberadaan order akan dicocokkan dengan order ini (jikapriceadalah kurang dari atau sama denganbid, tidak ada prioritas yang diberikan kepada transaksi.pricedisesuaikan dengan urutan ini.)

Harga yang cocok adalahprice, dan volume adalah volume transaksiEach Individual Transaction, sampai pesanan selesai atau pesanan dibatalkan.ask, dianggap sebagaitakerSetelah itu, selama waktu ketika pesanan ada, semua transaksi dengan harga transaksi lebih rendah dari atau sama denganpriceyang cocok dengan pesanan ini, dan harga yang cocok adalah harga transaksi dariEach Individual TransactionPerbedaan antaramakerdantakerstrategi frekuensi tinggi, perbedaan ini harus dipertimbangkan.

Sangat mudah untuk melihat masalah dengan jenis pencocokan ini.taker, situasi sebenarnya adalah bahwa hal itu dapat dilaksanakan segera, daripada menunggu pesanan baru untuk dicocokkan dengan itu. pertama-tama, kita tidak mempertimbangkan volume pesanan yang tertunda, bahkan jika ada beberapa data, langsung menilai transaksi juga telah mengubah kedalaman harga, mempengaruhi pasar.

Berdasarkan pencocokan pesanan baru, ini setara dengan mengganti pesanan yang ada dalam sejarah dengan pesanan Anda. Dalam hal apapun, itu tidak akan melebihi batas volume perdagangan pasar sendiri, dan keuntungan akhir tidak dapat melebihi keuntungan maksimum yang dihasilkan oleh pasar. Bagian dari mekanisme pencocokan juga mempengaruhi volume pesanan, yang pada gilirannya mempengaruhi pendapatan strategi, secara kuantitatif mencerminkan kapasitas strategi. Tidak akan ada backtest tradisional, ketika jumlah dana berlipat ganda dan keuntungan berlipat ganda.

Masih ada beberapa detail kecil. Jika harga pembelian pesanan sama dengan Buy 1, masih ada probabilitas tertentu bahwa harga pembelian akan dicocokkan dengan Buy 1, situasi semacam ini tidak akan dipertimbangkan di sini.

Kode yang cocok

Objek pertukaran dapat merujuk pada pengenalan di awal, pada dasarnya tidak berubah, hanya menambahkan perbedaan antaramakerdantakerBiaya, dan mengoptimalkan kecepatan backtest. Berikut ini terutama akan memperkenalkan kode pencocokan.

 symbol = 'XTZ'
    loop_time = 0
    intervel = 1000 # The sleep time of the strategy is 1000ms
    init_price = data[0][2] # Initial price
    e = Exchange([symbol],initial_balance=1000000,maker_fee=maker_fee,taker_fee=taker_fee,log='') # Initialize the exchange
    depth = {'ask':data[0][2], 'bid':data[0][2]} # depth
    order = {'buy':{'price':0,'amount':0,'maker':False,'priority':False,'id':0},
             'sell':{'price':0,'amount':0,'maker':False,'priority':False,'id':0}} # order
    for tick in data:
        price = int(tick[2]/tick_sizes[symbol])*tick_sizes[symbol] # executed price
        trade_amount = tick[3] # executed volume
        time_stamp = tick[1] # executed timestamp
        if tick[4] == 'False\n':
            depth['ask'] = price
        else:
            depth['bid'] = price
        
        if depth['bid'] < order['buy']['price']:
            order['buy']['priority'] = True
        if depth['ask'] > order['sell']['price']:
            order['sell']['priority'] = True
        if price > order['buy']['price']:
            order['buy']['maker'] = True
        if price < order['sell']['price']:
            order['sell']['maker'] = True
        
        # Order network delay can also be used as one of the matching conditions, not considered here
        cond1 = order['buy']['priority'] and order['buy']['price'] >= price and order['buy']['amount'] > 0
        cond2 = not order['buy']['priority'] and order['buy']['price'] > price and order['buy']['amount'] > 0
        cond3 = order['sell']['priority'] and order['sell']['price'] <= price and order['sell']['amount'] > 0
        cond4 = not order['sell']['priority'] and order['sell']['price'] < price and order['sell']['amount'] > 0

        if cond1 or cond2:
            buy_price = order['buy']['price'] if order['buy']['maker'] else price
            e.Buy(symbol, buy_price, min(order['buy']['amount'],trade_amount), order['buy']['id'], order['buy']['maker'])
            order['buy']['amount'] -= min(order['buy']['amount'],trade_amount)
            e.Update(time_stamp,[symbol],{symbol:price})
        if cond3 or cond4:
            sell_price = order['sell']['price'] if order['sell']['maker'] else price
            e.Sell(symbol, sell_price, min(order['sell']['amount'],trade_amount), order['sell']['id'], order['sell']['maker'])
            order['sell']['amount'] -= min(order['sell']['amount'],trade_amount)
            e.Update(time_stamp,[symbol],{symbol:price})

        if time_stamp - loop_time > intervel:
            order = get_order(e,depth,order) # Trading logic, not given here
            loop_time += int((time_stamp - loop_time)/intervel)*intervel

Beberapa detail untuk dicatat:

  • Ketika ada transaksi baru, kita harus terlebih dahulu mencocokkan pesanan, dan kemudian menempatkan pesanan sesuai dengan harga terbaru.

  • Setiap order memiliki dua atribut: makerapakah itu maker, prioritymatching priority, mengambil order beli sebagai contoh, ketika harga beli kurang dari Sell 1, itu ditandai sebagaimaker, dan ketika harga beli lebih besar dari Buy 1, itu ditandai sebagaiPriority matching, prioritymenentukan apakah harga sama dengan harga beli atau tidak, dan pembuat menentukan biaya transaksi.

  • PeraturanmakerdanpriorityJika pembelian besar dilakukan dan melebihi kapasitas pasar. Ketika harga lebih besar dari harga pembelian, volume yang tersisa akanmaker.

  • Strategiintervaldiperlukan, itu bisa mewakili penundaan pasar.

Tes latar belakang strategi jaringan

Akhirnya, ini adalah tahap backtest yang sebenarnya. Mari kita backtest salah satu strategi grid paling klasik di sini untuk melihat apakah kita dapat mencapai hasil yang diharapkan. Prinsip strategi adalah bahwa setiap kali harga naik sebesar 1%, kita memegang pesanan pendek dari nilai tertentu (sebaliknya, kita memegang pesanan panjang), menghitung pesanan beli dan jual terlebih dahulu. saya tidak akan menunjukkan kode sumber. mereka semua dikemas ke dalamGrid('XTZ', 100, 0.3, 1000, maker_fee=-0.00002, taker_fee=0.0003)Fungsi, parameter adalah: pasangan perdagangan, harga menyimpang dari nilai kepemilikan 1%, kepadatan pesanan tertunda adalah 0,3%, interval tidurms, biaya order yang belum selesai dan biaya order yang telah dilaksanakan.

Harga pasar XTZ telah mengalami kejutan selama 5 hari terakhir, yang sangat cocok untuk jaringan.

img

Pertama kita melakukan backtest efek dari posisi kepemilikan yang berbeda pada laba kembali. laba kembali yang diuji oleh mekanisme backtest tradisional pasti akan meningkat sebanding dengan peningkatan posisi kepemilikan.

e1 = Grid('XTZ',100,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e1.account['USDT'])
e2 = Grid('XTZ',1000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e2.account['USDT'])
e3 = Grid('XTZ',10000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e3.account['USDT'])
e4 = Grid('XTZ',100000,0.3,1000,maker_fee=-0.00002,taker_fee=0.0003)
print(e4.account['USDT'])

Secara total empat kelompok diuji kembali, nilai posisi memegang adalah 100, 1000, 10000, 100.000, dan total waktu uji kembali adalah 1,3 s. Hasilnya adalah sebagai berikut:

{'realised_profit': 28.470993031132966, 'margin': 0.7982662957624465, 'unrealised_profit': 0.0104554474048441, 'total': 10000028.481448, 'leverage': 0.0, 'fee': -0.3430967859046398, 'maker_fee': -0.36980249726699727, 'taker_fee': 0.026705711362357405}
{'realised_profit': 275.63148945320177, 'margin': 14.346335829979132, 'unrealised_profit': 4.4382117331794045e-14, 'total': 10000275.631489, 'leverage': 0.0, 'fee': -3.3102045933457784, 'maker_fee': -3.5800688964477048, 'taker_fee': 0.2698643031019274}
{'realised_profit': 2693.8701498889504, 'margin': 67.70120400534114, 'unrealised_profit': 0.5735269329348516, 'total': 10002694.443677, 'leverage': 0.0001, 'fee': -33.984021415250744, 'maker_fee': -34.879233866850974, 'taker_fee': 0.8952124516001403}
{'realised_profit': 22610.231198585603, 'margin': 983.3853688758861, 'unrealised_profit': -20.529965947304365, 'total': 10022589.701233, 'leverage': 0.002, 'fee': -200.87094000385412, 'maker_fee': -261.5849078470078, 'taker_fee': 60.71396784315319}

Hal ini juga sesuai dengan situasi yang sebenarnya. Semakin besar nilai posisi kepemilikan, semakin besar nilai pesanan yang sedang menunggu, semakin besar kemungkinan transaksi parsial akan terjadi, dan semakin kecil keuntungan akhir yang direalisasikan relatif terhadap jumlah pesanan yang sedang menunggu. Bagan berikut adalah perbandingan laba relatif nilai posisi masing-masing 100 dan 10000:

img

Kita juga dapat melakukan backtest dampak dari parameter yang berbeda pada pendapatan backtest, seperti kepadatan pesanan yang menunggu, waktu tidur, biaya transaksi, dll. Ambil waktu tidur sebagai contoh, ubah menjadi 100ms, dan bandingkan waktu tidur dengan 1000ms untuk melihat laba kembali. Hasil backtest adalah sebagai berikut:

{'realised_profit': 29.079440803790423, 'margin': 0.7982662957624695, 'unrealised_profit': 0.0104554474048441, 'total': 10000029.089896, 'leverage': 0.0, 'fee': -0.3703702128662524, 'maker_fee': -0.37938946377435134, 'taker_fee': 0.009019250908098965}

pendapatan telah meningkat sedikit, karena strategi hanya mengirim satu set pesanan, beberapa pesanan tidak akan dapat melaksanakan harga berfluktuasi karena mereka tidak memiliki waktu untuk berubah, dan pengurangan waktu tidur memperbaiki masalah ini.

Untuk meringkas

Artikel ini secara inovatif mengusulkan sistem backtest baru berdasarkan aliran order, yang dapat sebagian mensimulasikan situasi pencocokan order yang tertunda, order yang dieksekusi, order yang dieksekusi sebagian, penundaan, dll, dan sebagian mencerminkan dampak dari jumlah dana strategi pada pendapatan. Untuk strategi frekuensi tinggi dan lindung nilai, Ini memiliki nilai referensi yang penting.


Berkaitan

Lebih banyak