Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds options and futures quotes. #6

Merged
merged 4 commits into from
Jul 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ cache:

env:
global:
- FINANCE_MOCK_VERSION=0.0.4
- FINANCE_MOCK_VERSION=0.0.5

go:
- "1.9"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Status | Description | Source
[x] | ETF quote(s) | Yahoo finance
[x] | Mutual fund quote(s) | Yahoo finance
[x] | Historical quotes | Yahoo finance
[x] | Options straddles | Yahoo finance
[ ] | Options chains | Yahoo finance
[ ] | Symbols list | BATS

Expand Down
98 changes: 58 additions & 40 deletions history/client.go → chart/client.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package history
package chart

import (
"context"

finance "github.com/piquette/finance-go"
"github.com/piquette/finance-go/datetime"
form "github.com/piquette/finance-go/form"
"github.com/piquette/finance-go/iter"
"github.com/shopspring/decimal"
)

// Client is used to invoke quote APIs.
// Client is used to invoke chart APIs.
type Client struct {
B finance.Backend
}
Expand All @@ -23,87 +25,85 @@ type Params struct {
finance.Params `form:"-"`

// Accessible fields.
Symbol string `form:"-"`
Start *Datetime `form:"-"`
End *Datetime `form:"-"`
Interval Interval `form:"-"`
Symbol string `form:"-"`
Start *datetime.Datetime `form:"-"`
End *datetime.Datetime `form:"-"`
Interval datetime.Interval `form:"-"`

IncludeExt bool `form:"includePrePost"`

// Internal request fields.
interval string `form:"interval"`
start int `form:"period1"`
end int `form:"period2"`
region string `form:"region"`
domain string `form:"corsDomain"`
}

