package examples;

import java.util.ArrayList;

import org.quantlib.Actual360;
import org.quantlib.Actual365Fixed;
import org.quantlib.ActualActual;
import org.quantlib.BlackIborCouponPricer;
import org.quantlib.BusinessDayConvention;
import org.quantlib.Calendar;
import org.quantlib.ConstantOptionletVolatility;
import org.quantlib.Date;
import org.quantlib.DateGeneration;
import org.quantlib.DayCounter;
import org.quantlib.DepositRateHelper;
import org.quantlib.DiscountingBondEngine;
import org.quantlib.DoubleVector;
import org.quantlib.Euribor6M;
import org.quantlib.FixedRateBond;
import org.quantlib.FixedRateBondHelper;
import org.quantlib.FloatingRateBond;
import org.quantlib.FloatingRateCouponPricer;
import org.quantlib.Frequency;
import org.quantlib.IborCouponPricer;
import org.quantlib.IborIndex;
import org.quantlib.Month;
import org.quantlib.OptionletVolatilityStructureHandle;
import org.quantlib.Period;
import org.quantlib.PiecewiseFlatForward;
import org.quantlib.PricingEngine;
import org.quantlib.QuantLib;
import org.quantlib.QuantLibJNI;
import org.quantlib.QuoteHandle;
import org.quantlib.QuoteVector;
import org.quantlib.RateHelper;
import org.quantlib.RateHelperVector;
import org.quantlib.RelinkableQuoteHandleVector;
import org.quantlib.RelinkableYieldTermStructureHandle;
import org.quantlib.Schedule;
import org.quantlib.SimpleQuote;
import org.quantlib.SwapRateHelper;
import org.quantlib.TARGET;
import org.quantlib.Thirty360;
import org.quantlib.TimeUnit;
import org.quantlib.USDLibor;
import org.quantlib.UnitedStates;
import org.quantlib.YieldTermStructure;
import org.quantlib.ZeroCouponBond;

