Esempio n. 1
0
    def test_roll(self):
        """
        
            TODO: include assert for each scenario shift
        
        :return: 
        """
        self.sdate = datetime.datetime(2018, 1, 8)
        self.value_date = self.sdate.strftime('%d/%m/%Y')
        self.verbose = 0
        self.is_buy_protection = 0

        # build imm_dates TODO: hide this away internally?
        self.imm_dates = [
            f[1] for f in imm_date_vector(start_date=self.sdate,
                                          tenor_list=self.tenor_list)
        ]

        f = cds_all_in_one(self.trade_date, self.effective_date,
                           self.maturity_date, self.value_date,
                           self.accrual_start_date, self.recovery_rate,
                           self.coupon, self.notional, self.is_buy_protection,
                           self.swap_rates, self.swap_tenors,
                           self.swap_maturity_dates, self.credit_spreads,
                           self.credit_spread_tenors, self.spread_roll_tenors,
                           self.imm_dates, self.scenario_shifts, self.verbose)

        for scenario, tt in enumerate(f[2:]):
            print self.scenario_shifts[scenario], tt
Esempio n. 2
0
    def test_buy_protection(self):
        self.sdate = datetime.datetime(2018, 1, 8)
        self.value_date = self.sdate.strftime('%d/%m/%Y')

        # build imm_dates TODO: hide this away internally?
        self.imm_dates = [
            f[1] for f in imm_date_vector(start_date=self.sdate,
                                          tenor_list=self.tenor_list)
        ]

        self.verbose = 0
        f = cds_all_in_one_exclude_ir_tenor_dates(
            self.trade_date, self.effective_date, self.maturity_date,
            self.value_date, self.accrual_start_date, self.recovery_rate,
            self.coupon, self.notional, self.is_buy_protection,
            self.swap_rates, self.swap_tenors, self.credit_spreads,
            self.credit_spread_tenors, self.spread_roll_tenors, self.imm_dates,
            self.scenario_shifts, self.verbose)

        # expand tuple
        pv_dirty, pv_clean, ai, cs01, dv01, duration_in_milliseconds = f[0]
        pvbp6m, pvbp1y, pvbp2y, pvbp3y, pvbp4y, pvbp5y, pvbp7y, pvbp10y = f[1]

        # buy protection -ve npv
        # buy protection -ve npv
        # buy protection +ve cs01
        # buy protection +ve dv01

        print "cob_date: {0} pv_dirty: {1} pv_clean: {2} ai: {3} cs01: {4} dv01: {5} wall_time: {6}".format(
            self.value_date, pv_dirty, pv_clean, ai, cs01 * 1e6, dv01 * 1e6,
            duration_in_milliseconds)

        self.assertAlmostEquals(-1.23099324435, pv_dirty)
        self.assertAlmostEquals(-1.19210435546, pv_clean)
        self.assertAlmostEquals(0.0388888888889, ai)
        self.assertAlmostEquals(14014.5916905, cs01 * 1.0e6)
        self.assertAlmostEquals(131.61798715, dv01 * 1.0e6)

        six_month_equivalent_notional = -cs01 / pvbp6m
        one_year_equivalent_notional = -cs01 / pvbp1y
        two_year_equivalent_notional = -cs01 / pvbp2y
        three_year_equivalent_notional = -cs01 / pvbp3y
        four_year_equivalent_notional = -cs01 / pvbp4y
        five_year_equivalent_notional = -cs01 / pvbp5y
        seven_year_equivalent_notional = -cs01 / pvbp7y
        ten_year_equivalent_notional = -cs01 / pvbp10y

        # print six_month_equivalent_notional, one_year_equivalent_notional, two_year_equivalent_notional, \
        #    three_year_equivalent_notional, four_year_equivalent_notional, five_year_equivalent_notional, \
        #    seven_year_equivalent_notional, ten_year_equivalent_notional

        self.assertAlmostEquals(307.495318062, six_month_equivalent_notional)
        self.assertAlmostEquals(145.357246478, one_year_equivalent_notional)
        self.assertAlmostEquals(70.8820514668, two_year_equivalent_notional)
        self.assertAlmostEquals(46.8826264701, three_year_equivalent_notional)
        self.assertAlmostEquals(35.1120297467, four_year_equivalent_notional)
        self.assertAlmostEquals(28.1221873429, five_year_equivalent_notional)
        self.assertAlmostEquals(20.2184428985, seven_year_equivalent_notional)
        self.assertAlmostEquals(14.4072625131, ten_year_equivalent_notional)
    def test_single_factor_shift(self):
        """

            base case roll test; 
            
            '1D' - moves the roll date one day past maturity 
            '-1D' - moves the stepin date one day closer to maturity
            '-1W' - moves stepin one week closer to maturity
            '-1M' - 1 month closer
            '-6M' - 6 months closer
            '-1Y' - 1 whole year closer
            '-5Y' - 5 whole years closer

        :return: 
        """
        self.sdate = datetime.datetime(2018, 1, 8)
        self.value_date = self.sdate.strftime('%d/%m/%Y')
        self.verbose = 0
        self.is_buy_protection = 0

        # used to generate and shock roll dataset
        self.spread_roll_tenors = [
            '1D', '-1D', '-1W', '-1M', '-6M', '-1Y', '-5Y'
        ]
        self.scenario_shifts = [0]

        # build imm_dates TODO: hide this away internally somewhere?
        self.imm_dates = [
            f[1] for f in imm_date_vector(start_date=self.sdate,
                                          tenor_list=self.tenor_list)
        ]

        f = cds_all_in_one(self.trade_date, self.effective_date,
                           self.maturity_date, self.value_date,
                           self.accrual_start_date, self.recovery_rate,
                           self.coupon, self.notional, self.is_buy_protection,
                           self.swap_rates, self.swap_tenors,
                           self.swap_maturity_dates, self.credit_spreads,
                           self.credit_spread_tenors, self.spread_roll_tenors,
                           self.imm_dates, self.scenario_shifts, self.verbose)

        # self.spread_roll_tenors zero shift
        self.spread_roll_tenors_results = [
            0.0050220109323667605, -0.0016744535183860904,
            -0.01172141527276311, -0.0502382139885996, -0.3065609282865831,
            -0.6116351775358528, -1.1921043554642177
        ]

        for test_value, result_value in zip(f[2:][0],
                                            self.spread_roll_tenors_results):
            self.assertAlmostEquals(test_value, result_value)
    def test_buy_protection(self):
        self.sdate = datetime.datetime(2018, 4, 13)
        self.value_date = self.sdate.strftime('%d/%m/%Y')

        # build imm_dates TODO: hide this away internally?
        self.imm_dates = [
            f[1] for f in imm_date_vector(start_date=self.sdate,
                                          tenor_list=self.tenor_list)
        ]

        self.verbose = 0
        f = cds_all_in_one_exclude_ir_tenor_dates(
            self.trade_date, self.effective_date, self.maturity_date,
            self.value_date, self.accrual_start_date, self.recovery_rate,
            self.coupon, self.notional, self.is_buy_protection,
            self.swap_rates, self.swap_tenors, self.credit_spreads,
            self.credit_spread_tenors, self.spread_roll_tenors, self.imm_dates,
            self.scenario_shifts, self.verbose)

        # expand tuple
        pv_dirty, pv_clean, ai, cs01, dv01, duration_in_milliseconds = f[0]
        pvbp6m, pvbp1y, pvbp2y, pvbp3y, pvbp4y, pvbp5y, pvbp7y, pvbp10y = f[1]

        print "cob_date: {0} pv_dirty: {1} pv_clean: {2} ai: {3} cs01: {4} dv01: {5} wall_time: {6}".format(
            self.value_date, pv_dirty, pv_clean, ai, cs01 * 1e6, dv01 * 1e6,
            duration_in_milliseconds)

        # self.assertAlmostEquals(-1.23099324435, pv_dirty)
        # self.assertAlmostEquals(-1.19210435546, pv_clean)
        # self.assertAlmostEquals(0.0388888888889, ai)
        # self.assertAlmostEquals(14014.5916905, cs01 * 1.0e6)
        # self.assertAlmostEquals(131.61798715, dv01 * 1.0e6)

        six_month_equivalent_notional = -cs01 / pvbp6m
        one_year_equivalent_notional = -cs01 / pvbp1y
        two_year_equivalent_notional = -cs01 / pvbp2y
        three_year_equivalent_notional = -cs01 / pvbp3y
        four_year_equivalent_notional = -cs01 / pvbp4y
        five_year_equivalent_notional = -cs01 / pvbp5y
        seven_year_equivalent_notional = -cs01 / pvbp7y
        ten_year_equivalent_notional = -cs01 / pvbp10y
    def test_1day_roll_buy_protection_cds_shift(self):
        """
    
            base case roll test;     
            '-1D' - moves the stepin date one day closer to maturity
    
        :return: 
        """
        self.sdate = datetime.datetime(2018, 1, 8)
        self.value_date = self.sdate.strftime('%d/%m/%Y')
        self.verbose = 0
        self.is_buy_protection = 1

        # used to generate and shock roll dataset
        self.spread_roll_tenors = ['-1D', '-1W', '-1M', '-1Y']
        self.scenario_shifts = [0]

        # build imm_dates TODO: hide this away internally somewhere?
        self.imm_dates = [
            f[1] for f in imm_date_vector(start_date=self.sdate,
                                          tenor_list=self.tenor_list)
        ]

        f = cds_all_in_one(self.trade_date, self.effective_date,
                           self.maturity_date, self.value_date,
                           self.accrual_start_date, self.recovery_rate,
                           self.coupon, self.notional, self.is_buy_protection,
                           self.swap_rates, self.swap_tenors,
                           self.swap_maturity_dates, self.credit_spreads,
                           self.credit_spread_tenors, self.spread_roll_tenors,
                           self.imm_dates, self.scenario_shifts, self.verbose)

        # self.spread_roll_tenors zero shift
        self.spread_roll_tenors_results = [-0.00167445351801]

        for test_value, result_value in zip(f[2:][0],
                                            self.spread_roll_tenors_results):
            self.assertAlmostEquals(f[0][1] - test_value, result_value)
