-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbacktest.py
More file actions
114 lines (94 loc) · 4.51 KB
/
backtest.py
File metadata and controls
114 lines (94 loc) · 4.51 KB
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
import config
import backtrader, pandas, sqlite3
from datetime import date, datetime, time, timedelta
class OpeningRangeBreakout(backtrader.Strategy):
params = dict(
num_opening_bars=15
)
def __init__(self):
self.opening_range_low = 0
self.opening_range_high = 0
self.opening_range = 0
self.bought_today = False
self.order = None
def log(self, txt, dt=None):
if dt is None:
dt = self.datas[0].datetime.datetime()
print('%s, %s' % (dt, txt))
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
return
# Check if an order has been completed
if order.status in [order.Completed]:
order_details = f"{order.executed.price}, Cost: {order.executed.value}, Comm {order.executed.comm}"
if order.isbuy():
self.log(f"BUY EXECUTED, Price: {order_details}")
else: # Sell
self.log(f"SELL EXECUTED, Price: {order_details}")
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
def next(self):
current_bar_datetime = self.data.num2date(self.data.datetime[0])
previous_bar_datetime = self.data.num2date(self.data.datetime[-1])
if current_bar_datetime.date() != previous_bar_datetime.date():
self.opening_range_low = self.data.low[0]
self.opening_range_high = self.data.high[0]
self.bought_today = False
opening_range_start_time = time(9, 30, 0)
dt = datetime.combine(date.today(), opening_range_start_time) + timedelta(minutes=self.p.num_opening_bars)
opening_range_end_time = dt.time()
if current_bar_datetime.time() >= opening_range_start_time \
and current_bar_datetime.time() < opening_range_end_time:
self.opening_range_high = max(self.data.high[0], self.opening_range_high)
self.opening_range_low = min(self.data.low[0], self.opening_range_low)
self.opening_range = self.opening_range_high - self.opening_range_low
else:
if self.order:
return
if self.position and (self.data.close[0] > (self.opening_range_high + self.opening_range)):
self.close()
if self.data.close[0] > self.opening_range_high and not self.position and not self.bought_today:
self.order = self.buy()
self.bought_today = True
if self.position and (self.data.close[0] < (self.opening_range_high - self.opening_range)):
self.order = self.close()
if self.position and current_bar_datetime.time() >= time(15, 45, 0):
self.log("RUNNING OUT OF TIME - LIQUIDATING POSITION")
self.close()
def stop(self):
self.log('(Num Opening Bars %2d) Ending Value %.2f' %
(self.params.num_opening_bars, self.broker.getvalue()))
if self.broker.getvalue() > 130000:
self.log("*** BIG WINNER ***")
if self.broker.getvalue() < 70000:
self.log("*** MAJOR LOSER ***")
if __name__ == '__main__':
conn = sqlite3.connect(config.DB_FILE)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("""
SELECT DISTINCT(stock_id) as stock_id FROM stock_price_minute
""")
stocks = cursor.fetchall()
for stock in stocks:
print(f"== Testing {stock['stock_id']} ==")
cerebro = backtrader.Cerebro()
cerebro.broker.setcash(100000.0)
cerebro.addsizer(backtrader.sizers.PercentSizer, percents=95)
dataframe = pandas.read_sql("""
select datetime, open, high, low, close, volume
from stock_price_minute
where stock_id = :stock_id
and strftime('%H:%M:%S', datetime) >= '09:30:00'
and strftime('%H:%M:%S', datetime) < '16:00:00'
order by datetime asc
""", conn, params={"stock_id": stock['stock_id']}, index_col='datetime', parse_dates=['datetime'])
data = backtrader.feeds.PandasData(dataname=dataframe)
cerebro.adddata(data)
cerebro.addstrategy(OpeningRangeBreakout)
#strats = cerebro.optstrategy(OpeningRangeBreakout, num_opening_bars=[15, 30, 60])
cerebro.run()
#cerebro.plot()
# //cerebro.run()