185 lines
4.3 KiB
Go
185 lines
4.3 KiB
Go
|
package max
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"git.qtrade.icu/lychiyu/bbgo/pkg/fixedpoint"
|
||
|
"git.qtrade.icu/lychiyu/bbgo/pkg/types"
|
||
|
)
|
||
|
|
||
|
type PublicService struct {
|
||
|
client *RestClient
|
||
|
}
|
||
|
|
||
|
type Market struct {
|
||
|
ID string `json:"id"`
|
||
|
Name string `json:"name"`
|
||
|
Status string `json:"market_status"` // active
|
||
|
BaseUnit string `json:"base_unit"`
|
||
|
BaseUnitPrecision int `json:"base_unit_precision"`
|
||
|
QuoteUnit string `json:"quote_unit"`
|
||
|
QuoteUnitPrecision int `json:"quote_unit_precision"`
|
||
|
MinBaseAmount fixedpoint.Value `json:"min_base_amount"`
|
||
|
MinQuoteAmount fixedpoint.Value `json:"min_quote_amount"`
|
||
|
SupportMargin bool `json:"m_wallet_supported"`
|
||
|
}
|
||
|
|
||
|
type Ticker struct {
|
||
|
Time time.Time
|
||
|
|
||
|
At int64 `json:"at"`
|
||
|
Buy fixedpoint.Value `json:"buy"`
|
||
|
Sell fixedpoint.Value `json:"sell"`
|
||
|
Open fixedpoint.Value `json:"open"`
|
||
|
High fixedpoint.Value `json:"high"`
|
||
|
Low fixedpoint.Value `json:"low"`
|
||
|
Last fixedpoint.Value `json:"last"`
|
||
|
Volume fixedpoint.Value `json:"vol"`
|
||
|
VolumeInBTC fixedpoint.Value `json:"vol_in_btc"`
|
||
|
}
|
||
|
|
||
|
func (s *PublicService) Timestamp(ctx context.Context) (int64, error) {
|
||
|
req := s.client.NewGetTimestampRequest()
|
||
|
ts, err := req.Do(ctx)
|
||
|
if err != nil || ts == nil {
|
||
|
return 0, nil
|
||
|
}
|
||
|
|
||
|
return int64(*ts), nil
|
||
|
}
|
||
|
|
||
|
func (s *PublicService) Markets(ctx context.Context) ([]Market, error) {
|
||
|
req := s.client.NewGetMarketsRequest()
|
||
|
return req.Do(ctx)
|
||
|
}
|
||
|
|
||
|
func (s *PublicService) Tickers(ctx context.Context) (TickerMap, error) {
|
||
|
req := s.client.NewGetTickersRequest()
|
||
|
return req.Do(ctx)
|
||
|
}
|
||
|
|
||
|
func (s *PublicService) Ticker(market string) (*Ticker, error) {
|
||
|
req := s.client.NewGetTickerRequest()
|
||
|
req.Market(market)
|
||
|
return req.Do(context.Background())
|
||
|
}
|
||
|
|
||
|
type Interval int64
|
||
|
|
||
|
func ParseInterval(a string) (Interval, error) {
|
||
|
switch strings.ToLower(a) {
|
||
|
|
||
|
case "1m":
|
||
|
return 1, nil
|
||
|
|
||
|
case "5m":
|
||
|
return 5, nil
|
||
|
|
||
|
case "15m":
|
||
|
return 15, nil
|
||
|
|
||
|
case "30m":
|
||
|
return 30, nil
|
||
|
|
||
|
case "1h":
|
||
|
return 60, nil
|
||
|
|
||
|
case "2h":
|
||
|
return 60 * 2, nil
|
||
|
|
||
|
case "3h":
|
||
|
return 60 * 3, nil
|
||
|
|
||
|
case "4h":
|
||
|
return 60 * 4, nil
|
||
|
|
||
|
case "6h":
|
||
|
return 60 * 6, nil
|
||
|
|
||
|
case "8h":
|
||
|
return 60 * 8, nil
|
||
|
|
||
|
case "12h":
|
||
|
return 60 * 12, nil
|
||
|
|
||
|
case "1d":
|
||
|
return 60 * 24, nil
|
||
|
|
||
|
case "3d":
|
||
|
return 60 * 24 * 3, nil
|
||
|
|
||
|
case "1w":
|
||
|
return 60 * 24 * 7, nil
|
||
|
|
||
|
}
|
||
|
|
||
|
return 0, fmt.Errorf("incorrect resolution: %q", a)
|
||
|
}
|
||
|
|
||
|
type KLine struct {
|
||
|
Symbol string
|
||
|
Interval string
|
||
|
StartTime, EndTime time.Time
|
||
|
Open, High, Low, Close fixedpoint.Value
|
||
|
Volume fixedpoint.Value
|
||
|
Closed bool
|
||
|
}
|
||
|
|
||
|
func (k KLine) KLine() types.KLine {
|
||
|
return types.KLine{
|
||
|
Exchange: types.ExchangeMax,
|
||
|
Symbol: strings.ToUpper(k.Symbol), // global symbol
|
||
|
Interval: types.Interval(k.Interval),
|
||
|
StartTime: types.Time(k.StartTime),
|
||
|
EndTime: types.Time(k.EndTime),
|
||
|
Open: k.Open,
|
||
|
Close: k.Close,
|
||
|
High: k.High,
|
||
|
Low: k.Low,
|
||
|
Volume: k.Volume,
|
||
|
// QuoteVolume: util.MustParseFloat(k.QuoteAssetVolume),
|
||
|
// LastTradeID: 0,
|
||
|
// NumberOfTrades: k.TradeNum,
|
||
|
Closed: k.Closed,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *PublicService) KLines(symbol string, resolution string, start time.Time, limit int) ([]KLine, error) {
|
||
|
interval, err := ParseInterval(resolution)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
req := s.client.NewGetKLinesRequest()
|
||
|
req.Market(symbol).Period(int(interval)).Timestamp(start).Limit(limit)
|
||
|
data, err := req.Do(context.Background())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
var kLines []KLine
|
||
|
for _, slice := range data {
|
||
|
ts := int64(slice[0])
|
||
|
startTime := time.Unix(ts, 0)
|
||
|
endTime := startTime.Add(time.Duration(interval)*time.Minute - time.Millisecond)
|
||
|
isClosed := time.Now().Before(endTime)
|
||
|
kLines = append(kLines, KLine{
|
||
|
Symbol: symbol,
|
||
|
Interval: resolution,
|
||
|
StartTime: startTime,
|
||
|
EndTime: endTime,
|
||
|
Open: fixedpoint.NewFromFloat(slice[1]),
|
||
|
High: fixedpoint.NewFromFloat(slice[2]),
|
||
|
Low: fixedpoint.NewFromFloat(slice[3]),
|
||
|
Close: fixedpoint.NewFromFloat(slice[4]),
|
||
|
Volume: fixedpoint.NewFromFloat(slice[5]),
|
||
|
Closed: isClosed,
|
||
|
})
|
||
|
}
|
||
|
return kLines, nil
|
||
|
// return parseKLines(resp.Body, symbol, resolution, interval)
|
||
|
}
|