def setUp(self):
     domAlias = 'EUR'
     domModel = HWModel(0.01, 0.0050, 0.03)
     forAliases = ['USD', 'GBP', 'JPY']
     spotS0 = [1.0, 1.0, 1.0]
     spotVol = [0.3, 0.3, 0.3]
     rates = [0.01, 0.01, 0.01]
     ratesVols = [0.006, 0.007, 0.008]
     mean = [0.01, 0.01, 0.01]
     #
     forAssetModels = [
         AssetModel(S0, vol) for S0, vol in zip(spotS0, spotVol)
     ]
     forRatesModels = [
         HWModel(r, v, m) for r, v, m in zip(rates, ratesVols, mean)
     ]
     #
     corr = np.identity(2 * len(forAliases) + 1)
     corr[1, 2] = 0.6  # USD quanto
     corr[2, 1] = 0.6
     corr[3, 4] = 0.8  # GBP quanto
     corr[4, 3] = 0.8
     corr[5, 6] = -0.7  # JPY quanto
     corr[6, 5] = -0.7
     #
     self.model = HybridModel(domAlias, domModel, forAliases,
                              forAssetModels, forRatesModels, corr)
예제 #2
0
 def test_CreditHybridModel(self):
     # Rates-FX
     eurRates = HullWhiteModel(YieldCurve(0.015),0.03,np.array([10.0]),np.array([0.0050]))
     usdRates = HullWhiteModel(YieldCurve(0.015),0.03,np.array([10.0]),np.array([0.0050]))
     usdFx    = AssetModel(1.25,0.15)
     hybModel = HybridModel('EUR',eurRates,['USD'],[usdFx],[usdRates],np.eye(3))
     # Credit
     spreadLevel = 0.05
     spreadCurve = YieldCurve(spreadLevel)  # use 5% instantanous default probablility
     mean  = 0.0001  # 1bp
     sigma = 0.0100  # 100bp
     skew = 0.5*sigma/spreadLevel
     #
     spreadModel = QuasiGaussianModel(spreadCurve,1,np.array([10.0]),np.array([[sigma]]),
         np.array([[skew]]),np.array([[-skew]]),np.array([0.01]),np.array([mean]),np.identity(1))
     corr = np.eye(4)
     corr[1,3] = -0.85  # credit-FX
     corr[3,1] = -0.85
     creditModel = CreditModel(hybModel,['CP'],[spreadModel],corr)
     # print(creditModel.factorAliases())
     #
     obsTimes = np.linspace(0.0,10.0,3)
     nPaths = 2
     seed = 314159265359
     mcSim = McSimulation(creditModel,obsTimes,nPaths,seed,True,False)
예제 #3
0
 def test_FxSwap(self):
     today = ql.Settings.instance().getEvaluationDate()
     startDate = ql.WeekendsOnly().advance(today,ql.Period('5d'))
     endDate   = ql.WeekendsOnly().advance(today,ql.Period('1y'))
     eurLeg = ql.Leg([
         ql.SimpleCashFlow(1.0,startDate),
         ql.SimpleCashFlow(-1.0,endDate)
     ])
     usdLeg = ql.Leg([
         ql.SimpleCashFlow(1.25,startDate),
         ql.SimpleCashFlow(-1.25,endDate)
     ])
     swap = Swap([eurLeg,usdLeg],[1.0,-1.0],discYtsHs=None,currencyAliases=['EUR','USD'])
     obsTimes = np.array([0.0, 0.5, 1.1])
     timeLine = swap.timeLine(obsTimes)
     #
     print('')
     for t in timeLine:
         print('ObsTime: %.2f' % t)
         for p in timeLine[t]:
             print(p)
     #
     # we set up a very simplistic hybrid model
     eurModel = HWModel()
     usdModel = HWModel()
     fxModel  = AssetModel(1.25,0.15)
     hybModel = HybridModel('EUR',eurModel,['USD'],[fxModel],[usdModel],np.eye(3))
     mcSim    = McSimulation(hybModel,obsTimes,2,123,True)
     V = swap.scenarios(obsTimes,mcSim)
     print(V)
