Saya merilis mesin backtesting dalam artikel
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.
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.
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
[['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.
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
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.
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:
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.
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.