-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
200 lines (180 loc) · 5.85 KB
/
main.go
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Project repository: https://github.com/theluqmn/compound-interest-calculator
package main
import (
"fmt"
"log"
"strconv"
"errors"
"github.com/shopspring/decimal"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/widget"
)
func main() {
// Initialize Fyne app and window
myApp := app.New()
myWindow := myApp.NewWindow("Compound Interest Calculator")
myWindow.Resize(fyne.NewSize(500, 400))
// Create title and status labels
title := widget.NewLabelWithStyle("Compound Interest Calculator", fyne.TextAlignCenter, fyne.TextStyle{Bold: true})
status := widget.NewLabelWithStyle("Awaiting inputs", fyne.TextAlignLeading, fyne.TextStyle{Bold: false})
// Create input fields
principalEntry := widget.NewEntry()
principalEntry.SetPlaceHolder("Principal amount")
principalEntry.Validator = func(s string) error {
for _, r := range s {
if (r < '0' || r > '9') && r != '.' {
return fmt.Errorf("only numbers and decimal point allowed")
}
}
return nil
}
rateEntry := widget.NewEntry()
rateEntry.SetPlaceHolder("Rate of interest")
rateEntry.Validator = func(s string) error {
for _, r := range s {
if (r < '0' || r > '9') && r != '.' {
return fmt.Errorf("only numbers and decimal point allowed")
}
}
return nil
}
timesCompoundEntry := widget.NewEntry()
timesCompoundEntry.SetPlaceHolder("Times compounded")
timesCompoundEntry.Validator = func(s string) error {
for _, r := range s {
if (r < '0' || r > '9') && r != '.' {
return fmt.Errorf("only numbers and decimal point allowed")
}
}
return nil
}
yearsEntry := widget.NewEntry()
yearsEntry.SetPlaceHolder("Years")
yearsEntry.Validator = func(s string) error {
for _, r := range s {
if (r < '0' || r > '9') && r != '.' {
return fmt.Errorf("only numbers and decimal point allowed")
}
}
return nil
}
// Create result labels that we can reference later
totalReturnsLabel := widget.NewLabelWithStyle("N/A", fyne.TextAlignTrailing, fyne.TextStyle{Bold: false})
totalInterestLabel := widget.NewLabelWithStyle("N/A", fyne.TextAlignTrailing, fyne.TextStyle{Bold: false})
// Result container (shows output of the CompoundInterest function)
result := container.NewGridWithRows(
2,
container.NewGridWithColumns(
2,
widget.NewLabelWithStyle("Total returns", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
totalReturnsLabel,
),
container.NewGridWithColumns(
2,
widget.NewLabelWithStyle("Total interest", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
totalInterestLabel,
),
)
// Main content container
content := container.NewVBox(
title,
principalEntry,
rateEntry,
container.NewGridWithColumns(
2,
timesCompoundEntry,
yearsEntry,
),
status,
widget.NewButton("Calculate", func() {
// Validate inputs and type conversions
principal, err := strconv.ParseFloat(principalEntry.Text, 64)
if err != nil {
status.SetText("Invalid principal amount")
return
}
rate, err := strconv.ParseFloat(rateEntry.Text, 64)
if err != nil {
status.SetText("Invalid rate of interest")
return
}
timesCompound, err := strconv.ParseInt(timesCompoundEntry.Text, 10, 64)
if err != nil {
status.SetText("Invalid times compounded")
return
}
years, err := strconv.ParseInt(yearsEntry.Text, 10, 64)
if err != nil {
status.SetText("Invalid years")
return
}
// Calculate compound interest
total, interest, err := CompoundInterest(principal, rate, int(timesCompound), int(years))
if err != nil {
status.SetText(err.Error())
return
}
// Update result labels
totalReturnsLabel.SetText(fmt.Sprintf("%.2f", total))
totalInterestLabel.SetText(fmt.Sprintf("%.2f", interest))
status.SetText("Calculated")
}),
result,
layout.NewSpacer(),
widget.NewRichTextFromMarkdown("Created by [theluqmn](https://theluqmn.github.io) using Go [Fyne](https://fyne.io). [Source code](https://github.com/theluqmn/compound-interest-calculator)"),
)
// Set content and show window (runs the app)
myWindow.SetContent(content)
myWindow.ShowAndRun()
quit()
}
// Runs on program exit
func quit() {
log.Println("Exiting program...")
}
// Check out the repo at https://github.com/theluqmn/go4finance
// Calculates the total returns of a compound interest investment, and the total interest earned.
// It uses the shopspring/decimal library to handle floating-point arithmetic accurately, making it suitable for financial applications.
//
// Parameters:
// - principal: The initial investment amount.
// - rate: The annual interest rate as a decimal.
// - timesCompounded: The number of times the interest is compounded per year.
// - years: The number of years the investment is held.
//
// Returns:
// - total: The total amount of money after the investment period.
// - interest: The total interest earned.
// - err: An error if any of the inputs are invalid.
//
// Made by https://theluqmn.github.io
func CompoundInterest(principal float64, rate float64, timesCompounded int, years int) (total float64, interest float64, err error) {
// Convert to decimals
P := decimal.NewFromFloat(principal)
r := decimal.NewFromFloat(rate)
n := decimal.NewFromInt(int64(timesCompounded))
t := decimal.NewFromInt(int64(years))
one := decimal.NewFromInt(1)
// Validate inputs
if principal <= 0 {
return 0, 0, errors.New("principal must be greater than 0")
}
if rate <= 0 {
return 0, 0, errors.New("rate must be greater than 0")
}
if timesCompounded <= 0 {
return 0, 0, errors.New("timesCompounded must be greater than 0")
}
if years <= 0 {
return 0, 0, errors.New("years must be greater than 0")
}
// Calculate compound interest
CalcExponent := n.Mul(t)
CalcBracket := one.Add(r.Div(n))
CalcTotal := P.Mul(CalcBracket.Pow(CalcExponent))
CalcInterest := CalcTotal.Sub(P)
return CalcTotal.InexactFloat64(), CalcInterest.InexactFloat64(), nil
}