예제 #4
0
 def test_HybridModelWithDeterministicRates(self):
     curve0 = YieldCurve(0.03)
     dcfModel0 = DcfModel(curve0)
     #
     times = np.array([0.0, 1.0])
     nPaths = 1
     seed = 314159265359
     # hybrid adjuster
     hybAdjTimes = np.array([0.0, 1.0, 2.0])
     # simulate deterministic model only
     mcSim = McSimulation(dcfModel0,times,nPaths,seed,False)
     self.assertEqual(mcSim.path(0).zeroBond(1.0,10.0,None),curve0.discount(10.0)/curve0.discount(1.0))
     # simulate deterministic domestic model
     hwModel = HWModel(0.01,0.0050,0.03)
     asModel = AssetModel(1.0,0.30)
     corr = np.identity(2)
     model = HybridModel('EUR',dcfModel0,['USD'],[asModel],[hwModel],corr)
     model.recalculateHybridVolAdjuster(hybAdjTimes)
     mcSim = McSimulation(model,times,nPaths,seed,False)
     dcfModel0.domAlias = 'EUR'
     p = mcSim.path(0)
     self.assertEqual(p.asset(0.0,'USD'),self.model.forAssetModels[0].X0)
     self.assertEqual(p.zeroBond(0.0,5.0,'EUR'),curve0.discount(5.0))
     self.assertEqual(p.zeroBond(0.0,5.0,'USD'),model.forRatesModels[0].yieldCurve.discount(5.0))
     # simulate deterministic foreign model
     model = HybridModel('EUR',hwModel,['USD'],[asModel],[dcfModel0],corr)
     model.recalculateHybridVolAdjuster(hybAdjTimes)
     mcSim = McSimulation(model,times,nPaths,seed,False)
     dcfModel0.domAlias = 'USD'
     p = mcSim.path(0)
     self.assertEqual(p.asset(0.0,'USD'),self.model.forAssetModels[0].X0)
     self.assertEqual(p.zeroBond(0.0,5.0,'EUR'),model.domRatesModel.yieldCurve.discount(5.0))
     self.assertEqual(p.zeroBond(0.0,5.0,'USD'),curve0.discount(5.0))
     # simulate deterministic domestic and foreign curve
     curve1 = YieldCurve(0.05)
     dcfModel1 = DcfModel(curve1)
     corr = np.identity(1)
     model = HybridModel('EUR',dcfModel0,['USD'],[asModel],[dcfModel1],corr)
     model.recalculateHybridVolAdjuster(hybAdjTimes)
     mcSim = McSimulation(model,times,nPaths,seed,False)
     dcfModel0.domAlias = 'EUR'
     dcfModel1.domAlias = 'USD'
     p = mcSim.path(0)
     self.assertEqual(p.asset(0.0,'USD'),self.model.forAssetModels[0].X0)
     self.assertEqual(p.zeroBond(0.0,5.0,'EUR'),curve0.discount(5.0))
     self.assertEqual(p.zeroBond(0.0,5.0,'USD'),curve1.discount(5.0))
