Skip to content

Commit 7508311

Browse files
committed
date period implemented
1 parent 63529c3 commit 7508311

File tree

5 files changed

+168
-79
lines changed

5 files changed

+168
-79
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,18 @@ This project aims to provide some useful tools to fetch stock data for BIST via
1313
func main() {
1414
bist := gobist.New()
1515

16-
dt, _ := time.Parse(time.DateOnly, "2024-09-25")
17-
q, err := bist.GetQuoteWithHistory([]string{"TUPRS", "BIMAS", "VESBE", "THYAO"}, dt)
16+
tBegin, _ := time.Parse(time.DateOnly, "2023-09-25")
17+
tEnd, _ := time.Parse(time.DateOnly, "2024-10-25")
18+
19+
q, err := bist.GetQuoteWithHistory([]string{"TUPRS", "BIMAS", "VESBE", "THYAO"}, tBegin, tEnd)
1820
if err != nil {
1921
log.Fatal(err)
2022
}
2123

24+
fmt.Println(fmt.Sprintf("%-10s %-30s %-20s %-20s %-20s %-15s %-30s", "Symbol", "Name", "Current Price", "History Begin", "History End", "Change", "Error"))
2225
for _, item := range q.Items {
23-
fmt.Println(fmt.Sprintf("symbol=%s name=%s price=%f, history_price=%f, change=%f", item.Symbol, item.Name, item.Price, item.History.Price, item.History.Change.ByRatio))
26+
fmt.Println(fmt.Sprintf("%-10s %-30s %-20f %-20f %-20f %-15f %-30s",
27+
item.Symbol, item.Name, item.Price, item.History.Begin.Price, item.History.End.Price, item.History.Change.ByRatio, item.Error))
2428
}
2529
}
2630
```

api.go

Lines changed: 111 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -65,76 +65,135 @@ func (a *api) getSymbolList() (*SymbolList, error) {
6565
return res.fromDTO(&resp), nil
6666
}
6767

68-
func (a *api) getQuote(symbols []string, date *time.Time) (*QuoteList, error) {
69-
data := quote{}
68+
type TPeriod [2]string
7069

71-
var (
72-
dtAdjusted time.Time
73-
dt string
74-
)
70+
func (p *TPeriod) SetBegin(s string) {
71+
p[0] = s
72+
}
7573

76-
if date != nil {
77-
dtAdjusted, _ = time.Parse(time.DateOnly, date.Format("2006-01-02"))
78-
dtAdjusted = dtAdjusted.Add(time.Hour * 20)
74+
func (p *TPeriod) SetEnd(s string) {
75+
p[1] = s
76+
}
7977

80-
dt = strconv.Itoa(int(dtAdjusted.Unix()))
81-
}
78+
func (p *TPeriod) Begin() string {
79+
return p[0]
80+
}
8281

83-
rq := a.c.yahoo.R().
84-
SetRetryCount(1).
85-
SetRetryFixedInterval(1 * time.Second).
86-
AddRetryHook(func(resp *req.Response, err error) {
87-
setYahooCrumb()
88-
}).
89-
AddRetryCondition(func(resp *req.Response, err error) bool {
90-
return resp.StatusCode == http.StatusUnauthorized
91-
}).
92-
SetSuccessResult(&data)
82+
func (p *TPeriod) End() string {
83+
return p[1]
84+
}
85+
86+
func (p *TPeriod) IsSingleDay() bool {
87+
return p.Begin() == p.End()
88+
}
89+
90+
func (a *api) getQuote(symbols []string, dates ...time.Time) (*QuoteList, error) {
91+
var period TPeriod
92+
93+
dtToday := adjustDate(time.Now())
94+
95+
switch len(dates) {
96+
case 0:
97+
period.SetBegin(dtToday)
98+
period.SetEnd(dtToday)
99+
case 1:
100+
period.SetBegin(adjustDate(dates[0]))
101+
period.SetEnd(dtToday)
102+
default:
103+
period.SetBegin(adjustDate(dates[0]))
104+
period.SetEnd(adjustDate(dates[1]))
105+
}
93106

94107
quoteList := &QuoteList{
95108
Count: len(symbols),
96109
Items: make([]Quote, len(symbols)),
97110
}
111+
98112
for i, symbol := range symbols {
99-
url := fmt.Sprintf(yahooChartPath, symbol, dt, dt)
100-
r, err := rq.Get(url)
101-
if err != nil {
102-
return nil, err
103-
}
113+
q := &quoteList.Items[i]
114+
q.Symbol = symbol
104115

105-
if r.IsErrorState() {
106-
return nil, err
116+
data, err := a.fetchYahooChart(symbol, period.Begin())
117+
if err != nil {
118+
q.SetError(err.Error())
119+
continue
107120
}
108121

109122
if len(data.Chart.Result) == 0 {
110-
return nil, ErrNoDataFound
123+
q.SetError("no data found")
124+
continue
111125
}
112126

113-
q := data.Chart.Result[0]
127+
q.Name = data.Chart.Result[0].Meta.ShortName
128+
q.Price = data.Chart.Result[0].Meta.RegularMarketPrice
114129

115-
h := &History{}
116-
if date != nil {
117-
if len(q.Indicators.Adjclose[0].Adjclose) > 0 {
118-
h.Date = &dtAdjusted
119-
h.Price = q.Indicators.Adjclose[0].Adjclose[0]
120-
h.Change = &Change{
121-
ByRatio: (q.Meta.RegularMarketPrice - h.Price) * (100 / q.Meta.RegularMarketPrice),
122-
ByAmount: q.Meta.RegularMarketPrice - h.Price,
123-
}
130+
if !period.IsSingleDay() {
131+
h := History{}
132+
133+
if len(data.Chart.Result[0].Indicators.Adjclose) == 0 {
134+
q.SetError("close price not found")
135+
continue
124136
}
125-
}
126137

127-
quoteList.Items[i] = Quote{
128-
Symbol: symbol,
129-
Name: q.Meta.ShortName,
130-
Price: q.Meta.RegularMarketPrice,
131-
History: h,
138+
h.SetBegin(period.Begin(), data.Chart.Result[0].Indicators.Adjclose[0].Adjclose[0])
139+
140+
data, err = a.fetchYahooChart(symbol, period.End())
141+
if err != nil {
142+
q.SetError(err.Error())
143+
continue
144+
}
145+
146+
if len(data.Chart.Result[0].Indicators.Adjclose[0].Adjclose) == 0 {
147+
q.SetError("close price not found")
148+
continue
149+
}
150+
h.SetEnd(period.Begin(), data.Chart.Result[0].Indicators.Adjclose[0].Adjclose[0])
151+
152+
if h.IsValid() {
153+
h.Change = HistoryChange{
154+
ByRatio: (h.End.Price - h.Begin.Price) * (100 / h.End.Price),
155+
ByAmount: h.End.Price - h.Begin.Price,
156+
}
157+
158+
q.History = h
159+
}
132160
}
133161
}
134162

135163
return quoteList, nil
136164
}
137165

166+
func (a *api) fetchYahooChart(symbol, dt string) (*quote, error) {
167+
data := &quote{}
168+
169+
rq := a.c.yahoo.R().
170+
SetRetryCount(1).
171+
SetRetryFixedInterval(1 * time.Second).
172+
AddRetryHook(func(resp *req.Response, err error) {
173+
setYahooCrumb()
174+
}).
175+
AddRetryCondition(func(resp *req.Response, err error) bool {
176+
return resp.StatusCode == http.StatusUnauthorized
177+
}).
178+
SetSuccessResult(&data)
179+
180+
url := fmt.Sprintf(yahooChartPath, symbol, dt, dt)
181+
r, err := rq.Get(url)
182+
if err != nil {
183+
return nil, err
184+
}
185+
186+
if r.IsErrorState() {
187+
return nil, errors.New(r.Status)
188+
}
189+
190+
if len(data.Chart.Result) == 0 {
191+
return nil, ErrNoDataFound
192+
}
193+
194+
return data, nil
195+
}
196+
138197
func setYahooCrumb() string {
139198
res, err := req.C().R().Get(yahooCrumbPath)
140199
if err != nil {
@@ -146,3 +205,10 @@ func setYahooCrumb() string {
146205
fmt.Printf("crumb has been set: %v\n", crumb)
147206
return crumb
148207
}
208+
209+
func adjustDate(d time.Time) string {
210+
dta, _ := time.Parse(time.DateOnly, d.Format("2006-01-02"))
211+
dta = dta.Add(time.Hour * 20)
212+
213+
return strconv.Itoa(int(dta.Unix()))
214+
}

examples/quote.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@ import (
1111
func main() {
1212
bist := gobist.New()
1313

14-
t, _ := time.Parse(time.DateOnly, "2024-09-25")
15-
q, err := bist.GetQuoteWithHistory([]string{"TUPRS", "BIMAS", "VESBE", "THYAO"}, t)
14+
tBegin, _ := time.Parse(time.DateOnly, "2023-09-25")
15+
tEnd, _ := time.Parse(time.DateOnly, "2024-10-25")
16+
17+
q, err := bist.GetQuoteWithHistory([]string{"TUPRS", "BIMAS", "VESBE", "THYAO", "BINBN"}, tBegin, tEnd)
1618
if err != nil {
1719
log.Fatal(err)
1820
}
1921

22+
fmt.Println(fmt.Sprintf("%-10s %-30s %-20s %-20s %-20s %-15s %-30s", "Symbol", "Name", "Current Price", "History Begin", "History End", "Change", "Error"))
2023
for _, item := range q.Items {
21-
fmt.Println(fmt.Sprintf("symbol=%s name=%s price=%f, history_price=%f, change=%f", item.Symbol, item.Name, item.Price, item.History.Price, item.History.Change.ByRatio))
24+
fmt.Println(fmt.Sprintf("%-10s %-30s %-20f %-20f %-20f %-15f %-30s",
25+
item.Symbol, item.Name, item.Price, item.History.Begin.Price, item.History.End.Price, item.History.Change.ByRatio, item.Error))
2226
}
2327
}

gobist.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,9 @@ func (b *Bist) GetSymbolList() (*SymbolList, error) {
2424
}
2525

2626
func (b *Bist) GetQuote(symbols []string) (*QuoteList, error) {
27-
return b.api.getQuote(symbols, nil)
27+
return b.api.getQuote(symbols)
2828
}
2929

30-
func (b *Bist) GetQuoteWithHistory(symbols []string, date ...time.Time) (*QuoteList, error) {
31-
var dt *time.Time
32-
33-
if len(date) > 0 {
34-
dt = &date[0]
35-
}
36-
37-
return b.api.getQuote(symbols, dt)
30+
func (b *Bist) GetQuoteWithHistory(symbols []string, period ...time.Time) (*QuoteList, error) {
31+
return b.api.getQuote(symbols, period...)
3832
}

type.go

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,49 @@ package gobist
33
import (
44
"encoding/json"
55
"fmt"
6-
"time"
76
)
87

98
type Quote struct {
10-
Symbol string `json:"symbol"`
11-
Name string `json:"name"`
12-
Price float64 `json:"price"`
13-
History *History `json:"history,omitempty"`
9+
Symbol string `json:"symbol"`
10+
Name string `json:"name"`
11+
Price float64 `json:"price"`
12+
History History `json:"history,omitempty"`
13+
Error string `json:"error,omitempty"`
14+
}
15+
16+
func (q *Quote) ToJson() string {
17+
d, _ := json.MarshalIndent(q, "", " ")
18+
return string(d)
19+
}
20+
21+
func (q *Quote) SetError(err string) {
22+
q.Error = err
1423
}
1524

1625
type History struct {
17-
Date *time.Time `json:"date,omitempty"`
18-
Price float64 `json:"price,omitempty"`
19-
Change *Change `json:"change,omitempty"`
26+
Begin HistoryData `json:"begin,omitempty"`
27+
End HistoryData `json:"end,omitempty"`
28+
Change HistoryChange `json:"change,omitempty"`
29+
}
30+
31+
func (h *History) SetBegin(d string, price float64) {
32+
h.Begin = HistoryData{d, price}
33+
}
34+
35+
func (h *History) SetEnd(d string, price float64) {
36+
h.End = HistoryData{d, price}
37+
}
38+
39+
func (h *History) IsValid() bool {
40+
return h.Begin.Date != "" && h.End.Date != ""
41+
}
42+
43+
type HistoryData struct {
44+
Date string `json:"date,omitempty"`
45+
Price float64 `json:"price,omitempty"`
2046
}
2147

22-
type Change struct {
48+
type HistoryChange struct {
2349
ByRatio float64 `json:"byRatio"`
2450
ByAmount float64 `json:"byAmount"`
2551
}
@@ -36,16 +62,6 @@ type SymbolList struct {
3662
Items []Symbol `json:"items"`
3763
}
3864

39-
type QuoteList struct {
40-
Count int `json:"count"`
41-
Items []Quote `json:"items"`
42-
}
43-
44-
func (q Quote) ToJson() string {
45-
d, _ := json.MarshalIndent(q, "", " ")
46-
return string(d)
47-
}
48-
4965
func (s *SymbolList) fromDTO(d *symbolListResponse) *SymbolList {
5066
if d == nil {
5167
return s
@@ -61,6 +77,11 @@ func (s *SymbolList) fromDTO(d *symbolListResponse) *SymbolList {
6177
return s
6278
}
6379

80+
type QuoteList struct {
81+
Count int `json:"count"`
82+
Items []Quote `json:"items"`
83+
}
84+
6485
func (ql QuoteList) ToJson() string {
6586
d, _ := json.MarshalIndent(ql, "", " ")
6687
return string(d)

0 commit comments

Comments
 (0)