def test_PayoffStrings(self): self.assertEqual(str(Fixed(1.0) @ 1.0), '(1.0000 @ 1.00)') self.assertEqual(str(Asset(3.0, 'EUR') @ 4.0), '(EUR(3.00) @ 4.00)') self.assertEqual(str(ZeroBond(5.0, 10.0)), 'P_None(5.00,10.00)') self.assertEqual(str(LiborRate(5.0, 5.0, 10.0, alias='USD')), 'L_USD(5.00;5.00,10.00)') self.assertEqual( str( SwapRate(2.0, [2.0, 5.0], [1.0, -1.0], [3.0, 4.0, 5.0], [1.0, 1.0, 1.0])), 'S_None(2.00;2.00,5.00)') y = Asset(2.0, 'S') self.assertEqual(str(1.0 + y), '(S(2.00) + 1.0000)') self.assertEqual(str(1.0 - y), '(1.0000 - S(2.00))') self.assertEqual(str(0.5 * y), '0.5000 S(2.00)') self.assertEqual(str(y / 0.5 + 1.0), '(2.0000 S(2.00) + 1.0000)') x = LiborRate(5.0, 5.0, 10.0, alias='USD') self.assertEqual(str(x * y), 'L_USD(5.00;5.00,10.00) S(2.00)') self.assertEqual(str(x / y * Fixed(2.4)), 'L_USD(5.00;5.00,10.00) / S(2.00) 2.4000') self.assertEqual(str(Max(x, y)), 'Max(L_USD(5.00;5.00,10.00), S(2.00))') self.assertEqual(str(Min(x, y)), 'Min(L_USD(5.00;5.00,10.00), S(2.00))') self.assertEqual(str((x > y) * 2.0), '2.0000 (L_USD(5.00;5.00,10.00) > S(2.00))') self.assertEqual(str(x == y), '(L_USD(5.00;5.00,10.00) == S(2.00))') self.assertEqual(str(~(0.5 * y) * 1.0), '1.0000 ~{0.5000 S(2.00)}')
def test_staticPayoffs(self): a = 0.5 px = 1.0 py = 2.0 x = Fixed(px) y = Fixed(py) # self.assertEqual((x + y).at(None), px + py) self.assertEqual((x - y).at(None), px - py) self.assertEqual((x * y).at(None), px * py) self.assertEqual((x / y).at(None), px / py) # self.assertEqual((x + a).at(None), px + a) self.assertEqual((x - a).at(None), px - a) self.assertEqual((x * a).at(None), px * a) self.assertEqual((x / a).at(None), px / a) # self.assertEqual((a + y).at(None), a + py) self.assertEqual((a - y).at(None), a - py) self.assertEqual((a * y).at(None), a * py) self.assertEqual((a / y).at(None), a / py) # z = a * x + a * x * y - y self.assertEqual(z.at(None), a * px + a * px * py - py) self.assertEqual((~z).at(not None), a * px + a * px * py - py) # we can't use None here # self.assertEqual((x < y).at(None), float(px < py)) self.assertEqual((x <= y).at(None), float(px <= py)) self.assertEqual((x == y).at(None), float(px == py)) self.assertEqual((x >= y).at(None), float(px >= py)) self.assertEqual((x > y).at(None), float(px > py)) # self.assertEqual((x < a).at(None), float(px < a)) self.assertEqual((x <= a).at(None), float(px <= a)) self.assertEqual((x == a).at(None), float(px == a)) self.assertEqual((x >= a).at(None), float(px >= a)) self.assertEqual((x > a).at(None), float(px > a)) # self.assertEqual((a < y).at(None), float(a < py)) self.assertEqual((a <= y).at(None), float(a <= py)) self.assertEqual((a == y).at(None), float(a == py)) self.assertEqual((a >= y).at(None), float(a >= py)) self.assertEqual((a > y).at(None), float(a > py)) # self.assertEqual((x + y).obsTime, 0.0) self.assertEqual(((x + y) @ 1.0).obsTime, 1.0)
def test_HybridVolAdjusterCalculation(self): model = copy.deepcopy(self.model) # model = copy.deepcopy(self.gaussianModel) hybVolAdjTimes = np.linspace(0.0, 20.0, 21) model.recalculateHybridVolAdjuster(hybVolAdjTimes) plt.plot(model.hybAdjTimes, model.hybVolAdj[0], 'r*', label='USD') plt.plot(model.hybAdjTimes, model.hybVolAdj[1], 'b*', label='GBP') plt.legend() # times = np.linspace(0.0, 20.0, 101) plt.plot(times, [model.hybridVolAdjuster(0, t) for t in times], 'r-') plt.plot(times, [model.hybridVolAdjuster(1, t) for t in times], 'b-') plt.show() # # return times = np.linspace(0.0, 10.0, 11) nPaths = 2**13 seed = 314159265359 # risk-neutral simulation print('') mcSim = McSimulation(model, times, nPaths, seed, False) # T = 10.0 for k, alias in enumerate(model.forAliases): # ATM forward xT = model.forAssetModels[k].X0 * \ model.forRatesModels[k].yieldCurve.discount(T) / \ model.domRatesModel.yieldCurve.discount(T) K = Fixed(xT) Z = Fixed(0.0) C = Pay(Max(Asset(T, alias) - K, Z), T) fw, err = fwd(mcSim, C) vol = BlackImpliedVol(fw, xT, xT, T, 1.0) vega = BlackVega(xT, xT, vol, T) err /= vega volRef = model.forAssetModels[k].sigma print('C_%s @ %4.1lfy %8.6lf vs %8.6lf (curve) - mc_err = %8.6lf' % (alias, T, vol, volRef, err)) P = Pay(Max(K - Asset(T, alias), Z), T) fw, err = fwd(mcSim, P) vol = BlackImpliedVol(fw, xT, xT, T, -1.0) vega = BlackVega(xT, xT, vol, T) err /= vega volRef = model.forAssetModels[k].sigma print('P_%s @ %4.1lfy %8.6lf vs %8.6lf (curve) - mc_err = %8.6lf' % (alias, T, vol, volRef, err))
def test_cachePayoff(self): a = 1.0 b = 1.0 x = ~(Fixed(1.0) + 0.5) #print(x.at(a)) #print(x.at(b)) self.assertEqual(x._lastPath, None) x.at(a) self.assertEqual(x._lastPath, a) x.at(b) self.assertEqual(x._lastPath, b)
def test_SpreadSimulation(self): times = np.linspace(0.0, 10.0, 11) nPaths = 2**10 seed = 1234 # risk-neutral simulation print('') mcSim = McSimulation(self.model,times,nPaths,seed,False) # T = 10.0 P = Pay(Fixed(1.0),T) pv, err = fwd(mcSim,P) # domestic numeraire print('1.0 @ %4.1lfy %8.6lf - mc_err = %8.6lf' % (T,pv,err))
def test_HybridSimulation(self): times = np.concatenate([np.linspace(0.0, 10.0, 11), [10.5]]) nPaths = 2**13 seed = 314159265359 # risk-neutral simulation print('') mcSim = McSimulation(self.model, times, nPaths, seed, False) # T = 10.0 P = Pay(Fixed(1.0), T) fw, err = fwd(mcSim, P) # domestic numeraire print('1.0 @ %4.1lfy %8.6lf - mc_err = %8.6lf' % (T, fw, err)) # foreign assets for k, alias in enumerate(self.model.forAliases): p = Asset(T, alias) xT = self.model.forAssetModels[k].X0 * \ self.model.forRatesModels[k].yieldCurve.discount(T) / \ self.model.domRatesModel.yieldCurve.discount(T) fw, err = fwd(mcSim, p) print(alias + ' @ %4.1lfy %8.6lf vs %8.6lf (curve) - mc_err = %8.6lf' % (T, fw, xT, err)) # domestic Libor rate Tstart = 10.0 Tend = 10.5 L = Pay(LiborRate(T, Tstart, Tend, alias='EUR'), Tend) fw, err = fwd(mcSim, L) Lref = (mcSim.model.domRatesModel.yieldCurve.discount(Tstart) / \ mcSim.model.domRatesModel.yieldCurve.discount(Tend) - 1) / \ (Tend - Tstart) print('L_EUR @ %4.1lfy %8.6lf vs %8.6lf (curve) - mc_err = %8.6lf' % (T, fw, Lref, err)) # foreign Lbor rates for k, alias in enumerate(self.model.forAliases): L = Pay( LiborRate(T, Tstart, Tend, alias=alias) * Asset(Tend, alias), Tend) fw, err = fwd(mcSim, L) fw *= mcSim.model.domRatesModel.yieldCurve.discount(Tend) / \ mcSim.model.forRatesModels[k].yieldCurve.discount(Tend) / \ mcSim.model.forAssetModels[k].X0 err *= mcSim.model.domRatesModel.yieldCurve.discount(Tend) / \ mcSim.model.forRatesModels[k].yieldCurve.discount(Tend) / \ mcSim.model.forAssetModels[k].X0 Lref = (mcSim.model.forRatesModels[k].yieldCurve.discount(Tstart) / \ mcSim.model.forRatesModels[k].yieldCurve.discount(Tend) - 1) / \ (Tend - Tstart) print('L_%s @ %4.1lfy %8.6lf vs %8.6lf (curve) - mc_err = %8.6lf' % (alias, T, fw, Lref, err))
def QuantLibPayoff(p): # if isinstance(p, Pay): x = QuantLibPayoff(p.x) return RealMCPay(x, p.obsTime) # if isinstance(p, Fixed): return RealMCFixedAmount(p.x) # if isinstance(p, ZeroBond): alias = p.alias if alias is None: alias = '' return RealMCZeroBond(p.obsTime, p.payTime, alias) # if isinstance(p, LiborRate): alias = p.alias if alias is None: alias = '' P0 = RealMCZeroBond(p.obsTime, p.startTime, alias) P1 = RealMCZeroBond(p.obsTime, p.endTime, alias) P0_over_P1 = RealMCDivision(P0, P1) D_over_tau = p.tenorBasis / p.yearFraction minus_one_over_tau = RealMCFixedAmount(-1.0 / p.yearFraction) return RealMCAxpy(D_over_tau, P0_over_P1, minus_one_over_tau) # if isinstance(p, Asset): return RealMCAsset(p.obsTime, p.alias) # if isinstance(p, Axpy): x = QuantLibPayoff(p.x) if p.y is None: p.y = Fixed(0.0) y = QuantLibPayoff(p.y) return RealMCAxpy(p.a, x, y) # if isinstance(p, Mult): x = QuantLibPayoff(p.x) y = QuantLibPayoff(p.y) return RealMCMult(x, y) # if isinstance(p, Div): x = QuantLibPayoff(p.x) y = QuantLibPayoff(p.y) return RealMCDivision(x, y) else: raise NotImplementedError( 'Implementation of QuantLibPayoff for %s required.' % str(type(p))) return
def JuliaPayoff(p): # if isinstance(p,Pay): x = JuliaPayoff(p.x) return Main.Pay(x,p.obsTime) # if isinstance(p,Fixed): return Main.Fixed(p.x) # if isinstance(p,ZeroBond): alias = p.alias if p.alias is None: alias = '' return Main.ZeroBond(p.obsTime,p.payTime,alias) # if isinstance(p,LiborRate): alias = p.alias if p.alias is None: alias = '' return Main.LiborRate(p.obsTime,p.startTime,p.endTime,p.yearFraction,p.tenorBasis,alias,False) # if isinstance(p,Asset): return Main.Asset(p.obsTime,p.alias) # if isinstance(p,Axpy): x = JuliaPayoff(p.x) if p.y is None: p.y = Fixed(0.0) y = JuliaPayoff(p.y) return Main.Axpy(p.a,x,y) # if isinstance(p,Mult): x = JuliaPayoff(p.x) y = JuliaPayoff(p.y) return Main.Mult(x,y) if isinstance(p,Div): x = JuliaPayoff(p.x) y = JuliaPayoff(p.y) return Main.Div(x,y) else: raise NotImplementedError('Implementation of JuliaPayoff for %s required.' % str(type(p))) return
def PayoffFromCashFlow(cf, payOrReceive, discYtsH=None): # this is a bit dangerous if someone changes evaluation date today = ql.Settings.instance().getEvaluationDate() # model time is measured via Act/365 (Fixed) dc = ql.Actual365Fixed() # payTime = dc.yearFraction(today, cf.date()) # first we try fixed rate cash flow cp = ql.as_fixed_rate_coupon(cf) if cp is not None: return Fixed(payOrReceive * cp.amount()) @ payTime # second try a libor coupon cp = ql.as_floating_rate_coupon(cf) if cp is not None: # first we need to puzzle out the dates for the index projIndex = ql.as_iborindex(cp.index()) fixingDate = cp.fixingDate() startDate = projIndex.valueDate(fixingDate) endDate = projIndex.maturityDate(startDate) #print(index, fixingDate, startDate, endDate) tau = projIndex.dayCounter().yearFraction(startDate, endDate) tenorBasis = 1.0 # default if discYtsH is not None: # we apply deterministic basis calculation dfProj = 1.0 + tau * projIndex.fixing(fixingDate) discIndex = projIndex.clone(discYtsH) dfDisc = 1.0 + tau * discIndex.fixing(fixingDate) tenorBasis = dfProj / dfDisc #print(tenorBasis) fixingTime = dc.yearFraction(today, fixingDate) startTime = dc.yearFraction(today, startDate) endTime = dc.yearFraction(today, endDate) # fixed Libor or Libor forward rate L = LiborRate(fixingTime, startTime, endTime, tau, tenorBasis) factor = payOrReceive * cp.nominal() * cp.accrualPeriod() return (factor * (L + cp.spread())) @ payTime return None
def test_HybridVolAdjusterCalculation(self): # we set up a hybrid model consistent to QuantLib domAlias = 'EUR' domModel = HWModel(0.01, 0.0050, 0.01) forAliases = ['USD', 'GBP'] forAssetModels = [AssetModel(1.0, 0.30), AssetModel(2.0, 0.15)] forRatesModels = [ HWModel(0.02, 0.0060, 0.02), HWModel(0.02, 0.0070, 0.03) ] corr = np.identity(2 * len(forAliases) + 1) # [ EUR, USD-EUR, USD, GBP-EUR, GBP ] # 0 1 2 3 4 # USD-EUR - EUR corr[0, 1] = 0.5 corr[1, 0] = 0.5 # USD-EUR - USD corr[1, 2] = -0.5 corr[2, 1] = -0.5 # EUR - USD corr[0, 2] = -0.5 corr[2, 0] = -0.5 # GBP-EUR - EUR corr[0, 3] = -0.5 corr[3, 0] = -0.5 # GBP-EUR - GBP corr[3, 4] = 0.5 corr[4, 3] = 0.5 # EUR - GBP corr[0, 4] = -0.8 corr[4, 0] = -0.8 # USD - GBP corr[2, 4] = 0.0 corr[4, 2] = 0.0 # overwrtite # corr = np.identity(2 * len(forAliases) + 1) # print(corr-corr.transpose()) model = HybridModel(domAlias, domModel, forAliases, forAssetModels, forRatesModels, corr) hybVolAdjTimes = np.linspace(0.0, 20.0, 21) model.recalculateHybridVolAdjuster(hybVolAdjTimes) #plt.plot(model.hybAdjTimes,model.hybVolAdj[0], 'r*') #plt.plot(model.hybAdjTimes,model.hybVolAdj[1], 'b*') # #times = np.linspace(0.0,20.0,101) #plt.plot(times,[ model.hybridVolAdjuster(0,t) for t in times ] , 'r-') #plt.plot(times,[ model.hybridVolAdjuster(1,t) for t in times ] , 'b-') # plt.show() # times = np.linspace(0.0, 10.0, 11) nPaths = 2**13 seed = 314159265359 # risk-neutral simulation print('') mcSim = McSimulation(model, times, nPaths, seed, False) # T = 10.0 for k, alias in enumerate(model.forAliases): # ATM forward xT = model.forAssetModels[k].X0 * \ model.forRatesModels[k].yieldCurve.discount(T) / \ model.domRatesModel.yieldCurve.discount(T) K = Fixed(xT) Z = Fixed(0.0) C = Pay(Max(Asset(T, alias) - K, Z), T) fw, err = fwd(mcSim, C) vol = BlackImpliedVol(fw, xT, xT, T, 1.0) vega = BlackVega(xT, xT, vol, T) err /= vega volRef = model.forAssetModels[k].sigma print('C_%s @ %4.1lfy %8.6lf vs %8.6lf (curve) - mc_err = %8.6lf' % (alias, T, vol, volRef, err)) P = Pay(Max(K - Asset(T, alias), Z), T) fw, err = fwd(mcSim, P) vol = BlackImpliedVol(fw, xT, xT, T, -1.0) vega = BlackVega(xT, xT, vol, T) err /= vega volRef = model.forAssetModels[k].sigma print('P_%s @ %4.1lfy %8.6lf vs %8.6lf (curve) - mc_err = %8.6lf' % (alias, T, vol, volRef, err))