Implement marketsim without commission and impact

This commit is contained in:
2020-10-09 10:39:17 -04:00
parent 117d97b8e9
commit cb72af1781

View File

@@ -29,9 +29,11 @@ import pandas as pd
import numpy as np
import datetime as dt
import os
import sys
from util import get_data, plot_data
from optimize_something.optimization import calculate_stats
def read_orders(orders_file):
"""
Parser orders into the form:
@@ -48,35 +50,78 @@ def read_orders(orders_file):
2011-01-10,AAPL,SELL,1500
"""
orders = pd.read_csv(orders_file,
index_col=['Date'],
dtype='|str, str, str, i4',
parse_dates=["Date"])
parse_dates=['Date'])
orders.sort_values(by="Date", inplace=True)
return orders
def get_order_book_info(orders):
"""Return start_date, end_date, and symbols (as a list)."""
start_date = orders.iloc[0].Date
end_date = orders.iloc[0].Date
start_date = orders.index[0]
end_date = orders.index[-1]
symbols = sorted(list((set(orders.Symbol.tolist()))))
return start_date, end_date, symbols
def get_portfolio_value(holding, prices):
"""Calculate the current portofolio value."""
value = 0
for ticker, shares in holding.items():
if ticker == 'cash':
value += shares
else:
value += shares * prices[ticker]
return value
def handle_orders(orders, holding, adj_closing_prices):
"""Process the orders."""
for date, order in orders.iterrows():
symbol, order, shares = order
adj_closing_price = adj_closing_prices[symbol]
cost = shares * adj_closing_price
if order == "BUY":
# print(f"Buy {shares:6} of {symbol:4} on {date}")
holding['cash'] -= cost
holding[symbol] += shares
elif order == "SELL":
# print(f"Sell {shares:6} of {symbol:4} on {date}")
holding['cash'] += cost
holding[symbol] -= shares
else:
raise Exception("Unexpected order type.")
def compute_portvals(orders_file="./orders/orders-01.csv", start_val=1000000, commission=9.95, impact=0.005):
orders = read_orders(orders_file)
start_date, end_date, symbols = get_order_book_info(orders)
# In the template, instead of computing the value of the portfolio, we just
# read in the value of IBM over 6 months
start_date = dt.datetime(2008, 1, 1)
end_date = dt.datetime(2008, 6, 1)
portvals = get_data(['IBM'], pd.date_range(start_date, end_date))
portvals = portvals[['IBM']] # remove SPY
# Tickers in the orderbook over the date_range in the order book.
prices = get_data(symbols, pd.date_range(start_date, end_date))
prices['Portval'] = pd.Series(0.0, index=prices.index)
# A dictionary to keep track of the assets we are holding.
holding = {s: 0 for s in symbols}
holding['cash'] = start_val
orders_processed = 0
for date, values in prices.iterrows():
if date in orders.index:
current_orders = orders.loc[date:date]
orders_processed += current_orders.shape[0]
handle_orders(current_orders, holding, values)
# Compute portfolio value at the end of day.
values['Portval'] = get_portfolio_value(holding, values)
# Make sure we have processed all orders. If there was an order on a
# non-trading day we would currently not handle it.
assert(orders.shape[0] == orders_processed)
portvals = prices[['Portval']]
return portvals
# Don't know why this was in template. Keep for now.
# rv = pd.DataFrame(index=portvals.index, data=portvals.values)
# return rv
def test_code():
@@ -89,20 +134,14 @@ def test_code():
else:
raise Exception("warning, code did not return a DataFrame")
# One way of getting the portfolio dates
# print(portvals.index[0])
# Get portfolio stats.
start_date = dt.datetime(2008, 1, 1)
end_date = dt.datetime(2008, 6, 1)
start_date = portvals.index[0]
end_date = portvals.index[-1]
cum_ret, avg_daily_ret, \
std_daily_ret, sharpe_ratio = calculate_stats(portvals.to_frame(), [1])
std_daily_ret, sharpe_ratio = calculate_stats(portvals.to_frame(), [1])
spy = get_data(['SPY'], pd.date_range(start_date, end_date))
cum_ret_SPY, avg_daily_ret_SPY, \
std_daily_ret_SPY, sharpe_ratio_SPY = calculate_stats(spy, [1])
std_daily_ret_SPY, sharpe_ratio_SPY = calculate_stats(spy, [1])
# Compare portfolio against $SPY
print(f"Date Range: {start_date} to {end_date}")