aboutsummaryrefslogtreecommitdiffstats
path: root/R/thetas-durations.R
blob: 011ceb707f61a4d051ffc2c3784167f0f4fd1638 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
library(lubridate)
library(doParallel)
library(dplyr)
library(tidyr)

hostname <- system("hostname", intern=TRUE)
registerDoParallel(if(hostname=="debian") 4 else 8)

source("db.R")
source("cds_functions_generic.R")
source("yieldcurve.R")

serenitasdb <- dbConn("serenitasdb")

get.indexquotes.table <- function(indextype, series, tenors=c("3yr", "5yr", "7yr"),
                                  onlymissing=TRUE) {
    df <- serenitasdb %>%
        tbl("index_quotes") %>%
        filter(index == !!indextype, series == !!series, tenor %in% !!tenors) %>%
        {if(onlymissing) filter(., is.null(duration)) else .} %>%
        arrange(date) %>% select(date, tenor, close_price) %>%
        collect() %>%
        mutate(tenor=factor(tenor, !!tenors))
    if(nrow(df) == 0) {
        return( df )
    } else {
        return( df %>% spread(tenor, close_price) )
    }
}

get.indexmaturity <- function(index, series){
    index.maturity <- tbl(serenitasdb, "index_maturity")
    df <- index.maturity %>%
        filter(index == !!index, series == !!series) %>%
        mutate(running = coupon/10000) %>%
        select(maturity, running, tenor) %>%
        arrange(maturity) %>%
        collect()
    return( df )
}

fastduration <- function(sc, cs, tradedate, maturities){
    r <- rep(NA, length(maturities))
    if(is.null(sc)) {
        return( r )
    }
    startdate <- tradedate + 1
    acc <- cdsAccrued(tradedate, 1)
    for(i in seq_along(maturities)) {
        if(startdate <= maturities[i]) {
            r[i] <- couponleg(cs[cs$unadj.dates<=maturities[i],], sc,
                              startdate, accruedondefault=TRUE) - acc
        }
    }
    return( r )
}

fasttheta <- function(sc, cs, recov, tradedate, maturities, quotes, fixedrate=0.05){
    r <- rep(NA, length(maturities))
    if(is.null(sc)) {
        return(r)
    }
    startdate <- tradedate + 1
    acc <- cdsAccrued(tradedate, 1)

    newmaturities <- maturities + years(-1)
    for(i in seq_along(newmaturities)){
        ## never extrapolate, and do not attempt to compute theta if within 1 year
        if(startdate > newmaturities[i] || is.na(quotes[i])) {
            next
        } else {
            newcs <- cs[cs$unadj.dates<=newmaturities[i],]
            upfront <- defaultleg(newcs, sc, recov, startdate) -
                (couponleg(newcs, sc, startdate, accruedondefault=TRUE)-acc)*fixedrate
            r[i] <- quotes[i] - upfront + fixedrate
        }
    }
    return( r )
}

sqlstr.duration <- paste("UPDATE index_quotes set duration=$1 where date=$2 and index=$3",
                         "and series=$4 and tenor=$5")
sqlstr.theta <- paste("UPDATE index_quotes set theta=$1 where date=$2 and index=$3",
                      "and series=$4 and tenor=$5")

