/
analyzer.py
179 lines (167 loc) · 8.91 KB
/
analyzer.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
import getdata
import pandas as pd
import portfolio
from datetime import datetime as dt
from dateutil.relativedelta import relativedelta
import numpy as np
import pandas.stats.moments as m
def construct_ranking_table(portfolio,lookbackDays=None,oldTable=None,enddate=dt.today().date(),index=None,silent=False):
#One,only one and exactly one of lookbackDays and oldTable should be specified.
dfarr = []
for stock in portfolio.stocks:
if index == None:
idx = getdata.getIndexTicker(getdata.getData([stock.ticker],getdata.getParamDict('stock exchange')))
else:
idx = index
indexCurrVal = getdata.get_history([idx],
dt.today()-relativedelta(days=5))[-1:]['Close'].values[0]
try:
indexPrevVal = getdata.get_history([idx],
oldTable.ix[stock.ticker]['Date'])['Close'].values[0]
except:
indexPrevVal = getdata.get_history([idx],
dt.today()-relativedelta(days=lookbackDays))['Close'].values[0]
dftemp = pd.DataFrame(data=[0],index=[0])
dftemp['Symbol'] = stock.ticker
dftemp['Name'] = getdata.getData([stock.ticker],"n")
dftemp['Price'] = getdata.get_history([stock.ticker],
enddate-relativedelta(days=5))[-1:]['Close'].values[0]
dftemp['Number Owned'] = stock.getSharesOwned()
dftemp['Current Value'] = dftemp['Price']*dftemp['Number Owned']
# try:
# dftemp['Previous Value'] = oldTable.ix[stock.ticker]['Current Value']
# except:
# prev_number_owned = dftemp['Number Owned']
# for transaction in stock.transactions:
# if transaction['Date'] > (enddate-relativedelta(days=lookbackDays)):
# if transaction['Type'] == 'Bought':
# prev_number_owned = prev_number_owned - transaction['Number']
# elif transaction['Type'] == 'Sold':
# prev_number_owned = prev_number_owned + transaction['Number']
# dftemp['Previous Value'] = prev_number_owned*getdata.get_history([stock.ticker],
# enddate-relativedelta(days=lookbackDays))['Close'].values[0]
# dftemp['%Gain (Period)'] = 100*(dftemp['Current Value'] - dftemp['Previous Value'])/dftemp['Previous Value']
prev_adj_close = getdata.get_history([stock.ticker],
enddate-relativedelta(days=lookbackDays))['Adj Close'].values[0]
dftemp['%Gain (Period)'] = 100*((getdata.get_history([stock.ticker],
enddate-relativedelta(days=5))[-1:]['Adj Close'].values[0]
- prev_adj_close)/prev_adj_close)
dftemp['%Gain Index (Period)'] = 100*(indexCurrVal - indexPrevVal)/indexPrevVal
dftemp['Index'] = idx
dftemp['GainSt - GainIdx'] = dftemp['%Gain (Period)'] - dftemp['%Gain Index (Period)']
#if dftemp['%Gain Index (Period)'] > dftemp['%Gain (Period)']:
# dftemp['Stock > Index'] = 'N'
#else:
# dftemp['Stock > Index'] = 'Y'
dftemp['Total Investment'] = stock.investment
dftemp['%Total Gain'] = 100*(dftemp['Current Value'] - stock.investment)/stock.investment
dftemp = dftemp.drop(0,axis=1)
dftemp.index = dftemp['Symbol']
dftemp = dftemp.drop('Symbol',axis=1)
dfarr.append(dftemp)
dftoret = pd.concat(dfarr)
#dftoret = dftoret.sort(columns='Stock > Index',ascending=False)
dftoret = dftoret.sort(columns='GainSt - GainIdx',ascending=False)
dftoret = dftoret.drop('GainSt - GainIdx',axis=1)
dftoret['Rank'] = range(1,len(dftoret)+1)
dftoret['Date'] = np.repeat(enddate,dftoret.shape[0])
if not silent:
print "Stocks doing better than the market:",dftoret[dftoret['%Gain (Period)']>dftoret['%Gain Index (Period)']].index.values
print "Stocks doing worse than the market:",dftoret[dftoret['%Gain (Period)']<dftoret['%Gain Index (Period)']].index.values[::-1]
return dftoret
def calc_sharpe_ratio_sym(data,symbol,lookbackDays,enddate=dt.today(),index=None,silent=False):
#data: Dataframe containing at least date for the required time period for the required symbol and index
#symbol: Symbol for which sharpe ratio is to be calculated
#lookbackDays: # of days to look back from the enddate to calculate sharpe ratio
#enddate: Last day for sharpe ratio calculation
#index: Reference index to be used
#silent: silence print statements
if index == None:
index = getdata.getIndexTicker(getdata.getData([symbol],getdata.getParamDict('stock exchange')))
#data = getdata.get_history([symbol,index],dt.today()-relativedelta(days=days))
#data = data.drop(['Open','High','Low','Close','Volume'],axis=1)
#data = data.unstack(0).swaplevel(0,1,axis=1).sortlevel(0,axis=1)
data = append_return(data)
r_sym = data.ix[symbol]['return'].ix[(enddate-relativedelta(days=lookbackDays)):enddate]
r_index = data.ix[index]['return'].ix[(enddate-relativedelta(days=lookbackDays)):enddate]
r_sym_mean = r_sym.mean()
r_index_mean = r_index.mean()
std_sym_wrt_index = (r_sym-r_index).std()
answer = (r_sym_mean-r_index_mean)/std_sym_wrt_index
if not silent:
print days, "day Sharpe Ratio for",symbol, "=",answer
return answer
def calc_sharpe_ratio_pf(data,portfolio,lookbackDays,enddate=dt.today(),index='^GSPC',silent=False):
#data: Dataframe containing at least date for the required time period for all stocks in portfoilo and index
#portfolio: Portfolio object for which sharpe ratio is to be calculated
#lookbackDays: # of days to look back from the enddate to calculate sharpe ratio
#enddate: Last day for sharpe ratio calculation
#index: Reference index to be used
#silent: silence print statements
#tickers = portfolio.getTickersInPortfolio()
#tickers.append(index)
#data = getdata.get_history(tickers,dt.today()-relativedelta(days=days))
#data = data.drop(['Open','High','Low','Close','Volume'],axis=1)
data = data.unstack(0).swaplevel(0,1,axis=1).sortlevel(0,axis=1)
data['PF','Adj Close'] = np.zeros(len(data))
for stock in portfolio.getStocksInPortfolio():
data['PF','Adj Close'] += data[stock.ticker,'Adj Close'] * stock.getSharesOwned()
#data = data.drop(stock.ticker,axis=1,level=0)
data = data.stack(0).swaplevel(0,1,axis=0).sortlevel(0,axis=0)
data = append_return(data)
r_sym = data.ix['PF']['return'].ix[(enddate-relativedelta(days=lookbackDays)):enddate]
r_index = data.ix[index]['return'].ix[(enddate-relativedelta(days=lookbackDays)):enddate]
r_sym_mean = r_sym.mean()
r_index_mean = r_index.mean()
std_sym_wrt_index = (r_sym-r_index).std()
answer = (r_sym_mean-r_index_mean)/std_sym_wrt_index
if not silent:
print days, "day Sharpe Ratio for portfolio",portfolio.name,"=",answer
return answer
def append_return(data):
#helper function to append %return column to the dataframe
data['return'] = np.zeros(len(data))
for symbol in data.index.levels[0]:
data.ix[symbol]['return'] = (data.ix[symbol]['Adj Close'] - data.ix[symbol]['Adj Close'].shift(1))/data.ix[symbol]['Adj Close']
return data
def get_up_days(data):
#helper function to filter only updays from dataframe
return data[data['Open'] < data['Close']]
def get_down_days(data):
#helper function to filer only down days from dataframe
return data[data['Open'] > data['Close']]
def calc_RSI(data,symbol,lookbackDays,enddate=dt.today(),silent=False):
#calculates relative strength index.
#data: Dataframe containing at least date for the required time period for the required symbol
#symbol: Symbol for which RSI is to be calculated
#lookbackDays: # of days to look back from the enddate to calculate RSI
#enddate: Last day for RSI
#silent: silence print statements
#data = getdata.get_history([symbol],dt.today()-relativedelta(days=days))
data = data.ix[symbol].ix[(enddate-relativedelta(days=lookbackDays)):enddate]
upDays = get_up_days(data)
downDays = get_down_days(data)
upAverage = (upDays['Close']-upDays['Open']).mean()
downAverage = (downDays['Open']-downDays['Close']).mean()
rs = upAverage/downAverage
rsi = 100 - (100/(1+rs))
if not silent:
print days, "day RSI for",symbol,"=",rsi
if rsi > 70:
print "stock may be overbought."
elif rsi < 30:
print "stock may be oversold."
return rsi
def look_for_RSI_divergence(data,symbol,days,silent=False):
## A bullish divergence occurs when the underlying security
## makes a lower low and RSI forms a higher low. RSI does not
## confirm the lower low and this shows strengthening momentum.
## A bearish divergence forms when the security records a
## higher high and RSI forms a lower high. RSI does not
## confirm the new high and this shows weakening momentum.
## Before getting too excited about divergences as great trading
## signals, it must be noted that divergences are misleading in a
## strong trend. A strong uptrend can show numerous bearish divergences
## before a top actually materializes. Conversely, bullish divergences
## can appear in a strong downtrend - and yet the downtrend continues.
pass