Dependencies: - Linux, bash - Python: matplotlib, pandas, numpy - Modules: yi_1tools, yi_fred, yi_timeseries
CHANGE LOG
2014-12-06 Update code and commentary.
2014-08-11 First version.
# NOTEBOOK settings and system details:
# Assume that the backend is LINUX (our particular distro is Ubuntu, running bash shell):
print '\n :: TIMESTAMP of last notebook execution:'
!date
print '\n :: IPython version:'
!ipython --version
# Automatically reload modified modules:
%load_ext autoreload
%autoreload 2 # 0 will disable autoreload.
# Generate plots inside notebook:
%matplotlib inline
# DISPLAY options
from IPython.display import Image
# e.g. Image(filename='holt-winters-equations.png', embed=True)
from IPython.display import YouTubeVideo
# e.g. YouTubeVideo('1j_HxD4iLn8')
from IPython.display import HTML # useful for snippets
# e.g. HTML('<iframe src=http://en.mobile.wikipedia.org/?useformat=mobile width=700 height=350></iframe>')
import pandas as pd
print '\n :: pandas version:'
print pd.__version__
# pandas DataFrames are represented as text by default; enable HTML representation:
# [Deprecated: pd.core.format.set_printoptions( notebook_repr_html=True ) ]
pd.set_option( 'display.notebook_repr_html', False )
# MATH display, use %%latex, rather than the following:
# from IPython.display import Math
# from IPython.display import Latex
print '\n :: Working directory (set as $workd):'
workd, = !pwd
print workd + '\n'
:: TIMESTAMP of last notebook execution: Sun Dec 7 11:45:35 PST 2014 :: IPython version: 2.3.0 :: pandas version: 0.15.0 :: Working directory (set as $workd): /home/yaya/Dropbox/ipy/fecon235/nb
# Some useful modules:
from yi_1tools import *
from yi_fred import *
from yi_timeseries import *
# GET DATA released monthly since 1964
# for private-sector nonfarm production/nonsupervisory jobs:
wage = getfred( m4wage )
# wage in dollars/hour
inc = wage * 2000
# Assume 40 hours/week at 50 weeks/year
# to derive ANNUAL INCOME for average nonfarm worker.
# We also want to consider dollars in today's real terms:
deflator = getfred(m4defl)
tail( deflator )
Y T 2014-04-01 1.007236 2014-05-01 1.004633 2014-06-01 1.002719 2014-07-01 1.001779 2014-08-01 1.002172 2014-09-01 1.001099 2014-10-01 1.000000
# = REAL annual income
rinc = todf( inc * deflator )
stats( rinc )
Y count 610.000000 mean 36882.474376 std 2224.209179 min 32852.481683 25% 34894.258560 50% 36603.214874 75% 38345.660801 max 41441.690745 :: Index on min: Y 1964-03-01 dtype: datetime64[ns] :: Index on max: Y 2014-02-01 dtype: datetime64[ns] :: Head: Y T 1964-01-01 32899.763431 1964-02-01 32874.224674 1964-03-01 32852.481683 1964-04-01 33096.498702 1964-05-01 33080.111205 1964-06-01 33160.762789 1964-07-01 33137.010060 :: Tail: Y T 2014-04-01 41296.675599 2014-05-01 41270.318117 2014-06-01 41271.898392 2014-07-01 41293.348465 2014-08-01 41429.776439 2014-09-01 41385.426582 2014-10-01 41400.000000 :: Correlation matrix: Y Y 1
# plot of inc is an uninteresting upward slope,
# and it is difficult to gauge worth of
# old dollars from decades ago.
# Therefore, plot rinc
plotfred(rinc, 'Real annual wage')
:: Finished: plotdf-Real_annual_wage.png
It is interesting that real annual income ranges from 34K to 42K in a non-monotonic way historically. Real earnings can go down dramatically when inflation rages.
# Let see what the geometric growth rate of real annual income:
georet( rinc, 12 )
[0.45, 0.46, 0.83, 12]
Thus real growth in wages (and thus income) since 1964 is about 0.45% per annum.
# We use three-month Treasury bills as our "risk-free" interest rate.
irate = monthly(getfred( d4bills ))
# irate is used as a divisor in our calculations,
# so if it is zero or negative, that's a numerical disaster!
# Assert 25 bp FLOOR, esp. in the event of negative interest rates!
irate[ irate < 0.25 ] = 0.25
# ^conditional example in pandas,
# no need for apply or max functions here.
# In practice, the floor could be maintained by increasing
# the duration of our Treasury bill, perhaps to a Treasury note.
plotfred( irate )
Note how that 25 basis point FLOOR will make a vast difference at the zero end of interest rates: for otherwise, capital equivalence could be absurdly high as $350 million.
rcap = todf( rinc / (irate * 10000.0) )
# Real capital expressed in $million
stats(rcap)
Y count 610.000000 mean 2.711055 std 5.048234 min 0.221214 25% 0.542302 50% 0.718531 75% 1.085734 max 16.576676 :: Index on min: Y 1981-05-01 dtype: datetime64[ns] :: Index on max: Y 2014-02-01 dtype: datetime64[ns] :: Head: Y T 1964-01-01 0.932005 1964-02-01 0.933927 1964-03-01 0.928036 1964-04-01 0.956546 1964-05-01 0.953317 1964-06-01 0.955642 1964-07-01 0.957717 :: Tail: Y T 2014-04-01 16.518670 2014-05-01 16.508127 2014-06-01 16.508759 2014-07-01 16.517339 2014-08-01 16.571911 2014-09-01 16.554171 2014-10-01 16.560000 :: Correlation matrix: Y Y 1
plotfred(rcap[:'2007-12-31'])
plotfred(rcap)
The mean since 1964 of the real capital equivalent (computed around the risk-free interest rate) to real wages is around $2.7 million. Clearly one should be cautious of that figure because of the extraordinary range.
So supposing real capital is fixed at $1 million, let's compute the equivalency rate of return to break-even with real wage.
bereturn = todf( rinc / 10000.0 )
plotfred( bereturn )
bereturn.describe()
Y count 610.000000 mean 3.688247 std 0.222421 min 3.285248 25% 3.489426 50% 3.660321 75% 3.834566 max 4.144169