我々は,過去数ヶ月をQuantStartでPythonとパンダを使用して様々な取引戦略のバックテストに費やした.パンダのベクトル化された性質は,大規模なデータセット上の特定の操作が非常に高速であることを保証する.しかし,これまで研究したベクトル化されたバックテストの形態は,取引実行がシミュレーションされる方法にいくつかの欠点があります.このシリーズでは,Pythonを使用してイベント主導のバックテスト環境を構築することによって,歴史的な戦略シミュレーションに対するより現実的なアプローチについて議論します.
このようなバックテストの開発に深入する前に,イベント駆動システムの概念を理解する必要があります. ビデオゲームはイベント駆動ソフトウェアの自然な用例を提供し,探求するための簡単な例を提供します. ビデオゲームには,リアルタイム設定で高フレームレートで相互に相互作用する複数のコンポーネントがあります. これはイベントループまたはゲームループとして知られる"無限"ループ内の計算の全セットを実行することによって処理されます.
ゲームループの各クリックで,ゲーム内の対応する以前のアクションによって生成された最新のイベントを受信するために機能が呼び出されます.イベントの性質に応じて,キープレスまたはマウスクリックを含む後続的なアクションが実行され,ループを終了するか,追加のイベントを生成します. プロセスはその後も続きます. 以下はいくつかの例の偽コードです:
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
コードは,新しいイベントを継続的にチェックし,それらのイベントに基づいてアクションを実行しています.特に,コードが継続的にループされ,イベントがチェックされているため,リアルタイムレスポンスハンドリングの錯覚を可能にします. 明らかになるように,これは,高周波取引シミュレーションを実行するために必要なものです.
イベント駆動システムではベクトル化方法よりも多くの利点があります.
イベント駆動システムには多くの利点があるが,よりシンプルなベクトリ化システムに対して2つの大きな欠点がある.第一に,実装とテストがはるかに複雑である.バグの導入の可能性を高める"動く部品"が多くある.この適切なソフトウェアテスト方法論を緩和するために,テスト駆動開発などの使用が可能である.
2つ目は,ベクトル化されたシステムと比較して実行が遅い.数学的な計算を行うときに最適なベクトル化された演算は利用できない.これらの制限を克服する方法については,次の記事で説明します.
バックテストシステムにイベント駆動アプローチを適用するには,特定のタスクを処理するコンポーネント (またはオブジェクト) を定義する必要があります.
これは,取引エンジンの非常に基本的なモデルである.特にポートフォリオの使用方法に関して,拡張する大きな余地がある.また,異なるトランザクションコストモデルも,独自のクラス階層に抽象化され得る.この段階では,このシリーズ記事の中で不必要な複雑さを導入しているため,我々は現在それについてさらに議論しない.後のチュートリアルでは,追加のリアリズムを含むため,システムを拡張する可能性があります.
Python のコードのスニペットは,バックテストが実際にどのように動作するかを示しています.コードには2つのループがあります.外側のループは,バックテストに心拍を伝えるために使用されます.ライブ取引では,これは新しい市場データがアンケートされる頻度です.バックテスト戦略では,バックテストがドリップフィード形式で提供された市場データを使用しているため,これは厳密に必要ではありません (bars.update_bars (()) ラインを参照してください).
内ループは,実際にイベントキューオブジェクトからイベントを処理する.特定のイベントはそれぞれのコンポーネントに委任され,その後,新しいイベントがキューに追加される.イベントキューが空いているとき,ハートビートループは継続する:
# 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)
これは,イベント駆動バックテストがどのように設計されるのかの一般的な概要です. 次の記事では,イベントクラス階層について議論します.