Skip to content

Instantly share code, notes, and snippets.

@zhengwy888
Created April 20, 2015 02:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhengwy888/63404185ba39fae9d254 to your computer and use it in GitHub Desktop.
Save zhengwy888/63404185ba39fae9d254 to your computer and use it in GitHub Desktop.
To use run: > go run <script_name> <stock symbol> and it will display Price and Volume graph from the past year in your terminal
// +build ignore
// Author: Weiyi Zheng, 2015
/* learning termui and go language
To use run: > go run <script_name> <stock symbol>
and it will display Price and Volume info from last year in your terminal
things are lacking:
- two graphs can't be scaled to the same width
- no control over axis label
- be cautious running any termui stuff in chromebook's Secure Shell, it will freeze
Things I learned when coding this:
- With a typed language, it is easier to access elements inside a struct with accessor function, not Pluck (in Go's case, it's Reflect)
- Strict variable checking and module checking sometimes is a little annoying. By commenting out one line that consumes a variable, you will have to comment out the definition (if there is no other place that use this variable), and comments out the imports
- "go fmt" is nice to have, but don't run it too often as it slows you down
- I still don't know how to create an array using variable as size. From pointer perspective it makes sense. Just use append
- NewList is such a strange syntax. You have no way telling whether you are calling a plain function or creating a object by simply looking at the function name.
- what happened on January 2nd, 2006 at 3pm? why formatting a time requires me to remember this specific date? I rather remember one more person's birthday.
- var variable Int doesn't seemed to be needed in most use case. := is better. Though it increases the amount of documentation look up
- if you return an err object, you are forcing the caller to write some err handling code. Doesn't this lead to error handling everywhere?
*/
package main
import ui "github.com/gizak/termui"
import "github.com/doneland/yquotes"
import "time"
import "reflect"
import "os"
import "fmt"
// from reflect package, two reasons not to use
// 1, unpresented key will croak
// 2. look up is slow comparing to use static name
// to check the interface, checkout documentation at
// https://github.com/doneland/yquotes/blob/master/yquotes.go
func Pluck(prices []yquotes.PriceH, key string) []float64 {
ps := []float64{}
for _, price := range prices {
reflected := reflect.ValueOf(price)
ps = append(ps, reflect.Indirect(reflected).FieldByName(key).Float())
}
return ps
}
func FsToInts(data []float64) []int {
ps := []int{}
for _, v := range data {
ps = append(ps, int(v))
}
return ps
}
func main() {
err := ui.Init()
sticker := os.Args[1]
if sticker == "" {
fmt.Printf("Please add your sticker symbol as the first argument")
os.Exit(1)
}
if err != nil {
panic(err)
}
defer ui.Close()
ui.UseTheme("helloworld")
//from,_ := time.Parse("2006-01-02", "2015-01-01")
//to := time.Now()
//prices, err := yquotes.GetDailyHistory("AAPL", from, to)
prices, err := yquotes.HistoryForYears(sticker, 1, yquotes.Daily)
if err != nil {
panic(err)
}
// reverse, how to use a function?
for i, j := 0, len(prices)-1; i < j; i, j = i+1, j-1 {
prices[i], prices[j] = prices[j], prices[i]
}
stock, err := yquotes.NewStock(sticker, true)
if err != nil {
panic(err)
}
// title and stock symbol
titlePar := ui.NewPar(fmt.Sprintf("Stock Price for %s - 1Y Daily (q to quit)", stock.Name))
titlePar.Height = 1
titlePar.Y = 1
titlePar.HasBorder = false
// price
quoteC := ui.NewLineChart()
quoteC.Border.Label = "Daily Adjusted Close"
quoteC.Data = Pluck(prices, "AdjClose")
quoteC.Height = 11
quoteC.AxesColor = ui.ColorWhite
quoteC.LineColor = ui.ColorYellow
// Price information
lastPrice := stock.Price // Price struct
strs := []string{
fmt.Sprintf("Bid: %.2f", lastPrice.Bid),
fmt.Sprintf("Ask: %.2f", lastPrice.Ask),
fmt.Sprintf("Open: %.2f", lastPrice.Open),
fmt.Sprintf("Last: %.2f", lastPrice.Last),
}
lastInfo := ui.NewList()
lastInfo.Items = strs
lastInfo.ItemFgColor = ui.ColorYellow
lastInfo.Border.Label = "Info"
lastInfo.Height = 11
// volume
/*
spark := ui.NewSparkline()
spark.Height = 8
//spdata := sinpsint
spark.Data = FsToInts(Pluck(prices, "Volume"))
spark.TitleColor = ui.ColorWhite
spark.Title = "Volume"
sparklines := ui.NewSparklines(spark)
sparklines.Height = 8
sparklines.Border.Label = "Volume"
*/
volumeC := ui.NewLineChart()
volumeC.Height = 6
//volumeC.Mode = "dot"
volumeC.Data = Pluck(prices, "Volume")
volumeC.AxesColor = ui.ColorWhite
volumeC.LineColor = ui.ColorWhite
volumeC.Border.Label = "Volume"
par := ui.NewPar("Author is too lazy to leave anything here")
par.Height = 5
par.Border.Label = "Preserved Space"
// build layout
ui.Body.AddRows(
ui.NewRow(
ui.NewCol(10, 2, titlePar),
),
ui.NewRow(
ui.NewCol(10, 0, quoteC),
ui.NewCol(2, 0, lastInfo)),
ui.NewRow(
ui.NewCol(10, 0, volumeC),
ui.NewCol(2, 0, par)),
)
// calculate layout
ui.Body.Align()
draw := func(t int) {
//volumnSpark.Lines[0].Data = spdata[t:]
//quoteC.Data = sinps[2*t:]
ui.Render(ui.Body)
}
evt := ui.EventCh()
i := 0
for {
select {
case e := <-evt:
if e.Type == ui.EventKey && e.Ch == 'q' {
return
}
default:
ui.Body.Width = ui.TermWidth()
ui.Body.Align()
draw(i)
i++
if i == 102 {
return
}
time.Sleep(time.Second / 2)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment