Skip to content

Commit

Permalink
Added paper 01C.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hvass-Labs committed Dec 22, 2018
1 parent 7b9c584 commit faa29e7
Show file tree
Hide file tree
Showing 16 changed files with 3,794 additions and 46 deletions.
3,249 changes: 3,249 additions & 0 deletions 01C_Theory_of_Long-Term_Stock_Forecasting.ipynb

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ modified and run again.

1-B. Better Long-Term Stock Forecasts ([Notebook](https://github.com/Hvass-Labs/FinanceOps/blob/master/01B_Better_Long-Term_Stock_Forecasts.ipynb)) ([Google Colab](https://colab.research.google.com/github/Hvass-Labs/FinanceOps/blob/master/01B_Better_Long-Term_Stock_Forecasts.ipynb))

1-C. Theory of Long-Term Stock Forecasting ([Notebook](https://github.com/Hvass-Labs/FinanceOps/blob/master/01C_Theory_of_Long-Term_Stock_Forecasting.ipynb)) ([Google Colab](https://colab.research.google.com/github/Hvass-Labs/FinanceOps/blob/master/01C_Theory_of_Long-Term_Stock_Forecasting.ipynb))

2. Comparing Stock Indices ([Notebook](https://github.com/Hvass-Labs/FinanceOps/blob/master/02_Comparing_Stock_Indices.ipynb)) ([Google Colab](https://colab.research.google.com/github/Hvass-Labs/FinanceOps/blob/master/02_Comparing_Stock_Indices.ipynb))

3. Portfolio Optimization Using Signals ([Notebook](https://github.com/Hvass-Labs/FinanceOps/blob/master/03_Portfolio_Optimization_Using_Signals.ipynb)) ([Google Colab](https://colab.research.google.com/github/Hvass-Labs/FinanceOps/blob/master/03_Portfolio_Optimization_Using_Signals.ipynb))
Expand Down
194 changes: 148 additions & 46 deletions data.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,122 @@ def _load_price_yahoo(ticker):
return price_daily


def _load_earnings_per_share(ticker, df, profit_margin=True):
"""
Load the Earnings Per Share from a data-file and add it to the DataFrame.
Also calculate the P/E ratio and profit margin.
:param ticker:
Name of the stock used in the filenames e.g. "WMT"
:param df:
Pandas DataFrame with SHARE_PRICE.
:param profit_margin:
Boolean whether to add the profit margin to the DataFrame.
Requires that df already contains SALES_PER_SHARE.
:return:
None. Data is added to the `df` DataFrame.
"""

# Load data.
path = os.path.join(data_dir, ticker + " Earnings Per Share.txt")
earnings_per_share = _load_data(path=path)

# Add to the DataFrame (interpolated daily).
df[EARNINGS_PER_SHARE] = _resample_daily(earnings_per_share)

# Add valuation ratio to the DataFrame (daily).
df[PE] = df[SHARE_PRICE] / df[EARNINGS_PER_SHARE]

# Add profit margin to the DataFrame (daily).
if profit_margin:
df[PROFIT_MARGIN] = df[EARNINGS_PER_SHARE] / df[SALES_PER_SHARE]


def _load_sales_per_share(ticker, df):
"""
Load the Sales Per Share from a data-file and add it to the DataFrame.
Also calculate the P/Sales ratio and one-year growth in Sales Per Share.
:param ticker:
Name of the stock used in the filenames e.g. "WMT"
:param df:
Pandas DataFrame with SHARE_PRICE.
:return:
None. Data is added to the `df` DataFrame.
"""

# Load data.
path = os.path.join(data_dir, ticker + " Sales Per Share.txt")
sales_per_share = _load_data(path=path)

# Add to the DataFrame (interpolated daily).
df[SALES_PER_SHARE] = _resample_daily(sales_per_share)

# Add valuation ratio to the DataFrame (daily).
df[PSALES] = df[SHARE_PRICE] / df[SALES_PER_SHARE]

# Add growth to the DataFrame (daily).
df[SALES_GROWTH] = df[SALES_PER_SHARE].pct_change(periods=365)


def _load_book_value_per_share(ticker, df):
"""
Load the Book-Value Per Share from a data-file and add it to the DataFrame.
Also calculate the P/Book ratio.
:param ticker:
Name of the stock used in the filenames e.g. "WMT"
:param df:
Pandas DataFrame with SHARE_PRICE.
:return:
None. Data is added to the `df` DataFrame.
"""

# Load data.
path = os.path.join(data_dir, ticker + " Book-Value Per Share.txt")
book_value_per_share = _load_data(path=path)

# Add to the DataFrame (interpolated daily).
df[BOOK_VALUE_PER_SHARE] = _resample_daily(book_value_per_share)

# Add valuation ratio to the DataFrame (daily).
df[PBOOK] = df[SHARE_PRICE] / df[BOOK_VALUE_PER_SHARE]


def _load_dividend_TTM(ticker, df):
"""
Load the Dividend Per Share TTM (Trailing Twelve Months) from a data-file and
add it to the DataFrame. Also calculate some related valuation ratios.
:param ticker:
Name of the stock-index used in the filenames e.g. "S&P 500"
:param df:
Pandas DataFrame with SHARE_PRICE.
:return:
None. Data is added to the `df` DataFrame.
"""

# Load data.
path = os.path.join(data_dir, ticker + " Dividend Per Share TTM.txt")
dividend_per_share_TTM = _load_data(path=path)

# Add to the DataFrame (interpolated daily).
df[DIVIDEND_TTM] = _resample_daily(dividend_per_share_TTM)

# Add valuation ratios to the DataFrame (daily).
df[PDIVIDEND] = df[SHARE_PRICE] / df[DIVIDEND_TTM]
df[DIVIDEND_YIELD] = df[DIVIDEND_TTM] / df[SHARE_PRICE]


########################################################################
# Public functions.

Expand Down Expand Up @@ -214,7 +330,7 @@ def load_index_data(ticker, sales=True, book_value=True, dividend_TTM=True):
path = os.path.join(data_dir, ticker + " Dividend Per Share.txt")
dividend_per_share = _load_data(path=path)

# Merge price and dividend into a single data-frame.
# Merge price and dividend into a single DataFrame.
df = pd.concat([price_daily, dividend_per_share], axis=1)

# Only keep the rows where the share-price is defined.
Expand All @@ -225,82 +341,68 @@ def load_index_data(ticker, sales=True, book_value=True, dividend_TTM=True):
# for stock indices because it does not reinvest dividends.
df[TOTAL_RETURN] = total_return(df=df)

# Load Sales Per Share data.
if sales:
# Load Sales Per Share data.
path = os.path.join(data_dir, ticker + " Sales Per Share.txt")
sales_per_share = _load_data(path=path)

# Add to the data-frame (interpolated daily).
df[SALES_PER_SHARE] = _resample_daily(sales_per_share)

# Add P/Sales ratio to the data-frame (daily).
df[PSALES] = df[SHARE_PRICE] / df[SALES_PER_SHARE]
_load_sales_per_share(ticker=ticker, df=df)

# Load Book-Value Per Share data.
if book_value:
# Load Book-Value Per Share data.
path = os.path.join(data_dir, ticker + " Book-Value Per Share.txt")
book_value_per_share = _load_data(path=path)

# Add to the data-frame (interpolated daily).
df[BOOK_VALUE_PER_SHARE] = _resample_daily(book_value_per_share)

# Add P/Book to the data-frame (daily).
df[PBOOK] = df[SHARE_PRICE] / df[BOOK_VALUE_PER_SHARE]
_load_book_value_per_share(ticker=ticker, df=df)

# Load Dividend Per Share TTM data.
if dividend_TTM:
# Load Dividend Per Share TTM data.
path = os.path.join(data_dir, ticker + " Dividend Per Share TTM.txt")
dividend_per_share_TTM = _load_data(path=path)

# Add to the data-frame (interpolated daily).
df[DIVIDEND_TTM] = _resample_daily(dividend_per_share_TTM)

# Add Dividend Yield to the data-frame (daily).
df[DIVIDEND_YIELD] = df[DIVIDEND_TTM] / df[SHARE_PRICE]

# Add P/Dividend to the data-frame (daily).
df[PDIVIDEND] = df[SHARE_PRICE] / df[DIVIDEND_TTM]
_load_dividend_TTM(ticker=ticker, df=df)

return df


def load_stock_data(ticker):
def load_stock_data(ticker, earnings=True, sales=True, book_value=True):
"""
Load data for a single stock from several different files
and combine them into a single Pandas DataFrame.
- Price is loaded from a Yahoo-file.
- Sales Per Share and Book-Value Per Share are loaded from separate files.
- Other data is loaded from separate files.
The Total Return is taken directly from the Yahoo price-data.
The P/Sales and P/Book ratios are calculated daily.
Valuation ratios such as P/E and P/Sales are calculated daily
from interpolated data.
:param ticker:
Name of the stock used in the filenames e.g. "WMT"
:param earnings:
Boolean whether to load data-file for Earnings Per Share.
:param sales:
Boolean whether to load data-file for Sales Per Share.
:param book_value:
Boolean whether to load data-file for Book-Value Per Share.
:return: Pandas DataFrame with the data.
"""
# Paths for the data-files.
path_sales_per_share = os.path.join(data_dir, ticker + " Sales Per Share.txt")
path_book_value_per_share = os.path.join(data_dir, ticker + " Book-Value Per Share.txt")

# Load the data-files.
price_daily = _load_price_yahoo(ticker=ticker)
sales_per_share = _load_data(path=path_sales_per_share)
book_value_per_share = _load_data(path=path_book_value_per_share)

# Use the DataFrame for the price and add more data-columns to it.
df = price_daily

# Only keep the rows where the share-price is defined.
df.dropna(subset=[SHARE_PRICE], inplace=True)

# Add financial data to the data-frame (interpolated daily).
df[SALES_PER_SHARE] = _resample_daily(sales_per_share)
df[BOOK_VALUE_PER_SHARE] = _resample_daily(book_value_per_share)
# Load Sales Per Share data.
if sales:
_load_sales_per_share(ticker=ticker, df=df)

# Add financial ratios to the data-frame (daily).
df[PSALES] = df[SHARE_PRICE] / df[SALES_PER_SHARE]
df[PBOOK] = df[SHARE_PRICE] / df[BOOK_VALUE_PER_SHARE]
# Load Earnings Per Share data.
# This needs the Sales Per Share data to calculate the profit margin.
if earnings:
_load_earnings_per_share(ticker=ticker, df=df)

# Load Book-Value Per Share data.
if book_value:
_load_book_value_per_share(ticker=ticker, df=df)

return df

Expand Down
28 changes: 28 additions & 0 deletions data/CLX Earnings Per Share.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Date Earnings Per Share
06/30/1992 0.45
06/30/1993 0.76
06/30/1994 0.99
06/30/1995 0.95
06/30/1996 1.07
06/30/1997 1.21
06/30/1998 1.46
06/30/1999 1.05
06/30/2000 1.67
06/30/2001 1.37
06/30/2002 1.39
06/30/2003 2.26
06/30/2004 2.31
06/30/2005 2.93
06/30/2006 2.94
06/30/2007 3.31
06/30/2008 3.30
06/30/2009 3.86
06/30/2010 4.30
06/30/2011 4.07
06/30/2012 4.13
06/30/2013 4.36
06/30/2014 4.31
06/30/2015 4.45
06/30/2016 5.00
06/30/2017 5.44

36 changes: 36 additions & 0 deletions data/CPB Earnings Per Share.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
Date Earnings Per Share
07/30/1984 0.37
07/30/1985 0.38
07/30/1986 0.43
07/30/1987 0.48
07/30/1988 0.53
07/30/1989 0.03
07/30/1990 0.01
07/30/1991 0.79
07/30/1992 0.97
07/30/1993 0.02
07/30/1994 1.26
07/30/1995 1.40
07/30/1996 1.61
07/30/1997 1.51
07/30/1998 1.45
07/30/1999 1.64
07/30/2000 1.68
07/30/2001 1.57
07/30/2002 1.28
07/30/2003 1.45
07/30/2004 1.58
07/30/2005 1.73
07/30/2006 1.88
07/30/2007 2.21
07/30/2008 3.12
07/30/2009 2.09
07/30/2010 2.48
07/30/2011 2.47
07/30/2012 2.44
07/30/2013 1.46
07/30/2014 2.61
07/30/2015 2.21
07/30/2016 1.82
07/30/2017 2.91

31 changes: 31 additions & 0 deletions data/DE Earnings Per Share.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Date Earnings Per Share
10/29/1989 0.84
10/29/1990 0.90
10/29/1991 -0.04
10/29/1992 0.08
10/29/1993 -1.99
10/29/1994 1.17
10/29/1995 1.36
10/29/1996 1.57
10/29/1997 1.89
10/29/1998 2.10
10/29/1999 0.51
10/29/2000 1.04
10/29/2001 -0.14
10/29/2002 0.67
10/29/2003 1.34
10/29/2004 2.84
10/29/2005 2.97
10/29/2006 3.63
10/29/2007 4.06
10/29/2008 4.76
10/29/2009 2.06
10/29/2010 4.40
10/29/2011 6.71
10/29/2012 7.72
10/29/2013 9.18
10/29/2014 8.71
10/29/2015 5.82
10/29/2016 4.84
10/29/2017 6.76

26 changes: 26 additions & 0 deletions data/DIS Earnings Per Share.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Date Earnings Per Share
09/30/1994 0.68
09/30/1995 0.87
09/30/1996 0.65
09/30/1997 0.97
09/30/1998 0.91
09/30/1999 0.63
09/30/2000 0.44
09/30/2001 -0.08
09/30/2002 0.61
09/30/2003 0.62
09/30/2004 1.14
09/30/2005 1.25
09/30/2006 1.68
09/30/2007 2.34
09/30/2008 2.34
09/30/2009 1.76
09/30/2010 2.03
09/30/2011 2.52
09/30/2012 3.17
09/30/2013 3.42
09/30/2014 4.31
09/30/2015 4.95
09/30/2016 5.76
09/30/2017 5.73

Loading

0 comments on commit faa29e7

Please sign in to comment.