/
candle.go
127 lines (112 loc) · 3.43 KB
/
candle.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
package persistence
import (
"database/sql"
"errors"
"fmt"
"time"
"github.com/Fukkatsuso/cryptocurrency-trading-bot/dashboard/domain/model"
"github.com/Fukkatsuso/cryptocurrency-trading-bot/dashboard/domain/repository"
)
type candleRepository struct {
db DB
candleTableName string
timeFormat string
}
func NewCandleRepository(db DB, candleTableName, timeFormat string) repository.CandleRepository {
if candleTableName == "" {
return nil
}
return &candleRepository{
db: db,
candleTableName: candleTableName,
timeFormat: timeFormat,
}
}
func (cr candleRepository) Save(candle model.Candle) error {
cmd := fmt.Sprintf(`
INSERT INTO %s
(time, open, close, high, low, volume)
VALUES
(?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
open = VALUES(open),
close = VALUES(close),
high = VALUES(high),
low = VALUES(low),
volume = VALUES(volume)
`,
cr.candleTableName,
)
_, err := cr.db.Exec(cmd, candle.Time().Format(cr.timeFormat), candle.Open(), candle.Close(), candle.High(), candle.Low(), candle.Volume())
return err
}
func (cr candleRepository) FindByCandleTime(productCode string, duration time.Duration, candleTime model.CandleTime) (*model.Candle, error) {
cmd := fmt.Sprintf(`
SELECT
open, close, high, low, volume
FROM
%s
WHERE
time = ?
`,
cr.candleTableName,
)
row := cr.db.QueryRow(cmd, candleTime.Format(cr.timeFormat))
var candleOpen, candleClose, candleHigh, candleLow, candleVolume float64
err := row.Scan(&candleOpen, &candleClose, &candleHigh, &candleLow, &candleVolume)
// 発見できなかったらそのままnilを返す
if err == sql.ErrNoRows {
return nil, nil
}
if err != nil {
return nil, err
}
candle := model.NewCandle(productCode, duration, candleTime, candleOpen, candleClose, candleHigh, candleLow, candleVolume)
if candle == nil {
return nil, errors.New(fmt.Sprint("invalid candle:", productCode, duration, candleTime, candleOpen, candleClose, candleHigh, candleLow, candleVolume))
}
return candle, nil
}
func (cr candleRepository) FindAll(productCode string, duration time.Duration, limit int64) ([]model.Candle, error) {
cmd := fmt.Sprintf(`
SELECT
*
FROM (
SELECT
time, open, close, high, low, volume
FROM
%s
ORDER BY
time DESC
LIMIT ?
) AS candle
ORDER BY
time ASC
`,
cr.candleTableName,
)
rows, err := cr.db.Query(cmd, limit)
if err != nil {
return nil, err
}
defer rows.Close()
candles := make([]model.Candle, 0)
for rows.Next() {
var timeTime time.Time
var candleOpen, candleClose, candleHigh, candleLow, candleVolume float64
err := rows.Scan(&timeTime, &candleOpen, &candleClose, &candleHigh, &candleLow, &candleVolume)
if err != nil {
return nil, err
}
candleTime := model.NewCandleTime(timeTime)
candle := model.NewCandle(productCode, duration, candleTime, candleOpen, candleClose, candleHigh, candleLow, candleVolume)
if candle == nil {
return nil, errors.New(fmt.Sprint("invalid candle:", productCode, duration, candleTime, candleOpen, candleClose, candleHigh, candleLow, candleVolume))
}
candles = append(candles, *candle)
}
if err = rows.Err(); err != nil {
return nil, err
}
return candles, nil
}