-
Notifications
You must be signed in to change notification settings - Fork 0
/
backtest.py
147 lines (122 loc) · 3.83 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
140
141
142
143
144
145
146
#!/usr/bin/env python -i
from mdcache import mdcache
import datetime
from sto import sto
from account import account
import matplotlib.dates as dates
import commission
import os
def backtest(symbol=None, start=None, write_to_disk=False, fixed_value=None):
if symbol is None:
raise ValueError("symbol is required")
fname = "eq.%s.bt.dat" % symbol
if os.path.exists(fname):
print("FILE ALREADY EXISTS: %s" % fname)
return
if start is None:
dt_start = datetime.date(year=2000, month=1, day=1) # 20000101 by default
else:
dt_start = start
mdata = mdcache(symbol, date_from=dt_start)
data = mdata.get_data()
acct = account(name=symbol, commission=commission.pershare(0.05))
acct.fixed_value = fixed_value
acct.ignore_fixed_value_assertion = True
pos_qty = None
end = 0
next_buy_at = None
next_buy_qty = None
next_sell_at = None
next_sell_qty = None
x = None # last xact
for (d, o, c, h, l, v) in data:
if d == 733898.0:
# flash crash
continue
end += 1
# date, open, close, high, low, volume
if pos_qty is None:
# no buys yet, waiting for weakness to enter
if sto(data[:end])[-1][0] > 20.:
continue
# weakness detected -- entry point
acct.add_xact(date=dates.num2date(d).date(), qty=3, price=c)
pos_qty = 3
x = acct.xacts[-1]
print("%s" % x)
next_buy_at = x.next_buy_at
next_buy_qty = x.next_buy_qty
next_sell_at = x.next_sell_at
next_sell_qty = x.next_sell_qty
continue
# we have an initial buy, now start looking for new opportunities
# foundational trades
while l <= next_buy_at:
# buys triggered
acct.add_xact(date=dates.num2date(d).date(), qty=next_buy_qty, price=next_buy_at)
x = acct.xacts[-1]
next_buy_at = x.next_buy_at
next_buy_qty = x.next_buy_qty
while h >= next_sell_at:
# sells triggered
acct.add_xact(date=dates.num2date(d).date(), qty=next_sell_qty*-1, price=next_sell_at)
x = acct.xacts[-1]
next_sell_at = x.next_sell_at
next_sell_qty = x.next_sell_qty
x = acct.xacts[-1]
next_buy_at = x.next_buy_at
next_buy_qty = x.next_buy_qty
next_sell_at = x.next_sell_at
next_sell_qty = x.next_sell_qty
# stochastic opportunity trades
if x.price > x.dca_min_ask:
# above break-even, look for weakness
start = 0
if end > 11:
start = end - 10
s = sto(data[start:end])
if s[-1][0] <= 20.:
# weakness detected, see if it's ok to trade on
# FIXME: this doesn't go back far enough
buy_ok = False
sto_r = s.__reversed__()
idx = 0
for (sr_k, sr_d) in sto_r:
if sr_d > 80.:
# 3day avg was over 80, so this is new weakness coming down from strength
if dates.date2num(x.date) < [z for z in data[start:end].__reversed__()][idx][0]:
# last xact was before weakness developed
buy_ok = True
break
if buy_ok:
acct.add_xact(date=dates.num2date(d).date(), qty=next_buy_qty, price=c)
elif x.price < x.dca_min_ask:
# below break-even, look for strength
start = 0
if end > 11:
start = end - 10
s = sto(data[start:end])
if s[-1][0] >= 80.:
# strength detected, see if it's ok to trade on
# FIXME: this doesn't go back far enough
sell_ok = False
sto_r = s.__reversed__()
idx = 0
for (sr_k, sr_d) in sto_r:
if sr_d < 20.:
# 3day avg was under 20, so this is new strength coming up from weakness
if dates.date2num(x.date) < [z for z in data[start:end].__reversed__()][idx][0]:
# last xact was before strength developed
sell_ok = True
break
if sell_ok:
acct.add_xact(date=dates.num2date(d).date(), qty=next_sell_qty, price=c)
x = acct.xacts[-1]
print("%s" % x)
next_buy_at = x.next_buy_at
next_buy_qty = x.next_buy_qty
next_sell_at = x.next_sell_at
next_sell_qty = x.next_sell_qty
if write_to_disk:
acct.write_to_disk(fname="eq.%s.bt.dat" % symbol)
return acct