예제 #5
0
class TestHybridModel(unittest.TestCase):

    # set up the stage for testing the models
    def setUp(self):
        domAlias = 'EUR'
        domModel = HWModel(0.01, 0.0050, 0.03)
        forAliases = [ 'USD', 'GBP', 'JPY' ]
        spotS0     = [   1.0,   1.0,   1.0 ]
        spotVol    = [   0.3,   0.3,   0.3 ]
        rates      = [  0.01,  0.01,  0.01 ]
        ratesVols  = [ 0.006, 0.007, 0.008 ]
        mean       = [  0.01,  0.01,  0.01 ]
        #
        forAssetModels = [
            AssetModel(S0, vol) for S0, vol in zip(spotS0,spotVol) ]
        forRatesModels = [
            HWModel(r,v,m) for r,v,m in zip(rates,ratesVols,mean) ]
        #
        corr = np.identity(2 * len(forAliases) + 1)
        corr[1,2] = 0.6  # USD quanto
        corr[2,1] = 0.6
        corr[3,4] = 0.8  # GBP quanto
        corr[4,3] = 0.8
        corr[5,6] = -0.7  # JPY quanto
        corr[6,5] = -0.7
        #
        self.model = HybridModel(domAlias,domModel,forAliases,forAssetModels,forRatesModels,corr)

    def test_HybridModelSetup(self):
        # we check against known values
        self.assertListEqual(self.model.modelsStartIdx, [2, 3, 5, 6, 8, 9])
        self.assertDictEqual(self.model.index, {'USD': 0, 'GBP': 1, 'JPY': 2})
        self.assertEqual(self.model.size(), len(self.model.stateAliases()))
        self.assertEqual(self.model.factors(), len(self.model.factorAliases()))
        self.assertListEqual(self.model.stateAliases(), \
            [            'EUR_x', 'EUR_s', 
             'USD_logS', 'USD_x', 'USD_s',
             'GBP_logS', 'GBP_x', 'GBP_s',
             'JPY_logS', 'JPY_x', 'JPY_s' ])
        self.assertListEqual(self.model.factorAliases(), \
            ['EUR_x', 'USD_logS', 'USD_x', 'GBP_logS', 'GBP_x', 'JPY_logS', 'JPY_x'])
        # check correlation
        C = self.model.L.dot(self.model.L.transpose())
        C = np.abs(C - self.model.correlations)
        self.assertLess(np.max(C), 1.0e-15)

    def test_HybridModelEvolution(self):
        times = np.array([0.0])
        nPaths = 1
        seed = 314159265359
        # risk-neutral simulation
        mcSim = McSimulation(self.model,times,nPaths,seed,False)
        p = mcSim.path(0)
        #
        self.assertEqual(p.asset(0.0,'USD'),self.model.forAssetModels[0].X0)
        self.assertEqual(p.asset(0.0,'GBP'),self.model.forAssetModels[1].X0)
        self.assertEqual(p.asset(0.0,'JPY'),self.model.forAssetModels[2].X0)
        #
        self.assertEqual(p.zeroBond(0.0,5.0,'EUR'),self.model.domRatesModel.yieldCurve.discount(5.0))
        self.assertEqual(p.zeroBond(0.0,5.0,'USD'),self.model.forRatesModels[0].yieldCurve.discount(5.0))
        self.assertEqual(p.zeroBond(0.0,5.0,'GBP'),self.model.forRatesModels[1].yieldCurve.discount(5.0))
        self.assertEqual(p.zeroBond(0.0,5.0,'JPY'),self.model.forRatesModels[2].yieldCurve.discount(5.0))

    def test_HybridModelWithDeterministicRates(self):
        curve0 = YieldCurve(0.03)
        dcfModel0 = DcfModel(curve0)
        #
        times = np.array([0.0, 1.0])
        nPaths = 1
        seed = 314159265359
        # hybrid adjuster
        hybAdjTimes = np.array([0.0, 1.0, 2.0])
        # simulate deterministic model only
        mcSim = McSimulation(dcfModel0,times,nPaths,seed,False)
        self.assertEqual(mcSim.path(0).zeroBond(1.0,10.0,None),curve0.discount(10.0)/curve0.discount(1.0))
        # simulate deterministic domestic model
        hwModel = HWModel(0.01,0.0050,0.03)
        asModel = AssetModel(1.0,0.30)
        corr = np.identity(2)
        model = HybridModel('EUR',dcfModel0,['USD'],[asModel],[hwModel],corr)
        model.recalculateHybridVolAdjuster(hybAdjTimes)
        mcSim = McSimulation(model,times,nPaths,seed,False)
        dcfModel0.domAlias = 'EUR'
        p = mcSim.path(0)
        self.assertEqual(p.asset(0.0,'USD'),self.model.forAssetModels[0].X0)
        self.assertEqual(p.zeroBond(0.0,5.0,'EUR'),curve0.discount(5.0))
        self.assertEqual(p.zeroBond(0.0,5.0,'USD'),model.forRatesModels[0].yieldCurve.discount(5.0))
        # simulate deterministic foreign model
        model = HybridModel('EUR',hwModel,['USD'],[asModel],[dcfModel0],corr)
        model.recalculateHybridVolAdjuster(hybAdjTimes)
        mcSim = McSimulation(model,times,nPaths,seed,False)
        dcfModel0.domAlias = 'USD'
        p = mcSim.path(0)
        self.assertEqual(p.asset(0.0,'USD'),self.model.forAssetModels[0].X0)
        self.assertEqual(p.zeroBond(0.0,5.0,'EUR'),model.domRatesModel.yieldCurve.discount(5.0))
        self.assertEqual(p.zeroBond(0.0,5.0,'USD'),curve0.discount(5.0))
        # simulate deterministic domestic and foreign curve
        curve1 = YieldCurve(0.05)
        dcfModel1 = DcfModel(curve1)
        corr = np.identity(1)
        model = HybridModel('EUR',dcfModel0,['USD'],[asModel],[dcfModel1],corr)
        model.recalculateHybridVolAdjuster(hybAdjTimes)
        mcSim = McSimulation(model,times,nPaths,seed,False)
        dcfModel0.domAlias = 'EUR'
        dcfModel1.domAlias = 'USD'
        p = mcSim.path(0)
        self.assertEqual(p.asset(0.0,'USD'),self.model.forAssetModels[0].X0)
        self.assertEqual(p.zeroBond(0.0,5.0,'EUR'),curve0.discount(5.0))
        self.assertEqual(p.zeroBond(0.0,5.0,'USD'),curve1.discount(5.0))
 def setUp(self):
     ### full smile/skew model
     # domestic rates
     domAlias = 'EUR'
     eurCurve = YieldCurve(0.03)
     d = 2
     times = np.array([10.0])
     sigma = np.array([[0.0060], [0.0040]])
     slope = np.array([[0.10], [0.15]])
     curve = np.array([[0.05], [0.10]])
     delta = np.array([1.0, 10.0])
     chi = np.array([0.01, 0.15])
     Gamma = np.array([[1.0, 0.6], [0.6, 1.0]])
     eurRatesModel = QuasiGaussianModel(eurCurve, d, times, sigma, slope,
                                        curve, delta, chi, Gamma)
     # assets
     forAliases = ['USD', 'GBP']
     spotS0 = [1.0, 2.0]
     spotVol = [0.3, 0.2]
     forAssetModels = [
         AssetModel(S0, vol) for S0, vol in zip(spotS0, spotVol)
     ]
     # USD rates
     usdCurve = YieldCurve(0.02)
     d = 3
     times = np.array([10.0])
     sigma = np.array([[0.0060], [0.0050], [0.0040]])
     slope = np.array([[0.10], [0.20], [0.30]])
     curve = np.array([[0.05], [0.10], [0.20]])
     delta = np.array([1.0, 5.0, 20.0])
     chi = np.array([0.01, 0.05, 0.15])
     Gamma = np.array([[1.0, 0.8, 0.6], [0.8, 1.0, 0.8], [0.6, 0.8, 1.0]])
     usdRatesModel = QuasiGaussianModel(usdCurve, d, times, sigma, slope,
                                        curve, delta, chi, Gamma)
     #
     gbpRatesModel = HWModel()
     #
     # 'EUR_x_0', 'EUR_x_1', 'USD_logS', 'USD_x_0', 'USD_x_1', 'USD_x_2', 'GBP_logS', 'GBP_x'
     corr = np.array([
         [1.0, 0.0, 0.5, -0.5, 0.0, 0.0, -0.5, -0.5],  # EUR_x_0
         [0.0, 1.0, 0.0, 0.0, -0.5, 0.0, -0.5, 0.0],  # EUR_x_1
         [0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0],  # USD_logS
         [-0.5, 0.0, -0.5, 1.0, 0.0, 0.0, 0.0, 0.0],  # USD_x_0
         [0.0, -0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 0.0],  # USD_x_1
         [0.0, 0.0, -0.5, 0.0, 0.0, 1.0, 0.0, 0.0],  # USD_x_2
         [-0.5, -0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.5],  # GBP_logS
         [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 1.0],  # GBP_x
     ])
     #
     # corr = np.identity(2 + 1 + 3 + 1 + 1 )  # overwrite
     #
     self.model = HybridModel(domAlias, eurRatesModel, forAliases,
                              forAssetModels,
                              [usdRatesModel, gbpRatesModel], corr)
     ### Gaussian model
     # domestic rates
     domAlias = 'EUR'
     eurCurve = YieldCurve(0.03)
     d = 2
     times = np.array([10.0])
     sigma = np.array([[0.0060], [0.0040]])
     slope = np.array([[0.00], [0.00]])
     curve = np.array([[0.00], [0.00]])
     delta = np.array([1.0, 10.0])
     chi = np.array([0.01, 0.15])
     Gamma = np.array([[1.0, 0.6], [0.6, 1.0]])
     eurRatesModel = QuasiGaussianModel(eurCurve, d, times, sigma, slope,
                                        curve, delta, chi, Gamma)
     # assets
     forAliases = ['USD', 'GBP']
     spotS0 = [1.0, 2.0]
     spotVol = [0.3, 0.2]
     forAssetModels = [
         AssetModel(S0, vol) for S0, vol in zip(spotS0, spotVol)
     ]
     # USD rates
     usdCurve = YieldCurve(0.02)
     d = 3
     times = np.array([10.0])
     sigma = np.array([[0.0060], [0.0050], [0.0040]])
     slope = np.array([[0.10], [0.20], [0.30]])
     curve = np.array([[0.05], [0.10], [0.20]])
     delta = np.array([1.0, 5.0, 20.0])
     chi = np.array([0.01, 0.05, 0.15])
     Gamma = np.array([[1.0, 0.8, 0.6], [0.8, 1.0, 0.8], [0.6, 0.8, 1.0]])
     self.gaussianModel = HybridModel(domAlias, eurRatesModel, forAliases,
                                      forAssetModels,
                                      [usdRatesModel, gbpRatesModel], corr)
