#!/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.30 $"
# $Source: /cvsroot/quantlib/QuantLib-Python/QuantLib/test/piecewiseflatforward.py,v $

from QuantLib import *
import unittest

class PiecewiseFlatForwardTest(unittest.TestCase):
    def setUp(self):
        import time
        gmt = time.gmtime(time.time())
        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 = map(
            lambda n,unit,rate,settlementDays=self.settlementDays,
                   calendar=self.calendar,
                   rollingConvention=rollingConvention,
                   dayCounter=dayCounter:
                DepositRateHelper(
                    MarketElementHandle(SimpleMarketElement(rate/100)),
                    settlementDays, n, unit,
                    calendar, rollingConvention, dayCounter),
            self.depositNs,
            self.depositUnits,
            self.depositRates)
        # 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 = map(
            lambda n,rate,settlementDays=self.settlementDays,
                   calendar=self.calendar,
                   swapRollingConvention=self.swapRollingConvention,
                   fixedFrequency=self.fixedFrequency,
                   fixedIsAdjusted=self.fixedIsAdjusted,
                   fixedDayCount=self.fixedDayCount,
                   floatingFrequency=self.floatingFrequency:
                SwapRateHelper(
                    MarketElementHandle(SimpleMarketElement(rate/100)),
                    settlementDays, n, calendar,
                    swapRollingConvention, fixedFrequency, fixedIsAdjusted,
                    fixedDayCount, floatingFrequency),
            self.swapYears,
            self.swapRates)
        self.instruments = deposits + swaps
    def runTest(self):
        "Testing piecewise flat forward curve"
        termStructure = PiecewiseFlatForward('EUR',DayCounter('Act/360'),
            self.today,self.calendar,self.settlementDays,self.instruments)
        settlement = termStructure.settlementDate()
        self.euriborHandle.linkTo(termStructure)
        # check deposits
        for i in range(len(self.depositRates)):
            index = Euribor(self.depositNs[i], self.depositUnits[i],
                            self.euriborHandle)
            estimatedRate = index.fixing(settlement)
            if not (abs(estimatedRate - self.depositRates[i]/100) <= 1.0e-9):
                n = self.depositNs[i]
                unit = self.depositUnits[i]
                expectedRate = self.depositRates[i]/100
                self.fail("""
%(n)d %(unit)s deposit:
    estimated rate: %(estimatedRate)12.10f
    input rate:     %(expectedRate)12.10f
    tolerance exceeded
                          """ % locals())

        # check swaps
        index = Euribor(12/self.floatingFrequency,'Months',
                        self.euriborHandle)
        for i in range(len(self.swapRates)):
            swap = SimpleSwap(1,settlement,self.swapYears[i],'years',
                self.calendar,self.swapRollingConvention,100.0,
                self.fixedFrequency,0.0,self.fixedIsAdjusted,
                self.fixedDayCount,self.floatingFrequency,index,
                self.indexFixingDays,0.0,
                self.euriborHandle)
            estimatedRate = -swap.NPV()/swap.fixedLegBPS()
            if not (abs(estimatedRate - self.swapRates[i]/100) <= 1.0e-9):
                years = self.swapYears[i]
                expectedRate = self.swapRates[i]/100
                self.fail("""
%(years)d years swap:
    estimated rate: %(estimatedRate)12.10f
    input rate:     %(expectedRate)12.10f
    tolerance exceeded
	                      """ % locals())

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