189 lines
4.8 KiB
Go
189 lines
4.8 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
|
|
"time"
|
|
|
|
"strings"
|
|
|
|
"github.com/ananthakumaran/paisa/internal/model/price"
|
|
"github.com/ananthakumaran/paisa/internal/scraper/mutualfund"
|
|
"github.com/ananthakumaran/paisa/internal/utils"
|
|
"github.com/google/btree"
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
"math/rand"
|
|
)
|
|
|
|
const START_YEAR = 2015
|
|
|
|
var initCmd = &cobra.Command{
|
|
Use: "init",
|
|
Short: "generates a sample config and journal file",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
generateConfigFile(cwd)
|
|
generateJournalFile(cwd)
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(initCmd)
|
|
}
|
|
|
|
func generateConfigFile(cwd string) {
|
|
configFilePath := path.Join(cwd, "paisa.yaml")
|
|
config := `
|
|
journal_path: "%s"
|
|
db_path: "%s"
|
|
commodities:
|
|
- name: NIFTY
|
|
type: mutualfund
|
|
code: 120716
|
|
- name: NIFTY_JR
|
|
type: mutualfund
|
|
code: 120684
|
|
- name: ABCBF
|
|
type: mutualfund
|
|
code: 119533
|
|
`
|
|
log.Info("Generating config file: ", configFilePath)
|
|
journalFilePath := path.Join(cwd, "personal.ledger")
|
|
dbFilePath := path.Join(cwd, "paisa.db")
|
|
err := ioutil.WriteFile(configFilePath, []byte(fmt.Sprintf(config, journalFilePath, dbFilePath)), 0644)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func loadPrices(schemeCode string, commodityName string, pricesTree map[string]*btree.BTree) {
|
|
prices, err := mutualfund.GetNav(schemeCode, commodityName)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
pricesTree[commodityName] = btree.New(2)
|
|
for _, price := range prices {
|
|
pricesTree[commodityName].ReplaceOrInsert(*price)
|
|
|
|
}
|
|
}
|
|
|
|
func formatFloat(num float64) string {
|
|
s := fmt.Sprintf("%.4f", num)
|
|
return strings.TrimRight(strings.TrimRight(s, "0"), ".")
|
|
}
|
|
|
|
func emitSalary(file *os.File, start time.Time) {
|
|
var salary float64 = 100000 + (float64(start.Year())-START_YEAR)*(100000*0.05)
|
|
var company string
|
|
if start.Year() > 2017 {
|
|
company = "Globex"
|
|
} else {
|
|
company = "Acme"
|
|
}
|
|
|
|
_, err := file.WriteString(fmt.Sprintf(`
|
|
%s Salary
|
|
Income:Salary:%s
|
|
Asset:Debt:EPF %s INR
|
|
Tax %s INR
|
|
Checking %s INR
|
|
`, start.Format("2006/01/02"), company, formatFloat(salary*0.12), formatFloat(salary*0.20), formatFloat(salary*0.68)))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if start.Year() > START_YEAR && start.Month() == time.March {
|
|
_, err = file.WriteString(fmt.Sprintf(`
|
|
%s EPF Interest
|
|
Income:Interest:EPF
|
|
Asset:Debt:EPF %s INR
|
|
`, start.Format("2006/01/02"), formatFloat(salary*0.12*((float64(start.Year())-START_YEAR)*12)*0.075)))
|
|
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func emitEquityMutualFund(file *os.File, start time.Time, pricesTree map[string]*btree.BTree) {
|
|
multiplier := 1.0
|
|
if start.Year() > START_YEAR+1 && rand.Intn(3) == 0 {
|
|
multiplier = -1.0
|
|
}
|
|
pc := utils.BTreeDescendFirstLessOrEqual(pricesTree["NIFTY"], price.Price{Date: start})
|
|
log.Info(pc)
|
|
_, err := file.WriteString(fmt.Sprintf(`
|
|
%s Mutual Fund Nifty
|
|
Asset:Equity:NIFTY %s NIFTY @ %s INR
|
|
Checking
|
|
`, start.Format("2006/01/02"), formatFloat(10000/pc.Value*multiplier), formatFloat(pc.Value)))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
pc = utils.BTreeDescendFirstLessOrEqual(pricesTree["NIFTY_JR"], price.Price{Date: start})
|
|
_, err = file.WriteString(fmt.Sprintf(`
|
|
%s Mutual Fund Nifty Next 50
|
|
Asset:Equity:NIFTY_JR %s NIFTY_JR @ %s INR
|
|
Checking
|
|
`, start.Format("2006/01/02"), formatFloat(10000/pc.Value*multiplier), formatFloat(pc.Value)))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
}
|
|
|
|
func emitDebtMutualFund(file *os.File, start time.Time, pricesTree map[string]*btree.BTree) {
|
|
multiplier := 1.0
|
|
if start.Year() > START_YEAR+1 && rand.Intn(3) == 0 {
|
|
multiplier = -1.0
|
|
}
|
|
pc := utils.BTreeDescendFirstLessOrEqual(pricesTree["ABCBF"], price.Price{Date: start})
|
|
_, err := file.WriteString(fmt.Sprintf(`
|
|
%s Mutual Fund Birla Corporate Fund
|
|
Asset:Debt:ABCBF %s ABCBF @ %s INR
|
|
Checking
|
|
`, start.Format("2006/01/02"), formatFloat(10000/pc.Value*multiplier), formatFloat(pc.Value)))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func generateJournalFile(cwd string) {
|
|
journalFilePath := path.Join(cwd, "personal.ledger")
|
|
log.Info("Generating journal file: ", journalFilePath)
|
|
ledgerFile, err := os.OpenFile(journalFilePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
end := time.Now()
|
|
start, err := time.Parse("02-01-2006", fmt.Sprintf("01-01-%d", START_YEAR))
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
pricesTree := make(map[string]*btree.BTree)
|
|
loadPrices("120716", "NIFTY", pricesTree)
|
|
loadPrices("120684", "NIFTY_JR", pricesTree)
|
|
loadPrices("119533", "ABCBF", pricesTree)
|
|
|
|
for ; start.Before(end); start = start.AddDate(0, 1, 0) {
|
|
emitSalary(ledgerFile, start)
|
|
emitEquityMutualFund(ledgerFile, start, pricesTree)
|
|
emitDebtMutualFund(ledgerFile, start, pricesTree)
|
|
}
|
|
}
|