Kami telah menghabiskan beberapa bulan terakhir pada QuantStart backtesting berbagai strategi perdagangan menggunakan Python dan panda. Sifat vektorisasi panda memastikan bahwa operasi tertentu pada set data besar sangat cepat. Namun bentuk backtester vektorisasi yang telah kami pelajari sejauh ini menderita beberapa kelemahan dalam cara eksekusi perdagangan disimulasikan. Dalam seri artikel ini kami akan membahas pendekatan yang lebih realistis untuk simulasi strategi historis dengan membangun lingkungan backtesting berbasis peristiwa menggunakan Python.
Sebelum kita menyelidiki pengembangan backtester semacam itu, kita perlu memahami konsep sistem yang didorong oleh peristiwa. Video game memberikan kasus penggunaan alami untuk perangkat lunak yang didorong oleh peristiwa dan memberikan contoh yang mudah untuk dijelajahi. Sebuah video game memiliki beberapa komponen yang berinteraksi satu sama lain dalam pengaturan waktu nyata pada framerate tinggi. Hal ini ditangani dengan menjalankan seluruh set perhitungan dalam lingkaran
Pada setiap klik game-loop sebuah fungsi dipanggil untuk menerima peristiwa terbaru, yang akan dihasilkan oleh beberapa tindakan sebelumnya yang sesuai dalam permainan. Tergantung pada sifat peristiwa, yang dapat mencakup menekan tombol atau mengklik mouse, beberapa tindakan berikutnya diambil, yang akan mengakhiri loop atau menghasilkan beberapa peristiwa tambahan. Prosesnya kemudian akan berlanjut. Berikut adalah beberapa contoh pseudo-kode:
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
Kode terus-menerus memeriksa untuk peristiwa baru dan kemudian melakukan tindakan berdasarkan peristiwa ini. Secara khusus memungkinkan ilusi penanganan respon real-time karena kode terus-menerus dilipat dan peristiwa diperiksa. Seperti yang akan menjadi jelas ini adalah persis apa yang kita butuhkan untuk melakukan simulasi perdagangan frekuensi tinggi.
Sistem yang didorong oleh peristiwa memberikan banyak keuntungan dibandingkan dengan pendekatan vektor:
Meskipun sistem event-driven memiliki banyak manfaat, mereka menderita dua kelemahan utama dibandingkan dengan sistem vektorisasi yang lebih sederhana. Pertama, mereka jauh lebih kompleks untuk diimplementasikan dan diuji. Ada lebih banyak bagian bergerak yang mengarah pada peluang lebih besar untuk memperkenalkan bug. Untuk mengurangi metodologi pengujian perangkat lunak yang tepat seperti pengembangan test-driven dapat digunakan.
Operasi vektor optimal tidak dapat digunakan saat melakukan perhitungan matematika. Kami akan membahas cara mengatasi keterbatasan ini di artikel berikutnya.
Untuk menerapkan pendekatan yang didorong oleh peristiwa untuk sistem backtesting, perlu untuk mendefinisikan komponen (atau objek) kami yang akan menangani tugas tertentu:
Ini adalah model yang cukup dasar dari mesin perdagangan. Ada ruang yang signifikan untuk perluasan, terutama dalam hal bagaimana portofolio digunakan. Selain itu, model biaya transaksi yang berbeda juga dapat di abstrak ke dalam hirarki kelas mereka sendiri. Pada tahap ini, ini memperkenalkan kompleksitas yang tidak perlu dalam seri artikel ini sehingga kami tidak akan membahasnya lebih lanjut.
Di sini adalah cuplikan kode Python yang menunjukkan bagaimana backtester bekerja dalam praktek. Ada dua loop yang terjadi dalam kode. loop luar digunakan untuk memberi backtester detak jantung. Untuk perdagangan langsung ini adalah frekuensi di mana data pasar baru disurvei. Untuk strategi backtesting ini tidak benar-benar diperlukan karena backtester menggunakan data pasar yang disediakan dalam bentuk drop-feed (lihat baris bars.update_bars)).
The internal loop sebenarnya menangani Event dari event Queue object. Event tertentu didelegasikan ke komponen masing-masing dan kemudian event baru ditambahkan ke queue.
# 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 dasar bagaimana backtester event-driven dirancang.