go-examples/go-financial/main.go
2017-07-08 09:43:10 +02:00

223 lines
4.2 KiB
Go

package main
import "encoding/csv"
import "fmt"
import "io"
import "log"
import "os"
import "strconv"
var COLUMNS []string
type FinancialData struct {
Date string
Open, High, Low, Close, Adj_Close, Volume float64
}
func printHTML(data []FinancialData, out io.Writer) {
io.WriteString(out, `<!DOCTYPE html>
<html>
<head><title>Financial</title></head>
<body>
<table border="1">
<tr>
`)
for _, col := range COLUMNS {
io.WriteString(out, " <th>")
io.WriteString(out, col)
io.WriteString(out, "</th>\n")
}
io.WriteString(out, " </tr>\n")
// data
for _, row := range data {
row.printHTMLRow(out)
}
io.WriteString(out, ` </table>
<div id="container"></div>
<style>
#container {
min-width: 310px;
max-width: 800px;
height: 400px;
margin: 0 auto
}
</style>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<script src="https://code.highcharts.com/highcharts.src.js"></script>
<script>
Highcharts.chart('container', {
title: {
text: 'Financial data'
},
subtitle: {
text: 'Source: yahoo.com'
},
yAxis: {
title: {
text: 'Value'
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle'
},
series: [{
name: 'Open',
data: [`+getDataOpen(data)+`]
}, {
name: 'Close',
data: [`+getDataClose(data)+`]
}]
});
</script>
</body>
</html>`)
}
func getDataOpen(data []FinancialData) string {
str := ""
for i, v := range data {
str += fmt.Sprintf("%.4f", v.Open)
if i < len(data)-1 {
str += ","
}
}
return str
}
func getDataClose(data []FinancialData) string {
str := ""
for i, v := range data {
str += fmt.Sprintf("%.4f", v.Close)
if i < len(data)-1 {
str += ","
}
}
return str
}
func (data FinancialData) printHTMLRow(out io.Writer) {
io.WriteString(out, " <tr>")
printCellString(data.Date, out)
printCellFloat(data.Open, out)
printCellFloat(data.High, out)
printCellFloat(data.Low, out)
printCellFloat(data.Close, out)
printCellFloat(data.Adj_Close, out)
printCellFloatFmt(data.Volume, "%f", out)
io.WriteString(out, "</tr>\n")
}
func printCellString(val string, out io.Writer) {
io.WriteString(out, "<td>"+val+"</td>")
}
func printCellFloatFmt(val float64, format string, out io.Writer) {
io.WriteString(out, fmt.Sprintf("<td>"+format+"</td>", val))
}
func printCellFloat(val float64, out io.Writer) {
printCellFloatFmt(val, "%.2f", out)
}
func printFooter() {
fmt.Println(` </table>
</body>
</html> `)
}
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()
// output
var out io.Writer
if len(os.Args) > 2 {
fout, err := os.Create(os.Args[2])
if err != nil {
log.Fatalln("Error creating output file", err)
}
defer fout.Close()
out = fout
} else {
out = os.Stdout
}
// parse data
data := readCsv(csv)
printHTML(data, out)
}