diff --git a/Makefile b/Makefile deleted file mode 100644 index 7cf1029..0000000 --- a/Makefile +++ /dev/null @@ -1,124 +0,0 @@ -PY?=python -PELICAN?=pelican -PELICANOPTS= - -BASEDIR=$(CURDIR) -INPUTDIR=$(BASEDIR)/content -OUTPUTDIR=$(BASEDIR)/output -CONFFILE=$(BASEDIR)/pelicanconf.py -PUBLISHCONF=$(BASEDIR)/publishconf.py - -FTP_HOST=localhost -FTP_USER=anonymous -FTP_TARGET_DIR=/ - -SSH_HOST=localhost -SSH_PORT=22 -SSH_USER=root -SSH_TARGET_DIR=/var/www - -S3_BUCKET=my_s3_bucket - -CLOUDFILES_USERNAME=my_rackspace_username -CLOUDFILES_API_KEY=my_rackspace_api_key -CLOUDFILES_CONTAINER=my_cloudfiles_container - -DROPBOX_DIR=~/Dropbox/Public/ - -GITHUB_PAGES_BRANCH=master - -DEBUG ?= 0 -ifeq ($(DEBUG), 1) - PELICANOPTS += -D -endif - -RELATIVE ?= 0 -ifeq ($(RELATIVE), 1) - PELICANOPTS += --relative-urls -endif - -help: - @echo 'Makefile for a pelican Web site ' - @echo ' ' - @echo 'Usage: ' - @echo ' make html (re)generate the web site ' - @echo ' make clean remove the generated files ' - @echo ' make regenerate regenerate files upon modification ' - @echo ' make publish generate using production settings ' - @echo ' make serve [PORT=8000] serve site at http://localhost:8000' - @echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 ' - @echo ' make devserver [PORT=8000] start/restart develop_server.sh ' - @echo ' make stopserver stop local server ' - @echo ' make ssh_upload upload the web site via SSH ' - @echo ' make rsync_upload upload the web site via rsync+ssh ' - @echo ' make dropbox_upload upload the web site via Dropbox ' - @echo ' make ftp_upload upload the web site via FTP ' - @echo ' make s3_upload upload the web site via S3 ' - @echo ' make cf_upload upload the web site via Cloud Files' - @echo ' make github upload the web site via gh-pages ' - @echo ' ' - @echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html ' - @echo 'Set the RELATIVE variable to 1 to enable relative urls ' - @echo ' ' - -html: - $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) - -clean: - [ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR) - -regenerate: - $(PELICAN) -r $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) - -serve: -ifdef PORT - cd $(OUTPUTDIR) && $(PY) -m pelican.server $(PORT) -else - cd $(OUTPUTDIR) && $(PY) -m pelican.server -endif - -serve-global: -ifdef SERVER - cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 $(SERVER) -else - cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 0.0.0.0 -endif - - -devserver: -ifdef PORT - $(BASEDIR)/develop_server.sh restart $(PORT) -else - $(BASEDIR)/develop_server.sh restart -endif - -stopserver: - $(BASEDIR)/develop_server.sh stop - @echo 'Stopped Pelican and SimpleHTTPServer processes running in background.' - -publish: - $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS) - -ssh_upload: publish - scp -P $(SSH_PORT) -r $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) - -rsync_upload: publish - rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --delete $(OUTPUTDIR)/ $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) --cvs-exclude - -dropbox_upload: publish - cp -r $(OUTPUTDIR)/* $(DROPBOX_DIR) - -ftp_upload: publish - lftp ftp://$(FTP_USER)@$(FTP_HOST) -e "mirror -R $(OUTPUTDIR) $(FTP_TARGET_DIR) ; quit" - -s3_upload: publish - s3cmd sync $(OUTPUTDIR)/ s3://$(S3_BUCKET) --acl-public --delete-removed --guess-mime-type - -cf_upload: publish - cd $(OUTPUTDIR) && swift -v -A https://auth.api.rackspacecloud.com/v1.0 -U $(CLOUDFILES_USERNAME) -K $(CLOUDFILES_API_KEY) upload -c $(CLOUDFILES_CONTAINER) . - -github: publish - ghp-import -m "Generate Pelican site" -b $(GITHUB_PAGES_BRANCH) $(OUTPUTDIR) - git push origin $(GITHUB_PAGES_BRANCH) - -.PHONY: html help clean regenerate serve serve-global devserver publish ssh_upload rsync_upload dropbox_upload ftp_upload s3_upload cf_upload github diff --git a/_nb_header.html b/_nb_header.html deleted file mode 100644 index defd29d..0000000 --- a/_nb_header.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - - - - - - - - - - - diff --git a/archives.html b/archives.html new file mode 100644 index 0000000..71b8c93 --- /dev/null +++ b/archives.html @@ -0,0 +1,122 @@ + + +
+ + + + + + + +Bradlee Speice, Fri 27 November 2015, Blog
+ + + +My only non-core class this semester has been in Structure Products. We've been surveying a wide variety of products, and the final project was to pick one to report on. +Because these are all very similar, we decided to demonstrate all 3 products at once.
+What follows below is a notebook demonstrating the usage of Julia for Monte-Carlo simulation of some exotic products.
++
using Gadfly
+
In order to price the autocallable bonds, we need to simulate the underlying assets. Let's go ahead and set up the simulation first, as this lays the foundation for what we're trying to do. We're going to use JNJ as the basis for our simulation. This implies the following parameters:
+We additionally define some parameters for simulation:
+T
: The number of years to simulatem
: The number of paths to simulaten
: The number of steps to simulate in a yearS0 = 102.2
+nominal = 100
+q = 2.84 / 100
+σ = 15.37 / 100
+term = [0, .49, .9, 1.21, 1.45, 1.69] / 100 + 1
+
+###
+# Potential: Based on PEP
+# S0 = 100.6
+# σ = 14.86
+# q = 2.7
+###
+
+# Simulation parameters
+T = 5 # Using years as the unit of time
+n = 250 # simulations per year
+m = 100000 # paths
+num_simulations = 5; # simulation rounds per price
+
To make things simpler, we simulate a single year at a time. This allows us to easily add in a dividend policy without too much difficulty, and update the simulation every year to match the term structure. The underlying uses GBM for simulation between years.
+ +simulate_gbm = function(S0, μ, σ, T, n)
+ # Set the initial state
+ m = length(S0)
+ t = T / n
+ motion = zeros(m, n)
+ motion[:,1] = S0
+
+ # Build out all states
+ for i=1:(n-1)
+ motion[:,i+1] = motion[:,i] .* exp((μ - σ^2/2)*t) .* exp(sqrt(t) * σ .* randn(m))
+ end
+
+ return motion
+end
+
+function display_motion(motion, T)
+ # Given a matrix of paths, display the motion
+ n = length(motion[1,:])
+ m = length(motion[:,1])
+ x = repmat(1:n, m)
+
+ # Calculate the ticks we're going to use. We'd like to
+ # have an xtick every month, so calculate where those
+ # ticks will actually be at.
+ if (T > 3)
+ num_ticks = T
+ xlabel = "Years"
+ else
+ num_ticks = T * 12
+ xlabel = "Months"
+ end
+ tick_width = n / num_ticks
+ x_ticks = []
+ for i=1:round(num_ticks)
+ x_ticks = vcat(x_ticks, i*tick_width)
+ end
+
+ # Use one color for each path. I'm not sure if there's
+ # a better way to do this without going through DataFrames
+ colors = []
+ for i = 1:m
+ colors = vcat(colors, ones(n)*i)
+ end
+
+ plot(x=x, y=motion', color=colors, Geom.line,
+ Guide.xticks(ticks=x_ticks, label=false),
+ Guide.xlabel(xlabel),
+ Guide.ylabel("Value"))
+end;
+
Let's go ahead and run a sample simulation to see what the functions got us!
+ +initial = ones(5) * S0
+# Using μ=0, T=.25 for now, we'll use the proper values later
+motion = simulate_gbm(initial, 0, σ, .25, 200)
+
+display_motion(motion, .25)
+
Now that we've got the basic motion set up, let's start making things a bit more sophisticated for the model. We're going to assume that the drift of the stock is the difference between the implied forward rate and the quarterly dividend rate.
+We're given the yearly term structure, and need to calculate the quarterly forward rate to match this structure. The term structure is assumed to follow:
+$d(0, t) = d(0,t-1)\cdot f_{i-1, i}$
+Where $f_{i-1, i}$ is the quarterly forward rate.
+ +forward_term = function(yearly_term)
+ # It is assumed that we have a yearly term structure passed in, and starts at year 0
+ # This implies a nominal rate above 0 for the first year!
+ years = length(term)-1 # because we start at 0
+ structure = [(term[i+1] / term[i]) for i=1:years]
+end;
+
Now that we've got our term structure, let's validate that we're getting the correct results! If we've done this correctly, then:
+ +term[2] == term[1] * structure[1]
+
+# Example term structure taken from:
+# http://www.treasury.gov/resource-center/data-chart-center/interest-rates/Pages/TextView.aspx?data=yield
+# Linear interpolation used years in-between periods, assuming real-dollar
+# interest rates
+forward_yield = forward_term(term)
+calculated_term2 = term[1] * forward_yield[1]
+
+println("Actual term[2]: $(term[2]); Calculated term[2]: $(calculated_term2)")
+
Now that we have the term structure set up, we can actually start doing some real simulation! Let's construct some paths through the full 5-year time frame. In order to do this, we will simulate 1 year at a time, and use the forward rates at those times to compute the drift. Thus, there will be 5 total simulations batched together.
+ +full_motion = ones(5) * S0
+full_term = vcat(term[1], forward_yield)
+for i=1:T
+ μ = (full_term[i] - 1 - q)
+ year_motion = simulate_gbm(full_motion[:,end], μ, σ, 1, n)
+ full_motion = hcat(full_motion, year_motion)
+end
+
+display_motion(full_motion, T)
+
We're now going to actually build out the full motion that we'll use for computing the pricing of our autocallable products. It will be largely the same, but we will use far more sample paths for the simulation.
+ +full_simulation = function(S0, T, n, m, term)
+ forward = vcat(term[1], forward_term(term))
+
+ # And an S0 to kick things off.
+ final_motion = ones(m) * S0
+ for i=1:T
+ μ = (forward[i] - 1 - q)
+ year_motion = simulate_gbm(final_motion[:,end], μ, σ, 1, n)
+ final_motion = hcat(final_motion, year_motion)
+ end
+ return final_motion
+end
+
+tic()
+full_simulation(S0, T, n, m, term)
+time = toq()
+@printf("Time to run simulation: %.2fs", time)
+
Now that we've defined our underlying simulation, let's actually try and price an Athena note. Athena has the following characteristics:
+call_barrier = S0
+strike = S0
+protection_barrier = S0 * .6
+coupon = nominal * .07
+
+price_athena = function(initial_price, year_prices, call_barrier,
+ protection_barrier, coupon, forward_structure)
+
+ total_coupons = 0
+
+ t = length(year_prices)
+
+ for i=1:t
+ price = year_prices[i]
+ if price ≥ call_barrier
+ return (nominal + coupon*i) * exp((prod(forward_structure[i:end])-1)*(t-i))
+ end
+ end
+
+ # We've reached maturity, time to check capital protection
+ if year_prices[end] > protection_barrier
+ return nominal
+ else
+ put = (strike - year_prices[end]) / strike
+ return nominal*(1-put)
+ end
+end
+
+forward_structure = forward_term(term)
+price_function = (year_prices) -> price_athena(S0, year_prices,
+ call_barrier, protection_barrier, coupon, forward_structure)
+
+athena = function()
+ year_indexes = [n*i for i=1:T]
+ motion = full_simulation(S0, T, n, m, term)
+ payoffs = [price_function(motion[i, year_indexes]) for i=1:m]
+ return mean(payoffs)
+end
+
+mean_payoffs = zeros(num_simulations)
+for i=1:num_simulations
+ tic()
+ mean_payoffs[i] = athena()
+ time = toq()
+ @printf("Mean of simulation %i: \$%.4f; Simulation time: %.2fs\n", i, mean_payoffs[i], time)
+end
+
+final_mean = mean(mean_payoffs)
+println("Mean over $num_simulations simulations: $(mean(mean_payoffs))")
+pv = final_mean * (exp(-(prod(forward_structure)-1)*T))
+@printf("Present value of Athena note: \$%.2f, notional: \$%.2f", pv, nominal)
+
Let's move into pricing a Phoenix without memory. It's very similar to the Athena production, with the exception that we introduce a coupon barrier so coupons are paid even when the underlying is below the initial price.
+The Phoenix product has the following characteristics (example here):
+Some example paths (all assume that a call barrier of the current price, and coupon barrier some level below that):
+We're going to re-use the same simulation, with the following parameters:
+call_barrier = S0
+coupon_barrier = S0 * .8
+protection_barrier = S0 * .6
+coupon = nominal * .06
+
+price_phoenix_no_memory = function(initial_price, year_prices, call_barrier, coupon_barrier,
+ protection_barrier, coupon, forward_structure)
+
+ total_coupons = 0
+ t = length(year_prices)
+
+ for i=1:t
+ price = year_prices[i]
+ if price ≥ call_barrier
+ return (nominal + coupon + total_coupons)*exp((prod(forward_structure[i:end])-1)*(t-i))
+ elseif price ≥ coupon_barrier
+ total_coupons = total_coupons * exp(forward_structure[i]-1) + coupon
+ else
+ total_coupons *= exp(forward_structure[i]-1)
+ end
+ end
+
+ # We've reached maturity, time to check capital protection
+ if year_prices[end] > protection_barrier
+ return nominal + total_coupons
+ else
+ put = (strike - year_prices[end]) / strike
+ return nominal*(1-put)
+ end
+end
+
+forward_structure = forward_term(term)
+price_function = (year_prices) -> price_phoenix_no_memory(S0, year_prices,
+ call_barrier, coupon_barrier, protection_barrier, coupon, forward_structure)
+
+phoenix_no_memory = function()
+ year_indexes = [n*i for i=1:T]
+ motion = full_simulation(S0, T, n, m, term)
+ payoffs = [price_function(motion[i, year_indexes]) for i=1:m]
+ return mean(payoffs)
+end
+
+mean_payoffs = zeros(num_simulations)
+for i=1:num_simulations
+ tic()
+ mean_payoffs[i] = phoenix_no_memory()
+ time = toq()
+ @printf("Mean of simulation %i: \$%.4f; Simulation time: %.2fs\n", i, mean_payoffs[i], time)
+end
+
+final_mean = mean(mean_payoffs)
+println("Mean over $num_simulations simulations: $(mean(mean_payoffs))")
+pv = final_mean * exp(-(prod(forward_structure)-1)*(T))
+@printf("Present value of Phoenix without memory note: \$%.2f", pv)
+
The Phoenix with Memory structure is very similar to the Phoenix, but as the name implies, has a special "memory" property: It remembers any coupons that haven't been paid at prior observation times, and pays them all if the underlying crosses the coupon barrier. For example:
+You can also find an example here.
+Let's go ahead and set up the simulation! The parameters will be the same, but we can expect that the value will go up because of the memory attribute
+ +call_barrier = S0
+coupon_barrier = S0 * .8
+protection_barrier = S0 * .6
+coupon = nominal * .07
+
+price_phoenix_with_memory = function(initial_price, year_prices, call_barrier,
+ coupon_barrier, protection_barrier, coupon, forward_structure)
+
+ last_coupon = 0
+ total_coupons = 0
+
+ t = length(year_prices)
+
+ for i=1:t
+ price = year_prices[i]
+ if price > call_barrier
+ return (nominal + coupon + total_coupons)*exp((prod(forward_structure[i:end])-1)*(t-i))
+ elseif price > coupon_barrier
+ ####################################################################
+ # The only difference between with/without memory is the below lines
+ memory_coupons = (i - last_coupon) * coupon
+ last_coupon = i
+ total_coupons = total_coupons * exp(forward_structure[i]-1) + memory_coupons
+ ####################################################################
+ else
+ total_coupons *= exp(forward_structure[i]-1)
+ end
+ end
+
+ # We've reached maturity, time to check capital protection
+ if year_prices[end] > protection_barrier
+ return nominal + total_coupons
+ else
+ put = (strike - year_prices[end]) / strike
+ return nominal*(1-put)
+ end
+end
+
+forward_structure = forward_term(term)
+price_function = (year_prices) -> price_phoenix_with_memory(S0, year_prices,
+ call_barrier, coupon_barrier, protection_barrier, coupon, forward_structure)
+
+phoenix_with_memory = function()
+ year_indexes = [n*i for i=1:T]
+ motion = full_simulation(S0, T, n, m, term)
+ payoffs = [price_function(motion[i, year_indexes]) for i=1:m]
+ return mean(payoffs)
+end
+
+mean_payoffs = zeros(num_simulations)
+for i=1:num_simulations
+ tic()
+ mean_payoffs[i] = phoenix_with_memory()
+ time = toq()
+ @printf("Mean of simulation %i: \$%.4f; Simulation time: %.2fs\n",
+ i, mean_payoffs[i], time)
+end
+
+final_mean = mean(mean_payoffs)
+println("Mean over $num_simulations simulations: $(mean(mean_payoffs))")
+pv = final_mean * exp(-(prod(forward_structure)-1)*(T))
+@printf("Present value of Phoenix with memory note: \$%.2f", pv)
+
"Blog"
+Bradlee Speice, Sat 23 January 2016, Blog
+ + + ++
import pickle
+import pandas as pd
+import numpy as np
+from bokeh.plotting import output_notebook, figure, show
+from bokeh.palettes import RdBu4 as Palette
+from datetime import datetime
+import warnings
+
+output_notebook()
+