-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds dividends and refactors baseURL
- Loading branch information
1 parent
7d94651
commit a265619
Showing
5 changed files
with
338 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package stock | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"strings" | ||
|
||
e "errors" | ||
|
||
"github.com/covertbert/iex-cli/errors" | ||
"github.com/covertbert/iex-cli/iex" | ||
ui "github.com/gizak/termui" | ||
) | ||
|
||
// Dividends structure | ||
type Dividends []struct { | ||
ExDate string `json:"exDate"` | ||
PaymentDate string `json:"paymentDate"` | ||
RecordDate string `json:"recordDate"` | ||
DeclaredDate string `json:"declaredDate"` | ||
Amount float64 `json:"amount"` | ||
Flag string `json:"flag"` | ||
Type string `json:"type"` | ||
Qualified string `json:"qualified"` | ||
Indicated string `json:"indicated"` | ||
} | ||
|
||
// QueryDividends displays live dividends information | ||
func QueryDividends(symbol string, rng string) { | ||
if noSymbol := len(symbol) < 1; noSymbol { | ||
errors.Error("No argument supplied") | ||
} | ||
|
||
d := &Dividends{} | ||
|
||
path, err := divQueryPath(symbol, rng) | ||
|
||
if err != nil { | ||
errors.Error("Incorrect arguments passed to dividends command", err) | ||
} | ||
|
||
body := iex.Query(path) | ||
|
||
if err := json.Unmarshal(body, &d); err != nil { | ||
errors.Error("Failed to unmarshal", err) | ||
} | ||
|
||
if noData := len(*d) < 1; noData { | ||
errors.Error("Currently no data for the specified range") | ||
} | ||
|
||
if err := ui.Init(); err != nil { | ||
errors.Error("Failed to initialize graph", err) | ||
} | ||
|
||
defer ui.Close() | ||
|
||
h := divChartHeader(symbol, rng) | ||
ld := dividendsData(*d) | ||
p := dividendsInformation() | ||
|
||
ui.Body.AddRows( | ||
ui.NewRow(ui.NewCol(10, 0, h)), | ||
ui.NewRow( | ||
ui.NewCol(10, 0, ld), | ||
), | ||
ui.NewRow(ui.NewCol(10, 0, p)), | ||
) | ||
|
||
ui.Body.Align() | ||
|
||
ui.Render(ui.Body) | ||
|
||
ui.Handle("/sys/kbd/q", func(ui.Event) { | ||
ui.StopLoop() | ||
}) | ||
|
||
ui.Loop() | ||
} | ||
|
||
func divQueryPath(symbol string, rng string) (string, error) { | ||
allowedRanges := []string{"5y", "2y", "1y", "ytd", "6m", "3m", "1m", "1d", ""} | ||
|
||
for _, allowedRng := range allowedRanges { | ||
if rng == allowedRng { | ||
return fmt.Sprintf("/stock/%v/dividends/%v", symbol, rng), nil | ||
} | ||
} | ||
|
||
return "", e.New("Range is not valid. Run iex-cli dividends --range for help") | ||
} | ||
|
||
func divChartHeader(symbol string, rng string) *ui.Par { | ||
if noRangeSpecified := len(rng) == 0; noRangeSpecified { | ||
rng = "default" | ||
} | ||
|
||
headerString := fmt.Sprintf("Range: %v", rng) | ||
|
||
i := ui.NewPar(fmt.Sprintf("%v", headerString)) | ||
i.Height = 3 | ||
i.Width = 100 | ||
i.TextFgColor = ui.ColorWhite | ||
i.BorderLabel = strings.ToUpper(symbol) | ||
i.BorderFg = ui.ColorWhite | ||
|
||
return i | ||
} | ||
|
||
func dividendsInformation() *ui.Par { | ||
i := ui.NewPar(":PRESS q TO QUIT") | ||
i.Height = 3 | ||
i.Width = 100 | ||
i.TextFgColor = ui.ColorWhite | ||
i.BorderLabel = "Keyboard shortcuts" | ||
i.BorderFg = ui.ColorWhite | ||
|
||
return i | ||
} | ||
|
||
func dividendsData(d Dividends) *ui.LineChart { | ||
p := []float64{} | ||
|
||
for _, element := range d { | ||
p = append(p, element.Amount) | ||
p = append(p, element.Amount) | ||
p = append(p, element.Amount) | ||
} | ||
|
||
lc := ui.NewLineChart() | ||
lc.BorderLabel = "Dividends" | ||
lc.BorderFg = ui.ColorWhite | ||
lc.Data = p | ||
lc.DataLabels = divDataLabels(d) | ||
lc.Height = 15 | ||
lc.X = 0 | ||
lc.Y = 0 | ||
lc.AxesColor = ui.ColorWhite | ||
lc.LineColor = ui.ColorYellow | ||
lc.Mode = "dot" | ||
|
||
return lc | ||
} | ||
|
||
func divDataLabels(d Dividends) []string { | ||
p := []string{} | ||
|
||
for _, element := range d { | ||
l := element.ExDate | ||
p = append(p, l) | ||
p = append(p, l) | ||
p = append(p, l) | ||
} | ||
|
||
return p | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
package stock | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/rendon/testcli" | ||
) | ||
|
||
var testDividends = Dividends{ | ||
{ | ||
Amount: 1, | ||
ExDate: "2018-11-05", | ||
}, | ||
{ | ||
Amount: 2, | ||
ExDate: "2018-11-05", | ||
}, | ||
{ | ||
Amount: 3, | ||
ExDate: "2018-11-05", | ||
}, | ||
} | ||
|
||
func Test_divDataLabels(t *testing.T) { | ||
type args struct { | ||
c Dividends | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want []string | ||
}{ | ||
{ | ||
name: "Data labels", | ||
args: args{ | ||
c: testDividends, | ||
}, | ||
want: []string{"2018-11-05", "2018-11-05", "2018-11-05", "2018-11-05", "2018-11-05", "2018-11-05", "2018-11-05", "2018-11-05", "2018-11-05"}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if got := divDataLabels(tt.args.c); !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("divDataLabels() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func Test_divQueryPath(t *testing.T) { | ||
type args struct { | ||
symbol string | ||
rng string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want string | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "chicken", | ||
args: args{ | ||
rng: "chicken", | ||
}, | ||
want: "", | ||
wantErr: true, | ||
}, | ||
{ | ||
name: "5yy", | ||
args: args{ | ||
rng: "5yy", | ||
}, | ||
want: "", | ||
wantErr: true, | ||
}, | ||
{ | ||
name: "5y", | ||
args: args{ | ||
rng: "5y", | ||
}, | ||
want: "/stock//dividends/5y", | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "2y", | ||
args: args{ | ||
rng: "2y", | ||
}, | ||
want: "/stock//dividends/2y", | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "1y", | ||
args: args{ | ||
rng: "1y", | ||
}, | ||
want: "/stock//dividends/1y", | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "ytd", | ||
args: args{ | ||
rng: "ytd", | ||
}, | ||
want: "/stock//dividends/ytd", | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "6m", | ||
args: args{ | ||
rng: "6m", | ||
}, | ||
want: "/stock//dividends/6m", | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "3m", | ||
args: args{ | ||
rng: "3m", | ||
}, | ||
want: "/stock//dividends/3m", | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "1m", | ||
args: args{ | ||
rng: "1m", | ||
}, | ||
want: "/stock//dividends/1m", | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "1d", | ||
args: args{ | ||
rng: "1d", | ||
}, | ||
want: "/stock//dividends/1d", | ||
wantErr: false, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := divQueryPath(tt.args.symbol, tt.args.rng) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("divQueryPath() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if got != tt.want { | ||
t.Errorf("divQueryPath() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestDividendsNoArgs(t *testing.T) { | ||
testcli.Run("../iex-cli", "dividends") | ||
|
||
if !testcli.StdoutContains("Error: No argument supplied") { | ||
t.Fatalf("Expected %q to contain %q", testcli.Stdout(), "Error: No argument supplied") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters