forked from maroldaluke/mean-reversion-tradebot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbacktesting.py
More file actions
176 lines (123 loc) · 5.43 KB
/
backtesting.py
File metadata and controls
176 lines (123 loc) · 5.43 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
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
from tradebot import *
### JULY 2022: Historical Testing ###
# pulled variety of stocks from dow jones, and tested trading strategy on this
# past 250 days price action data, using daily candles.
dow = ["AXP", "AMGN", "AAPL", "BA", "CAT", "CSCO", "CVX", "GS", "HD", "HON",
"IBM", "INTC", "JNJ", "KO", "JPM", "MCD", "MMM", "MRK", "MSFT", "NKE",
"PG", "TRV", "UNH", "CRM", "VZ", "V", "WBA", "WMT", "DIS", "DOW"]
api = alpaca.REST(key_id= API_KEY,
secret_key= SECRET_KEY,
base_url= "https://paper-api.alpaca.markets")
active_assets = api.list_assets(status='active')
stocks = [ asset for asset in active_assets if asset.exchange == "NASDAQ" ]
tickers = [ symbol.symbol for symbol in stocks ] # 5002 total
# take in a list of tickers and return the most volatile assets
def getMostVolatile():
numOfCloses = "250"
volatile = []
for ticker in tickers:
print(ticker)
currentStock = Stock(ticker)
closes = currentStock.get_historical_closes("2021-07-01T12:00:00.000Z",
"2022-07-01T12:00:00.000Z", numOfCloses, "1Day")
if closes == 0:
continue
percentageChanges = [0]
for i in range(1, len(closes)):
(price, prevPrice) = (closes[i], closes[i - 1])
percentChange = ((price - prevPrice) / prevPrice) * 100
percentageChanges.append(percentChange)
converted = np.array(percentageChanges)
# volatility is being measured as the standard dev of the assets
# percentage changes between daily closes
std = np.std(converted)
volatile.append({"asset": ticker, "vol" : std})
volatileSorted = sorted(volatile, key=lambda d: d['vol'], reverse=True)
stocks = [stock["asset"] for stock in volatileSorted]
return stocks
def testStrategy(assets):
# now lets test!
cash = 100000
portfolios = []
numProfitable = 0
percentReturns = []
start = time.time()
# testing on exactly one thousands assets from input list
for ticker in assets[0:1000]:
stock = Stock(ticker)
val = testTradingAlgo(stock)
# if there was no data to run the backtest on
if val == cash:
continue
portfolio = {ticker : val}
portfolios.append(portfolio)
if portfolio[ticker] > cash:
numProfitable += 1
percentReturn = ( (val - cash) / cash) * 100
percentReturns.append(percentReturn)
avgReturn = sum(percentReturns) / len(percentReturns)
print(f"Total Number of Assets Tested: {len(portfolios)}")
print(f"Number of Assets Profitable: {numProfitable}")
print(f"List of Percentage Returns: {percentReturns}")
print(f"Average Return of Strategy: {avgReturn}")
# calculating sharpe ratio
# s = ( (expected rate of return) - (risk free return) ) / ( sd of excess return)
# all assets have inherent risk, theoretical risk free return is 0
riskFree1 = 0
# however, lets also calculate sharpe with interest rate on treasury bill
riskFree2 = 2.92
excessReturns1 = [ (ret - riskFree1) for ret in percentReturns ]
excessReturns2 = [ (ret - riskFree2) for ret in percentReturns ]
returns1 = np.array(excessReturns1)
sd1 = np.std(returns1)
returns2 = np.array(excessReturns2)
sd2 = np.std(returns2)
sharpe1 = ( avgReturn - riskFree1 ) / sd1
sharpe2 = ( avgReturn - riskFree2 ) / sd2
print(f"Sharpe Ratio (0% risk-free return): {sharpe1}")
print(f"Sharpe Ratio (2.92% risk-free return): {sharpe2}")
end = time.time()
print(f"Total Testing Duration: {end - start}")
"""
RESULTS:
when testing on all assets, independent of their properties (VERY BAD!)
BB: 2sd, 1.5-2.0dw, 1day
Total Number of Assets Tested: 2436
Number of Assets Profitable: 1445
Average Return of Strategy: 1.109591904089901
Sharpe Ratio (0% risk-free return): 0.11082204779884391
Sharpe Ratio (2.92% risk-free return): -0.18081704796226358
Total Testing Duration: 694.9535341262817
BB: 2.25sd, 1.5-2.0dw, 1day
Total Number of Assets Tested: 2400
Number of Assets Profitable: 1358
Average Return of Strategy: 0.7089374483612483
Sharpe Ratio (0% risk-free return): 0.08560637809095775
Sharpe Ratio (2.92% risk-free return): -0.26699260592860397
Total Testing Duration: 690.0966069698334
thoeretically, this strat should be most efficient on volatile assets
lets measure vol, then only trade the assests with highest
BB: 2sd, 1.5-2.0dw, 1day, 0.1cash/trade
Total Number of Assets Tested: 452
Number of Assets Profitable: 235
Average Return of Strategy: 2.8533263097743404
Sharpe Ratio (0% risk-free return): 0.12928940924802113
Sharpe Ratio (2.92% risk-free return): -0.0030211062759039355
Total Testing Duration: 137.9612443447113
BB: 2sd, 1.5-2.0dw, 1day, 0.25cash/trade
Total Number of Assets Tested: 515
Number of Assets Profitable: 252
Average Return of Strategy: 5.427154373165053
Sharpe Ratio (0% risk-free return): 0.1148054531599892
Sharpe Ratio (2.92% risk-free return): 0.05303608008212978
Total Testing Duration: 158.06818175315857
BEST CONFIG:
BB: 2sd, 1.5-2.0dw, 1day, 0.2cash/trade
Total Number of Assets Tested: 467
Number of Assets Profitable: 225
Average Return of Strategy: 5.789752858402573
Sharpe Ratio (0% risk-free return): 0.1314210207035786
Sharpe Ratio (2.92% risk-free return): 0.06514023293255651
Total Testing Duration: 143.86122798919678
"""
testStrategy(getMostVolatile())