package main import ( "net/http" "strings" "time" chart "github.com/wcharczuk/go-chart" "github.com/wcharczuk/go-chart/seq" util "github.com/wcharczuk/go-chart/util" ) type price struct { Timestamp string Price float64 } func (p price) format() (time.Time, float64) { t, err := time.ParseInLocation("2006-01-02 15:04:05", strings.Split(p.Timestamp, ".")[0], util.Date.Eastern()) if err != nil { panic(err) } return t, p.Price } func stockData() (times []time.Time, prices []float64) { rawPrices := []price{ {"2017-05-12 19:45:04.482809", 238.84}, {"2017-05-12 19:30:04.349476", 238.92}, {"2017-05-12 19:15:04.160628", 238.98}, {"2017-05-12 19:00:03.994135", 239.05}, {"2017-05-12 18:45:03.947176", 238.87}, {"2017-05-12 18:30:03.653826", 238.97}, {"2017-05-12 18:15:03.319783", 239.00}, {"2017-05-12 18:00:03.293044", 238.87}, {"2017-05-12 17:45:03.010216", 238.85}, {"2017-05-12 17:30:07.808406", 238.84}, {"2017-05-12 17:15:02.814348", 238.93}, {"2017-05-12 17:00:03.153611", 239.00}, {"2017-05-12 16:45:02.352906", 238.93}, {"2017-05-12 16:30:02.339523", 239.00}, {"2017-05-12 16:15:02.051624", 239.05}, {"2017-05-12 16:00:01.920557", 239.10}, {"2017-05-12 15:45:06.866833", 239.00}, {"2017-05-12 15:30:01.60765", 238.92}, {"2017-05-12 15:15:01.481936", 238.80}, {"2017-05-12 15:00:01.298738", 238.85}, {"2017-05-12 14:45:01.19513", 238.78}, {"2017-05-12 14:30:01.037173", 239.03}, {"2017-05-12 14:15:00.835599", 239.02}, {"2017-05-12 14:00:00.654748", 239.00}, {"2017-05-12 13:45:00.65331", 239.05}, {"2017-05-11 19:45:03.940287", 239.26}, {"2017-05-11 19:30:03.796674", 239.42}, {"2017-05-11 19:15:03.709477", 239.31}, {"2017-05-11 19:00:03.533934", 239.37}, {"2017-05-11 18:45:03.383436", 239.44}, {"2017-05-11 18:30:03.224035", 239.23}, {"2017-05-11 18:15:03.127204", 239.31}, {"2017-05-11 18:00:02.8859", 239.27}, {"2017-05-11 17:45:02.796172", 239.00}, {"2017-05-11 17:30:02.767553", 239.12}, {"2017-05-11 17:15:02.56807", 238.96}, {"2017-05-11 17:00:02.613708", 239.08}, {"2017-05-11 16:45:02.348852", 238.99}, {"2017-05-11 16:30:02.165067", 238.84}, {"2017-05-11 16:15:02.043199", 238.69}, {"2017-05-11 16:00:01.831857", 238.67}, {"2017-05-11 15:45:01.705654", 238.72}, {"2017-05-11 15:30:01.641864", 238.75}, {"2017-05-11 15:15:01.387109", 238.58}, {"2017-05-11 15:00:01.212597", 238.53}, {"2017-05-11 14:45:01.148888", 238.35}, {"2017-05-11 14:30:00.915767", 238.59}, {"2017-05-11 14:15:00.655649", 238.55}, {"2017-05-11 14:00:00.596624", 239.05}, {"2017-05-11 13:45:00.565487", 239.36}, {"2017-05-10 19:45:04.220057", 239.69}, {"2017-05-10 19:30:04.102519", 239.82}, {"2017-05-10 19:15:03.950613", 239.77}, {"2017-05-10 19:00:03.871972", 239.73}, {"2017-05-10 18:45:03.697585", 239.59}, {"2017-05-10 18:30:03.490385", 239.72}, {"2017-05-10 18:15:03.327691", 239.71}, {"2017-05-10 18:00:03.277211", 239.68}, {"2017-05-10 17:45:03.270592", 239.76}, {"2017-05-10 17:30:03.124085", 239.69}, {"2017-05-10 17:15:02.811264", 239.76}, {"2017-05-10 17:00:02.696942", 239.71}, {"2017-05-10 16:45:02.435806", 239.66}, {"2017-05-10 16:30:02.373372", 239.65}, {"2017-05-10 16:15:02.130672", 239.66}, {"2017-05-10 16:00:02.04879", 239.71}, {"2017-05-10 15:45:01.91206", 239.74}, {"2017-05-10 15:30:01.710121", 239.57}, {"2017-05-10 15:15:01.485801", 239.39}, {"2017-05-10 15:00:01.43788", 239.44}, {"2017-05-10 14:45:01.184263", 239.25}, {"2017-05-10 14:30:00.940762", 239.45}, {"2017-05-10 14:15:00.885742", 239.41}, {"2017-05-10 14:00:00.640709", 239.38}, {"2017-05-10 13:45:00.548287", 239.38}, {"2017-05-09 19:45:04.220057", 239.69}, {"2017-05-09 19:30:04.102519", 239.82}, {"2017-05-09 19:15:03.950613", 239.77}, {"2017-05-09 19:00:03.871972", 239.73}, {"2017-05-09 18:45:03.697585", 239.59}, {"2017-05-09 18:30:03.490385", 239.72}, {"2017-05-09 18:15:03.327691", 239.71}, {"2017-05-09 18:00:03.277211", 239.68}, {"2017-05-09 17:45:03.270592", 239.76}, {"2017-05-09 17:30:03.124085", 239.69}, {"2017-05-09 17:15:02.811264", 239.76}, {"2017-05-09 17:00:02.696942", 239.71}, {"2017-05-09 16:45:02.435806", 239.66}, {"2017-05-09 16:30:02.373372", 239.65}, {"2017-05-09 16:15:02.130672", 239.66}, {"2017-05-09 16:00:02.04879", 239.71}, {"2017-05-09 15:45:01.91206", 239.74}, {"2017-05-09 15:30:01.710121", 239.57}, {"2017-05-09 15:15:01.485801", 239.39}, {"2017-05-09 15:00:01.43788", 239.44}, {"2017-05-09 14:45:01.184263", 239.25}, {"2017-05-09 14:30:00.940762", 239.45}, {"2017-05-09 14:15:00.885742", 239.41}, {"2017-05-09 14:00:00.640709", 239.38}, {"2017-05-09 13:45:00.548287", 239.38}, {"2017-05-05 19:45:04.220057", 239.69}, {"2017-05-05 19:30:04.102519", 239.82}, {"2017-05-05 19:15:03.950613", 239.77}, {"2017-05-05 19:00:03.871972", 239.73}, {"2017-05-05 18:45:03.697585", 239.59}, {"2017-05-05 18:30:03.490385", 239.72}, {"2017-05-05 18:15:03.327691", 239.71}, {"2017-05-05 18:00:03.277211", 239.68}, {"2017-05-05 17:45:03.270592", 239.76}, {"2017-05-05 17:30:03.124085", 239.69}, {"2017-05-05 17:15:02.811264", 239.76}, {"2017-05-05 17:00:02.696942", 239.71}, {"2017-05-05 16:45:02.435806", 239.66}, {"2017-05-05 16:30:02.373372", 239.65}, {"2017-05-05 16:15:02.130672", 239.66}, {"2017-05-05 16:00:02.04879", 239.71}, {"2017-05-05 15:45:01.91206", 239.74}, {"2017-05-05 15:30:01.710121", 239.57}, {"2017-05-05 15:15:01.485801", 239.39}, {"2017-05-05 15:00:01.43788", 239.44}, {"2017-05-05 14:45:01.184263", 239.25}, {"2017-05-05 14:30:00.940762", 239.45}, {"2017-05-05 14:15:00.885742", 239.41}, {"2017-05-05 14:00:00.640709", 239.38}, {"2017-05-05 13:45:00.548287", 239.38}, {"2017-05-03 19:45:04.220057", 239.69}, {"2017-05-03 19:30:04.102519", 239.82}, {"2017-05-03 19:15:03.950613", 239.77}, {"2017-05-03 19:00:03.871972", 239.73}, {"2017-05-03 18:45:03.697585", 239.59}, {"2017-05-03 18:30:03.490385", 239.72}, {"2017-05-03 18:15:03.327691", 239.71}, {"2017-05-03 18:00:03.277211", 239.68}, {"2017-05-03 17:45:03.270592", 239.76}, {"2017-05-03 17:30:03.124085", 239.69}, {"2017-05-03 17:15:02.811264", 239.76}, {"2017-05-03 17:00:02.696942", 239.71}, {"2017-05-03 16:45:02.435806", 239.66}, {"2017-05-03 16:30:02.373372", 239.65}, {"2017-05-03 16:15:02.130672", 239.66}, {"2017-05-03 16:00:02.04879", 239.71}, {"2017-05-03 15:45:01.91206", 239.74}, {"2017-05-03 15:30:01.710121", 239.57}, {"2017-05-03 15:15:01.485801", 239.39}, {"2017-05-03 15:00:01.43788", 239.44}, {"2017-05-03 14:45:01.184263", 239.25}, {"2017-05-03 14:30:00.940762", 239.45}, {"2017-05-03 14:15:00.885742", 239.41}, {"2017-05-03 14:00:00.640709", 239.38}, {"2017-05-03 13:45:00.548287", 239.38}, {"2017-04-28 19:45:04.193877", 238.11}, {"2017-04-28 19:30:04.078242", 238.20}, {"2017-04-28 19:15:03.886795", 238.05}, {"2017-04-28 19:00:03.797682", 238.08}, {"2017-04-28 18:45:03.691054", 238.05}, {"2017-04-28 18:30:03.513045", 237.96}, {"2017-04-28 18:15:03.387037", 238.09}, {"2017-04-28 18:00:03.303554", 238.11}, {"2017-04-28 17:45:03.181305", 238.16}, {"2017-04-28 17:30:08.066927", 238.17}, {"2017-04-28 17:15:02.708957", 238.23}, {"2017-04-28 17:00:02.673222", 238.27}, {"2017-04-28 16:45:02.478988", 238.29}, {"2017-04-28 16:30:02.299229", 238.24}, {"2017-04-28 16:15:02.100061", 238.15}, {"2017-04-28 16:00:01.922355", 238.06}, {"2017-04-28 15:45:01.666185", 238.25}, {"2017-04-28 15:30:01.477215", 238.19}, {"2017-04-28 15:15:01.440657", 238.39}, {"2017-04-28 15:00:01.222734", 238.39}, {"2017-04-28 14:45:01.005045", 238.33}, {"2017-04-28 14:30:00.935222", 238.46}, {"2017-04-28 14:15:00.84484", 238.53}, {"2017-04-28 14:00:00.635436", 238.52}, {"2017-04-27 19:45:04.242597", 238.61}, } var t time.Time var v float64 var p price for i := len(rawPrices) - 1; i >= 0; i-- { p = rawPrices[i] t, v = p.format() times = append(times, t) prices = append(prices, v) } return } func drawChart(res http.ResponseWriter, req *http.Request) { xv, yv := stockData() priceSeries := chart.TimeSeries{ Name: "SPY", Style: chart.Style{ Show: true, StrokeColor: chart.GetDefaultColor(0), }, XValues: xv, YValues: yv, } candleSeries := chart.CandlestickSeries{ Name: "SPY", XValues: xv, YValues: yv, } graph := chart.Chart{ XAxis: chart.XAxis{ Style: chart.Style{Show: true}, TickPosition: chart.TickPositionBetweenTicks, Range: &chart.MarketHoursRange{ Min: seq.Times(xv...).Min().In(util.Date.Eastern()), Max: seq.Times(xv...).Max().In(util.Date.Eastern()), MarketOpen: util.NYSEOpen(), MarketClose: util.NYSEClose(), HolidayProvider: util.Date.IsNYSEHoliday, }, }, YAxis: chart.YAxis{ Style: chart.Style{Show: true}, }, Series: []chart.Series{ candleSeries, priceSeries, }, } res.Header().Set("Content-Type", "image/png") err := graph.Render(chart.PNG, res) if err != nil { panic(err) } } func main() { http.HandleFunc("/", drawChart) http.ListenAndServe(":8080", nil) }