def randTSGen(F0, Sigma, Kappa, StartDate, EndDate): ts = curve.Curve() factors = len(Sigma) date = StartDate ts[date] = F0 F = F0 while tenor.RDateAdd('1d', date, Holidays=[]) <= EndDate: lastDate = date date = tenor.RDateAdd('1d', date, Holidays=[]) dt = (date - lastDate).days / 365.0 tau = (EndDate - date).days / 365.0 x = 0.0 for sig, kap in zip(Sigma, Kappa): x = x - 0.5 * sig**2 * math.exp( -2 * kap * tau) * dt + sig * math.exp( -kap * tau) * math.sqrt(dt) * random.gauss(0, 1) F = F * math.exp(x) ts[date] = F return ts
def CF_DeltaHedge(IsCall, ts, strike, vol, expiryT, rd=0.0, rf=0.0, rehedgingTenor="1d", exceptionDateList=[]): Dates = ts.Dates() Prices = ts.Values() # annualized days startD = Dates[0] endD = Dates[-1] lastPrice = ts[startD] lastTau = (expiryT - startD).days / YEARLY_DAYS date = tenor.RDateAdd(rehedgingTenor, startD, exceptionDateList) CF = 0.0 while date < endD: if date in ts.Dates(): CF = CF + bsopt.BSDelta(IsCall, lastPrice, strike, vol, lastTau, rd, rf) * (ts[date] - lastPrice) lastPrice = ts[date] lastTau = (expiryT - date).days / YEARLY_DAYS date = tenor.RDateAdd(rehedgingTenor, date, exceptionDateList) CF = CF + bsopt.BSDelta(IsCall, lastPrice, strike, vol, lastTau, rd, rf) * (ts[endD] - lastPrice) return CF
def BS_ConstDelta_VolSurf(tsFwd, moneynessList, expiryT, rd=0.0, rf=0.0, exceptionDateList=[]): ts = curve.Curve() rptTenor = '-1m' rehedgingTenor = '1d' IsCall = 1 for d in tsFwd.Dates(): if d not in exceptionDateList: ts[d] = tsFwd[d] DateList = [x for x in ts.Dates() if x not in exceptionDateList] TSstart = DateList[0] TSend = DateList[-1] date = copy.copy(TSend) endDate = tenor.RDateAdd('1d', date) startDate = tenor.RDateAdd(rptTenor, date, exceptionDateList) volTS = curve.GRCurve() while startDate >= TSstart: subTS = ts.Slice(startDate, endDate) vol = [] if len(subTS) < 2: print 'No data in time series further than ', startDate break if 0.0 in subTS.Values(): print 'Price is zero at some date from ', startDate, ' to ', endDate break # for the moment, consider ATM vol for m in moneynessList: strike = subTS.Values()[0] * m if IsCall: finalValue = max((subTS.Values()[-1] - strike), 0) else: finalValue = max((strike - subTS.Values()[-1]), 0) vol += [ BSrealizedVol(IsCall, subTS, strike, expiryT, rd, rf, finalValue, rehedgingTenor, exceptionDateList) ] if None in vol: print 'no vol is found to match PnL- strike:' + str( m) + ' expiry:' + expiryT volTS[startDate] = vol startDate = tenor.RDateAdd(rptTenor, startDate, exceptionDateList) return volTS
def BSrealizedVol(IsCall, ts, strike, expiryT, rd=0.0, rf=0.0, optPayoff=0.0, rehedgingTenor="1d", exceptionDateList=[], refVol=0.5): startD = ts.Dates()[0] endD = ts.Dates()[-1] if tenor.RDateAdd(rehedgingTenor, startD, exceptionDateList) > endD: raise ValueError, 'the difference between the start and the end is smaller than the hedging step' if expiryT < endD: raise ValueError, 'Expiry time must be later than the end of the time series' F0 = ts.Values()[0] numTries = 0 diff = 1000.0 tau = (expiryT - startD).days / YEARLY_DAYS vol = refVol def func(x): return bsopt.BSOpt(IsCall, F0, strike, x, tau, rd, rf) + CF_DeltaHedge( IsCall, ts, strike, x, expiryT, rd, rf, rehedgingTenor, exceptionDateList) - optPayoff while diff >= SOLVER_ERROR_EPSILON and numTries <= ITERATION_NUM: current = func(vol) high = func(vol + ITERATION_STEP) low = func(vol - ITERATION_STEP) if high == low: volnext = max(vol - ITERATION_STEP, 1e-2) else: volnext = vol - 2 * ITERATION_STEP * current / (high - low) if volnext < 1e-2: volnext = vol / 2.0 diff = abs(volnext - vol) vol = volnext numTries += 1 if diff >= SOLVER_ERROR_EPSILON or numTries > ITERATION_NUM: return None else: return vol
def rand2DTSGen(F0, Sigma, Kappa, rho, StartDate, EndDate): ts1 = curve.Curve() ts2 = curve.Curve() date = StartDate ts1[date] = F0[0] ts2[date] = F0[1] P = F0[0] G = F0[1] while tenor.RDateAdd('1d', date, Holidays=[]) <= EndDate: lastDate = date date = tenor.RDateAdd('1d', date, Holidays=[]) dt = (date - lastDate).days / 365.0 tau = (EndDate - date).days / 365.0 y1 = random.gauss(0, 1) y2 = y1 * rho + math.sqrt(1 - rho**2) * random.gauss(0, 1) x1 = -0.5 * Sigma[0]**2 * math.exp( -2 * Kappa[0] * tau) * dt + Sigma[0] * math.exp( -Kappa[0] * tau) * math.sqrt(dt) * y1 x2 = -0.5 * Sigma[1]**2 * math.exp( -2 * Kappa[1] * tau) * dt + Sigma[1] * math.exp( -Kappa[1] * tau) * math.sqrt(dt) * y2 P = P * math.exp(x1) G = G * math.exp(x2) ts1[date] = P ts2[date] = G return ts1, ts2
def BS_ATMVol_TermStr(IsCall, tsFwd, expiryT, rd=0.0, rf=0.0, endVol=0.0, termTenor="1m", rehedgingTenor="1d", exceptionDateList=[]): ts = curve.Curve() for d in tsFwd.Dates(): if d not in exceptionDateList and d <= expiryT: ts[d] = tsFwd[d] rptTenor = '-' + termTenor DateList = [x for x in ts.Dates() if x not in exceptionDateList] TSstart = DateList[0] TSend = DateList[-1] date = copy.copy(TSend) endDate = tenor.RDateAdd('1d', date) startDate = tenor.RDateAdd(rptTenor, date, exceptionDateList) finalValue = 0.0 volTS = curve.Curve() while startDate >= TSstart: subTS = ts.Slice(startDate, endDate) if len(subTS) < 2: print 'No data in time series further than ', startDate break if 0.0 in subTS.Values(): print 'Price is zero at some date from ', startDate, ' to ', endDate break # for the moment, consider ATM vol strike = subTS.Values()[0] if endVol > 0: tau = (expiryT - subTS.Dates()[-1]).days / YEARLY_DAYS finalValue = bsopt.BSOpt(IsCall, subTS.Values()[-1], strike, endVol, tau, rd, rf) refVol = endVol elif endVol == 0: if IsCall: finalValue = max((subTS.Values()[-1] - strike), 0) else: finalValue = max((strike - subTS.Values()[-1]), 0) refVol = 0.5 elif endVol == None: raise ValueError, 'no vol is found to match PnL' vol = BSrealizedVol(IsCall, subTS, strike, expiryT, rd, rf, finalValue, rehedgingTenor, exceptionDateList, refVol=refVol) volTS[startDate] = vol endVol = vol date = startDate endDate = tenor.RDateAdd('1d', date) startDate = tenor.RDateAdd(rptTenor, date, exceptionDateList) return volTS