#!/usr/bin/python

"""
 Copyright (C) 2000, 2001, 2002 RiskMap srl

 This file is part of QuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://quantlib.org/

 QuantLib is free software: you can redistribute it and/or modify it under the
 terms of the QuantLib license.  You should have received a copy of the
 license along with this program; if not, please email ferdinando@ametrano.net
 The license is also available online at http://quantlib.org/html/license.html

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
"""

__version__ = "$Revision: 1.7 $"
# $Source: /cvsroot/quantlib/QuantLib-Python/QuantLib/test/forwardspreadedcurve.py,v $

from QuantLib import *
import unittest

tollerance = 1.0e-9

class ForwardSpreadedTest(unittest.TestCase):
    def setUp(self):
        import time
        gmt = time.gmtime(time.time())
        self.time_steps = 5
        self.spread_list = [0.0, 0.001, 0.01, 0.1, 0.5]
        self.euriborHandle = TermStructureHandle()
        self.calendar = Calendar('TARGET')
        self.today = Date(gmt[2],gmt[1],gmt[0])
        self.settlementDays = 2
        self.indexFixingDays = 2
        # deposits
        self.depositNs = \
            [     1,      1,       2,       3,       6,       9]
        self.depositUnits = \
            ['week','month','months','months','months','months']
        self.depositRates = \
            [ 4.559,  4.581,   4.573,   4.557,   4.496,   4.490]
        rollingConvention = 'ModifiedFollowing'
        dayCounter = DayCounter('Act/360')
        deposits = []
        self.rate_meh_list = []
        for i in range(len(self.depositNs)):
            n = self.depositNs[i]
            unit = self.depositUnits[i]
            rate = self.depositRates[i]
            deposit_meh = MarketElementHandle(SimpleMarketElement(rate/100))
            self.rate_meh_list.append(deposit_meh)
            deposits.append(
                DepositRateHelper(deposit_meh, self.settlementDays, n, unit,
                                  self.calendar, rollingConvention, dayCounter)
                )
        # swaps
        self.swapRollingConvention = 'modifiedFollowing'
        self.fixedFrequency = 1
        self.fixedIsAdjusted = 0
        self.fixedDayCount = DayCounter('30/360')
        self.floatingFrequency = 2
        self.swapYears = \
            [    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,
                      12,   15,   20,   25,   30]
        self.swapRates = \
            [ 4.54, 4.63, 4.75, 4.86, 4.99, 5.11, 5.23, 5.33, 5.41, 5.47,
                    5.60, 5.75, 5.89, 5.95, 5.96]
        swaps = []
        for i in range(len(self.swapYears)):
            n = self.swapYears[i]
            rate = self.swapRates[i]
            swap_meh =MarketElementHandle(SimpleMarketElement(rate/100))
            self.rate_meh_list.append(swap_meh)
            swaps.append(
                SwapRateHelper(swap_meh, self.settlementDays, n, self.calendar,
                    self.swapRollingConvention, self.fixedFrequency,
                    self.fixedIsAdjusted, self.fixedDayCount,
                    self.floatingFrequency)
                )
        self.instruments = deposits + swaps
    def runTest(self):
        "Testing forward-spreaded piecewise-flat-forward curve"
##        print
        termStructure = PiecewiseFlatForward('EUR',DayCounter('Act/360'),
            self.today,self.calendar,self.settlementDays,self.instruments)

        spread_handle = MarketElementHandle(SimpleMarketElement(0.0))

        spreaded_curve = ForwardSpreadedTermStructure(
                            TermStructureHandle(termStructure),
                            spread_handle
                        )
        spreaded_curve.discount(termStructure.maxTime()/2)
        # Change the underlying term structure giving a spread to the rates
        saved_rates = map(lambda x:x.value(), self.rate_meh_list)
        new_rates = map(lambda x:x+0.1, saved_rates)
        for rate_meh in self.rate_meh_list:
            rate_meh.linkTo(SimpleMarketElement(new_rates.pop(0)))

        # Apply a spread
        minTime = termStructure.minTime()
        maxTime = termStructure.maxTime()
        delta_t = (maxTime - minTime)/self.time_steps
        for spread in self.spread_list:
##            print "spread =",spread
            spread_handle.linkTo(SimpleMarketElement(spread))
            current_time = minTime
            for i in range(self.time_steps):
                termStructure_discount = termStructure.discount(current_time)
                spreaded_curve_discount = spreaded_curve.discount(current_time)
                termStructure_zeroYield = termStructure.zeroYield(current_time)
                spreaded_curve_zeroYield = spreaded_curve.zeroYield(current_time)
                termStructure_forward = termStructure.forward(current_time)
                spreaded_curve_forward = spreaded_curve.forward(current_time)
                fwd_curve_plus_spread = termStructure_forward + \
                                        spread_handle.value()
##                print "%8.5f | dscnt %8.5f %8.5f | zrYld  %8.5f %8.5f | frwd %8.5f %8.5f" % (
##                    current_time,
##                    termStructure.discount(current_time),
##                    spreaded_curve.discount(current_time),
##                    termStructure.zeroYield(current_time),
##                    spreaded_curve.zeroYield(current_time),
##                    termStructure.forward(current_time),
##                    spreaded_curve.forward(current_time)
##                    )
                if spread == 0.0:
                    assert abs(termStructure_discount -
                               spreaded_curve_discount) < tollerance,(
                            "discount is different for zero spread\n"+
                            str(termStructure_discount) + " : " +
                            str(spreaded_curve_discount)
                            )

                    assert abs(termStructure_zeroYield -
                               spreaded_curve_zeroYield) < tollerance,(
                            "zeroYield is different for zero spread" +
                            str(termStructure_zeroYield) + " : " +
                            str(spreaded_curve_zeroYield)
                            )

                    assert abs(termStructure_forward -
                               spreaded_curve_forward) < tollerance,(
                            "forward is different for zero spread" +
                            str(termStructure_forward) + " : " +
                            str(spreaded_curve_forward)
                            )

                assert abs(fwd_curve_plus_spread -
                           spreaded_curve_forward) < tollerance, (
                       ("spread = %10.7f; " % spread) +
                       ("time = %10.7f; " % current_time) +
                       ("curve + spread = %10.7f; " % fwd_curve_plus_spread) +
                       ("spreaded_curve = %10.7f " % spreaded_curve_forward)
                      )
                current_time = current_time + delta_t

if __name__ == '__main__':
    import QuantLib
    print 'testing QuantLib', QuantLib.__version__,
    print QuantLib.QuantLibc.__file__, QuantLib.__file__
    import sys
    suite = unittest.TestSuite()
    suite.addTest(ForwardSpreadedTest())
    if sys.hexversion >= 0x020100f0:
        unittest.TextTestRunner(verbosity=2).run(suite)
    else:
        unittest.TextTestRunner().run(suite)
    raw_input('press any key to continue')
