ready for dockerize
This commit is contained in:
parent
a10d6138e2
commit
e9f4b6be02
163
marketsim.py
163
marketsim.py
@ -1,163 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Created on Wed Feb 5 21:56:42 2020
|
|
||||||
|
|
||||||
@author: cpan
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""MC2-P1: Market simulator."""
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
# import datetime as dt
|
|
||||||
# import os
|
|
||||||
from util import get_data, plot_data
|
|
||||||
|
|
||||||
def normalize_data(df):
|
|
||||||
return df/df.iloc[0,:]
|
|
||||||
|
|
||||||
def fill_missing_values(df_data):
|
|
||||||
'''First fill forward and then fill backward'''
|
|
||||||
df_data.fillna(method="ffill", inplace=True)
|
|
||||||
df_data.fillna(method="bfill", inplace=True)
|
|
||||||
|
|
||||||
def get_orders(orders_file):
|
|
||||||
if isinstance(orders_file, pd.DataFrame):
|
|
||||||
# orders_df = orders_file.set_index('Date')
|
|
||||||
orders_df = orders_file
|
|
||||||
else:
|
|
||||||
orders_df = pd.read_csv(orders_file, index_col = 'Date', parse_dates = True,
|
|
||||||
na_values = ['nan'])
|
|
||||||
orders_df = orders_df.dropna()
|
|
||||||
orders_df = orders_df.sort_index()
|
|
||||||
return orders_df
|
|
||||||
|
|
||||||
def compute_daily_returns(df):
|
|
||||||
daily_returns = df.copy()
|
|
||||||
daily_returns[1:] = (df[1:] / df[:-1].values) - 1
|
|
||||||
daily_returns.iloc[0, :] = 0
|
|
||||||
return daily_returns
|
|
||||||
|
|
||||||
def compute_portfolio_stats(price, allocs=[0.1,0.2,0,3,0.4], rfr=0.0, sf=252.0):
|
|
||||||
norm_price = normalize_data(price)
|
|
||||||
norm_positions_val = norm_price * allocs
|
|
||||||
if len(norm_positions_val.columns) == 1:
|
|
||||||
norm_portfolio_val = norm_positions_val
|
|
||||||
else:
|
|
||||||
norm_portfolio_val = norm_positions_val.sum(axis=1).to_frame('PORTFOLIO')
|
|
||||||
cr = norm_portfolio_val.iloc[-1] / norm_portfolio_val.iloc[0] -1
|
|
||||||
daily_returns = compute_daily_returns(norm_portfolio_val)
|
|
||||||
daily_returns = daily_returns[1:] # remove first row (all zeros)
|
|
||||||
adr = daily_returns.mean()
|
|
||||||
sddr = daily_returns.std()
|
|
||||||
sr = np.sqrt(sf) * (adr - rfr)/sddr
|
|
||||||
return cr, adr, sddr, sr
|
|
||||||
|
|
||||||
def plot_against_SPY(df):
|
|
||||||
df_temp = df.copy()
|
|
||||||
if 'SPY' not in df_temp.columns:
|
|
||||||
df_SPY = get_data(['SPY'], pd.to_datetime(df_temp.index.values))
|
|
||||||
df_temp['SPY'] = df_SPY.values
|
|
||||||
else:
|
|
||||||
df_SPY = df_temp['SPY']
|
|
||||||
df_temp = normalize_data(df_temp)
|
|
||||||
plot_data(df_temp)
|
|
||||||
return df_SPY
|
|
||||||
|
|
||||||
def compute_portvals(orders_file = "./orders/orders.csv", start_val = 1000000,
|
|
||||||
commission=9.95, impact=0.005):
|
|
||||||
#read in order data
|
|
||||||
orders_df = get_orders(orders_file)
|
|
||||||
#scan symbols
|
|
||||||
symbols = list(set(orders_df['Symbol'].values))
|
|
||||||
#get date range
|
|
||||||
dates = pd.date_range(orders_df.index.values[0], orders_df.index.values[-1])
|
|
||||||
#read in prices
|
|
||||||
prices = get_data(symbols, dates)
|
|
||||||
# fill_missing_values(prices) # included in get_data() function
|
|
||||||
prices = prices[symbols]
|
|
||||||
#add an extra column 'Cash' and initialize it to all ones
|
|
||||||
prices['Cash'] = np.ones(prices.shape[0])
|
|
||||||
|
|
||||||
#duplicate price df into a units df, intialize it to all zeros
|
|
||||||
positions=prices*0.0
|
|
||||||
#initialize cash position with starting value
|
|
||||||
positions.loc[positions.index.values[0],['Cash']]=start_val
|
|
||||||
|
|
||||||
#adjust positions to show how stock units and cash are changing over time with orders
|
|
||||||
for index, row in orders_df.iterrows():
|
|
||||||
stock_sym = row['Symbol']
|
|
||||||
order_price = prices.loc[index, stock_sym]
|
|
||||||
order_shrs = row['Shares']
|
|
||||||
|
|
||||||
if row['Order'].upper() == 'BUY':
|
|
||||||
if positions.loc[index, 'Cash'] < order_shrs*order_price +\
|
|
||||||
commission + order_shrs*order_price*impact:
|
|
||||||
# print('Not enough cash to excute the order:\n', row)
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
#update positions on transaction days
|
|
||||||
positions.loc[index, stock_sym] += order_shrs
|
|
||||||
positions.loc[index, "Cash"] -= order_shrs*order_price
|
|
||||||
#deduct commission
|
|
||||||
positions.loc[index,"Cash"] -= commission
|
|
||||||
#impact = no. of orders in transaction * price of each share * impact.
|
|
||||||
positions.loc[index,"Cash"] -= order_shrs*order_price*impact
|
|
||||||
elif row['Order'].upper() == 'SELL':
|
|
||||||
if positions.loc[index, stock_sym] < order_shrs:
|
|
||||||
# print('Not enough shares to sell to fill the order:\n', row)
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
positions.loc[index, stock_sym] -= order_shrs
|
|
||||||
positions.loc[index, "Cash"] += order_shrs*order_price
|
|
||||||
#deduct commission
|
|
||||||
positions.loc[index,"Cash"] -= commission
|
|
||||||
#impact = no. of orders in transaction * price of each share * impact.
|
|
||||||
positions.loc[index,"Cash"] -= order_shrs*order_price*impact
|
|
||||||
|
|
||||||
# propagate positions beyond transaction days
|
|
||||||
start_row = positions.index.get_loc(index) + 1
|
|
||||||
positions.iloc[start_row:, :] = positions.iloc[start_row-1].values
|
|
||||||
|
|
||||||
#calculate port_vals
|
|
||||||
port_vals=prices*positions
|
|
||||||
port_vals.insert(0, 'Portfolio', port_vals.sum(axis=1))
|
|
||||||
|
|
||||||
return port_vals
|
|
||||||
|
|
||||||
def test_code():
|
|
||||||
of = "./orders/orders-05.csv"
|
|
||||||
sv = 1000000
|
|
||||||
|
|
||||||
# Process orders
|
|
||||||
portvals = compute_portvals(orders_file = of, start_val = sv)
|
|
||||||
if isinstance(portvals, pd.DataFrame):
|
|
||||||
portvals = portvals[portvals.columns[0]].to_frame() # just get the first column
|
|
||||||
else:
|
|
||||||
print("warning, code did not return a DataFrame")
|
|
||||||
|
|
||||||
# Get portfolio stats
|
|
||||||
start_date = pd.to_datetime(portvals.index.values[0])
|
|
||||||
end_date = pd.to_datetime(portvals.index.values[-1])
|
|
||||||
price_SPY = plot_against_SPY(portvals)
|
|
||||||
#portfolio stats calculated similar to assess_portfolio
|
|
||||||
rfr=0
|
|
||||||
sf=252
|
|
||||||
|
|
||||||
cr, adr, sddr, sr = compute_portfolio_stats(portvals, [1.0], rfr, sf)
|
|
||||||
crSP,adrSP,sddrSP,srSP = compute_portfolio_stats(price_SPY, [1.0], rfr, sf)
|
|
||||||
# Compare portfolio against $SPX
|
|
||||||
print("\nDate Range: {} to {}".format(start_date.date(), end_date.date()))
|
|
||||||
print()
|
|
||||||
print("Sharpe Ratio: {}, {}".format(sr, srSP))
|
|
||||||
print()
|
|
||||||
print("Cumulative Return: {}, {}".format(cr, crSP))
|
|
||||||
print()
|
|
||||||
print("Standard Deviation: {}, {}".format(sddr, sddrSP))
|
|
||||||
print()
|
|
||||||
print("Average Daily Return: {}, {}".format(adr, adrSP))
|
|
||||||
print()
|
|
||||||
print("Final Portfolio Value: {:.2f}".format(portvals['Portfolio'].iloc[-1]))
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
test_code()
|
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user