The notebook here allows to perform analysis for a single exchange security (shares).
In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
In [2]:
start = '2012-01-01'
end = '2017-12-31'
stock_symbol = 'SLV'
# Uncomment line below to download latest quotes for stocks
#%run ../money_machine_app/downloaders/stocks_data_downloader.py $start $end $stock_symbol
In [3]:
# The CSV file has following columns:
# Data, Otwarcie, Najwyzszy, Najnizszy, Zamkniecie, Wolumen
stock = pd.read_csv(f'../data-archive/stocks/{stock_symbol}.csv',
delimiter=',',
index_col='Data',
parse_dates=True)
In [4]:
# drop unnecessary columns
stock.drop(['Otwarcie', 'Najwyzszy', 'Najnizszy'], axis=1, inplace=True)
# rename column and index
stock.columns = ['Close', 'Volume']
stock.index.names = ['Date']
In [5]:
stock.info()
This is same as cumulative daily returns.
In [6]:
stock['Normed Return'] = stock['Close'] / stock.iloc[0]['Close']
In [7]:
stock['Normed Return'].plot(figsize=(14,10))
plt.title(f"'{stock_symbol}' - Total Stock Value");
In [8]:
stock['Daily Return'] = stock['Close'].pct_change(1)
In [9]:
stock.tail()
Out[9]:
In [10]:
stock['Daily Return'].plot(kind='hist', bins=100);
In [11]:
stock['Daily Return'].plot(kind='kde');
In [12]:
stock['Daily Return'].mean()
Out[12]:
In [13]:
stock['Daily Return'].std()
Out[13]:
In [14]:
SR = stock['Daily Return'].mean() / stock['Daily Return'].std()
if SR <= 1:
print(f'Sharpe Ratio = {SR}. Too risky asset.')
elif SR <= 2:
print(f'Sharpe Ratio = {SR}. Good.')
elif SR <= 3:
print(f'Sharpe Ratio = {SR}. Great.')
else:
print(f'Sharpe Ratio = {SR}. Excellent.')
In [15]:
ASR = (252**0.5) * SR
print(f'Annual Sharpe Ratio = {ASR}')
In [16]:
sma_1 = 10
sma_2 = 30
stock[f'SMA {sma_1}'] = stock['Close'].rolling(window=sma_1).mean()
stock[f'SMA {sma_2}'] = stock['Close'].rolling(window=sma_2).mean()
# crossovers
stock['signal'] = 0.0
stock['signal'][sma_1:] = np.where(stock[f'SMA {sma_1}'][sma_1:] > stock[f'SMA {sma_2}'][sma_1:], 1.0, 0.0)
stock['positions'] = stock['signal'].diff()
In [36]:
recent_stock = stock.tail(260);
fig = plt.figure(figsize=(14,10), dpi=200);
fig.patch.set_facecolor('white'); # Set the outer colour to white
ax1 = fig.add_subplot(111, ylabel='Price in PLN');
#stock['Close'].tail(260).plot(ax=ax1, color='r');
#stock[[f'SMA {sma_1}', f'SMA {sma_2}']].tail(260).plot(ax=ax1);
ax1.plot(recent_stock['Close'], color='blue')
ax1.plot(recent_stock[f'SMA {sma_1}'])
ax1.plot(recent_stock[f'SMA {sma_2}'], color='orange')
# Plot the "buy" trades
ax1.plot(recent_stock[recent_stock["positions"] == 1.0].index,
recent_stock[f'SMA {sma_1}'][recent_stock["positions"] == 1.0],
'^', markersize=10, color='g');
# Plot the "sell" trades
ax1.plot(recent_stock[recent_stock["positions"] == -1.0].index,
recent_stock[f'SMA {sma_1}'][recent_stock['positions'] == -1.0],
'v', markersize=10, color='r');
ax1.legend();
In [18]:
recent_stock[recent_stock["positions"] == 1.0].index.tolist()
Out[18]:
In [19]:
recent_stock[recent_stock["positions"] == -1.0].index.tolist()
Out[19]:
In [20]:
stock['SMA 20'] = stock['Close'].rolling(window=20).mean()
stock['B-Band Upper'] = stock['SMA 20'] + 2*stock['Close'].rolling(window=20).std()
stock['B-Band Lower'] = stock['SMA 20'] - 2*stock['Close'].rolling(window=20).std()
In [21]:
stock['BB-signal'] = 0.0
stock['BB-signal'][20:] = np.where(stock['Close'][20:] >= stock['B-Band Upper'][20:], 1.0, 0.0)
stock['BB-sell-positions'] = stock['BB-signal'].diff()
stock['BB-signal'] = 0.0
stock['BB-signal'][20:] = np.where(stock['Close'][20:] <= stock['B-Band Lower'][20:], -1.0, 0.0)
stock['BB-buy-positions'] = stock['BB-signal'].diff()
recent_stock = stock.tail(260)
In [37]:
fig,ax1 = plt.subplots(figsize=(16,10), dpi=200);
ax1.plot(recent_stock['Close'], color='cornflowerblue')
ax1.plot(recent_stock['SMA 20'], color='orange')
ax1.plot(recent_stock['B-Band Upper'], color='green')
ax1.plot(recent_stock['B-Band Lower'], color='red')
# Plot the "sell" trades
ax1.plot(recent_stock[recent_stock["BB-sell-positions"] == 1.0].index,
recent_stock['B-Band Upper'][recent_stock["BB-sell-positions"] == 1.0],
'v', markersize=10, color='r');
# Plot the "buy" trades
ax1.plot(recent_stock[recent_stock["BB-buy-positions"] == -1.0].index,
recent_stock['B-Band Lower'][recent_stock["BB-buy-positions"] == -1.0],
'^', markersize=10, color='g');
ax1.legend();
In [23]:
recent_stock[recent_stock["BB-buy-positions"] == -1.0].index.tolist()
Out[23]:
In [24]:
recent_stock[recent_stock["BB-sell-positions"] == 1.0].index.tolist()
Out[24]:
In [25]:
#temp_values = [1,2,4,6,7,10];
#temp_index = pd.date_range(pd.datetime.today(),
# periods = len(temp_values),
# normalize=True).tolist()
#temp_pd = pd.DataFrame(data=temp_values, index=temp_index)
#print(temp_pd)
#print(temp_pd.diff())
In [26]:
stock[f'EWMA {sma_1}'] = stock['Close'].ewm(span=10).mean()
stock[f'EWMA {sma_2}'] = stock['Close'].ewm(span=20).mean()
In [27]:
stock[['Close', f'EWMA {sma_1}', f'EWMA {sma_2}']].tail(260).plot(figsize=(16,10));
In [28]:
from statsmodels.tsa.stattools import adfuller
def adf_check(time_series):
"""
Pass in a time series, returns ADF report
"""
result = adfuller(time_series)
print('Augmented Dickey-Fuller Test:')
labels = ['ADF Test Statistic','p-value','#Lags Used','Number of Observations Used']
for value,label in zip(result,labels):
print(label+' : '+str(value) )
print("")
if result[1] <= 0.05:
print("Strong evidence against the null hypothesis, reject the null hypothesis. Data has no unit root and is stationary.")
else:
print("Weak evidence against null hypothesis, time series has a unit root, indicating it is non-stationary.")
In [29]:
adf_check(stock['SMA 20'].dropna())
In [30]:
stock['SMA 20 - First Diff'] = stock['SMA 20'] - stock['SMA 20'].shift(1)
adf_check(stock['SMA 20 - First Diff'].dropna())
In [31]:
stock['SMA 20 - First Diff'].plot()
Out[31]:
In [32]:
from statsmodels.tsa.seasonal import seasonal_decompose
decomposition = seasonal_decompose(stock['SMA 20 - First Diff'].dropna().tail(300), freq=12)
fig = plt.figure()
fig = decomposition.plot()
fig.set_size_inches(15, 8)
In [33]:
import statsmodels.api as sm
model = sm.tsa.statespace.SARIMAX(stock['SMA 20 - First Diff'].dropna().tail(300),order=(0,1,0), seasonal_order=(1,1,1,12))
results = model.fit()
#print(results.summary())
In [34]:
#stock['forecast'] = results.predict(start = 1300, end= 1440, dynamic= True)
#stock[['SMA 20 - First Diff','forecast']].plot(figsize=(12,8))