-
Notifications
You must be signed in to change notification settings - Fork 15
/
backtest.py
139 lines (117 loc) · 4.37 KB
/
backtest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 8 19:19:12 2015
@author: djunh
"""
from __future__ import print_function
import datetime
import pprint
try:
import Queue as queue
except ImportError:
import queue
import time
class Backtest(object):
"""
Enscapsulates the settings and components for carrying out
an event-driven backtest.
"""
def __init__(
self, csv_dir, symbol_list, initial_capital,
heartbeat, start_date, data_handler,
execution_handler, portfolio, strategy
):
"""
Initialises the backtest.
Parameters:
csv_dir - The hard root to the CSV data directory.
symbol_list - The list of symbol strings.
intial_capital - The starting capital for the portfolio.
heartbeat - Backtest "heartbeat" in seconds
start_date - The start datetime of the strategy.
data_handler - (Class) Handles the market data feed.
execution_handler - (Class) Handles the orders/fills for trades.
portfolio - (Class) Keeps track of portfolio current and prior positions.
strategy - (Class) Generates signals based on market data.
"""
self.csv_dir = csv_dir
self.symbol_list = symbol_list
self.initial_capital = initial_capital
self.heartbeat = heartbeat
self.start_date = start_date
self.data_handler_cls = data_handler
self.execution_handler_cls = execution_handler
self.portfolio_cls = portfolio
self.strategy_cls = strategy
self.events = queue.Queue()
self.signals = 0
self.orders = 0
self.fills = 0
self.num_strats = 1
self._generate_trading_instances()
def _generate_trading_instances(self):
"""
Generates the trading instance objects from
their class types.
"""
print(
"Creating DataHandler, Strategy, Portfolio and ExecutionHandler"
)
self.data_handler = self.data_handler_cls(self.events, self.csv_dir, self.symbol_list)
self.strategy = self.strategy_cls(self.data_handler, self.events)
self.portfolio = self.portfolio_cls(self.data_handler, self.events, self.start_date,
self.initial_capital)
self.execution_handler = self.execution_handler_cls(self.events)
def _run_backtest(self):
"""
Executes the backtest.
"""
i = 0
while True:
i += 1
print(i)
# Update the market bars
if self.data_handler.continue_backtest == True:
self.data_handler.update_bars()
else:
break
# Handle the events
while True:
try:
event = self.events.get(False)
except queue.Empty:
break
else:
if event is not None:
if event.type == 'MARKET':
self.strategy.calculate_signals(event)
self.portfolio.update_timeindex(event)
elif event.type == 'SIGNAL':
self.signals += 1
self.portfolio.update_signal(event)
elif event.type == 'ORDER':
self.orders += 1
self.execution_handler.execute_order(event)
elif event.type == 'FILL':
self.fills += 1
self.portfolio.update_fill(event)
time.sleep(self.heartbeat)
def _output_performance(self):
"""
Outputs the strategy performance from the backtest.
"""
self.portfolio.create_equity_curve_dataframe()
print("Creating summary stats...")
stats = self.portfolio.output_summary_stats()
print("Creating equity curve...")
print(self.portfolio.equity_curve.tail(10))
pprint.pprint(stats)
print("Signals: %s" % self.signals)
print("Orders: %s" % self.orders)
print("Fills: %s" % self.fills)
def simulate_trading(self):
"""
Simulates the backtest and outputs portfolio performance.
"""
self._run_backtest()
self._output_performance()