public class Bonds {
    static {
        try {
            System.loadLibrary("QuantLibJNI");
        } catch (RuntimeException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws Exception {
    	
    	// MARKET DATA
        Calendar cal = new TARGET();
        Date settlementDate = new Date(18, Month.September, 2008);
        //must be a business day
        settlementDate = cal.adjust(settlementDate);
        
        int fixingDays = 3;
        int settlementdays = 3;
        Period period = new Period(-fixingDays, TimeUnit.Days);

        Date todayDate = cal.advance(settlementDate, period);
        
        System.out.println("Today: " + todayDate.weekday() + ", " + todayDate);
        System.out.println("Settlement date: " + settlementDate.weekday() + ", " + settlementDate);
        
        // Building of the bonds discounting yield curve
        
        // RATE HELPERS
        
        // RateHelpers are built from the above quotes together with
        // other instrument dependant infos. Quotes are passed in relinkable handles 
        // which could be relinked to some other data source later.
        
        // Common data
        
        // ZC rates for the short end
        
        
        QuoteHandle zc3mRate = new QuoteHandle(new SimpleQuote(0.0096));
        QuoteHandle zc6mRate = new QuoteHandle(new SimpleQuote(0.0145));
        QuoteHandle zc1yRate = new QuoteHandle(new SimpleQuote(0.0194));

        //QuoteHandle rate, Period tenor, long fixingDays, Calendar calendar, 
        //BusinessDayConvention convention, boolean endOfMonth, DayCounter dayCounter

        DayCounter zcBondsDayCounter = new Actual365Fixed();
        Period tenor = new Period(3, TimeUnit.Months);
        
        DepositRateHelper zc3m = new DepositRateHelper(zc3mRate,
        		tenor, fixingDays, cal, BusinessDayConvention.ModifiedFollowing,
        		true, zcBondsDayCounter);
        
        DepositRateHelper zc6m = new DepositRateHelper(zc6mRate,
        		tenor, fixingDays, cal, BusinessDayConvention.ModifiedFollowing,
        		true, zcBondsDayCounter);

        DepositRateHelper zc1y = new DepositRateHelper(zc1yRate,
        		tenor, fixingDays, cal, BusinessDayConvention.ModifiedFollowing,
        		true, zcBondsDayCounter);
        
        
        // setup bonds
        double redemption = 100.0;
        final int numberOfBonds = 5;
        
        Date issueDates[] = {
        	new Date(15, Month.March, 2005),	
        	new Date(15, Month.June, 2005),	
        	new Date(30, Month.June, 2006),	
        	new Date(15, Month.November, 2002),	
        	new Date(15, Month.May, 1987),	
        };
        
        Date maturities[] = {
            	new Date(31, Month.August, 2010),	
            	new Date(31, Month.August, 2011),	
            	new Date(31, Month.August, 2013),	
            	new Date(15, Month.August, 2018),	
            	new Date(15, Month.May, 2038),	
            };
        
        double couponRates[] = {
        		0.02375,
        		0.04625,
        		0.03125,
        		0.04000,
        		0.04500
        };
        
        double marketQuotes[] = {
        		100.390625,
        		106.21875,
        		100.59375,
        		101.6875,
        		102.140625
        };
        
        QuoteVector quote = new QuoteVector();
        for (int i=0; i<numberOfBonds; i++){
        	quote.add(new SimpleQuote(marketQuotes[i]));
        }
        RelinkableQuoteHandleVector quoteHandle = new RelinkableQuoteHandleVector(numberOfBonds);
        for (int i=0; i<numberOfBonds; i++){
        	quoteHandle.get(i).linkTo(quote.get(i));
        }
        DoubleVector couponsVector = new DoubleVector();
        for (int i=0; i<numberOfBonds; i++){
        	couponsVector.add(couponRates[i]);;
        }

        ArrayList<FixedRateBondHelper> bondHelpers = new ArrayList<FixedRateBondHelper>(); 
        // Definition of the rate helpers
        for (int i=0; i<numberOfBonds;i++){
            Schedule schedule = new Schedule(issueDates[i], 
            		maturities[i],
            		new Period(Frequency.Semiannual),
            		new UnitedStates(UnitedStates.Market.GovernmentBond),
            		BusinessDayConvention.Unadjusted,
            		BusinessDayConvention.Unadjusted,
            		DateGeneration.Rule.Backward,
            		false);
	        //QuoteHandle cleanPrice, long settlementDays, double faceAmount, 
	        //Schedule schedule, DoubleVector coupons, DayCounter paymentDayCounter, 
	        //BusinessDayConvention paymentConvention, double redemption, Date issueDate
            
            DayCounter dayCountConvBond = new ActualActual(ActualActual.Convention.Bond);
            
	        FixedRateBondHelper bondHelper = new FixedRateBondHelper(quoteHandle.get(i),
            		settlementdays,
            		100.0,
            		schedule,
            		couponsVector,
            		dayCountConvBond,
            		BusinessDayConvention.Unadjusted,
            		redemption,
            		issueDates[i]);
	        bondHelpers.add(bondHelper);
        }
        
        // CURVE BUILDING
        
        // Any DayCounter would be fine
        // ActualActual::ISDA ensures that 30 years is 30.0
        DayCounter termStructureDayCounter = new ActualActual(ActualActual.Convention.ISDA);
        
        //double tolerance = 1.0e-15;
        
        // A depo-bond curve        
        RateHelperVector bondInstruments = new RateHelperVector();
        
        // Adding the ZC bonds to the curve for the short end
        bondInstruments.add(zc3m);
        bondInstruments.add(zc6m);
        bondInstruments.add(zc1y);
        
        // Adding the Fixed rate bonds to the curve for the long end
        for (int i=0; i<numberOfBonds;i++){
        	bondInstruments.add(bondHelpers.get(i));
        }
        
        //Date referenceDate, RateHelperVector instruments, 
        //DayCounter dayCounter
        YieldTermStructure bondDiscountingTermStructure = 
        		new PiecewiseFlatForward(settlementDate,bondInstruments,
        		termStructureDayCounter);
        // Building of the Libor forecasting curve
        //QUOTES      
        // SimpleQuote stores a value which can be manually changed; other Quote
        // subclasses could read the value from a database or some kind of data feed

        // deposits
        QuoteHandle d1wQuoteHandle = new QuoteHandle(new SimpleQuote(0.043375));
        QuoteHandle d1mQuoteHandle = new QuoteHandle(new SimpleQuote(0.031875));
        QuoteHandle d3mQuoteHandle = new QuoteHandle(new SimpleQuote(0.0320375));
        QuoteHandle d6mQuoteHandle = new QuoteHandle(new SimpleQuote(0.03385));
        QuoteHandle d9mQuoteHandle = new QuoteHandle(new SimpleQuote(0.0338125));
        QuoteHandle d1yQuoteHandle = new QuoteHandle(new SimpleQuote(0.0335125));
        //swaps
        QuoteHandle s2yQuoteHandle = new QuoteHandle(new SimpleQuote(0.0295));
        QuoteHandle s3yQuoteHandle = new QuoteHandle(new SimpleQuote(0.0323));
        QuoteHandle s5yQuoteHandle = new QuoteHandle(new SimpleQuote(0.0359));
        QuoteHandle s10yQuoteHandle = new QuoteHandle(new SimpleQuote(0.0412));
        QuoteHandle s15yQuoteHandle = new QuoteHandle(new SimpleQuote(0.0433));
        
        // RATE HELPERS
        // RateHelpers are built from the above quotes together with other
        // instrument dependant infos. Quotes are passed in relinkable handles
        // which could be relinked to some other data source later
        
        // deposits
        DayCounter depositDayCounter = new Actual360();
        
        //QuoteHandle rate, Period tenor, long fixingDays, Calendar calendar, 
        //BusinessDayConvention convention, boolean endOfMonth, 
        //DayCounter dayCounter
        RateHelper d1w = new DepositRateHelper(d1wQuoteHandle,
        		new Period(1, TimeUnit.Weeks),
        		fixingDays,
        		cal,
        		BusinessDayConvention.ModifiedFollowing,
        		true, depositDayCounter);
        RateHelper d1m = new DepositRateHelper(d1mQuoteHandle,
        		new Period(3, TimeUnit.Months),
        		fixingDays,
        		cal,
        		BusinessDayConvention.ModifiedFollowing,
        		true, depositDayCounter);
        RateHelper d3m = new DepositRateHelper(d3mQuoteHandle,
        		new Period(3, TimeUnit.Months),
        		fixingDays,
        		cal,
        		BusinessDayConvention.ModifiedFollowing,
        		true, depositDayCounter);
        RateHelper d6m = new DepositRateHelper(d6mQuoteHandle,
        		new Period(6, TimeUnit.Months),
        		fixingDays,
        		cal,
        		BusinessDayConvention.ModifiedFollowing,
        		true, depositDayCounter);
        RateHelper d9m = new DepositRateHelper(d9mQuoteHandle,
        		new Period(9, TimeUnit.Months),
        		fixingDays,
        		cal,
        		BusinessDayConvention.ModifiedFollowing,
        		true, depositDayCounter);
        RateHelper d1y = new DepositRateHelper(d1yQuoteHandle,
        		new Period(1, TimeUnit.Years),
        		fixingDays,
        		cal,
        		BusinessDayConvention.ModifiedFollowing,
        		true, depositDayCounter);
        		
        // setup swaps
        Frequency swFixedLegFrequency = Frequency.Annual;
        BusinessDayConvention swFixedLegConvention = BusinessDayConvention.Unadjusted;
        DayCounter swFixedLegDayCounter = new Thirty360(Thirty360.Convention.European);
        IborIndex swFloatingLegIndex = new Euribor6M();
        
        Period forwardStart  = new Period(1, TimeUnit.Days);
        //QuoteHandle rate, Period tenor, Calendar calendar, 
        //Frequency fixedFrequency, BusinessDayConvention fixedConvention, 
        //DayCounter fixedDayCount, IborIndex index, QuoteHandle spread, Period fwdStart
        QuoteHandle spread = new QuoteHandle();
        RateHelper s2y = new SwapRateHelper(s2yQuoteHandle,new Period(2, TimeUnit.Years),
        		cal,
        		swFixedLegFrequency,
        		swFixedLegConvention,
        		swFixedLegDayCounter,
        		swFloatingLegIndex,
        		spread, forwardStart);
        RateHelper s3y = new SwapRateHelper(s3yQuoteHandle,new Period(3, TimeUnit.Years),
        		cal,
        		swFixedLegFrequency,
        		swFixedLegConvention,
        		swFixedLegDayCounter,
        		swFloatingLegIndex,
        		spread, forwardStart);
        RateHelper s5y = new SwapRateHelper(s5yQuoteHandle,new Period(5, TimeUnit.Years),
        		cal,
        		swFixedLegFrequency,
        		swFixedLegConvention,
        		swFixedLegDayCounter,
        		swFloatingLegIndex,
        		spread, forwardStart);
        RateHelper s10y = new SwapRateHelper(s10yQuoteHandle,new Period(10, TimeUnit.Years),
        		cal,
        		swFixedLegFrequency,
        		swFixedLegConvention,
        		swFixedLegDayCounter,
        		swFloatingLegIndex,
        		spread, forwardStart);
        RateHelper s15y = new SwapRateHelper(s15yQuoteHandle,new Period(15, TimeUnit.Years),
        		cal,
        		swFixedLegFrequency,
        		swFixedLegConvention,
        		swFixedLegDayCounter,
        		swFloatingLegIndex,
        		spread, forwardStart);
        // CURVE BUILDING
        // Any DayCounter would be fine.
        // ActualActual/ISDA ensures that 30 years is 30.0
        
        // A depo-swap curve
        RateHelperVector depoSwapInstruments = new RateHelperVector();
        depoSwapInstruments.add(d1w);
        depoSwapInstruments.add(d1m);
        depoSwapInstruments.add(d3m);
        depoSwapInstruments.add(d6m);
        depoSwapInstruments.add(d9m);
        depoSwapInstruments.add(d1y);
        depoSwapInstruments.add(s2y);
        depoSwapInstruments.add(s3y);
        depoSwapInstruments.add(s5y);
        depoSwapInstruments.add(s10y);
        depoSwapInstruments.add(s15y);
        
        YieldTermStructure depoSwapTermStructure = new PiecewiseFlatForward(
        		settlementDate,depoSwapInstruments,
        		termStructureDayCounter);
        
        // Term structures that will be used for pricing
        // the one used for discounting cash flows
        RelinkableYieldTermStructureHandle discountingTermStructure = new RelinkableYieldTermStructureHandle();
        RelinkableYieldTermStructureHandle forecastingTermStructure = new RelinkableYieldTermStructureHandle();
        
        // BONDS TO BE PRICED
        
        // Common data
        
        double faceAmount = 100.0;
        
        // Price engine
        PricingEngine bondEngine = new DiscountingBondEngine(discountingTermStructure);
        
        // Zero coupon bond
        
        //long settlementDays, Calendar calendar, double faceAmount, Date maturityDate, 
        //BusinessDayConvention paymentConvention, double redemption, Date issueDate
        ZeroCouponBond zeroCouponBond = new ZeroCouponBond(
        		settlementdays,
        		new UnitedStates(UnitedStates.Market.GovernmentBond),
        		faceAmount,
        		new Date(15, Month.August, 2013),
        		BusinessDayConvention.Following,
        		116.92,
        		new Date(15, Month.August, 2003));

        zeroCouponBond.setPricingEngine(bondEngine);
        
        // Fixed 4.5% US Treasury Note
        Schedule fixedRateBondSchedule = new Schedule(
        		new Date(15, Month.May, 2007),
        		new Date(15, Month.May, 2017),
        		new Period(Frequency.Semiannual),
        		new UnitedStates(UnitedStates.Market.GovernmentBond),
        		BusinessDayConvention.Unadjusted,
        		BusinessDayConvention.Unadjusted,
        		DateGeneration.Rule.Backward,
        		false);
        		
        DoubleVector rateVector = new DoubleVector();
        rateVector.add(1);
        rateVector.add(0.045);
        //int settlementDays, double faceAmount, Schedule schedule, 
        // DoubleVector coupons, DayCounter paymentDayCounter, 
        //BusinessDayConvention paymentConvention, double redemption, Date issueDate        
        FixedRateBond fixedRateBond = new FixedRateBond(
        		settlementdays,
        		faceAmount,
        		fixedRateBondSchedule,
        		rateVector,
        		new ActualActual(ActualActual.Convention.Bond),
        		BusinessDayConvention.ModifiedFollowing,
        		100.0,
        		new Date(15, Month.May, 2007));
        
        fixedRateBond.setPricingEngine(bondEngine);
        		
        RelinkableYieldTermStructureHandle liborTermStructure = new RelinkableYieldTermStructureHandle();
        
        IborIndex libor3m = new USDLibor(
        		new Period(3, TimeUnit.Months),
        		liborTermStructure);
        libor3m.addFixing(new Date(17, Month.July, 2008), 0.0278625);
        
        Schedule floatingBondSchedule = new Schedule(
			new Date(21, Month.October, 2005),
			new Date(21, Month.October, 2010),
			new Period(Frequency.Quarterly),
			new UnitedStates(UnitedStates.Market.NYSE),
			BusinessDayConvention.Unadjusted,
			BusinessDayConvention.Unadjusted,
			DateGeneration.Rule.Backward,
			true);
        
        //long settlementDays, double faceAmount, Schedule schedule, IborIndex index, 
        //DayCounter paymentDayCounter, BusinessDayConvention paymentConvention, 
        //long fixingDays, DoubleVector gearings, DoubleVector spreads, 
        //DoubleVector caps, DoubleVector floors, boolean inArrears, double redemption, 
        //Date issueDate

        DoubleVector gearings = new DoubleVector();
        gearings.add(1);
        gearings.add(1.0);

        DoubleVector spreads = new DoubleVector();
        spreads.add(1);
        spreads.add(0.001);
        
        DoubleVector caps = new DoubleVector();

        DoubleVector floors = new DoubleVector();
        
        
        FloatingRateBond floatingRateBond = new FloatingRateBond(
        		settlementdays,
        		faceAmount,
        		floatingBondSchedule,
        		libor3m,
        		new Actual360(),
        		BusinessDayConvention.ModifiedFollowing,
        		2,
        		gearings,
        		spreads,
        		caps,
        		floors,
        		true,
        		100.0,
        		new Date(21, Month.October, 2005));
        floatingRateBond.setPricingEngine(bondEngine);
        
        IborCouponPricer pricer = new BlackIborCouponPricer();
        OptionletVolatilityStructureHandle volatility = new OptionletVolatilityStructureHandle(new ConstantOptionletVolatility(
        		settlementdays,
        		cal,
        		BusinessDayConvention.ModifiedFollowing,
        		0.0,
        		new Actual365Fixed()
        		));
        
        pricer.setCapletVolatility(volatility);
        QuantLib.setCouponPricer(floatingRateBond.cashflows(), pricer);
       
        //Yield curve bootstrapping
        discountingTermStructure.linkTo(bondDiscountingTermStructure);
        forecastingTermStructure.linkTo(depoSwapTermStructure);
        // We are using the depo & swap curve to esitmate the future Libor rates
        liborTermStructure.linkTo(depoSwapTermStructure);
        
        		
        //System.out.println("NPV: " + zeroCouponBond.NPV());
        System.out.println("ZC Dirty Price: " + zeroCouponBond.dirtyPrice());
        System.out.println("ZC Clean Price: " + zeroCouponBond.cleanPrice());
        System.out.println("Fixed Rate Bond Dirty Price: " + fixedRateBond.dirtyPrice());
        System.out.println("Fixed Rate Bond Clean Price: " + fixedRateBond.cleanPrice());
        System.out.println("Floating Rate Bond Dirty Price: " + floatingRateBond.dirtyPrice());
        System.out.println("Floating Rate Bond Clean Price: " + floatingRateBond.cleanPrice());
        
        System.out.println("End");
    }
}