#!/usr/bin/env python3 # -*- coding: utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt import sys stdoutOrigin = sys.stdout sys.stdout = open("log.txt","w") def create_observation_prices(df, column_name = ''): """create a dataframe with prices of the stock """ # set the index: df.index = pd.to_datetime(df['Date']) df2 = pd.DataFrame(index = df.index) # setting column names if column_name != '': df2['Observation Price'] = df[column_name] else: df2['Observation Price'] = df.iloc[:,1] return df2 def get_daily_stock_returns(df): """function will calculate the daily returns of the stock""" # set the index df2 = pd.DataFrame(index = df.index) # find the daily returns of the stock df2['Daily Returns'] = (df - df.shift(1)) / df.shift(1) # set the first column to zeroes so you dont have NaN inputs df2['Daily Returns'].iloc[0] = 0 df2 = df2.fillna(method = 'ffill') return df2 def create_long_short_position(df): """apply a long-short strategy, comparing the elements of the stock returns dataframe and comparing that against a scalar value (whether to buy/sell) \ we are going to apply a modified version of the 1% risk rule for day trading \ note: this is WITHOUT TRADING FEES INCLUDED""" # set the index df2 = pd.DataFrame(index = df.index) # create a metric (signal) on which to trade signal = pd.Series(index = df.index, data = 0) # go through all the daily returns of the stock, if it is less than -0.5% we will buy, if it is more than 0.05% we will sell # essentially: "buy low and sell high" for i in range(len(df)): if df['Daily Returns'].iloc[i - 1] < -0.005: signal[i] = 1 # BUY if df['Daily Returns'].iloc[i - 1] > 0.005: signal[i] = -1 # SELL # add signal into the dataframe df2['Position'] = signal df2 = df2.fillna(method = 'ffill') return df2 def create_long_short_position_tradingfees(df): """apply a long-short strategy, comparing the elements of the stock returns dataframe and comparing that against a scalar value (whether to buy/sell) \ we are going to apply a modified version of the 1% risk rule for day trading \ note: this is WITH TRADING FEES INCLUDED""" # set the index df2 = pd.DataFrame(index = df.index) # create a metric (signal) on which to trade signal = pd.Series(index = df.index, data = 0) # go through all the daily returns of the stock, if it is less than -0.5% we will buy, if it is more than 0.05% we will sell # essentially: "buy low and sell high" for i in range(len(df)): # within each if statement, we will apply a 0.25% trading fee if df['Daily Returns'].iloc[i - 1] < -0.005: signal[i] = 1 # BUY df['Daily Returns'].iloc[i - 1] * 1.0025 if df['Daily Returns'].iloc[i - 1] > 0.005: signal[i] = -1 # SELL df['Daily Returns'].iloc[i - 1] * 0.9975 # add signal into the dataframe df2['Position'] = signal df2 = df2.fillna(method = 'ffill') return df2 def calculate_long_short_returns(df, position, column_name = ''): """returns a pandas.DataFrame object containing the columns ['Market Return', 'Strategy Return', and 'Abnormal Return']""" # set the index df2 = pd.DataFrame(index = df.index) # setting column names if column_name != '': df2['Observation Price'] = df[column_name] else: df2['Observation Price'] = df.iloc[:,1] # calculate market returns long_returns = df2['Observation Price'] / df2['Observation Price'].shift(1) - 1 df2['Market Return'] = long_returns # calculate strategy returns strategy_returns = position['Position'] * df2['Market Return'] df2['Strategy Return'] = strategy_returns # calculate abnormal returns: how good is our strategy? df2['Abnormal Return'] = df2['Strategy Return'] - df2['Market Return'] # delete the observation column del df2['Observation Price'] # set the first row to 0 so we don't have a row of all NaN values df2.iloc[0] = 0 return df2 def plot_returns(df): """create a plot of the cumulative return for each column in the parameter df, a pandas.DataFrame object with market, strategy, and abnormal returns""" # return a cumulative sum of the market, strategy, and abnormal returns and plot it df[['Market Return', 'Strategy Return', 'Abnormal Return']].cumsum().plot() # set the title plt.title("Cumulative Returns") def statistics(df): """Compute descriptive statistics to how the investing strategy performed in terms of mean rate of return and standard deviation of returns, as well as the cumulative abnormal returns""" # set the index df2 = pd.DataFrame(index = df.index) # we will convert the strategy return dataframe into a series so we can apply the numpy mean function to it strategy_return = pd.Series(df['Strategy Return']) print("Mean rate of strategy returns: " + f'{np.mean(strategy_return):.5f}') # we will convert the strategy return dataframe into a series so we can apply the numpy STD function to it sd_return = pd.Series(df['Strategy Return']) print("Standard deviation of strategy returns: " + f'{np.std(strategy_return):.5f}') # we will convert the strategy return dataframe into a series so we can apply the numpy cumsum function to it df2['Cumulative Sum'] = df['Abnormal Return'].cumsum() print("Cumulative of abnormal returns: ") # print the cumulative abnormal returns print(f'{df2}') if __name__ == '__main__': filename = './my_data.csv' df = pd.read_csv(filename) df.index = df['Date'] bb = create_observation_prices(df, column_name = 'Adj Close') position = get_daily_stock_returns(bb) position2 = create_long_short_position(position) returns = calculate_long_short_returns(df, position2, column_name = 'Adj Close') plot = plot_returns(returns) statistics(returns) sys.stdout.close() sys.stdout=stdoutOrigin