// Chart is a structure containing results
// Iter is a structure containing results
// and related metadata for a
// yfin chart request.
type Chart struct {
*finance.Iter
type Iter struct {
*iter.Iter
}

// Bar returns the next Bar
// visited by a call to Next.
func (ch *Chart) Bar() *finance.ChartBar {
return ch.Current().(*finance.ChartBar)
func (i *Iter) Bar() *finance.ChartBar {
return i.Current().(*finance.ChartBar)
}

// Meta returns the chart metadata
// related to a chart response.
func (ch *Chart) Meta() *finance.ChartMeta {
return ch.Meta()
func (i *Iter) Meta() *finance.ChartMeta {
return i.Iter.Meta().(*finance.ChartMeta)
}

// Get returns a historical chart.
// and requires a params
// struct as an argument.
func Get(params *Params) *Chart {
func Get(params *Params) *Iter {
return getC().Get(params)
}

// Get returns a historical chart.
func (c Client) Get(params *Params) *Chart {

if params.Context == nil {
ctx := context.TODO()
params.Context = &ctx
}
func (c Client) Get(params *Params) *Iter {

// Construct request from params input.
// TODO: validate symbol..
if params == nil || len(params.Symbol) == 0 {
return &Chart{finance.GetErrIter(finance.CreateArgumentError())}
return &Iter{iter.NewE(finance.CreateArgumentError())}
}

// Start and End times.
if params.Context == nil {
ctx := context.TODO()
params.Context = &ctx
}

// Start and End times
params.start = -1
params.end = -1
if params.Start != nil {
params.start = params.Start.ToUnix()
params.start = params.Start.Unix()
}
if params.End != nil {
params.end = params.End.ToUnix()
params.end = params.End.Unix()
}
if params.start > params.end {
return &Chart{finance.GetErrIter(finance.CreateChartTimeError())}
return &Iter{iter.NewE(finance.CreateChartTimeError())}
}

// Parse interval.
if params.Interval != "" {
params.interval = string(params.Interval)
}

// Set meta data.
params.domain = "com.finance.yahoo"
params.region = "US"

// Build request.
body := &form.Values{}
form.AppendTo(body, params)
// Set request meta data.
body.Set("region", "US")
body.Set("corsDomain", "com.finance.yahoo")

return &Chart{finance.GetChartIter(body, func(b *form.Values) (m interface{}, bars []interface{}, err error) {
return &Iter{iter.New(body, func(b *form.Values) (m interface{}, bars []interface{}, err error) {

resp := response{}
err = c.B.Call("v8/finance/chart/"+params.Symbol, body, params.Context, &resp)
Expand All @@ -116,22 +116,22 @@ func (c Client) Get(params *Params) *Chart {
return
}

chartResp := resp.Inner.Result[0]
if chartResp == nil || chartResp.Indicators == nil {
result := resp.Inner.Results[0]
if result == nil || result.Indicators == nil {
err = finance.CreateRemoteErrorS("no results in chart response")
return
}

barQuotes := chartResp.Indicators.Quote
barQuotes := result.Indicators.Quote
if barQuotes == nil || barQuotes[0] == nil {
err = finance.CreateRemoteErrorS("no results in chart response")
return
}
adjCloses := chartResp.Indicators.Adjclose
adjCloses := result.Indicators.Adjclose

// Process chart response
// and chart meta data.
for i, t := range chartResp.Timestamp {
for i, t := range result.Timestamp {

b := &finance.ChartBar{
Timestamp: t,
Expand All @@ -149,14 +149,32 @@ func (c Client) Get(params *Params) *Chart {
bars = append(bars, b)
}

return chartResp.Meta, bars, nil
return result.Meta, bars, nil
})}
}

// response is a yfin chart response.
type response struct {
Inner struct {
Result []*finance.ChartResponse `json:"result"`
Error *finance.YfinError `json:"error"`
Results []*result `json:"result"`
Error *finance.YfinError `json:"error"`
} `json:"chart"`
}

// result is an umbrella object for chart results.
type result struct {
Meta finance.ChartMeta `json:"meta"`
Timestamp []int `json:"timestamp"`
Indicators *struct {
Quote []*struct {
Open []float64 `json:"open"`
Low []float64 `json:"low"`
High []float64 `json:"high"`
Close []float64 `json:"close"`
Volume []int `json:"volume"`
} `json:"quote"`
Adjclose []*struct {
Adjclose []float64 `json:"adjclose"`
} `json:"adjclose"`
} `json:"indicators"`
}
18 changes: 9 additions & 9 deletions history/client_test.go → chart/client_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package history
package chart

import (
"testing"
Expand All @@ -9,26 +9,26 @@ import (

func TestGetEquityChart(t *testing.T) {
p := &Params{Symbol: tests.TestEquitySymbol}
chart := Get(p)
assert.True(t, chart.Next())
iter := Get(p)
assert.True(t, iter.Next())
}

func TestGetETFChart(t *testing.T) {
p := &Params{Symbol: tests.TestETFSymbol}
chart := Get(p)
assert.True(t, chart.Next())
iter := Get(p)
assert.True(t, iter.Next())
}

func TestGetFutureChart(t *testing.T) {
p := &Params{Symbol: tests.TestFutureSymbol}
chart := Get(p)
assert.True(t, chart.Next())
iter := Get(p)
assert.True(t, iter.Next())
}

func TestGetIndexChart(t *testing.T) {
p := &Params{Symbol: tests.TestIndexSymbol}
chart := Get(p)
assert.True(t, chart.Next())
iter := Get(p)
assert.True(t, iter.Next())
}

func TestGetOptionChart(t *testing.T) {
Expand Down
9 changes: 5 additions & 4 deletions crypto/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

finance "github.com/piquette/finance-go"
form "github.com/piquette/finance-go/form"
"github.com/piquette/finance-go/iter"
)

// Client is used to invoke quote APIs.
Expand All @@ -30,7 +31,7 @@ type Params struct {
// The embedded Iter carries methods with it;
// see its documentation for details.
type Iter struct {
*finance.Iter
*iter.Iter
}

// CryptoPair returns the most recent CryptoPair
Expand Down Expand Up @@ -72,14 +73,14 @@ func (c Client) ListP(params *Params) *Iter {
// Validate input.
// TODO: validate symbols..
if params == nil || len(params.Symbols) == 0 {
return &Iter{finance.GetErrIter(finance.CreateArgumentError())}
return &Iter{iter.NewE(finance.CreateArgumentError())}
}
params.sym = strings.Join(params.Symbols, ",")

body := &form.Values{}
form.AppendTo(body, params)

return &Iter{finance.GetIter(body, func(b *form.Values) ([]interface{}, error) {
return &Iter{iter.New(body, func(b *form.Values) (interface{}, []interface{}, error) {

resp := response{}
err := c.B.Call("/v7/finance/quote", body, params.Context, &resp)
Expand All @@ -95,7 +96,7 @@ func (c Client) ListP(params *Params) *Iter {
err = finance.CreateRemoteError(resp.Inner.Error)
}

return ret, err
return nil, ret, err
})}
}

Expand Down
30 changes: 14 additions & 16 deletions history/time.go → datetime/datetime.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package history
package datetime

import (
"time"
Expand Down Expand Up @@ -58,18 +58,24 @@ type Datetime struct {
t *time.Time
}

// NewDatetime creates a new instance of Datetime.
func NewDatetime(t time.Time) *Datetime {
// New creates a new instance of Datetime from a go time struct.
func New(t *time.Time) *Datetime {
year, month, day := t.Date()
return &Datetime{
Month: int(month),
Day: day,
Year: year,
t: &t,
t: t,
}
}

// Time returns a time object from a datetime.
// FromUnix returns a new instance of Datetime from a unix timestamp.
func FromUnix(timestamp int) *Datetime {
t := time.Unix(int64(timestamp), 0)
return New(&t)
}

// Time returns a go time struct from a datetime.
func (d *Datetime) Time() *time.Time {
if d.t != nil {
return d.t
Expand All @@ -78,22 +84,14 @@ func (d *Datetime) Time() *time.Time {
return d.Time()
}

// ToUnix converts a Datetime struct to
// a valid unix timestamp.
func (d *Datetime) ToUnix() int {
// Unix returns a valid unix timestamp from Datetime fields.
func (d *Datetime) Unix() int {
if d.t != nil {
return int(d.t.Unix())
}

d.calculateTime()
return d.ToUnix()
}

// NewDatetimeU converts a valid unix timestamp
// to a datetime object.
func NewDatetimeU(timestamp int) *Datetime {
t := time.Unix(int64(timestamp), 0)
return NewDatetime(t)
return d.Unix()
}

func (d *Datetime) calculateTime() {
Expand Down
Loading