for(index in c('IG', 'HY', 'EU', 'XO')) {
    recov <- if(index %in% c('IG', 'EU')) 0.4 else 0.3
    coupon <-  if(index %in% c('IG', 'EU')) 0.01 else 0.05
    for(series in 18:30) {
        tenors <- switch(index,
                         IG = c("3yr", "5yr", "7yr", "10yr"),
                         HY = c("3yr", "5yr", "7yr"),
                         EU = c("3yr", "5yr", "7yr", "10yr"),
                         XO = c("3yr", "5yr", "7yr", "10yr"))
        if( index %in% c('EU', 'XO') && series == 30) {
            next
        }

        indexquotes <- get.indexquotes.table(index, series, tenors)
        if(nrow(indexquotes) == 0) {
            next
        }
        maturities <- get.indexmaturity(index, series)
        maturities <- maturities[maturities$tenor %in% colnames(indexquotes)[-1],]
        durations <- matrix(0, nrow(indexquotes), nrow(maturities))
        thetas <- matrix(0, nrow(indexquotes), nrow(maturities))
        last_maturity <- maturities %>% slice(n()) %>% pull(maturity)
        durandthetas <- foreach(i = 1:nrow(indexquotes), .combine='rbind') %dopar% {
            tradedate <- indexquotes  %>% slice(i) %>% pull(date)
            exportYC(tradedate, currency = if (index %in% c("IG", "HY")) "USD" else "EUR")
            cs <- couponSchedule(IMMDate(tradedate, noadj=TRUE), last_maturity, "Q", "FIXED", 1,
                                 0, tradedate, IMMDate(tradedate, "prev"))
            quotes <- data.frame(upfront=(100-as.numeric(indexquotes[i,maturities$tenor]))/100,
                                 maturities)
            ## prevent negative hazardrates
            quotes$upfront <- pmax(-yearFrac(tradedate + 1, quotes$maturity, "act/360") *
                                   quotes$running + 1e-6, quotes$upfront)
            sc <- cdshazardrate(quotes, recov, tradedate, cs)
            c(fastduration(sc, cs, tradedate, maturities$maturity),
              fasttheta(sc, cs, recov, tradedate, maturities$maturity, quotes$upfront, coupon))
        }
        ## non parallel version for easier debugging
        ## durandthetas <- c()
        ## for(i in 1:nrow(indexquotes)) {
        ##     tradedate <- indexquotes  %>% slice(i) %>% pull(date)
        ##     exportYC(tradedate, currency = if (index %in% c("IG", "HY")) "USD" else "EUR")
        ##     cs <- couponSchedule(IMMDate(tradedate, noadj=TRUE), last_maturity,"Q", "FIXED", 1,
        ##                          0, tradedate, IMMDate(tradedate, "prev"))
        ##     quotes <- data.frame(upfront=(100-as.numeric(indexquotes[i,maturities$tenor]))/100,
        ##                          maturities)
        ##     quotes$upfront <- pmax(-yearFrac(tradedate + 1, quotes$maturity, "act/360") *
        ##                            quotes$running + 1e-6, quotes$upfront)
        ##     sc <- cdshazardrate(quotes, recov, tradedate, cs)
        ##     durandthetas <- rbind(durandthetas, c(fastduration(sc, cs, tradedate, maturities$maturity),
        ##                     fasttheta(sc, cs, recov, tradedate, maturities$maturity, quotes$upfront, coupon)))
        ## }
        if(is.null(dim(durandthetas))) {
            dim(durandthetas) <- c(1, length(durandthetas))
        }
        n <- nrow(maturities)
        df.durations <- data.frame(date=indexquotes$date, durandthetas[,1:n, drop=F])
        df.thetas <- data.frame(date=indexquotes$date, durandthetas[,(n+1):(2*n), drop=F])
        colnames(df.durations) <- c("date", maturities$tenor)
        colnames(df.thetas) <- c("date", maturities$tenor)
        for(i in 1:nrow(df.durations)) {
            for(tenor in maturities$tenor) {
                if(!is.na(df.durations[i, tenor])) {
                    r <- dbSendQuery(serenitasdb, sqlstr.duration,
                                     params = list(df.durations[i, tenor],
                                         df.durations[i,"date"], index, series, tenor))
                    if(dbHasCompleted(r)) {
                        dbClearResult(r)
                    }
                }
                if(!is.na(df.thetas[i,tenor])) {
                    r <- dbSendQuery(serenitasdb, sqlstr.theta,
                                     params = list(df.thetas[i, tenor],
                                         df.thetas[i, "date"], index, series, tenor))
                    if(dbHasCompleted(r)) {
                        dbClearResult(r)
                    }
                }
            }
        }
    }
}
## ## nice plot, now I'm just showing off
## library(ggplot2)
## ggplot(df.durations, aes(x=date))+geom_line(aes(y=`3yr`, colour="3yr"))+
##     geom_line(aes(y=`5yr`, colour="5yr"))+
##         geom_line(aes(y=`7yr`, colour="7yr"))+ylab("duration")+labs(colour="tenor")
## ggsave(filename=paste0("HY", series, " durations.png"))
## ## plot thetas
## ggplot(df.thetas, aes(x=date))+geom_line(aes(y=`3yr`, colour="3yr"))+
##     geom_line(aes(y=`5yr`, colour="5yr"))+
##         geom_line(aes(y=`7yr`, colour="7yr"))+ylab("theta")+labs(colour="tenor")
## ggsave(filename=paste0("HY", series, " thetas.png"))