Last active
July 1, 2019 05:05
-
-
Save sshariff01/6c6ec2086072aa2c57aa6ccd26dc4d72 to your computer and use it in GitHub Desktop.
ML4T - Project 6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Student Name: Shoabe Shariff | |
GT User ID: sshariff3 | |
GT ID: 903272097 | |
""" | |
import pandas as pd | |
import numpy as np | |
import datetime as dt | |
import os | |
from util import get_data, plot_data | |
import matplotlib.pyplot as plt | |
import pdb | |
def author(): | |
return 'sshariff3' | |
def illustrate_indicators(symbols = ['JPM'], start_date = dt.datetime(2008, 1, 1), end_date = dt.datetime(2009, 12, 31)): | |
prices = get_data(symbols, pd.date_range(start_date, end_date), addSPY=False).dropna(axis=0) | |
plot_data(calculate_momentum(prices), title='Technical Indicator 1: Momentum', xlabel='Date', ylabel='Momentum') | |
plot_data(calculate_bollinger_bands(prices), title='Technical Indicator 2: Bollinger Bands', xlabel='Date', ylabel='Price') | |
plot_data(calculate_sma(prices), title='Technical Indicator 3: Simple Moving Average (SMA)', xlabel='Date', ylabel='Normalized Price') | |
plot_data(calculate_macd(prices), title='Technical Indicator 4: Moving Average Convergence Divergence (MACD)', xlabel='Date', ylabel='Price') | |
""" | |
Technical Indicator 1 - Momentum | |
momentum[t] = price[t] / price[t-n] | |
* n = 10 | |
""" | |
def calculate_momentum(prices): | |
df_temp = prices.copy() | |
df_temp[1:] = (df_temp[10:] / df_temp[:-10].values) - 1 | |
df_temp.iloc[0:10] = np.nan | |
return df_temp | |
""" | |
Technical Indicator 2 - Bollinger Bands | |
1. Compute rolling mean | |
2. Compute rolling std deviation | |
3. Compute upper and lower bands | |
* window size = 20 | |
""" | |
def calculate_bollinger_bands(prices): | |
rolling_mean = get_rolling_mean(prices['JPM'], window_size=20) | |
rolling_std = get_rolling_std(prices['JPM'], window_size=20) | |
upper_band, lower_band = get_bollinger_bands(rolling_mean, rolling_std) | |
rolling_mean = rolling_mean.to_frame('Rolling Mean') | |
rolling_std = rolling_std.to_frame('Rolling Std') | |
upper_band = upper_band.to_frame('Upper Band') | |
lower_band = lower_band.to_frame('Lower Band') | |
bollinger_band = (prices['JPM'] - rolling_mean['Rolling Mean']) / (2 * rolling_std['Rolling Std']) | |
bollinger_band = bollinger_band.to_frame('Bollinger Band') | |
df_temp = prices.join(rolling_mean).join(upper_band).join(lower_band).join(bollinger_band) | |
return df_temp | |
def get_rolling_mean(values, window_size): | |
return pd.rolling_mean(values, window=window_size) | |
def get_rolling_std(values, window_size): | |
return pd.rolling_std(values, window=window_size) | |
def get_bollinger_bands(rm, rstd): | |
upper_band = rm + rstd*2 | |
lower_band = rm - rstd*2 | |
return upper_band, lower_band | |
""" | |
Technical Indicator 3 - SMA | |
1. Plot SMA | |
2. Plot Price | |
3. Plot Price/SMA | |
* moving window size = 10 | |
""" | |
def calculate_sma(prices): | |
normalized_prices = prices / prices.ix[0,:] | |
rolling_mean = get_rolling_mean(normalized_prices['JPM'], window_size=10) | |
rolling_mean = rolling_mean.to_frame('SMA') | |
df_temp = normalized_prices.join(rolling_mean) | |
df_temp['JPM/SMA'] = df_temp['JPM'] / df_temp['SMA'] - 1 | |
return df_temp | |
""" | |
Technical Indicator 4 - MACD | |
MACD = (12 period EMA) - (26 period EMA) | |
Sources: | |
* MACD - https://www.investopedia.com/terms/m/macd.asp | |
* DataFrame EWM - http://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.ewm.html | |
""" | |
def calculate_macd(prices): | |
ema_12 = prices.ewm(span=12).mean() | |
ema_12 = ema_12.rename(columns={'JPM': 'JPM 12-period Exp Moving Avg'}) | |
ema_26 = prices.ewm(span=26).mean() | |
ema_26 = ema_26.rename(columns={'JPM': 'JPM 26-period Exp Moving Avg'}) | |
df_temp = ema_12.join(ema_26) | |
df_temp['MACD'] = df_temp['JPM 12-period Exp Moving Avg'] - df_temp['JPM 26-period Exp Moving Avg'] | |
df_temp['Signal Line'] = df_temp['MACD'].ewm(span=9).mean() | |
return df_temp | |
if __name__ == "__main__": | |
illustrate_indicators() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Student Name: Shoabe Shariff | |
GT User ID: sshariff3 | |
GT ID: 903272097 | |
""" | |
import pandas as pd | |
import numpy as np | |
import datetime as dt | |
import os | |
from util import get_data, plot_data | |
from indicators import calculate_momentum, calculate_bollinger_bands, calculate_sma, calculate_macd | |
from marketsimcode import compute_portvals | |
import matplotlib.pyplot as plt | |
import pdb | |
def testPolicy(symbol = "AAPL", sd=dt.datetime(2010, 1, 1), ed=dt.datetime(2011, 12, 31), sv = 100000): | |
adjusted_close_prices = get_data([symbol], pd.date_range(sd, ed), addSPY=False).dropna() | |
adjusted_close_prices.index.name = 'Date' | |
momentum = calculate_momentum(adjusted_close_prices).rename(columns={symbol: 'Momentum'}) | |
bollinger_bands = calculate_bollinger_bands(adjusted_close_prices).drop('JPM', axis=1) | |
sma = calculate_sma(adjusted_close_prices)['JPM/SMA'] | |
portfolio = {} | |
portfolio['Shares'] = 0 | |
indicators = adjusted_close_prices.join(momentum).join(bollinger_bands).join(sma) | |
return indicators.apply(lambda x: generate_orders(x, portfolio), axis=1, raw=False) | |
def generate_orders(indicators, portfolio): | |
order = 0 | |
if portfolio['firstRun'] == True: | |
portfolio['firstRun'] = False | |
indicators['Orders'] = 0 | |
return indicators['Orders'] | |
if indicators['JPM/SMA'] < 0 and indicators['Bollinger Band'] < 1 and indicators['Momentum'] < 0: | |
if portfolio['Shares'] < 1000: # BUY 1000 shares | |
order = 1000 | |
portfolio['Shares'] = portfolio['Shares'] + 1000 | |
elif indicators['JPM/SMA'] > 0 and indicators['Bollinger Band'] > -1 and indicators['Momentum'] > 0: | |
if portfolio['Shares'] > -1000: # SELL 1000 shares | |
order = -1000 | |
portfolio['Shares'] = portfolio['Shares'] - 1000 | |
elif indicators['JPM/SMA'] > 0.5 and indicators['Bollinger Band'] > 1 and indicators['Momentum'] < 0: | |
if portfolio['Shares'] > 0: # SELL 2000 shares | |
order = -2000 | |
portfolio['Shares'] = portfolio['Shares'] - 2000 | |
elif portfolio['Shares'] == 0: # SELL 1000 shares | |
order = -1000 | |
portfolio['Shares'] = portfolio['Shares'] - 1000 | |
elif indicators['Momentum'] < 0: | |
if portfolio['Shares'] >= 0: # SELL 1000 shares | |
order = -1000 | |
portfolio['Shares'] = portfolio['Shares'] - 1000 | |
elif indicators['Momentum'] > 0: | |
if portfolio['Shares'] >= 0: # SELL 1000 shares | |
order = -1000 | |
portfolio['Shares'] = portfolio['Shares'] - 1000 | |
indicators['Orders'] = order | |
return indicators['Orders'] | |
def compute_daily_returns(df): | |
daily_returns = df.copy() | |
daily_returns[1:] = (df[1:] / df[:-1].values) - 1 | |
return daily_returns.ix[1:] | |
def report_metrics(port_vals, strategy): | |
daily_rets = compute_daily_returns(port_vals) | |
cr = (port_vals[-1]/port_vals[0]) - 1 | |
adr = daily_rets.mean() | |
sddr = daily_rets.std() | |
print "Cumulative Return of {}: {}".format(strategy, cr) | |
print "Standard Deviation of {}: {}".format(strategy, sddr) | |
print "Average Daily Return of {}: {}".format(strategy, adr) | |
def test_sample_data(sd = dt.datetime(2008, 1, 1), ed = dt.datetime(2009, 12, 31)): | |
symbol = "JPM" | |
start_val = 100000 | |
#### | |
# Manual Strategy | |
#### | |
df_trades = testPolicy(symbol=symbol, sd=sd, ed=ed, sv=start_val) | |
df_trades = df_trades.to_frame('Order') | |
manual_portvals = compute_portvals(df_trades, symbol, start_val=start_val, commission=9.95, impact=0.005) | |
report_metrics(manual_portvals, 'Manual Strategy') | |
manual_portvals = manual_portvals.to_frame('Manual Strategy') | |
normalized_manual_strategy = manual_portvals / manual_portvals.ix[0,:] | |
#### | |
# Benchmark | |
#### | |
benchmark_trades = df_trades.copy() | |
adjusted_close_prices = get_data([symbol], pd.date_range(sd, ed), addSPY=False).dropna() | |
adjusted_close_prices.index.name = 'Date' | |
first_transaction_date = adjusted_close_prices.index[adjusted_close_prices['JPM'] != 0][0] | |
benchmark_trades['Order'] = 0 | |
benchmark_trades.loc[first_transaction_date]['Order'] = 1000 | |
benchmark_portvals = compute_portvals(benchmark_trades, symbol, start_val=start_val, commission=9.95, impact=0.005) | |
report_metrics(benchmark_portvals, 'Benchmark') | |
benchmark_portvals = benchmark_portvals.to_frame('Benchmark') | |
normalized_benchmark = benchmark_portvals / benchmark_portvals.ix[0,:] | |
#### | |
# Plot | |
#### | |
df_temp = normalized_benchmark.join(normalized_manual_strategy) | |
ax = df_temp.plot(title='Manual Strategy vs Benchmark', fontsize=12, color=['green', 'red']) | |
ax.set_xlabel('Date') | |
ax.set_ylabel('Portfoio Value') | |
plt.show() | |
if __name__ == "__main__": | |
test_sample_data(sd = dt.datetime(2008, 1, 1), ed = dt.datetime(2009, 12, 31)) | |
test_sample_data(sd = dt.datetime(2010, 1, 1), ed = dt.datetime(2011, 12, 31)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""MC2-P1: Market simulator. | |
Copyright 2018, Georgia Institute of Technology (Georgia Tech) | |
Atlanta, Georgia 30332 | |
All Rights Reserved | |
Template code for CS 4646/7646 | |
Georgia Tech asserts copyright ownership of this template and all derivative | |
works, including solutions to the projects assigned in this course. Students | |
and other users of this template code are advised not to share it with others | |
or to make it available on publicly viewable websites including repositories | |
such as github and gitlab. This copyright statement should not be removed | |
or edited. | |
We do grant permission to share solutions privately with non-students such | |
as potential employers. However, sharing with other current or future | |
students of CS 7646 is prohibited and subject to being investigated as a | |
GT honor code violation. | |
-----do not edit anything above this line--- | |
Student Name: Shoabe Shariff | |
GT User ID: sshariff3 | |
GT ID: 903272097 | |
""" | |
import pandas as pd | |
import numpy as np | |
import datetime as dt | |
import os | |
from util import get_data, plot_data | |
import pdb | |
def author(): | |
return 'sshariff3' | |
def compute_portvals(df_trades, symbol, start_val = 1000000, commission=9.95, impact=0.005): | |
# this is the function the autograder will call to test your code | |
# NOTE: orders_file may be a string, or it may be a file object. Your | |
# code should work correctly with either input | |
# TODO: Your code here | |
orders = df_trades.sort_index() | |
start_date = orders.index[0] | |
end_date = orders.index[-1] | |
adjusted_close_prices = get_data([symbol], pd.date_range(start_date, end_date), addSPY=False) | |
adjusted_close_prices.index.name = 'Date' | |
adjusted_close_prices['PORTFOLIO'] = 0 | |
portfolio = dict.fromkeys([symbol], 0) | |
portfolio['CASH'] = start_val | |
return adjusted_close_prices.apply(lambda x: calculate_portfolio_value(x, orders, symbol, portfolio, commission, impact), axis=1, raw=False).dropna() | |
def calculate_portfolio_value(prices, orders_all, symbol, portfolio, commission, impact): | |
if prices.name in orders_all.index: | |
orders_for_the_day = orders_all.loc[orders_all.index == prices.name, ['Order']] | |
orders_for_the_day.apply(lambda x: update_portfolio(x, prices, symbol, portfolio, commission, impact), axis=1, raw=False) | |
prices['PORTFOLIO'] = portfolio['CASH'] # Initialize to cash holdings amount | |
for sym in portfolio.keys(): | |
if sym == 'CASH': | |
continue | |
num_shares_in_portfolio = portfolio[sym] | |
prices['PORTFOLIO'] = prices['PORTFOLIO'] + num_shares_in_portfolio * prices[sym] | |
return prices['PORTFOLIO'] | |
def update_portfolio(order, prices, purchase_symbol, portfolio, commission, impact): | |
trade_num_shares = order['Order'] | |
stock_price = prices[purchase_symbol] | |
# Update Portfolio Shares and Cash Holdings | |
if trade_num_shares > 0: | |
portfolio[purchase_symbol] = portfolio[purchase_symbol] + trade_num_shares | |
# Apply market impact - Price goes up by impact prior to purchase | |
stock_price = stock_price * (1 + impact) | |
portfolio['CASH'] = portfolio['CASH'] - trade_num_shares * stock_price | |
# Apply commission - To be applied on every transaction, regardless of BUY or SELL | |
portfolio['CASH'] = portfolio['CASH'] - commission | |
elif trade_num_shares < 0: | |
trade_num_shares = -1 * trade_num_shares | |
portfolio[purchase_symbol] = portfolio[purchase_symbol] - trade_num_shares | |
# Apply market impact - Price goes down by impact prior to sell | |
stock_price = stock_price * (1 - impact) | |
portfolio['CASH'] = portfolio['CASH'] + trade_num_shares * stock_price | |
# Apply commission - To be applied on every transaction, regardless of BUY or SELL | |
portfolio['CASH'] = portfolio['CASH'] - commission | |
if __name__ == "__main__": | |
compute_portvals() | |
# test_code() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Student Name: Shoabe Shariff | |
GT User ID: sshariff3 | |
GT ID: 903272097 | |
""" | |
import pandas as pd | |
import numpy as np | |
import datetime as dt | |
import os | |
from util import get_data, plot_data | |
from marketsimcode import compute_portvals | |
import matplotlib.pyplot as plt | |
import pdb | |
def testPolicy(symbol = "AAPL", sd=dt.datetime(2010, 1, 1), ed=dt.datetime(2011, 12, 31), sv = 100000): | |
adjusted_close_prices = get_data([symbol], pd.date_range(sd, ed), addSPY=False).dropna() | |
adjusted_close_prices.index.name = 'Date' | |
adjusted_close_prices = adjusted_close_prices.rename(columns={symbol: 'Today'}) | |
adjusted_close_prices['Next'] = adjusted_close_prices['Today'].shift(-1) | |
portfolio = {} | |
portfolio['Shares'] = 0 | |
portfolio['firstRun'] = True | |
current_holdings = 0 | |
return adjusted_close_prices.apply(lambda x: generate_orders(x, portfolio), axis=1, raw=False) | |
def generate_orders(data, portfolio): | |
if portfolio['firstRun']: | |
portfolio['firstRun'] = False | |
data['Orders'] = 0 | |
return data['Orders'] | |
future_price_increase = data['Next'] - data['Today'] | |
order = 0 | |
if future_price_increase > 0 and portfolio['Shares'] < 1000: | |
order = 1000 - portfolio['Shares'] | |
portfolio['Shares'] = 1000 | |
elif future_price_increase < 0 and portfolio['Shares'] > -1000: | |
order = -1000 - portfolio['Shares'] | |
portfolio['Shares'] = -1000 | |
data['Orders'] = order | |
return data['Orders'] | |
def compute_daily_returns(df): | |
daily_returns = df.copy() | |
daily_returns[1:] = (df[1:] / df[:-1].values) - 1 | |
return daily_returns.ix[1:] | |
def report_metrics(port_vals, strategy): | |
daily_rets = compute_daily_returns(port_vals) | |
cr = (port_vals[-1]/port_vals[0]) - 1 | |
adr = daily_rets.mean() | |
sddr = daily_rets.std() | |
print "Cumulative Return of {}: {}".format(strategy, cr) | |
print "Standard Deviation of {}: {}".format(strategy, sddr) | |
print "Average Daily Return of {}: {}".format(strategy, adr) | |
if __name__ == "__main__": | |
symbol = "JPM" | |
sd = dt.datetime(2008, 1, 1) | |
ed = dt.datetime(2009, 12, 31) | |
# sd = dt.datetime(2010, 1, 1) | |
# ed = dt.datetime(2011, 12, 31) | |
start_val = 100000 | |
#### | |
# Theoretically Optimal Strategy | |
#### | |
df_trades = testPolicy(symbol=symbol, sd=sd, ed=ed, sv=start_val) | |
df_trades = df_trades.to_frame('Order') | |
theoretically_optimal_portvals = compute_portvals(df_trades, symbol, start_val=start_val, commission=0., impact=0.) | |
report_metrics(theoretically_optimal_portvals, 'Theoretically Optimal Strategy') | |
theoretically_optimal_portvals = theoretically_optimal_portvals.to_frame('Theoretically Optimal Strategy') | |
normalized_optimal_strategy = theoretically_optimal_portvals / theoretically_optimal_portvals.ix[0,:] | |
#### | |
# Benchmark | |
#### | |
benchmark_trades = df_trades.copy() | |
adjusted_close_prices = get_data([symbol], pd.date_range(sd, ed), addSPY=False).dropna() | |
adjusted_close_prices.index.name = 'Date' | |
first_transaction_date = adjusted_close_prices.index[adjusted_close_prices['JPM'] != 0][0] | |
benchmark_trades['Order'] = 0 | |
benchmark_trades.loc[first_transaction_date]['Order'] = 1000 | |
benchmark_portvals = compute_portvals(benchmark_trades, symbol, start_val=start_val, commission=0., impact=0.) | |
report_metrics(benchmark_portvals, 'Benchmark') | |
benchmark_portvals = benchmark_portvals.to_frame('Benchmark') | |
normalized_benchmark = benchmark_portvals / benchmark_portvals.ix[0,:] | |
#### | |
# Plot | |
#### | |
df_temp = normalized_benchmark.join(normalized_optimal_strategy) | |
ax = df_temp.plot(title='Theoretically Optimal Strategy vs Benchmark', fontsize=12, color=['green', 'red']) | |
ax.set_xlabel('Date') | |
ax.set_ylabel('Portfoio Value') | |
plt.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment