Sistem backtesting frekuensi tinggi berdasarkan transaksi oleh transaksi dan kecacatan backtesting K-line

Penulis:Lydia, Dicipta: 2022-11-30 12:38:50, Dikemas kini: 2023-09-11 20:01:01

img

Sistem backtesting frekuensi tinggi berdasarkan transaksi oleh transaksi dan kecacatan backtesting K-line

Saya mengeluarkan enjin backtesting dalam artikel Studi mengenai Strategi Hedging Multi-mata wang Binance Futures (https://www.fmz.com/digest-topic/5584) Dan laporan pertama adalah berdasarkan satu jam K-line backtesting, yang mengesahkan keberkesanan strategi. Walau bagaimanapun, sebagai satu perkara yang sebenarnya, waktu tidur strategi awam adalah 1s, yang merupakan strategi frekuensi yang agak tinggi.https://www.fmz.com/digest-topic/5621Hasilnya, pulangan backtesting telah bertambah baik, tetapi masih mustahil untuk menentukan parameter apa yang harus digunakan dalam kes peringkat kedua, dan pemahaman keseluruhan strategi tidak begitu jelas.

Masalah berdasarkan pengujian belakang K-line

Pertama sekali, apakah garis K sejarah? Satu data garis K merangkumi empat harga: harga tertinggi, harga pembukaan, harga terendah dan harga penutupan, masa permulaan, masa akhir dan kuantiti perdagangan selang. Kebanyakan platform dan kerangka kuantitatif diuji semula berdasarkan garis K, dan FMZ Quant Platform juga menyediakan pengujian semula tahap Tick. Kelajuan pengujian balik garis K sangat cepat, dan ia tidak menjadi masalah dalam kebanyakan kes, tetapi terdapat juga kecacatan yang sangat serius, terutama strategi pelbagai jenis dan strategi frekuensi tinggi pengujian balik, yang hampir tidak dapat membuat kesimpulan yang betul.

Pertama sekali, ini adalah masalah masa. Masa harga tertinggi dan terendah data K-line tidak diberikan, jadi tidak perlu dipertimbangkan, tetapi harga pembukaan dan penutupan yang paling penting bukan masa pembukaan dan penutupan kedudukan. Walaupun jenis perdagangan tidak popular, mereka sering tidak diperdagangkan selama lebih dari sepuluh saat. Apabila kita menguji semula pelbagai strategi, kita sering lalai bahawa harga pembukaan dan penutupan mereka sama, yang juga merupakan asas untuk pengujian harga penutupan.

Bayangkan menggunakan garis minit untuk backtest arbitrase dua jenis. Perbezaan antara mereka biasanya 10 yuan. Sekarang didapati bahawa pada 10:01, harga penutupan kontrak A adalah 100 yuan, harga penutupan kontrak B adalah 112 yuan, dan perbezaannya adalah 12 yuan. Jadi strategi mula lindung nilai. Pada masa tertentu, perbezaan kembali, dan strategi memperoleh keuntungan pulangan 2 yuan.

Walau bagaimanapun, keadaan sebenar mungkin berlaku pada pukul 10:00:45, kontrak A menghasilkan transaksi 100 yuan, dan kemudian tidak ada transaksi. Kontrak B menghasilkan transaksi 112 yuan pada pukul 10:00:58. Pada pukul 10:01, kedua-dua harga tidak wujud. Apakah harga pembukaan pada masa ini? Dan berapa banyak perbezaan yang dapat diperoleh lindung nilai? Kami tidak tahu. Satu situasi yang mungkin adalah bahawa pada pukul 10:00:58, trend membeli satu dan menjual satu kontrak A adalah 101.9-102.1, dan tidak ada spread 2 yuan sama sekali, yang akan menyesatkan pengoptimuman strategi kami dengan besar.

Yang kedua adalah pencocokan. Pencocokan sebenar adalah harga dan masa terlebih dahulu. Jika pembeli melebihi satu harga jual, dia biasanya akan menyimpulkan transaksi pada satu harga jual, jika tidak, dia akan memasukkan buku pesanan dan menunggu. Jelas bahawa data K-line tidak mempunyai harga menjual satu atau membeli satu, yang tidak dapat mensimulasikan pencocokan pada tahap butiran.

Yang terakhir adalah kesan transaksi strategi itu sendiri pada pasaran. Jika ia adalah ujian backtest dana kecil, kesannya akan kecil. Walau bagaimanapun, jika kuantiti dagangan menyumbang sebahagian besar, ia akan memberi kesan kepada pasaran. Bukan sahaja titik slip harga akan besar apabila transaksi selesai dengan segera, tetapi jika pesanan pembelian anda diselesaikan dalam ujian backtest, ia sebenarnya mendahului transaksi pedagang asal lain yang ingin membeli, yang akan memberi kesan efek kupu-kupu di pasaran. Walau bagaimanapun, kesan ini tidak dapat diukur, dan hanya dapat dikatakan oleh pengalaman bahawa perdagangan frekuensi tinggi hanya dapat menampung dana kecil.

Ujian balik berdasarkan kedalaman masa nyata dan tanda

FMZ menyediakan tahap bot sebenar backtesting, yang boleh mendapatkan kedalaman 20-tingkat sejarah sebenar, waktu nyata tik kedua, urus niaga oleh urus niaga dan data lain, dan berdasarkan ini ia telah membuat fungsi main semula bot sebenar (https://www.fmz.com/m/databaseUntuk strategi yang mempunyai kekerapan yang agak tinggi atau memerlukan penilaian masa yang ketat, backtesting bot sebenar diperlukan. Pasangan dagangan dan masa yang dikumpulkan oleh FMZ tidak terlalu lama, tetapi terdapat lebih daripada 70 bilion keping data sejarah. Mekanisme pencocokan semasa adalah bahawa jika pesanan beli lebih besar daripada satu pesanan jual, ia akan dipadankan sepenuhnya dengan segera tanpa melihat kuantiti, dan jika pesanan beli kurang dari satu pesanan jual, ia akan memasuki barisan pencocokan. Mekanisme backtesting ini menyelesaikan dua masalah pertama backtesting K-line, tetapi ia masih tidak dapat menyelesaikan masalah terakhir. Dan kerana jumlah data terlalu besar, kelajuan dan masa backtest terhad.

img img

Mekanisme pengujian balik berdasarkan aliran pesanan urus niaga demi urus niaga

Terdapat terlalu sedikit maklumat mengenai K-Line, dan kedalaman juga mungkin salah. Walau bagaimanapun, satu jenis data adalah niat transaksi sebenar pasaran, yang mencerminkan sejarah transaksi yang paling sebenar - iaitu, transaksi demi transaksi. Dalam kertas ini, saya akan mencadangkan sistem backtesting frekuensi tinggi berdasarkan aliran pesanan, yang akan mengurangkan jumlah data dalam backtesting pada tahap bot sebenar, dan hingga tahap tertentu, mensimulasikan kesan jumlah perdagangan di pasaran.

Saya memuat turun urus niaga oleh urus niaga 5 hari terakhir Kontrak kekal Binance XTZ (alamat muat turun:https://www.fmz.com/upload/asset/1ff487b007e1a848ead.csvSebagai pelbagai yang kurang popular, terdapat 213,000 keping 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 senarai dua dimensi, diurutkan mengikut masa transaksi. Makna khusus adalah: nama spesies, harga transaksi, cap masa transaksi, kuantiti transaksi, dan sama ada pesanan penjualan dijalankan secara aktif. Terdapat kedua-dua pembelian dan penjualan. Setiap transaksi termasuk pembeli dan penjual. Jika pembeli adalah pembuat pasaran dan penjual adalah penerima transaksi aktif, data terakhir akan benar.

Pertama sekali, mengikut arah transaksi, kita boleh membuat spekulasi satu beli dan satu jual di pasaran dengan tepat. Jika ia adalah pesanan jual aktif, harga satu beli pada masa ini adalah harga transaksi. Jika ia adalah pesanan pembelian aktif, harga satu jual adalah harga transaksi. Jika terdapat transaksi baru, kita akan mengemas kini kedudukan pembukaan baru. Jika tidak dikemas kini, hasil terakhir akan dikekalkan. Mudah untuk melancarkan saat terakhir data di atas. Harga satu beli adalah 2.903 dan harga satu jual adalah 2.904.

Menurut aliran pesanan, ia boleh dipadankan dengan cara ini: ambil pesanan beli sebagai contoh, harga adalah harga, dan kuantiti pesanan adalah jumlah. Pada masa ini, beli satu dan jual satu dari kedudukan pembukaan masing-masing ditawar dan meminta. Jika harga lebih rendah daripada meminta dan lebih tinggi daripada tawaran, ia akan dinilai sebagai pembuat pertama, dan keutamaan boleh diberikan kepada pencocokan. Kemudian semua urus niaga dengan harga transaksi yang lebih rendah daripada atau sama dengan harga semasa umur pesanan akan dipadankan dengan pesanan ini (jika harga lebih rendah daripada atau sama dengan tawaran, keutamaan tidak boleh diberikan kepada urus niaga, dan pesanan dengan harga transaksi yang lebih rendah daripada harga akan dipadankan dengan pesanan ini). Harga pencocokan adalah harga, dan kuantiti urus niaga adalah kuantiti urus niaga setiap urus niaga, sehingga pesanan ditutup sepenuhnya atau dibatalkan. Jika perbezaan lebih tinggi daripada harga, ia akan dinilai sebagai pemegang pesanan. Untuk strategi ini, semua pemegang pesanan harus dianggap lebih rendah daripada harga yang menunggu.

Ia adalah mudah untuk melihat masalah pencocokan ini. Jika pesanan adalah seorang yang mengambil, keadaan sebenar adalah bahawa transaksi boleh dibuat dengan segera, dan bukannya menunggu pesanan baru untuk mencocokkannya. Pertama sekali, kami tidak mempertimbangkan bilangan pesanan yang disenaraikan di pasaran. Walaupun terdapat data, penghakiman langsung transaksi telah mengubah kedalaman dan mempengaruhi pasaran. Pencocokan berdasarkan pesanan baru adalah bersamaan dengan menggantikan pesanan anda dengan pesanan sebenar dalam sejarah, yang tidak akan melebihi had kuantiti transaksi pasaran itu sendiri dalam apa jua kes, dan keuntungan akhir tidak boleh melebihi keuntungan maksimum yang dihasilkan oleh pasaran. Beberapa mekanisme pencocokan juga mempengaruhi kuantiti pesanan transaksi, sehingga mempengaruhi pulangan strategi, yang secara kuantitatif mencerminkan strategi. Tidak akan ada uji balik tradisional, di mana jumlah pulangan berganda jika dana dua kali ganda.

Terdapat juga beberapa butiran kecil. Jika harga beli pesanan sama dengan harga beli satu, masih ada kebarangkalian tertentu bahawa pesanan akan sepadan pada harga beli satu. keutamaan pesanan dan kebarangkalian transaksi perlu dipertimbangkan, yang lebih kompleks, dan ia tidak akan dipertimbangkan di sini.

Kod perjumpaan

Objek pertukaran boleh merujuk kepada pengenalan pada permulaan, pada dasarnya tidak berubah. Hanya perbezaan antara komisen pembuat dan penerima ditambahkan, dan kelajuan backtesting dioptimumkan. Kod pencocokan terutamanya diperkenalkan di bawah.

    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] #Transaction price
        trade_amount = tick[3] #Number of transactions
        time_stamp = tick[1] #Transaction 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, which is 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 butiran perlu diperhatikan:

-1. Apabila ada transaksi baru, kita harus sepadan pesanan pertama, dan kemudian meletakkan pesanan mengikut harga terkini. -2. Setiap pesanan mempunyai dua atribut: pembuat sama ada ia adalah pembuat, dan keutamaan keutamaan pencocokan. Mengambil pesanan pembelian sebagai contoh, apabila harga pembelian kurang daripada satu harga jual, ia ditandakan sebagai pembuat, dan apabila harga pembelian lebih besar daripada satu harga membeli, ia ditandakan sebagai pencocokan keutamaan. Keutamaan menentukan sama ada untuk sepadan jika harga sama dengan harga pembelian, dan pembuat menentukan komisen. -3. pembuat dan keutamaan pesanan dikemas kini. Sebagai contoh, terdapat pesanan pembelian yang besar yang melebihi kedudukan pembukaan, apabila terdapat harga yang lebih besar daripada harga beli, pada masa ini, jumlah transaksi yang tersisa akan pembuat. -4. selang strategi adalah perlu, yang boleh mewakili kelewatan pasaran.

Ujian belakang strategi grid

Akhirnya, kita mencapai peringkat backtesting sebenar. Di sini, kita akan backtest strategi grid yang paling klasik untuk melihat sama ada ia telah mencapai kesan yang diharapkan. Prinsip strategi adalah bahawa setiap kali harga meningkat sebanyak 1%, kita akan memegang nilai tertentu pesanan kedudukan pendek (kalau tidak, kita akan memegang pesanan kedudukan panjang), dan kita akan mengira pesanan beli dan pesanan jual dan menunggu mereka terlebih dahulu. Kod tidak akan dikeluarkan.Grid ('XTZ ', 100,0.31000, maker_fee=-0.00002, taker_fee=0.0003)Parameter adalah: pasangan dagangan, nilai pegangan dengan perbezaan harga 1%, ketumpatan pesanan 0.3%, selang tidur ms, komisen pesanan menunggu, dan komisen pemegang.

Pasaran XTZ telah dalam kejutan dalam 5 hari yang lalu, yang sangat sesuai untuk strategi grid.

img

Kita akan backtest kesan kedudukan yang berbeza pada pulangan terlebih dahulu. pulangan yang diukur oleh mekanisme backtesting tradisional pasti akan meningkat secara beransur-ansur dengan peningkatan kedudukan.

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'])

Sebanyak empat kumpulan diuji semula dengan nilai kedudukan 100, 1000, 10000 dan 100000, dan jumlah masa pengujian semula adalah 1.3s. Hasilnya adalah seperti 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}

Ia dapat dilihat bahawa keuntungan yang diwujudkan akhir adalah 28.4%, 27.5%, 26.9% dan 22.6% dari nilai kedudukan masing-masing. Ini juga selaras dengan keadaan sebenar. Semakin besar nilai kedudukan, semakin besar nilai pesanan, dan lebih mungkin transaksi separa akan berlaku. Pulangan yang diwujudkan akhir akan lebih kecil berbanding dengan jumlah pesanan. Rajah di bawah menunjukkan perbandingan pulangan relatif dengan nilai kedudukan masing-masing 100 dan 10000:

img

Kita juga boleh backtest kesan parameter yang berbeza pada pulangan backtest, seperti ketumpatan pesanan yang menunggu, masa tidur dan komisen. Ambil masa tidur sebagai contoh, ubah menjadi 100ms, bandingkan dengan masa tidur 1000ms, dan amati pulangan. Hasil backtesting adalah seperti 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}

Keuntungan telah meningkat sedikit. Ini kerana hanya satu kumpulan pesanan yang menunggu untuk strategi, dan beberapa pesanan tidak dapat mendapatkan harga turun naik kerana mereka tidak mempunyai masa untuk berubah. Waktu tidur yang berkurangan memperbaiki masalah ini. Ini juga menunjukkan pentingnya pesanan pelbagai kumpulan yang menunggu dalam strategi grid.

Ringkasan

Artikel ini mencadangkan sistem backtesting baru berdasarkan aliran pesanan secara inovatif, yang sebahagiannya dapat mensimulasikan keadaan pencocokan seperti pesanan yang menunggu, pengambilan pesanan, transaksi separa dan kelewatan, sebahagiannya mencerminkan kesan jumlah dana strategik pada pulangan, dan mempunyai nilai rujukan penting untuk strategi frekuensi tinggi dan strategi lindung nilai.


Berkaitan

Lebih lanjut