우리는 지난 몇 달 동안 퀀트 스타트 (QuantStart) 에서 파이썬과 판다를 사용하여 다양한 거래 전략을 백테스트했습니다. 판다의 벡터화 된 성격은 큰 데이터 세트에 대한 특정 작업이 매우 빠르다는 것을 보장합니다. 그러나 지금까지 연구한 벡터화 백테스터의 형태는 거래 실행 시뮬레이션 방식에 몇 가지 단점이 있습니다. 이 시리즈의 기사에서는 파이썬을 사용하여 이벤트 기반 백테스트 환경을 구축하여 역사적 전략 시뮬레이션에 대한 더 현실적인 접근 방식을 논의 할 것입니다.
이러한 백테스터의 개발에 깊이 들어가기 전에 우리는 이벤트 기반 시스템의 개념을 이해해야합니다. 비디오 게임은 이벤트 기반 소프트웨어에 대한 자연스러운 사용 사례를 제공하고 탐구하기 쉬운 예를 제공합니다. 비디오 게임은 많은 구성 요소를 가지고 있으며 높은 프레임 레이트에서 실시간 설정에서 상호 작용합니다. 이것은 이벤트 루프 또는 게임 루프로 알려진
게임 루프의 각 틱에서 함수가 최신 이벤트를 수신하도록 호출되며, 이는 게임 내에서 해당되는 이전 동작에 의해 생성됩니다. 키 누르기 또는 마우스 클릭을 포함 할 수있는 이벤트의 성격에 따라 다음 동작이 수행되며, 루프를 종료하거나 추가 이벤트를 생성합니다. 프로세스는 계속됩니다. 다음은 몇 가지 예시 사이비 코드입니다:
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
코드는 지속적으로 새로운 이벤트를 확인하고 그 다음이 이벤트에 기반한 행동을 수행합니다. 특히 코드가 지속적으로 루프되고 이벤트를 확인하기 때문에 실시간 응답 처리 착각을 허용합니다. 분명히 알 수 있듯이 이것은 고주파 거래 시뮬레이션을 수행하는 데 필요한 것입니다.
이벤트 기반 시스템은 벡터화된 접근 방식에 비해 많은 장점을 제공합니다.
이벤트 구동 시스템에는 많은 이점이 있지만, 단순 벡터화 시스템보다 두 가지 주요 단점이 있습니다. 첫째, 구현 및 테스트가 훨씬 복잡합니다. 더 많은
두 번째로, 그들은 벡터화된 시스템에 비해 실행이 느립니다. 최적의 벡터화된 연산은 수학적 계산을 수행할 때 활용할 수 없습니다. 우리는 나중에 이 한계를 극복하는 방법을 논의할 것입니다.
백테스팅 시스템에 이벤트 기반 접근을 적용하려면 특정 작업을 처리하는 구성 요소 (또는 객체) 를 정의해야합니다.
이 모델은 트레이딩 엔진의 매우 기본적인 모델이다. 특히 포트폴리오의 사용 방식에 있어서 확장할 수 있는 상당한 범위가 있다. 또한 다른 트랜잭션 비용 모델도 그들 자신의 클래스 계층에 추상화될 수 있다. 이 단계에서 이 시리즈의 기사 내에서 불필요한 복잡성을 도입하기 때문에 현재는 더 이상 논의하지 않을 것이다. 후기 튜토리얼에서는 추가적인 사실주의를 포함하도록 시스템을 확장할 가능성이 있다.
다음은 백테스터가 실제로 어떻게 작동하는지 보여주는 파이썬 코드의 단편입니다. 코드에 두 개의 루프가 발생합니다. 외부 루프는 백테스터에게 심장 박동을 주기 위해 사용됩니다. 라이브 트레이딩에서는 새로운 시장 데이터가 조사되는 빈도입니다. 백테스팅 전략에서는 백테스터가 방울 피드 형태로 제공되는 시장 데이터를 사용하기 때문에 이것이 엄격히 필요하지 않습니다.
내부 루프는 실제로 이벤트 큐 객체에서 이벤트를 처리합니다. 특정 이벤트는 해당 구성 요소에 위임되고 그 후 새로운 이벤트가 큐에 추가됩니다. 이벤트 큐가 비어있을 때 심장 박동 루프는 계속됩니다:
# 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)
이것은 이벤트 주도 백테스터가 설계되는 기본적인 윤곽입니다. 다음 기사에서는 이벤트 클래스 계층에 대해 논의 할 것입니다.