-
Notifications
You must be signed in to change notification settings - Fork 1
/
mover.go
152 lines (128 loc) · 3.95 KB
/
mover.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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package main
import (
"fmt"
"sort"
"time"
"github.com/rs/zerolog"
)
type Mover struct {
MoverId uint64 `db:"mover_id"`
EId string
SourceId uint64 `db:"source_id"`
TickerId uint64 `db:"ticker_id"`
MoverDate time.Time `db:"mover_date"`
MoverType string `db:"mover_type"`
LastPrice float64 `db:"last_price"`
PriceChange float32 `db:"price_change"`
PriceChangePct float32 `db:"price_change_pct"`
Volume int64 `db:"volume"`
VolumeStr string
CreateDatetime time.Time `db:"create_datetime"`
UpdateDatetime time.Time `db:"update_datetime"`
}
type WebMover struct {
Mover Mover
Ticker Ticker
}
type Movers struct {
Gainers []WebMover
Losers []WebMover
Actives []WebMover
ForDate time.Time
}
// object methods -------------------------------------------------------------
type ByGainers Movers
func (a ByGainers) Len() int { return len(a.Gainers) }
func (a ByGainers) Less(i, j int) bool {
return a.Gainers[i].Mover.PriceChangePct < a.Gainers[j].Mover.PriceChangePct
}
func (a ByGainers) Swap(i, j int) { a.Gainers[i], a.Gainers[j] = a.Gainers[j], a.Gainers[i] }
type ByLosers Movers
func (a ByLosers) Len() int { return len(a.Losers) }
func (a ByLosers) Less(i, j int) bool {
return a.Losers[i].Mover.PriceChangePct < a.Losers[j].Mover.PriceChangePct
}
func (a ByLosers) Swap(i, j int) { a.Losers[i], a.Losers[j] = a.Losers[j], a.Losers[i] }
type ByActives Movers
func (a ByActives) Len() int { return len(a.Actives) }
func (a ByActives) Less(i, j int) bool {
return a.Actives[i].Mover.Volume < a.Actives[j].Mover.Volume
}
func (a ByActives) Swap(i, j int) { a.Actives[i], a.Actives[j] = a.Actives[j], a.Actives[i] }
func (m Movers) SortGainers() *[]WebMover {
sort.Sort(sort.Reverse(ByGainers(m)))
return &m.Gainers
}
func (m Movers) SortLosers() *[]WebMover {
sort.Sort(ByLosers(m))
return &m.Losers
}
func (m Movers) SortActives() *[]WebMover {
sort.Sort(sort.Reverse(ByActives(m)))
return &m.Actives
}
// misc -----------------------------------------------------------------------
func getMovers(deps *Dependencies, sublog zerolog.Logger) Movers {
db := deps.db
movers := Movers{}
gainers := make([]WebMover, 0)
losers := make([]WebMover, 0)
actives := make([]WebMover, 0)
latestMoverDate, err := getLatestMoversDate(deps)
if err != nil {
sublog.Error().Err(err).Msg("failed to get latest movers date")
return movers
}
sublog = sublog.With().Str("mover_date", latestMoverDate.Format("2006-01-02")).Logger()
rows, err := db.Queryx(`SELECT * FROM mover WHERE mover_date=?`, latestMoverDate.Format("2006-01-02"))
if err != nil {
sublog.Error().Err(err).Msg("failed to load movers")
return movers
}
defer rows.Close()
mover := Mover{}
for rows.Next() {
err = rows.StructScan(&mover)
if err != nil {
sublog.Warn().Err(err).Msg("failed reading row")
continue
}
if mover.Volume > 1_000_000 {
mover.VolumeStr = fmt.Sprintf("%.2fM", float32(mover.Volume)/1_000_000)
} else if mover.Volume > 1_000 {
mover.VolumeStr = fmt.Sprintf("%.2fK", float32(mover.Volume)/1_000)
}
ticker := Ticker{TickerId: mover.TickerId}
err := ticker.getById(deps, sublog)
if err != nil {
sublog.Warn().Err(err).Msg("failed reading row")
continue
}
switch mover.MoverType {
case "gainer":
if len(gainers) < 10 {
gainers = append(gainers, WebMover{mover, ticker})
}
case "loser":
if len(losers) < 10 {
losers = append(losers, WebMover{mover, ticker})
}
case "active":
if len(actives) < 10 {
actives = append(actives, WebMover{mover, ticker})
}
}
}
if err := rows.Err(); err != nil {
sublog.Warn().Err(err).Msg("failed reading rows")
return movers
}
movers = Movers{gainers, losers, actives, latestMoverDate}
return movers
}
func getLatestMoversDate(deps *Dependencies) (time.Time, error) {
db := deps.db
maxMoverDate := time.Time{}
err := db.QueryRowx(`SELECT MAX(mover_date) FROM mover`).Scan(&maxMoverDate)
return maxMoverDate, err
}