Esempio n. 6
0
notional = 1.0
is_buy_protection = 0  # only ever buy or sell protection!
verbose = 0

tenor_list = [0.5, 1, 2, 3, 4, 5, 7, 10]
day_count = 1
one_day = datetime.timedelta(1)

spread_roll_tenors = ['1D', '-1D', '-1W', '-1M', '-6M', '-1Y', '-5Y']
scenario_shifts = [-50, -10, 0, 10, 20, 50, 150, 100]

for day in range(day_count):

    # build imm_dates
    imm_dates = [
        f[1] for f in imm_date_vector(start_date=sdate, tenor_list=tenor_list)
    ]
    if verbose:
        print imm_dates

    # skip any weekend dates
    if sdate.weekday() in [5, 6]:
        sdate = sdate + one_day
        continue

    value_date = sdate.strftime('%d/%m/%Y')
    for coupon in coupon_list:

        f = cds_all_in_one_exclude_ir_tenor_dates(
            trade_date, effective_date, maturity_date, value_date,
            accrual_start_date, recovery_rate, coupon, notional,
Esempio n. 7
0
    def test_sell_protection_par_spread(self):

        self.sdate = datetime.datetime(2018, 1, 8)
        self.value_date = self.sdate.strftime('%d/%m/%Y')
        self.verbose = 0
        self.is_buy_protection = 0

        # build imm_dates TODO: hide this away internally?
        self.imm_dates = [
            f[1] for f in imm_date_vector(start_date=self.sdate,
                                          tenor_list=self.tenor_list)
        ]

        f = cds_all_in_one(self.trade_date, self.effective_date,
                           self.maturity_date, self.value_date,
                           self.accrual_start_date, self.recovery_rate,
                           self.coupon, self.notional, self.is_buy_protection,
                           self.swap_rates, self.swap_tenors,
                           self.swap_maturity_dates, self.credit_spreads,
                           self.credit_spread_tenors, self.spread_roll_tenors,
                           self.imm_dates, self.scenario_shifts, self.verbose)

        # expand tuple
        pv_dirty, pv_clean, ai, cs01, dv01, duration_in_milliseconds = f[0]
        pvbp6m, pvbp1y, pvbp2y, pvbp3y, pvbp4y, pvbp5y, pvbp7y, pvbp10y = f[1]
        ps_1m, ps_2m, ps_3M, ps_6M, ps_9M, ps_1Y, ps_2Y, ps_3Y, ps_4Y, ps_5Y, ps_6Y, ps_7Y, ps_8Y, ps_9Y, ps_10Y = f[
            2]

        self.assertAlmostEquals(0.00274826727324, ps_1m)
        self.assertAlmostEquals(0.00274883148583, ps_2m)
        self.assertAlmostEquals(0.00274929868985, ps_3M)
        self.assertAlmostEquals(0.00274939866579, ps_6M)
        self.assertAlmostEquals(0.00274936653181, ps_9M)
        self.assertAlmostEquals(0.00274937754343, ps_1Y)
        self.assertAlmostEquals(0.00274932944417, ps_2Y)
        self.assertAlmostEquals(0.00274932454643, ps_3Y)
        self.assertAlmostEquals(0.00274932165857, ps_4Y)
        self.assertAlmostEquals(0.0027493199385, ps_5Y)
        self.assertAlmostEquals(0.00274926894167, ps_6Y)
        self.assertAlmostEquals(0.00274932296072, ps_7Y)
        self.assertAlmostEquals(0.00274925367015, ps_8Y)
        self.assertAlmostEquals(0.00274927195173, ps_9Y)
        self.assertAlmostEquals(0.00274933238284, ps_10Y)

        # sell protection +ve npv
        # sell protection +ve npv
        # sell protection -ve cs01
        # sell protection -ve dv01

        self.assertAlmostEquals(1.23099324435, pv_dirty)
        self.assertAlmostEquals(1.19210435546, pv_clean)
        self.assertAlmostEquals(0.0388888888889, ai)
        self.assertAlmostEquals(-14014.5916905, cs01 * 1.0e6)
        self.assertAlmostEquals(-131.61798715, dv01 * 1.0e6)

        print "cob_date: {0} pv_dirty: {1} pv_clean: {2} ai: {3} cs01: {4} dv01: {5} wall_time: {6}".format(
            self.value_date, pv_dirty, pv_clean, ai, cs01 * 1e6, dv01 * 1e6,
            duration_in_milliseconds)

        six_month_equivalent_notional = -cs01 / pvbp6m
        one_year_equivalent_notional = -cs01 / pvbp1y
        two_year_equivalent_notional = -cs01 / pvbp2y
        three_year_equivalent_notional = -cs01 / pvbp3y
        four_year_equivalent_notional = -cs01 / pvbp4y
        five_year_equivalent_notional = -cs01 / pvbp5y
        seven_year_equivalent_notional = -cs01 / pvbp7y
        ten_year_equivalent_notional = -cs01 / pvbp10y

        self.assertAlmostEquals(307.495318062, six_month_equivalent_notional)
        self.assertAlmostEquals(145.357246478, one_year_equivalent_notional)
        self.assertAlmostEquals(70.8820514668, two_year_equivalent_notional)
        self.assertAlmostEquals(46.8826264701, three_year_equivalent_notional)
        self.assertAlmostEquals(35.1120297467, four_year_equivalent_notional)
        self.assertAlmostEquals(28.1221873429, five_year_equivalent_notional)
        self.assertAlmostEquals(20.2184428985, seven_year_equivalent_notional)
        self.assertAlmostEquals(14.4072625131, ten_year_equivalent_notional)
    def test_two_factor_shift(self):
        """
        
            roll and roll shocks generate a surface of pv change;
            for each shock the vector of roll tenors is evaluated
           
           The example below is a typical output from shock vector [-10, 0, 10] which translates internally 
           in the scenario engine; via the formula below; you can see that -10 is translated 
           into a -10/100 or -0.1 * spread_rate value and merged into the original spread_rates. This has the overall
           affect to move the spread_rate lower by 10% ahead of shocking the 
           
           spread_rates[r] + spread_rates[r]  * scenario_tenors[s]/100;
            
            -10 (0.024377398537551408, 0.017571131660956488, 0.007359432714929524, -0.0317885280270698, 
                -0.2922965009356705, -0.602319069762766, -1.1921043554642177)
            0 (0.0050220109323667605, -0.0016744535183860904, -0.01172141527276311, -0.0502382139885996, 
                -0.3065609282865831, -0.6116351775358528, -1.1921043554642177)
            10 (-0.014324638086876014, -0.020911398152265066, -0.030793768790011236, -0.06867995379960933, 
                -0.3208205888005652, -0.6209492443307575, -1.1921043554642177)

            The output above has been generated for 7 separate shocks to the time to maturity. It should be possible 
            to compute an entire surface before and after the maturity date of each CDS instrument using this approach
            which can provide detailed information around the roll of each CDS contract.
        
        :return: 
        """

        self.sdate = datetime.datetime(2018, 1, 8)
        self.value_date = self.sdate.strftime('%d/%m/%Y')
        self.verbose = 0
        self.is_buy_protection = 0

        # used to generate and shock roll dataset
        self.spread_roll_tenors = [
            '1D', '-1D', '-1W', '-1M', '-6M', '-1Y', '-5Y'
        ]
        self.scenario_shifts = [-10, 0, 10]

        # build imm_dates TODO: hide this away internally somewhere?
        self.imm_dates = [
            f[1] for f in imm_date_vector(start_date=self.sdate,
                                          tenor_list=self.tenor_list)
        ]

        f = cds_all_in_one(self.trade_date, self.effective_date,
                           self.maturity_date, self.value_date,
                           self.accrual_start_date, self.recovery_rate,
                           self.coupon, self.notional, self.is_buy_protection,
                           self.swap_rates, self.swap_tenors,
                           self.swap_maturity_dates, self.credit_spreads,
                           self.credit_spread_tenors, self.spread_roll_tenors,
                           self.imm_dates, self.scenario_shifts, self.verbose)

        # results to compare against
        self.spread_roll_tenors_results = {
            -10: [
                0.024377398537551408, 0.017571131660956488,
                0.007359432714929524, -0.0317885280270698, -0.2922965009356705,
                -0.602319069762766, -1.1921043554642177
            ],
            0: [
                0.0050220109323667605, -0.0016744535183860904,
                -0.01172141527276311, -0.0502382139885996, -0.3065609282865831,
                -0.6116351775358528, -1.1921043554642177
            ],
            10: [
                -0.014324638086876014, -0.020911398152265066,
                -0.030793768790011236, -0.06867995379960933,
                -0.3208205888005652, -0.6209492443307575, -1.1921043554642177
            ]
        }

        # confirm that we have managed to generate the accurate number of scenario details
        #
        self.assertTrue(len(f[2:]), 3)
        # confirm we have the same dataset
        for i, a in enumerate(f[2:]):
            for test_value, result_value in zip(
                    a,
                    self.spread_roll_tenors_results[self.scenario_shifts[i]]):
                self.assertAlmostEquals(test_value, result_value)