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))