Skip to content

Commit

Permalink
Report FII dividends + quote on terminal
Browse files Browse the repository at this point in the history
  • Loading branch information
dude333 committed Apr 27, 2021
1 parent 238a038 commit 948f639
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 94 deletions.
6 changes: 2 additions & 4 deletions cmd/rapina/fii_dividends.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
"os"
"strings"

"github.com/dude333/rapina/parsers"
"github.com/dude333/rapina/reports"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// fiiDividendsCmd represents the rendimentos command
Expand Down Expand Up @@ -59,10 +59,8 @@ func FIIDividends(code string, n int) error {
if err != nil {
return err
}
stockStore, _ := parsers.NewStockStore(db)
fiiParser := parsers.NewFIIStore(db)

r, err := reports.NewFIITerminalReport(db, stockStore, fiiParser)
r, err := reports.NewFIITerminalReport(db, viper.GetString("apikey"))
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion data_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type FIIDetails struct {
} `json:"shareHolder"`
}

type Quotation struct {
type Quote struct {
Code string
Date string
Val float64
Expand Down
1 change: 1 addition & 0 deletions fetch/fetch_fii.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func (fii FII) dividendsFromServer(code string, n int) (*[]rapina.Dividend, erro
log.Println("[x]", err)
continue
}
// fmt.Println("[d] from server", d.Code, d.Date, d.Val)
if d.Code == code {
dividends = append(dividends, *d)
}
Expand Down
36 changes: 27 additions & 9 deletions fetch/fetch_stockquote.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const apiServer = "https://www.alphavantage.co/"
type StockFetch struct {
apiKey string
store rapina.StockStore
cache map[string]bool
}

//
Expand All @@ -31,26 +32,43 @@ func NewStockFetch(store rapina.StockStore, apiKey string) (*StockFetch, error)
s := StockFetch{
apiKey: apiKey,
store: store,
cache: make(map[string]bool),
}
return &s, nil
}

// Quote returns the quote for 'code' on 'date'.
// Date format: YYYY-MM-DD.
func (s StockFetch) Quote(code, date string) (rapina.Quotation, error) {
func (s StockFetch) Quote(code, date string) (float64, error) {
if !rapina.IsDate(date) {
return rapina.Quotation{}, rapina.ErrInvalidDate
return 0, rapina.ErrInvalidDate
}

return s.store.Quote(code, date)
val, err := s.stockQuoteFromDB(code, date)
if err == nil {
return val, nil
}

fmt.Println("[d] FROM SERVER")
err = s.stockQuoteFromServer(code)
if err != nil {
return 0, err
}

return s.stockQuoteFromDB(code, date)
}

//
// FetchStockQuote fetches the daily time series (date, daily open, daily high,
// stockQuoteFromServer fetches the daily time series (date, daily open, daily high,
// daily low, daily close, daily volume) of the global equity specified,
// covering 20+ years of historical data.
//
func (s StockFetch) FetchStockQuote(code string) error {
func (s StockFetch) stockQuoteFromServer(code string) error {
if _, ok := s.cache[code]; ok {
return fmt.Errorf("cotação histórica para '%s' já foi feita", code)
}
s.cache[code] = true

tr := &http.Transport{
DisableCompression: true,
IdleConnTimeout: 30 * time.Second,
Expand All @@ -62,12 +80,12 @@ func (s StockFetch) FetchStockQuote(code string) error {
v.Set("function", "TIME_SERIES_DAILY")
v.Add("symbol", code+".SA")
v.Add("apikey", s.apiKey)
v.Add("outputsize", "compact")
v.Add("outputsize", "full")
v.Add("datatype", "csv")

u := rapina.JoinURL(apiServer, "query?"+v.Encode())

fmt.Print("[ ] Baixando cotações...")
fmt.Print("[ ] Baixando cotações...", u)

resp, err := client.Get(u)
if err != nil {
Expand All @@ -92,6 +110,6 @@ func (s StockFetch) FetchStockQuote(code string) error {
return err
}

func (s StockFetch) QuoteFromDB(code, date string) (float64, error) {
return 9.99, nil
func (s StockFetch) stockQuoteFromDB(code, date string) (float64, error) {
return s.store.Quote(code, date)
}
22 changes: 5 additions & 17 deletions fetch/fetch_stockquote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,9 @@ func (m MockStockFetch) CsvToDB(stream io.ReadCloser, code string) error {
return nil
}

func (m MockStockFetch) Quote(code, date string) (rapina.Quotation, error) {
func (m MockStockFetch) Quote(code, date string) (float64, error) {
// fmt.Printf("calling mock Quote(%s, %s)\n", code, date)
return rapina.Quotation{
Code: code,
Date: date,
Val: 123.45,
}, nil
return 123.45, nil
}

func TestStockFetch_Quote(t *testing.T) {
Expand All @@ -38,7 +34,7 @@ func TestStockFetch_Quote(t *testing.T) {
name string
fields fields
args args
want rapina.Quotation
want float64
wantErr bool
}{
{
Expand All @@ -51,11 +47,7 @@ func TestStockFetch_Quote(t *testing.T) {
code: "TEST11",
date: "2021-04-26",
},
want: rapina.Quotation{
Code: "TEST11",
Date: "2021-04-26",
Val: 123.45,
},
want: 123.45,
wantErr: false,
},
{
Expand All @@ -68,11 +60,7 @@ func TestStockFetch_Quote(t *testing.T) {
code: "TEST11",
date: "2021-04-32",
},
want: rapina.Quotation{
Code: "TEST11",
Date: "2021-04-26",
Val: 123.45,
},
want: 123.45,
wantErr: true,
},
}
Expand Down
2 changes: 1 addition & 1 deletion interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ type FIIParser interface {

type StockStore interface {
CsvToDB(stream io.ReadCloser, code string) error
Quote(code, date string) (Quotation, error)
Quote(code, date string) (float64, error)
}
2 changes: 1 addition & 1 deletion parsers/fiidb.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (fii FIIStore) Dividends(code, monthYear string) (*[]rapina.Dividend, error
return nil, err
}

// fmt.Println("[d reading]", tradingCode, baseDate, value)
fmt.Println("[d reading]", tradingCode, baseDate, value)

dividends = append(dividends, rapina.Dividend{
Code: tradingCode,
Expand Down
22 changes: 15 additions & 7 deletions parsers/stockquote.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"strconv"
"strings"

"github.com/dude333/rapina"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -54,6 +53,9 @@ func (s StockStore) CsvToDB(stream io.ReadCloser, code string) error {
for scanner.Scan() {
line := scanner.Text()
fields := strings.Split(line, ",")
if len(fields) != 6 {
continue
}

var err error
var floats [5]float64
Expand Down Expand Up @@ -137,10 +139,16 @@ func (s StockStore) close() error {
return err
}

func (s StockStore) Quote(code, date string) (rapina.Quotation, error) {
return rapina.Quotation{
Code: code,
Date: date,
Val: 123.45,
}, nil
//
// Quote returns the quote from DB.
//
func (s StockStore) Quote(code, date string) (float64, error) {
query := `SELECT close FROM stock_quotes WHERE stock=$1 AND date=$2;`
var close float64
err := s.db.QueryRow(query, code, date).Scan(&close)
if err != nil {
return 0, errors.Wrap(err, "lendo cotação do bd")
}

return close, nil
}
2 changes: 1 addition & 1 deletion parsers/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func createIndexes(db *sql.DB, table string) error {
}
case "stock_quotes":
indexes = []string{
"CREATE INDEX IF NOT EXISTS stock_quotes_stockdate ON stock_quotes (stock, date);",
"CREATE UNIQUE INDEX IF NOT EXISTS stock_quotes_stockdate ON stock_quotes (stock, date);",
}
case "fii_dividends":
indexes = []string{
Expand Down
53 changes: 0 additions & 53 deletions reports/fii.go

This file was deleted.

64 changes: 64 additions & 0 deletions reports/reports_fii.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package reports

import (
"database/sql"
"fmt"
"strings"

"github.com/pkg/errors"

"github.com/dude333/rapina/fetch"
"github.com/dude333/rapina/parsers"
)

type FIITerminalReport struct {
fetchFII *fetch.FII
fetchStock *fetch.StockFetch
}

func NewFIITerminalReport(db *sql.DB, apiKey string) (*FIITerminalReport, error) {
store, err := parsers.NewStockStore(db)
if err != nil {
return nil, err
}
parser := parsers.NewFIIStore(db)
if parser == nil {
return nil, errors.New("invalid parser")
}
fetchStock, err := fetch.NewStockFetch(store, apiKey)
if err != nil {
return nil, errors.Wrap(err, "new StockFetch instance")
}
fetchFII := fetch.NewFII(parser)
if fetchFII == nil {
return nil, errors.New("invalid FII fetcher")
}

return &FIITerminalReport{
fetchFII: fetchFII,
fetchStock: fetchStock,
}, nil
}

func (t FIITerminalReport) Dividends(code string, n int) error {

dividends, err := t.fetchFII.Dividends(code, n)
if err != nil {
return err
}

line := strings.Repeat("-", 55)
fmt.Println(line)
fmt.Println(code)
fmt.Println(line)
fmt.Println(" DATA RENDIMENTO COTAÇÃO YELD ")
fmt.Println(" ---------- ---------- ---------- ------")

for _, d := range *dividends {
q, _ := t.fetchStock.Quote(code, d.Date)
fmt.Printf(" %s %14.6f %14.6f %8.2f%%\n", d.Date, d.Val, q, 100*d.Val/q)
}

fmt.Println(line)
return nil
}

0 comments on commit 948f639

Please sign in to comment.