-
-
Notifications
You must be signed in to change notification settings - Fork 75
/
priceHistory.go
113 lines (98 loc) · 3.02 KB
/
priceHistory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package tdameritrade
import (
"context"
"fmt"
"time"
"github.com/google/go-querystring/query"
)
var (
validPeriodTypes = []string{"day", "month", "year", "ytd"}
validFrequencyTypes = []string{"minute", "daily", "weekly", "monthly"}
)
const (
defaultPeriodType = "day"
defaultFrequencyType = "minute"
)
// PriceHistoryService handles communication with the marketdata related methods of
// the TDAmeritrade API.
//
// TDAmeritrade API docs: https://developer.tdameritrade.com/price-history/apis
type PriceHistoryService struct {
client *Client
}
// PriceHistoryOptions is parsed and translated to query options in the https request
type PriceHistoryOptions struct {
PeriodType string `url:"periodType"`
Period int `url:"period"`
FrequencyType string `url:"frequencyType"`
Frequency int `url:"frequency"`
EndDate time.Time `url:"endDate,omitempty"`
StartDate time.Time `url:"startDate,omitempty"`
NeedExtendedHoursData *bool `url:"needExtendedHoursData"`
}
type PriceHistory struct {
Candles []Candle `json:"candles"`
Empty bool `json:"empty"`
Symbol string `json:"symbol"`
}
type Candle struct {
Close float64 `json:"close"`
Datetime int `json:"datetime"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Volume float64 `json:"volume"`
}
// PriceHistory get the price history for a symbol
// TDAmeritrade API Docs: https://developer.tdameritrade.com/price-history/apis/get/marketdata/%7Bsymbol%7D/pricehistory
func (s *PriceHistoryService) PriceHistory(ctx context.Context, symbol string, opts *PriceHistoryOptions) (*PriceHistory, *Response, error) {
u := fmt.Sprintf("marketdata/%s/pricehistory", symbol)
if opts != nil {
if err := opts.validate(); err != nil {
return nil, nil, err
}
q, err := query.Values(opts)
if err != nil {
return nil, nil, err
}
u = fmt.Sprintf("%s?%s", u, q.Encode())
}
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
priceHistory := new(PriceHistory)
resp, err := s.client.Do(ctx, req, priceHistory)
if err != nil {
return nil, resp, err
}
if priceHistory.Empty {
return priceHistory, resp, fmt.Errorf("no data, check time period and/or ticker %s", symbol)
}
return priceHistory, resp, nil
}
func (opts *PriceHistoryOptions) validate() error {
if opts.PeriodType != "" {
if !contains(opts.PeriodType, validPeriodTypes) {
return fmt.Errorf("invalid periodType, must have the value of one of the following %v", validPeriodTypes)
}
} else {
opts.PeriodType = defaultPeriodType
}
if opts.FrequencyType != "" {
if !contains(opts.FrequencyType, validFrequencyTypes) {
return fmt.Errorf("invalid frequencyType, must have the value of one of the following %v", validFrequencyTypes)
}
} else {
opts.PeriodType = defaultFrequencyType
}
return nil
}
func contains(s string, lst []string) bool {
for _, e := range lst {
if e == s {
return true
}
}
return false
}