class TestHybridQuasiGaussian(unittest.TestCase):

    # set up the stage for testing the models
    def setUp(self):
        ### full smile/skew model
        # domestic rates
        domAlias = 'EUR'
        eurCurve = YieldCurve(0.03)
        d = 2
        times = np.array([10.0])
        sigma = np.array([[0.0060], [0.0040]])
        slope = np.array([[0.10], [0.15]])
        curve = np.array([[0.05], [0.10]])
        delta = np.array([1.0, 10.0])
        chi = np.array([0.01, 0.15])
        Gamma = np.array([[1.0, 0.6], [0.6, 1.0]])
        eurRatesModel = QuasiGaussianModel(eurCurve, d, times, sigma, slope,
                                           curve, delta, chi, Gamma)
        # assets
        forAliases = ['USD', 'GBP']
        spotS0 = [1.0, 2.0]
        spotVol = [0.3, 0.2]
        forAssetModels = [
            AssetModel(S0, vol) for S0, vol in zip(spotS0, spotVol)
        ]
        # USD rates
        usdCurve = YieldCurve(0.02)
        d = 3
        times = np.array([10.0])
        sigma = np.array([[0.0060], [0.0050], [0.0040]])
        slope = np.array([[0.10], [0.20], [0.30]])
        curve = np.array([[0.05], [0.10], [0.20]])
        delta = np.array([1.0, 5.0, 20.0])
        chi = np.array([0.01, 0.05, 0.15])
        Gamma = np.array([[1.0, 0.8, 0.6], [0.8, 1.0, 0.8], [0.6, 0.8, 1.0]])
        usdRatesModel = QuasiGaussianModel(usdCurve, d, times, sigma, slope,
                                           curve, delta, chi, Gamma)
        #
        gbpRatesModel = HWModel()
        #
        # 'EUR_x_0', 'EUR_x_1', 'USD_logS', 'USD_x_0', 'USD_x_1', 'USD_x_2', 'GBP_logS', 'GBP_x'
        corr = np.array([
            [1.0, 0.0, 0.5, -0.5, 0.0, 0.0, -0.5, -0.5],  # EUR_x_0
            [0.0, 1.0, 0.0, 0.0, -0.5, 0.0, -0.5, 0.0],  # EUR_x_1
            [0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0],  # USD_logS
            [-0.5, 0.0, -0.5, 1.0, 0.0, 0.0, 0.0, 0.0],  # USD_x_0
            [0.0, -0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 0.0],  # USD_x_1
            [0.0, 0.0, -0.5, 0.0, 0.0, 1.0, 0.0, 0.0],  # USD_x_2
            [-0.5, -0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.5],  # GBP_logS
            [-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 1.0],  # GBP_x
        ])
        #
        # corr = np.identity(2 + 1 + 3 + 1 + 1 )  # overwrite
        #
        self.model = HybridModel(domAlias, eurRatesModel, forAliases,
                                 forAssetModels,
                                 [usdRatesModel, gbpRatesModel], corr)
        ### Gaussian model
        # domestic rates
        domAlias = 'EUR'
        eurCurve = YieldCurve(0.03)
        d = 2
        times = np.array([10.0])
        sigma = np.array([[0.0060], [0.0040]])
        slope = np.array([[0.00], [0.00]])
        curve = np.array([[0.00], [0.00]])
        delta = np.array([1.0, 10.0])
        chi = np.array([0.01, 0.15])
        Gamma = np.array([[1.0, 0.6], [0.6, 1.0]])
        eurRatesModel = QuasiGaussianModel(eurCurve, d, times, sigma, slope,
                                           curve, delta, chi, Gamma)
        # assets
        forAliases = ['USD', 'GBP']
        spotS0 = [1.0, 2.0]
        spotVol = [0.3, 0.2]
        forAssetModels = [
            AssetModel(S0, vol) for S0, vol in zip(spotS0, spotVol)
        ]
        # USD rates
        usdCurve = YieldCurve(0.02)
        d = 3
        times = np.array([10.0])
        sigma = np.array([[0.0060], [0.0050], [0.0040]])
        slope = np.array([[0.10], [0.20], [0.30]])
        curve = np.array([[0.05], [0.10], [0.20]])
        delta = np.array([1.0, 5.0, 20.0])
        chi = np.array([0.01, 0.05, 0.15])
        Gamma = np.array([[1.0, 0.8, 0.6], [0.8, 1.0, 0.8], [0.6, 0.8, 1.0]])
        self.gaussianModel = HybridModel(domAlias, eurRatesModel, forAliases,
                                         forAssetModels,
                                         [usdRatesModel, gbpRatesModel], corr)

    def test_ModelSetup(self):
        self.assertListEqual(self.model.stateAliases(), [
            'EUR_x_0', 'EUR_x_1', 'EUR_y_0_0', 'EUR_y_0_1', 'EUR_y_1_0',
            'EUR_y_1_1', 'EUR_s', 'USD_logS', 'USD_x_0', 'USD_x_1', 'USD_x_2',
            'USD_y_0_0', 'USD_y_0_1', 'USD_y_0_2', 'USD_y_1_0', 'USD_y_1_1',
            'USD_y_1_2', 'USD_y_2_0', 'USD_y_2_1', 'USD_y_2_2', 'USD_s',
            'GBP_logS', 'GBP_x', 'GBP_s'
        ])
        self.assertListEqual(self.model.factorAliases(), [
            'EUR_x_0', 'EUR_x_1', 'USD_logS', 'USD_x_0', 'USD_x_1', 'USD_x_2',
            'GBP_logS', 'GBP_x'
        ])

    # @unittest.skip('Too time consuming')
    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 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))
