In [ ]:
%matplotlib inline
import import_ipynb
import toyplot
import numpy as np
from blackscholes import black_scholes, date_fraction
import scipy
def get_alpha(alpha, x):
if x in alpha:
return alpha[x]
else:
return 1.0
def scale (prices, x, alpha={}):
return { k : prices[k]*((x-1.0)*get_alpha(alpha,k)+1.0) for k in prices.keys()}
def merge(x, y):
'''Given two dicts, merge them into a new dict as a shallow copy.'''
z = x.copy()
z.update(y)
return z
def plot_function(xrange, ylist, hlines=[], vlines=[], labels=[], yrange=None):
x = np.linspace(*xrange)
label_style = {"text-anchor":"start", "-toyplot-anchor-shift":"5px"}
canvas = toyplot.Canvas(width=600, height=400)
axes = canvas.cartesian()
ylast = []
if yrange != None:
[axes.y.domain.min, axes.y.domain.max] = yrange
for y in ylist:
yvec = np.vectorize(y)(x)
axes.plot(x, yvec)
ylast.append(yvec[-1])
# for i in range(len(ylast)):
# axes.text(x[-1], ylast[i], labels[i], style=label_style)
axes.hlines(hlines )
axes.vlines(vlines)
def plot_asset_dep(portfolios, asset, xrange, date, prices, yrange=None):
labels = [ "payoff %d" % (x+1) for x in range(len(portfolios)) ] + \
[ "MTM %d" % (x+1) for x in range(len(portfolios)) ]
plot_function(xrange,
[ x.asset_dep(asset, mtm=True, payoff_asset=asset, date=date) for x in portfolios] +
[ x.asset_dep(asset, mtm=True, date=date) for x in portfolios],
vlines=prices[asset], labels=labels, yrange=yrange)
def plot_delta(portfolios, asset, xrange, date, prices, yrange=None):
labels = [ "payoff %d" % (x+1) for x in range(len(portfolios)) ] + \
[ "MTM %d" % (x+1) for x in range(len(portfolios)) ]
plot_function(xrange, [ p.delta_dep(asset) for p in portfolios] +
[ p.delta_dep(asset, mtm=True, date=date) for p in portfolios],
vlines=[prices[asset]], labels=labels, yrange=yrange)
def difference(a, b):
return (lambda x: a(x) - b(x))
def trade_option(quantity, style, expiry, strike, underlying, price) :
return [
[ quantity, style, expiry, strike, underlying, price ],
[ -quantity * price, "cash"]
]
def trade_spot(quantity, underlying, price) :
return [
[ quantity, "spot", underlying, price ],
[ -quantity * price, "cash"]
]
class Portfolio(object):
def __init__(self, portfolio, prices={}, vols={}, alpha={}, r=0.0, **kwargs):
self.portfolio = portfolio
self.prices = prices
self.vols = vols
self.alpha=alpha
self.r = r
def portfolio_nav(self, prices = None, mtm=False, payoff_asset=None, date=None, dt = 0.0):
return sum(self.portfolio_items(prices, mtm, payoff_asset, date, dt), 0.0)
def portfolio_items(self, prices = None, mtm=False, payoff_asset=None, date=None, dt = 0.0):
retval = []
if prices == None:
prices = self.prices
for asset in self.portfolio:
if asset[1] == "cash":
retval.append(asset[0])
elif asset[1] == "spot":
quantity = asset[0]
underlying = asset[2]
retval.append(quantity * prices[underlying])
elif asset[1] == "put" or asset[1] == "call":
quantity = asset[0]
style = asset[1]
expiry = asset[2]
strike = asset[3]
underlying = asset[4]
price = prices[underlying]
value = 0.0
if strike < 0.0:
raise ValueError
if not mtm or underlying == payoff_asset:
if asset[1] == "put" and price < strike:
value = strike - price
if asset[1] == "call" and price > strike:
value = price - strike
else:
t = (date_fraction(date, expiry) -dt/365.0)
if (t < 0.0):
t = 0.0
vol = self.vols[underlying]
if (price < 0.0):
price = 0.0
value = black_scholes ((-1 if style == "put" else 1), price, \
strike, t, vol, self.r, 0.0)
retval.append(quantity * value )
elif asset[1] == "comment":
pass
else:
raise Exception ("unknown asset")
return retval
def asset_dep(self, asset, *args, **kwargs):
return lambda x: self.portfolio_nav(prices=merge(self.prices, {asset:x}), *args, **kwargs)
def delta_dep(self, asset, *args, **kwargs):
return lambda x: scipy.misc.derivative(self.asset_dep(asset, *args, **kwargs), x, dx=1e-6)
def market_dep(self, *args, **kwargs):
return lambda x: self.portfolio_nav(prices=scale(self.prices, x, self.alpha), *args, **kwargs)
def evolve(self, date, *args, **kwargs):
return lambda t: self.portfolio_nav(dt=t, date=date, mtm=True, *args, **kwargs)
def theta_portfolio(self, *args, **kwargs):
return lambda t: scipy.misc.derivative(self.evolve(*args, **kwargs), t, dx=1e-6)
def switch_assets(self, assets):
return Portfolio(assets, self.prices, self.vols, self.alpha, self.r)
def __add__(self, p):
return self.switch_assets(self.portfolio + p)
In [ ]:
if __name__ == '__main__':
%matplotlib inline
portfolio = [
[-10000, "put", "2015-09", 24.00, "3888.HK"],
[-10000, "put", "2015-07", 25.00, "3888.HK"],
[-10000, "put", "2015-07", 26.00, "3888.HK"],
[-10000, "put", "2015-08", 26.00, "3888.HK"],
[-5000, "call", "2015-08", 26.00, "3888.HK"],
[-5000, "call", "2015-08", 27.00, "3888.HK"],
[975928.19, "cash"]
]
trade = [
[-10000, "put","2015-08", 18.50, "3888.HK"]
]
exercise = [
[10000, "put", "2015-08", 25.00, "3888.HK"],
[-250000, "cash"],
[10000, "spot", '3888.HK']
]
prices = {
"3888.HK": 22.6
}
vols = {
"3888.HK":0.8
}
alpha = {
"3888.HK":3
}
today="2015-07-15"
yrange = [200000,800000]
p = Portfolio(portfolio, prices=prices, vols=vols, alpha=alpha, r=0.0)
portfolios = [ p, p + trade, p + trade + exercise ]
In [ ]:
if __name__ == '__main__':
plot_asset_dep(portfolios, '3888.HK', [10, 20], today, prices, yrange=yrange)
In [ ]:
if __name__ == '__main__':
plot_delta(portfolios, "3888.HK", [10,20], today, prices)
In [ ]:
if __name__ == '__main__':
plot_function([0,90], [p.evolve(date=today) for p in portfolios])
In [ ]:
if __name__ == '__main__':
plot_function([0,90], [p.theta_portfolio(date=today) for p in portfolios])
In [ ]:
if __name__ == '__main__':
plot_function([0.7,1.3], [p.market_dep() for p in portfolios] +
[p.market_dep(mtm=True, date=today) for p in portfolios], vlines=[1.0], yrange=yrange)
In [ ]:
In [ ]: