123 lines
2.1 KiB
Go
123 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"html/template"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
var COLUMNS []string
|
|
|
|
type FinancialData struct {
|
|
Date string
|
|
Open, High, Low, Close, Adj_Close, Volume float64
|
|
}
|
|
|
|
type TplData struct {
|
|
Columns []string
|
|
Rows []FinancialData
|
|
}
|
|
|
|
func printHTML(tpl *template.Template, data []FinancialData, out io.Writer) {
|
|
tplData := TplData{
|
|
COLUMNS,
|
|
data,
|
|
}
|
|
err := tpl.ExecuteTemplate(out, "tpl.html", tplData)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func readCsvLine(line []string) *FinancialData {
|
|
data := new(FinancialData)
|
|
for i, col := range line {
|
|
switch COLUMNS[i] {
|
|
case "Date":
|
|
data.Date = col
|
|
case "Open":
|
|
data.Open = toFloat(col)
|
|
case "High":
|
|
data.High = toFloat(col)
|
|
case "Low":
|
|
data.Low = toFloat(col)
|
|
case "Close":
|
|
data.Close = toFloat(col)
|
|
case "Adj Close":
|
|
data.Adj_Close = toFloat(col)
|
|
case "Volume":
|
|
data.Volume = toFloat(col)
|
|
}
|
|
}
|
|
return data
|
|
}
|
|
|
|
func toFloat(v string) float64 {
|
|
f, err := strconv.ParseFloat(v, 64)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
return f
|
|
}
|
|
|
|
func readCsvHeader(line []string) {
|
|
for _, col := range line {
|
|
COLUMNS = append(COLUMNS, col)
|
|
}
|
|
}
|
|
|
|
func readCsv(in io.Reader) []FinancialData {
|
|
data := []FinancialData{}
|
|
csvReader := csv.NewReader(in)
|
|
for {
|
|
line, err := csvReader.Read()
|
|
if err == io.EOF {
|
|
break
|
|
} else if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if len(COLUMNS) == 0 {
|
|
readCsvHeader(line)
|
|
} else {
|
|
data = append(data, *readCsvLine(line))
|
|
}
|
|
}
|
|
return data
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
log.Fatalln("Usage go-financial <file>")
|
|
}
|
|
|
|
// read input
|
|
csv, err := os.Open(os.Args[1])
|
|
if err != nil {
|
|
log.Fatalln("Error reading file", err)
|
|
}
|
|
defer csv.Close()
|
|
|
|
// parse data
|
|
data := readCsv(csv)
|
|
|
|
tpl, err := template.New("").Funcs(template.FuncMap{
|
|
"class": func(index int) string {
|
|
if index%2 == 0 {
|
|
return "even"
|
|
}
|
|
return "odd"
|
|
},
|
|
}).ParseFiles("tpl.html", "script.js")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
|
|
printHTML(tpl, data, res)
|
|
})
|
|
http.ListenAndServe(":9000", nil)
|
|
}
|