Kami telah menghabiskan beberapa bulan terakhir di QuantStart backtesting pelbagai strategi perdagangan menggunakan Python dan panda. Sifat vektor panda memastikan bahawa operasi tertentu pada set data yang besar sangat cepat. Walau bagaimanapun, bentuk backtester vektor yang telah kami kaji setakat ini mengalami beberapa kelemahan dalam cara pelaksanaan perdagangan disimulasikan. Dalam siri artikel ini kami akan membincangkan pendekatan yang lebih realistik untuk simulasi strategi sejarah dengan membina persekitaran backtesting yang didorong oleh peristiwa menggunakan Python.
Sebelum kita menggali dalam pembangunan backtester seperti itu, kita perlu memahami konsep sistem yang didorong oleh peristiwa. Permainan video menyediakan kes penggunaan semula jadi untuk perisian yang didorong oleh peristiwa dan memberikan contoh yang mudah untuk diterokai. Permainan video mempunyai beberapa komponen yang berinteraksi antara satu sama lain dalam tetapan masa nyata pada kadar bingkai yang tinggi. Ini dikendalikan dengan menjalankan keseluruhan set pengiraan dalam gelung
Pada setiap klik gelung permainan, fungsi dipanggil untuk menerima peristiwa terkini, yang akan dihasilkan oleh beberapa tindakan sebelumnya yang sepadan dalam permainan. Bergantung pada sifat peristiwa, yang mungkin termasuk menekan kekunci atau klik tetikus, beberapa tindakan berikutnya diambil, yang akan menamatkan gelung atau menghasilkan beberapa peristiwa tambahan. Proses itu kemudian akan diteruskan. Berikut adalah beberapa contoh kod palsu:
while True: # Run the loop forever
new_event = get_new_event() # Get the latest event
# Based on the event type, perform an action
if new_event.type == "LEFT_MOUSE_CLICK":
open_menu()
elif new_event.type == "ESCAPE_KEY_PRESS":
quit_game()
elif new_event.type == "UP_KEY_PRESS":
move_player_north()
# ... and many more events
redraw_screen() # Update the screen to provide animation
tick(50) # Wait 50 milliseconds
Kod ini sentiasa memeriksa peristiwa baru dan kemudian melakukan tindakan berdasarkan peristiwa ini. Khususnya, ia membolehkan ilusi pengendalian tindak balas masa nyata kerana kod itu terus-menerus dilipat dan peristiwa diperiksa. Seperti yang akan menjadi jelas ini adalah tepat apa yang kita perlukan untuk menjalankan simulasi perdagangan frekuensi tinggi.
Sistem yang didorong peristiwa memberikan banyak kelebihan berbanding pendekatan vektor:
Walaupun sistem yang didorong oleh peristiwa mempunyai banyak faedah, mereka mengalami dua kelemahan utama berbanding sistem vektor yang lebih mudah. Pertama, mereka jauh lebih kompleks untuk dilaksanakan dan diuji. Terdapat lebih banyak bahagian bergerak yang membawa kepada peluang yang lebih besar untuk memperkenalkan bug.
Kedua, ia lebih lambat untuk dilaksanakan berbanding sistem vektor. Operasi vektor yang optimum tidak dapat digunakan semasa menjalankan pengiraan matematik.
Untuk menggunakan pendekatan yang didorong oleh peristiwa kepada sistem backtesting adalah perlu untuk menentukan komponen (atau objek) kami yang akan menangani tugas tertentu:
Ini adalah model yang cukup asas dari enjin perdagangan. Terdapat ruang yang besar untuk pengembangan, terutamanya berkaitan dengan bagaimana Portfolio digunakan. Di samping itu, model kos transaksi yang berbeza juga mungkin diringkaskan ke dalam hierarki kelas mereka sendiri. Pada peringkat ini ia memperkenalkan kerumitan yang tidak perlu dalam siri artikel ini jadi kita tidak akan membincangkannya lebih lanjut. Dalam tutorial seterusnya kita mungkin akan mengembangkan sistem untuk memasukkan realisme tambahan.
Berikut adalah petikan kod Python yang menunjukkan bagaimana backtester berfungsi dalam amalan. Terdapat dua gelung yang berlaku dalam kod. Gelung luar digunakan untuk memberi denyutan jantung kepada backtester. Untuk perdagangan langsung ini adalah kekerapan di mana data pasaran baru disurvei. Untuk strategi backtesting ini tidak semestinya diperlukan kerana backtester menggunakan data pasaran yang disediakan dalam bentuk drip-feed (lihat baris bars.update_bars)).
Loop dalaman sebenarnya mengendalikan peristiwa dari objek Event Queue. Acara tertentu diarahkan kepada komponen masing-masing dan kemudian acara baru ditambahkan ke antrian. Apabila Event Queue kosong, gelung denyutan jantung berterusan:
# Declare the components with respective parameters
bars = DataHandler(..)
strategy = Strategy(..)
port = Portfolio(..)
broker = ExecutionHandler(..)
while True:
# Update the bars (specific backtest code, as opposed to live trading)
if bars.continue_backtest == True:
bars.update_bars()
else:
break
# Handle the events
while True:
try:
event = events.get(False)
except Queue.Empty:
break
else:
if event is not None:
if event.type == 'MARKET':
strategy.calculate_signals(event)
port.update_timeindex(event)
elif event.type == 'SIGNAL':
port.update_signal(event)
elif event.type == 'ORDER':
broker.execute_order(event)
elif event.type == 'FILL':
port.update_fill(event)
# 10-Minute heartbeat
time.sleep(10*60)
Ini adalah garis besar asas bagaimana backtester yang didorong oleh peristiwa direka.