148 lines
3.8 KiB
Python
148 lines
3.8 KiB
Python
import pandas as pd
|
|
import datetime as dt
|
|
import matplotlib.pyplot as plt
|
|
from util import get_data
|
|
|
|
|
|
def author():
|
|
return "felixm"
|
|
|
|
|
|
def normalize(timeseries):
|
|
return timeseries / timeseries.iloc[0]
|
|
|
|
|
|
def bollinger_band(df, symbol, period=20, m=2):
|
|
boll_sma = df[symbol].rolling(period).mean()
|
|
std = df[symbol].rolling(period).std()
|
|
boll_up = boll_sma + m * std
|
|
boll_lo = boll_sma - m * std
|
|
key_sma, key_up, key_lo = "boll_sma", "boll_up", "boll_lo"
|
|
df[key_sma] = boll_sma
|
|
df[key_up] = boll_up
|
|
df[key_lo] = boll_lo
|
|
return df[[key_sma, key_up, key_lo]]
|
|
|
|
|
|
def sma(df, symbol, period):
|
|
"""Adds SMA for one or multiple periods to df and returns SMAs"""
|
|
if type(period) is int:
|
|
period = [period]
|
|
keys = []
|
|
for p in period:
|
|
key = f"sma_{p}"
|
|
df[key] = df[symbol].rolling(p).mean()
|
|
keys.append(key)
|
|
return df[keys]
|
|
|
|
|
|
def ema(df, symbol, period):
|
|
"""Adds EMA for one or multiple periods to df and returns EMAs"""
|
|
if type(period) is int:
|
|
period = [period]
|
|
keys = []
|
|
for p in period:
|
|
key = f"ema_{p}"
|
|
df[key] = df[symbol].ewm(span=p).mean()
|
|
keys.append(key)
|
|
return df[keys]
|
|
|
|
|
|
def price_sma(df, symbol, period):
|
|
"""Calculates SMA and adds new column price divided by SMA to the df."""
|
|
if type(period) is int:
|
|
period = [period]
|
|
keys = []
|
|
for p in period:
|
|
key = f"price_sma_{p}"
|
|
sma = df[symbol].rolling(p).mean()
|
|
df[key] = df[symbol] / sma
|
|
keys.append(key)
|
|
return df[keys]
|
|
|
|
|
|
def rsi(df, symbol, period=14):
|
|
"""Calculates relative strength index over given period."""
|
|
|
|
def rsi(x):
|
|
pct = x.pct_change()
|
|
avg_gain = pct[pct > 0].mean()
|
|
avg_loss = pct[pct <= 0].abs().mean()
|
|
rsi = 100 - (100 /
|
|
(1 + ((avg_gain / period) /
|
|
(avg_loss / period))))
|
|
return rsi
|
|
|
|
key = f"rsi"
|
|
# Add one to get 'period' price changes (first change is nan).
|
|
period += 1
|
|
df[key] = df[symbol].rolling(period).apply(rsi)
|
|
return df[[key]]
|
|
|
|
|
|
def macd(df, symbol):
|
|
macd = df[symbol].ewm(span=12).mean() - df[symbol].ewm(span=26).mean()
|
|
k1 = "macd"
|
|
k2 = "macd_signal"
|
|
k3 = "macd_diff"
|
|
df[k1] = macd
|
|
df[k2] = macd.rolling(9).mean()
|
|
df[k3] = df[k1] - df[k2]
|
|
return df[[k1, k2, k3]]
|
|
|
|
|
|
def price_delta(df, symbol, period=1):
|
|
"""Calculate delta between previous day and today."""
|
|
k = f"diff_{period}"
|
|
df[k] = df[symbol].diff(periods=period)
|
|
return df[k]
|
|
|
|
|
|
def price_delta(df, symbol, period=1):
|
|
"""Calculate percentage change for period."""
|
|
k = f"pct_{period}"
|
|
df[k] = df[symbol].pct_change(periods=period)
|
|
df[k] = df[k].shift(-period)
|
|
return df[k]
|
|
|
|
|
|
def test_indicators():
|
|
symbol = "JPM"
|
|
|
|
sd = dt.datetime(2008, 1, 1)
|
|
ed = dt.datetime(2009, 12, 31)
|
|
df = get_data([symbol], pd.date_range(sd, ed))
|
|
df.drop(columns=["SPY"], inplace=True)
|
|
df_orig = df.copy()
|
|
# df = normalize(df)
|
|
|
|
sma(df, symbol, 21)
|
|
ema(df, symbol, 21)
|
|
df.plot(title="21 SMA and EMA")
|
|
plt.savefig('figure_1.png')
|
|
|
|
df = df_orig.copy()
|
|
sma(df, symbol, 8)
|
|
price_sma(df, symbol, 8)
|
|
df.plot(title="SMA and price / SMA", subplots=True)
|
|
plt.savefig('figure_2.png')
|
|
|
|
df = df_orig.copy()
|
|
bollinger_band(df, symbol)
|
|
df.plot(title="Bollinger Band")
|
|
plt.savefig('figure_3.png')
|
|
|
|
df = df_orig.copy()
|
|
rsi(df, symbol)
|
|
fig, axes = plt.subplots(nrows=2, sharex=True)
|
|
df[symbol].plot(ax=axes[0], title="JPM price action")
|
|
df["JPM-rsi(14)"].plot(ax=axes[1], title="RSI")
|
|
plt.savefig('figure_4.png')
|
|
|
|
df = df_orig.copy()
|
|
macd(df, symbol)
|
|
fig, axes = plt.subplots(nrows=2, sharex=True)
|
|
df[symbol].plot(ax=axes[0], title="JPM price action")
|
|
df[["JPM-macd", "JPM-macd-signal"]].plot(ax=axes[1])
|
|
plt.savefig('figure_5.png')
|