%matplotlib inline
from datetime import date
import time
import pandas as pd
import numpy as np
pd.options.display.max_colwidth = 60
from Curves.Corporates.CorporateDailyVasicek import CorporateRates
from Boostrappers.CDSBootstrapper.CDSVasicekBootstrapper import BootstrapperCDSLadder
from MonteCarloSimulators.Vasicek.vasicekMCSim import MC_Vasicek_Sim
from Products.Rates.CouponBond import CouponBond
from Products.Credit.CDS import CDS
from Scheduler.Scheduler import Scheduler
import quandl
import matplotlib.pyplot as plt
from parameters import WORKING_DIR
import itertools
marker = itertools.cycle((',', '+', '.', 'o', '*'))
from IPython.core.pylabtools import figsize
figsize(15, 4)
from pandas import ExcelWriter
import numpy.random as nprnd
from pprint import pprint

"""
Explanation: Loading of Libraries and Classes.
End of explanation
"""


t_step = 1.0 / 365.0
simNumber = 10
trim_start = date(2005,3,10)
trim_end = date(2010,12,31)  # Last Date of the Portfolio
start = date(2005, 3, 10)
referenceDate = date(2005, 5, 10)

"""
Explanation: Create forward bond future PV (Exposure) time profile
Setting up parameters
End of explanation
"""


myScheduler = Scheduler()
ReferenceDateList = myScheduler.getSchedule(start=referenceDate,end=trim_end,freq="1M", referencedate=referenceDate)
# Create Simulator
xOIS = [ 3.0,  0.07536509, -0.208477,  0.07536509]
myVasicek = MC_Vasicek_Sim(datelist = [trim_start,trim_end],x = xOIS,simNumber = simNumber,t_step =1/365.0 )
#myVasicek.setVasicek(x=xOIS,minDay=trim_start,maxDay=trim_end,simNumber=simNumber,t_step=1/365.0)
myVasicek.getLibor()

# Create Coupon Bond with several startDates.
SixMonthDelay = myScheduler.extractDelay("6M")
TwoYearsDelay = myScheduler.extractDelay("2Y")
startDates = [referenceDate + nprnd.randint(0,3)*SixMonthDelay for r in range(10)]

# For debugging uncomment this to choose a single date for the forward bond
# print(startDates)
startDates = [date(2005,3,10)+SixMonthDelay,date(2005,3,10)+TwoYearsDelay ]
maturities = [(x+TwoYearsDelay) for x in startDates]

myPortfolio = {}
coupon = 0.07536509
for i in range(len(startDates)):
    notional=(-1.0)**i
    myPortfolio[i] = CouponBond(fee=1.0,start=startDates[i],coupon=coupon,notional=notional,
                                maturity= maturities[i], freq="3M", referencedate=referenceDate)

"""
Explanation: Data input for the CouponBond portfolio
The word portfolio is used to describe just a dict of CouponBonds.
This line creates a referenceDateList
myScheduler = Scheduler()
ReferenceDateList = myScheduler.getSchedule(start=referenceDate,end=trim_end,freq="1M", referencedate=referenceDate)
Create Simulator
This section creates Monte Carlo Trajectories in a wide range. Notice that the BondCoupon maturities have to be
inside the Monte Carlo simulation range [trim_start,trim_end]
Sigma has been artificially increased (OIS has smaller sigma) to allow for visualization of distinct trajectories.
    # SDE parameters - Vasicek SDE
    # dr(t) = k(θ − r(t))dt + σdW(t)
    self.kappa = x[0]
    self.theta = x[1]
    self.sigma = x[2]
    self.r0 = x[3]

myVasicek = MC_Vasicek_Sim()
xOIS = [ 3.0,  0.07536509, -0.208477,  0.07536509]
myVasicek.setVasicek(x=xOIS,minDay=trim_start,maxDay=trim_end,simNumber=simNumber,t_step=1/365.0)
myVasicek.getLibor()
Create Coupon Bond with several startDates.
SixMonthDelay = myScheduler.extractDelay("6M")
TwoYearsDelay = myScheduler.extractDelay("2Y")
startDates = [referenceDate + nprnd.randint(0,3)*SixMonthDelay for r in range(10)]
For debugging uncomment this to choose a single date for the forward bond
print(startDates)
startDates = [date(2005,3,10)] # or
startDates = [date(2005,3,10) + SixMonthDelay]
maturities = [(x+TwoYearsDelay) for x in startDates]
You can change the coupon and see its effect on the Exposure Profile.  The breakevenRate is calculated, for simplicity, always at referenceDate=self.start, that is, at the first day of the CouponBond life.
Below is a way to create random long/short bond portfolio of any size.  The notional only affects the product class at the last stage of calculation. In my case, the only parameters affected are Exposure (PV on referenceDate), pvAvg(average PV on referenceDate)
myPortfolio = {}
coupon = 0.07536509
for i in range(len(startDates)):
    notional=(-1.0)**i
    myPortfolio[i] = CouponBond(fee=1.0,start=startDates[i],coupon=coupon,notional=notional,
                                maturity= maturities[i], freq="3M", referencedate=referenceDate)
End of explanation
"""


portfolioScheduleOfCF = set(ReferenceDateList)
for i in range(len(myPortfolio)):
    portfolioScheduleOfCF=portfolioScheduleOfCF.union(myPortfolio[i].getScheduleComplete()[0]
)
portfolioScheduleOfCF = sorted(portfolioScheduleOfCF.union(ReferenceDateList))
OIS = myVasicek.getSmallLibor(datelist=portfolioScheduleOfCF)
# at this point OIS contains all dates for which the discount curve should be known.
# If the OIS doesn't contain that date, it would not be able to discount the cashflows and the calcualtion would faill.

print(OIS)

pvs={}
for t in portfolioScheduleOfCF:
    pvs[t] = np.zeros([1,simNumber])
    for i in range(len(myPortfolio)):
        myPortfolio[i].setLibor(OIS)
        pvs[t] = pvs[t] + myPortfolio[i].getExposure(referencedate=t).values

#print(portfolioScheduleOfCF)        
#print(pvs)
pvsPlot = pd.DataFrame.from_dict(list(pvs.items()))
pvsPlot.index= list(pvs.keys())
pvs1={}
for i,t in zip(pvsPlot.values,pvsPlot.index):
    pvs1[t]=i[1][0]
pvs = pd.DataFrame.from_dict(data=pvs1,orient="index")
ax=pvs.plot(legend=False)
ax.set_xlabel("Year")
ax.set_ylabel("Coupon Bond Exposure")

"""
Explanation: Create Libor and portfolioScheduleOfCF.  This datelist contains all dates
to be used in any calculation of the portfolio positions.
BondCoupon class has to have a method getScheduleComplete, which return
fullSet on [0] and datelist on [1], calculated by BondCoupon as:
def getScheduleComplete(self):
 self.datelist=self.myScheduler.getSchedule(start=self.start,end=self.maturity,freq=self.freq,referencedate=self.referencedate)
    self.ntimes = len(self.datelist)
    fullset = sorted(set(self.datelist)
                               .union([self.referencedate])
                               .union([self.start])
                               .union([self.maturity])
                               )
    return fullset,self.datelist
portfolioScheduleOfCF is the concatenation of all fullsets. It defines the set of all dates for which Libor should be known.
End of explanation
"""


