-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathserver.R
112 lines (95 loc) · 3.8 KB
/
server.R
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
## Setup
library("shiny")
library("rCharts")
library("reshape2")
## Calculate payment
pay <- function(principal, interest, duration, payfreq, firstpay, compoundfreq) {
r <- interest / (100 * 12 / compoundfreq )
if(firstpay > 1) {
principal <- principal * (1 + r)^((firstpay - 1) / compoundfreq)
duration <- duration - (firstpay - 1) / 12
}
payment <- principal * r / ( 1 - ( 1 + r)^(-duration * 12 / compoundfreq) ) * payfreq / compoundfreq
res <- list(r=r, payment=payment, principal=principal)
return(res)
}
## Amortization table
amort <- function(principal, interest, duration, payfreq, firstpay, compoundfreq) {
pay <- pay(principal, interest, duration, payfreq, firstpay, compoundfreq)
data <- data.frame(month = seq(0, duration * 12))
data$payment <- 0
data$payment[ (data$month - firstpay) >= 0 & (data$month - firstpay) %% payfreq == 0 ] <- pay$payment
i <- which(data$payment != 0)
i <- i[length(i)]
data$payment[ i ] <- 0
data$payment[ i ] <- pay$payment * (duration - (firstpay - 1) / 12) * 12 / payfreq - sum(data$payment)
data$totalPayed <- cumsum(data$payment)
data$principal <- NA
data$principal[1] <- principal
idx <- (data$month - firstpay) >=0 & (data$month - firstpay) %% compoundfreq == 0
idx.pr <- which(idx)[-length(idx)] + compoundfreq - 1
if(any(idx.pr > max(data$month))) {
idx.pr <- idx.pr[-which(idx.pr > max(data$month))]
}
if(firstpay > 1) {
data$principal[firstpay] <- pay$principal
}
data$principal[ idx.pr ] <- (1 + pay$r)^seq_len(length(idx.pr)) * pay$principal - ( (1 + pay$r)^seq_len(length(idx.pr)) - 1 ) / pay$r * pay$payment * compoundfreq / payfreq
data$principal[ nrow(data)] <- 0
return(data)
}
## Main shiny function
shinyServer(function(input, output, session) {
## Update max payment frequency
observe({
updateNumericInput(session, "firstpay", "Month of the first payment", 1, min=0, max=input$duration * 12, step=1)
})
## Update interest compouding options
observe({
updateNumericInput(session, "compoundfreq", "How frequently are interests compounded? (in months)", input$payfreq, min=1, max=input$payfreq, step=1)
})
## Display payment
output$payment <- renderPrint({
payment <- pay(input$principal, input$interest, input$duration, input$payfreq, input$firstpay, as.integer(input$compoundfreq))$payment
cat("Your recurrent payment (every ")
if(input$payfreq > 1) {
cat(input$payfreq)
cat(" months")
} else {
cat("month")
}
cat(") will be ")
cat(round(payment, 2))
cat(".\nAt the end of the loan you will have payed a total of ")
total <- payment * (input$duration - (input$firstpay - 1) / 12) * 12 / input$payfreq
cat(round(total, 2))
cat(".\nThat is, a total of ")
cat(round(total - input$principal, 2))
cat(" in interests.")
})
## Make a chart with the data
output$myChart <- renderChart({
data <- amort(input$principal, input$interest, input$duration, input$payfreq, input$firstpay, as.integer(input$compoundfreq))
dat.chart <- melt(data, id = 'month')
dat.chart$value <- round(dat.chart$value, 0)
chart <- nPlot(value ~ month, group = 'variable',
data = dat.chart[complete.cases(dat.chart), ],
type = 'lineWithFocusChart'
)
chart$xAxis(axisLabel = 'Month')
chart$addParams(dom = 'myChart')
return(chart)
})
## Display amortization table
output$amort <- renderDataTable({
data <- amort(input$principal, input$interest, input$duration, input$payfreq, input$firstpay, as.integer(input$compoundfreq))
data[-1, ]
}, options = list(iDisplayLength = 12))
## Download table
output$downloadData <- downloadHandler(
filename = function() { paste("amortization-table-", round(runif(1, 1e12, 1e13-1), 0), '.csv', sep='') },
content = function(file) {
write.csv(amort(input$principal, input$interest, input$duration, input$payfreq, input$firstpay, as.integer(input$compoundfreq)), file)
}
)
})