Sistem backtesting frekuensi tinggi berdasarkan transaksi per transaksi dan cacat backtesting K-line

Penulis:Lydia, Dibuat: 2022-11-30 12:38:50, Diperbarui: 2023-09-11 20:01:01

img

Sistem backtesting frekuensi tinggi berdasarkan transaksi per transaksi dan cacat backtesting K-line

Saya merilis mesin backtesting dalam artikel Studi tentang Strategi Hedging Multi-Valuta Binance Futures (https://www.fmz.com/digest-topic/5584) Dan laporan pertama didasarkan pada backtesting K-line satu jam, yang memverifikasi efektivitas strategi. Namun, sebenarnya, waktu tidur dari strategi publik adalah 1s, yang merupakan strategi frekuensi yang cukup tinggi. Jelas tidak mungkin untuk mendapatkan hasil yang akurat dengan menggunakan backtesting K-line satu jam. Kemudian, hasil dari the backtest line ditambahkan (https://www.fmz.com/digest-topic/5621Sebagai hasilnya, hasil dari backtesting telah meningkat banyak, tetapi masih tidak mungkin untuk menentukan parameter apa yang harus digunakan dalam kasus tingkat kedua, dan pemahaman dari seluruh strategi tidak sangat jelas.

Masalah berdasarkan backtesting K-line

Pertama-tama, apa itu garis K historis? Satu data K-line mencakup empat harga: harga tertinggi, harga pembukaan, harga terendah dan harga penutupan, waktu awal, waktu akhir dan kuantitas perdagangan interval. Sebagian besar platform dan kerangka kerja kuantitatif diuji secara backtest berdasarkan garis K, dan FMZ Quant Platform juga menyediakan backtesting tingkat Tick. Kecepatan backtesting K-line sangat cepat, dan tidak ada masalah dalam kebanyakan kasus, tetapi ada juga cacat yang sangat serius, terutama strategi multi-varietas dan strategi frekuensi tinggi backtesting, yang hampir tidak dapat menarik kesimpulan yang benar.

Pertama-tama, ini adalah masalah waktu. Waktu harga tertinggi dan terendah dari data K-line tidak diberikan, jadi tidak perlu dipertimbangkan, tetapi harga pembukaan dan penutupan yang paling penting bukanlah waktu pembukaan dan penutupan posisi. Bahkan jika varietas perdagangan tidak populer, mereka sering tidak diperdagangkan selama lebih dari sepuluh detik. Ketika kita melakukan backtest berbagai strategi, kita sering lalai bahwa harga pembukaan dan penutupan mereka sama, yang juga merupakan dasar dari backtesting harga penutupan.

Bayangkan menggunakan garis menit untuk backtest arbitrage dari dua varietas. Perbedaan antara mereka biasanya 10 yuan. Sekarang ditemukan bahwa pada pukul 10:01, harga penutupan kontrak A adalah 100 yuan, harga penutupan kontrak B adalah 112 yuan, dan perbedaannya adalah 12 yuan. Jadi strategi mulai lindung nilai. Pada waktu tertentu, perbedaan kembali, dan strategi menghasilkan laba pengembalian 2 yuan.

Namun, situasi sebenarnya mungkin terjadi 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 harga tidak ada. Apa harga pembukaan pada saat ini? Dan berapa banyak perbedaan yang bisa diperoleh lindung nilai? Kami tidak tahu. Satu situasi yang mungkin adalah bahwa pada pukul 10:00:58, tren membeli satu dan menjual satu kontrak A adalah 101.9-102.1, dan tidak ada spread 2 yuan sama sekali, yang akan sangat menyesatkan optimasi strategi kami.

Yang kedua adalah matchmaking. Real matchmaking adalah harga dan waktu pertama. Jika pembeli melebihi satu harga jual, dia / dia umumnya akan menyimpulkan transaksi pada satu harga jual, jika tidak, dia / dia akan masuk ke buku pesanan dan menunggu.

Yang terakhir adalah dampak transaksi dari strategi itu sendiri pada pasar. Jika itu adalah backtest dana kecil, dampaknya akan kecil. Namun, jika jumlah perdagangan menyumbang sebagian besar, itu akan berdampak pada pasar. Tidak hanya titik slip harga akan besar ketika transaksi selesai segera, tetapi jika pesanan pembelian Anda selesai dalam backtest, itu sebenarnya mengantisipasi transaksi dari pedagang asli lain yang ingin membeli, yang akan memiliki efek kupu-kupu dampak pada pasar. Namun, dampak ini tidak dapat diukur, dan hanya dapat dikatakan oleh pengalaman bahwa perdagangan frekuensi tinggi hanya dapat menampung dana kecil.

Backtesting berdasarkan kedalaman dan tick real-time

FMZ menyediakan backtesting tingkat bot nyata, yang dapat memperoleh kedalaman 20-tingkat historis yang sebenarnya, tik detik real-time, transaksi per transaksi dan data lainnya, dan berdasarkan ini telah membuat fungsi pemutaran bot nyata (https://www.fmz.com/m/databaseUntuk strategi yang memiliki frekuensi yang relatif tinggi atau membutuhkan penilaian waktu yang ketat, backtesting bot nyata diperlukan. Pasangan perdagangan dan waktu yang dikumpulkan oleh FMZ tidak terlalu lama, tetapi ada lebih dari 70 miliar potongan data historis. Mekanisme pencocokan saat ini adalah bahwa jika pesanan beli lebih besar dari satu pesanan jual, itu akan sepenuhnya dicocokkan segera tanpa melihat kuantitasnya, dan jika pesanan beli lebih kecil dari satu pesanan jual, itu akan masuk ke antrian pencocokan. Mekanisme backtesting ini memecahkan dua masalah pertama dari backtesting K-line, tetapi masih tidak dapat memecahkan masalah terakhir. Dan karena jumlah data terlalu besar, kecepatan dan rentang waktu backtest terbatas.

img img

Mekanisme pengujian balik berdasarkan aliran pesanan transaksi per transaksi

Ada terlalu sedikit informasi tentang K-Line, dan kedalaman juga mungkin salah. Namun, satu jenis data adalah niat transaksi nyata pasar, yang mencerminkan sejarah transaksi yang paling nyata - yaitu, transaksi demi transaksi. Dalam makalah ini, saya akan mengusulkan sistem backtesting frekuensi tinggi berdasarkan aliran pesanan, yang akan sangat mengurangi jumlah data dalam backtesting di tingkat bot nyata, dan sampai batas tertentu, mensimulasikan dampak volume perdagangan di pasar.

Saya mengunduh transaksi demi transaksi dari 5 hari terakhir Kontrak abadi Binance XTZ (Alamat unduhan:https://www.fmz.com/upload/asset/1ff487b007e1a848ead.csvSebagai varietas yang kurang populer, ada 213.000 potongan 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 berdasarkan waktu transaksi. Makna spesifiknya adalah: nama spesies, harga transaksi, cap waktu transaksi, jumlah transaksi, dan apakah pesanan penjualan sedang dijalankan secara aktif. Ada pembelian dan penjualan. Setiap transaksi mencakup pembeli dan penjual. Jika pembeli adalah pembuat pasar dan penjual adalah penerima transaksi aktif, data terakhir akan benar.

Pertama-tama, menurut arah transaksi, kita dapat berspekulasi satu beli dan satu jual di pasar dengan akurat. Jika itu adalah pesanan jual aktif, harga satu beli pada saat ini adalah harga transaksi. Jika itu adalah pesanan pembelian aktif, harga satu jual adalah harga transaksi. Jika ada transaksi baru, kita akan memperbarui posisi pembukaan baru. Jika tidak diperbarui, hasil terakhir akan dipertahankan. Mudah untuk meluncurkan momen terakhir dari data di atas. Harga satu beli adalah 2.903 dan harga satu jual adalah 2.904.

Menurut aliran order, itu dapat dicocokkan dengan cara ini: mengambil pesanan beli sebagai contoh, harga adalah harga, dan kuantitas order adalah jumlah. Pada saat ini, membeli satu dan menjual satu dari posisi pembukaan masing-masing ditawar dan meminta. Jika harga lebih rendah dari permintaan dan lebih tinggi dari penawaran, itu akan dinilai sebagai pembuat pertama, dan prioritas dapat diberikan untuk pencocokan. Kemudian semua transaksi dengan harga transaksi lebih rendah dari atau sama dengan harga selama umur order akan dicocokkan dengan pesanan ini (jika harga lebih rendah dari atau sama dengan penawaran, prioritas tidak dapat diberikan kepada transaksi, dan pesanan dengan harga transaksi lebih rendah dari harga akan dicocokkan dengan pesanan ini). Harga pencocokan adalah harga, dan kuantitas transaksi adalah kuantitas transaksi frekuensi setiap transaksi, sampai pesanan ditutup sepenuhnya atau dibatalkan. Jika perbedaan lebih tinggi dari harga, itu akan dinilai sebagai pemegang pesanan. Untuk strategi pencocokan ini, semua pesanan harus disesuaikan dengan harga yang lebih rendah dari harga transaksi. Karena harga yang lebih tinggi, pemegang pesanan harus disesuaikan dengan harga transaksi.

Ini mudah untuk melihat masalah dari pencocokan ini. Jika pesanan adalah pemegang, situasi sebenarnya adalah bahwa transaksi dapat dilakukan segera, daripada menunggu pesanan baru untuk mencocokkannya. Pertama-tama, kami tidak mempertimbangkan jumlah pesanan yang tercantum di pasar. Bahkan jika ada data, penilaian langsung dari transaksi telah mengubah kedalaman dan memengaruhi pasar. Pencocokan berdasarkan pesanan baru setara dengan mengganti pesanan Anda dengan pesanan nyata dalam sejarah, yang tidak akan melebihi batas jumlah transaksi pasar itu sendiri dalam hal apapun, dan keuntungan akhir tidak dapat melebihi keuntungan maksimum yang dihasilkan oleh pasar. Beberapa mekanisme pencocokan juga mempengaruhi jumlah transaksi pesanan, sehingga mempengaruhi pengembalian strategi, yang secara kuantitatif mencerminkan strategi. Tidak akan ada backtesting tradisional, di mana jumlah pengembalian dua kali lipat jika dana dua kali lipat.

Ada juga beberapa detail kecil. jika harga beli order sama dengan harga beli satu, masih ada probabilitas tertentu bahwa order akan dicocokkan dengan harga beli satu. prioritas order dan probabilitas transaksi perlu dipertimbangkan, yang lebih kompleks, dan tidak akan dipertimbangkan di sini.

Kode pencocokan

Objek pertukaran dapat merujuk pada pengenalan di awal, pada dasarnya tidak berubah. hanya perbedaan antara komisi pembuat dan penerima yang ditambahkan, dan kecepatan backtesting dioptimalkan. kode matchmaking terutama diperkenalkan di bawah ini.

    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 detail harus dicatat:

-1. Ketika ada transaksi baru, kita harus mencocokkan pesanan pertama, dan kemudian menempatkan pesanan sesuai dengan harga terbaru. -2. Setiap order memiliki dua atribut: maker apakah itu maker, dan prioritas prioritas matchmaking. Mengambil order pembelian sebagai contoh, ketika harga beli kurang dari satu harga jual, itu ditandai sebagai maker, dan ketika harga beli lebih besar dari satu harga beli, itu ditandai sebagai priority matchmaking. Prioritas menentukan apakah akan cocok jika harga sama dengan harga beli, dan pembuat menentukan komisi. -3. pembuat dan prioritas pesanan diperbarui. misalnya, ada pesanan pembelian besar yang melebihi posisi pembukaan, ketika ada harga yang lebih besar dari harga beli, pada saat ini, jumlah transaksi yang tersisa akan dibuat. -4. Interval strategi diperlukan, yang dapat mewakili keterlambatan pasar.

Pengujian strategi jaringan

Akhirnya, kita mencapai tahap backtesting yang sebenarnya. Di sini, kita akan backtest strategi grid yang paling klasik untuk melihat apakah telah mencapai efek yang diharapkan. Prinsip strategi adalah bahwa setiap kali harga meningkat sebesar 1%, kita akan memegang nilai tertentu dari pesanan posisi pendek (jika tidak, kita akan memegang pesanan posisi panjang), dan kita akan menghitung pesanan beli dan penjualan dan menunggu mereka sebelumnya. Kode tidak akan dirilis.Grid ('XTZ ', 100,0.31000, maker_fee=-0.00002, taker_fee=0.0003)Parameternya adalah: pasangan perdagangan, nilai kepemilikan dengan deviasi harga 1%, kepadatan order 0,3%, interval tidur ms, komisi pesanan yang menunggu, dan komisi pengambil.

Pasar XTZ telah dalam keadaan shock dalam 5 hari terakhir, yang sangat cocok untuk strategi grid.

img

Kita akan backtest dampak dari posisi yang berbeda pada pengembalian pertama. pengembalian diukur oleh mekanisme backtesting tradisional pasti akan meningkat proporsional dengan peningkatan posisi.

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

Total empat kelompok diuji dengan nilai posisi 100, 1000, 10000 dan 100000, dan total waktu pengujian 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}

Dapat dilihat bahwa keuntungan akhir yang direalisasikan masing-masing 28,4%, 27,5%, 26,9% dan 22,6% dari nilai posisi. Ini juga sesuai dengan situasi aktual. Semakin besar nilai posisi, semakin besar nilai pesanan, dan semakin besar kemungkinan transaksi parsial akan terjadi. Pengembalian akhir yang direalisasikan akan lebih kecil dibandingkan dengan jumlah pesanan. Gambar di bawah ini menunjukkan perbandingan pengembalian relatif dengan nilai posisi masing-masing 100 dan 10000:

img

Kita juga dapat backtest dampak dari parameter yang berbeda pada pengembalian backtest, seperti kepadatan pesanan yang sedang menunggu, waktu tidur dan komisi.

{'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 karena hanya satu kelompok pesanan yang tertunda untuk strategi, dan beberapa pesanan tidak dapat mendapatkan harga fluktuasi karena mereka tidak memiliki waktu untuk berubah. Waktu tidur yang berkurang memperbaiki masalah ini. Ini juga menunjukkan pentingnya pesanan multi-kelompok yang tertunda dalam strategi grid.

Ringkasan

Makalah ini mengusulkan sistem backtesting baru berdasarkan aliran order secara inovatif, yang sebagian dapat mensimulasikan situasi pencocokan seperti order pending, order taking, partial transaction dan delay, sebagian mencerminkan dampak volume dana strategis pada pengembalian, dan memiliki nilai referensi penting untuk strategi frekuensi tinggi dan strategi lindung nilai.


Berkaitan

Lebih banyak