class TestHybridModel(unittest.TestCase):

    # set up the stage for testing the models
    def setUp(self):
        domAlias = 'EUR'
        domModel = HWModel(0.01, 0.0050, 0.03)
        forAliases = ['USD', 'GBP', 'JPY']
        spotS0 = [1.0, 1.0, 1.0]
        spotVol = [0.3, 0.3, 0.3]
        rates = [0.01, 0.01, 0.01]
        ratesVols = [0.006, 0.007, 0.008]
        mean = [0.01, 0.01, 0.01]
        #
        forAssetModels = [
            AssetModel(S0, vol) for S0, vol in zip(spotS0, spotVol)
        ]
        forRatesModels = [
            HWModel(r, v, m) for r, v, m in zip(rates, ratesVols, mean)
        ]
        #
        corr = np.identity(2 * len(forAliases) + 1)
        corr[1, 2] = 0.6  # USD quanto
        corr[2, 1] = 0.6
        corr[3, 4] = 0.8  # GBP quanto
        corr[4, 3] = 0.8
        corr[5, 6] = -0.7  # JPY quanto
        corr[6, 5] = -0.7
        #
        self.model = HybridModel(domAlias, domModel, forAliases,
                                 forAssetModels, forRatesModels, corr)

    def test_HybridModelSetup(self):
        # we check against known values
        self.assertListEqual(self.model.modelsStartIdx, [2, 3, 5, 6, 8, 9])
        self.assertDictEqual(self.model.index, {'USD': 0, 'GBP': 1, 'JPY': 2})
        self.assertEqual(self.model.size(), len(self.model.stateAliases()))
        self.assertEqual(self.model.factors(), len(self.model.factorAliases()))
        self.assertListEqual(self.model.stateAliases(), \
            [            'EUR_x', 'EUR_s',
             'USD_logS', 'USD_x', 'USD_s',
             'GBP_logS', 'GBP_x', 'GBP_s',
             'JPY_logS', 'JPY_x', 'JPY_s' ])
        self.assertListEqual(self.model.factorAliases(), \
            ['EUR_x', 'USD_logS', 'USD_x', 'GBP_logS', 'GBP_x', 'JPY_logS', 'JPY_x'])
        # check correlation
        C = self.model.L.dot(self.model.L.transpose())
        C = np.abs(C - self.model.correlations)
        self.assertLess(np.max(C), 1.0e-15)

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