-
Notifications
You must be signed in to change notification settings - Fork 1
/
environment.py
226 lines (197 loc) · 8.54 KB
/
environment.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
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
from DataHandler.mongoObjects import CollectionManager, MongoClient, MongoDocument
from Strategy.strategy import Strategy
from agent import InvestorAgent
from Models.arima import ArimaModel
from DataHandler.putAndGetData import avg_price_timeseries
import argparse
import utils
import warnings
from Models.LSTM import NeuralNet
from AsyncPython.logger import log
from Models.SVM import SVM
import numpy as np
from logger import Logger
def save_results(dict, manager, ticker):
"""
Saves the results of trading to the database
:param dict: results
:param manager: collection manager
:param ticker: stock ticker
:return: None
"""
newDoc = MongoDocument(dict, ticker, [])
manager.insert(newDoc)
def sharpe_ratio(portfolio, etf, rp, rf=1.72):
"""
Calculates the Sharpe Ratio -- a measurement of risk
:param portfolio: the portfolio
:param etf: the values of SPY
:param rp: expected portfolio return
:param rf: risk free rate
:return: sharpe ratio
"""
sigp = np.std(portfolio)
covariance = np.cov(portfolio, etf)[0][1]
varETF = np.var(etf)
beta = covariance / varETF # volatility
rx = sigp / beta
return (rp - rf) / rx
class Environment(object):
def __init__(self, manager: CollectionManager, agent: InvestorAgent, startDay: int):
self.timeperiod = manager.dates()
self.manager = manager
self.agent = agent
self.day = startDay
self.currentDate = self.timeperiod[self.day]
def increment_day(self, strategy):
"""
Steps through the days
:param strategy:
:return:
"""
self.day += 1
self.currentDate = self.timeperiod[self.day]
strategy.currentDate = self.timeperiod[self.day]
def update_total_assets(self, agent: InvestorAgent):
"""
Updates the total assets of an agent in the trading environment
:param agent: agent object
:return: None
"""
liquid = agent.capital_t
investments = []
for pos in agent.positions:
pos.update_investment(agent, self.currentDate)
investments.append(pos.currentInvestment)
agent.update_assets(sum(investments) + liquid)
def async_grid(args):
"""
Runs grid search to see parameter values
:param args: args for the trade method
:return: None
"""
manager = CollectionManager('grid_search', 'AlgoTradingDB')
try:
stock = args[-1]
result = trade(*args)
log(f"{args} SUCCESS!\n{result}\n")
save_results(result, manager, stock)
except Exception as e:
log(f"{args} failed {e}")
manager.close()
def trade(loss, statsModel, p, sharePer, startDate, startingCapital, stop, ticker, epochs=1, neurons=1,
plotting=False):
"""
TRADES a given stock for a period of time
:param loss: amount of loss willing to take
:param statsModel: string of the predictive model to be used
:param p: p value for the strategy
:param sharePer: share percentage for the strategy
:param startDate: date to start YYYY-MM-DD
:param startingCapital: capital to start trading with
:param stop: stop date YYYY-MM-DD
:param ticker: stock ticker
:param plotting: whether you want to plot or not
:return: results (dictionary)
"""
logger = Logger('comparison/{0}/trades/{1}.csv'.format(statsModel, ticker))
logger.log('Date,Open/Close,PositionNum,Type,Price,Shares,Investment,Profit,CurrentCapital')
positionOpenNum = 0
positionCloseNum = 0
warnings.filterwarnings("ignore")
"""Initialize Environment"""
# Data
manager = CollectionManager('5Y_technicals', 'AlgoTradingDB')
# Time
dates = manager.dates()
currentDate = startDate
startDay = dates.index(currentDate)
stopDay = dates.index(stop)
# bar = utils.ProgressBar(stopDay - startDay)
results = {'p': p, 'sharePer': sharePer}
# Predictive Model
if statsModel == 'Arima':
model = ArimaModel(1, 1, 0, ticker)
k = 5
if statsModel == 'LSTM':
model = NeuralNet(ticker, manager, startDay)
model.create_network()
model.train_network()
k = 1
if statsModel == 'SVM':
model = SVM(100, 0.01, ticker, manager, startDay)
model.fit()
k = 5
# Investor, Strategy and Trading Environment
stopLoss = (1 - loss) * startingCapital
tradingStrategy = Strategy(model, manager, ticker, currentDate, stopLoss, p)
investor = InvestorAgent(startingCapital, tradingStrategy, startDay)
environment = Environment(manager, investor, startDay)
# Simulate Trading Environment
print(f'Starting Trading {ticker}')
for d in range(startDay, stopDay):
if len(investor.positions):
for position in investor.positions:
currentPrice = investor.check_price(environment.currentDate)
actionDay = utils.laterDate(position.startDate,
position.holdTime)
if environment.currentDate == actionDay or position.at_trigger_point(currentPrice):
sellMessage = position.sell(investor, currentPrice)
logger.log(f'{environment.currentDate},close,{position.id},' + sellMessage)
positionCloseNum += 1
T = investor.strategy.arithmetic_returns(k, environment.day)
sig = investor.signal(T)
if sig != 0:
message = investor.strategy.make_position(investor, sig, environment.currentDate, stopLoss,
sharePer, posNum=positionOpenNum)
if message != None:
logger.log(f'{environment.currentDate},open,{positionOpenNum},' + message)
positionOpenNum += 1
environment.update_total_assets(investor)
if d != stopDay - 1:
environment.increment_day(investor.strategy)
# bar.progress()
"""PLOTTING"""
print('PLOTTING')
actualPrice = avg_price_timeseries(manager, ticker, dates[startDay:stopDay])
if not len(investor.capitalHistory):
expReturn = 0
else:
expReturn = round(((investor.totalAssetHistory[len(
investor.totalAssetHistory) - 1] - startingCapital) / startingCapital) * 100)
gain = str(expReturn) + '%'
possible = round(((actualPrice[-1] - actualPrice[0]) / actualPrice[0]) * 100, 1)
mdd = utils.MDD(investor.totalAssetHistory)
if plotting:
utils.plot_capital(investor.totalAssetHistory, dates[startDay:stopDay], ticker, actualPrice, gain, mdd,
possible, model=statsModel)
results['MDD'] = mdd
results['return'] = expReturn
results['possible'] = possible
etf = avg_price_timeseries(manager, 'spy', dates[startDay:stopDay])
print(f'RETURN ON INVESTMENT: {expReturn}')
print(f'Number of Positions Opened: {positionOpenNum}')
print(f'Number of Positions Closed:{positionCloseNum}')
print(f'Sharpe Ratio = {sharpe_ratio(investor.totalAssetHistory, etf, possible)}')
manager.close()
return (results)
if __name__ == '__main__':
warnings.filterwarnings("ignore")
"""Arguments"""
parser = argparse.ArgumentParser()
parser.add_argument('--model', choices=['Arima', 'LSTM', 'SVM'], metavar='M',
help='predictive model to use', default='Arima', required=False)
parser.add_argument('--startDate', help='start date YYYY-MM-DD', default='2017-09-05', required=False, type=str)
parser.add_argument('--startingCapital', help='amount of money to start with', default=5000.00, type=float,
required=False)
parser.add_argument('--loss', help='percent of money you are willing to lose', default=.30, type=float,
required=False)
parser.add_argument('--p', help='percent change to flag', default=0.03, type=float, required=False)
parser.add_argument('--ticker', help='stock to consider', default='aapl', type=str, required=False)
parser.add_argument('--sharePer', help='percent possible shares to buy', default=1.0, type=float, required=False)
parser.add_argument('--stop', help='stop date YYYY-MM-DD', default='2018-02-05', required=False, type=str)
parser.add_argument('--epochs', help='Number of Epochs for NN training', default=10, required=False, type=int)
parser.add_argument('--neurons', help='Number of neurons', default=4, required=False, type=int)
args = parser.parse_args()
trade(args.loss, args.model, args.p, args.sharePer, args.startDate, args.startingCapital, args.stop, args.ticker,
args.epochs, args.neurons, plotting=True)