mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
glassnode: add Request struct
This commit is contained in:
parent
5ce5571b5e
commit
99d6c0550d
|
@ -18,19 +18,44 @@ func New(apiKey string) *DataSource {
|
|||
return &DataSource{client: client}
|
||||
}
|
||||
|
||||
// query last futures open interest
|
||||
// https://docs.glassnode.com/api/derivatives#futures-open-interest
|
||||
func (d *DataSource) QueryFuturesOpenInterest(ctx context.Context, currency string) (float64, error) {
|
||||
req := glassnodeapi.DerivativesRequest{
|
||||
func (d *DataSource) Query(ctx context.Context, category, metric, asset, interval string, since, until *time.Time) (glassnodeapi.DataSlice, error) {
|
||||
req := glassnodeapi.Request{
|
||||
Client: d.client,
|
||||
Asset: currency,
|
||||
// 25 hours ago
|
||||
Since: time.Now().Add(-25 * time.Hour).Unix(),
|
||||
Interval: glassnodeapi.Interval24h,
|
||||
Metric: "futures_open_interest_sum",
|
||||
Asset: asset,
|
||||
Format: glassnodeapi.FormatJSON,
|
||||
|
||||
Category: category,
|
||||
Metric: metric,
|
||||
}
|
||||
|
||||
if since != nil {
|
||||
req.Since = since
|
||||
}
|
||||
|
||||
if until != nil {
|
||||
req.Until = until
|
||||
}
|
||||
|
||||
if interval != "" {
|
||||
req.SetInterval(glassnodeapi.Interval(interval))
|
||||
}
|
||||
|
||||
resp, err := req.Do(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return glassnodeapi.DataSlice(resp), nil
|
||||
}
|
||||
|
||||
// query last futures open interest
|
||||
// https://docs.glassnode.com/api/derivatives#futures-open-interest
|
||||
func (d *DataSource) QueryFuturesOpenInterest(ctx context.Context, currency string) (float64, error) {
|
||||
until := time.Now()
|
||||
since := until.Add(-25 * time.Hour)
|
||||
|
||||
resp, err := d.Query(ctx, "derivatives", "futures_open_interest_sum", currency, "24h", &since, &until)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -41,16 +66,11 @@ func (d *DataSource) QueryFuturesOpenInterest(ctx context.Context, currency stri
|
|||
// query last market cap in usd
|
||||
// https://docs.glassnode.com/api/market#market-cap
|
||||
func (d *DataSource) QueryMarketCapInUSD(ctx context.Context, currency string) (float64, error) {
|
||||
req := glassnodeapi.MarketRequest{
|
||||
Client: d.client,
|
||||
Asset: currency,
|
||||
// 25 hours ago
|
||||
Since: time.Now().Add(-25 * time.Hour).Unix(),
|
||||
Interval: glassnodeapi.Interval24h,
|
||||
Metric: "marketcap_usd",
|
||||
}
|
||||
until := time.Now()
|
||||
since := until.Add(-25 * time.Hour)
|
||||
|
||||
resp, err := d.Query(ctx, "market", "marketcap_usd", currency, "24h", &since, &until)
|
||||
|
||||
resp, err := req.Do(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
22
pkg/datasource/glassnode/glassnodeapi/request.go
Normal file
22
pkg/datasource/glassnode/glassnodeapi/request.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package glassnodeapi
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/c9s/requestgen"
|
||||
)
|
||||
|
||||
//go:generate requestgen -method GET -type Request -url "/v1/metrics/:category/:metric" -responseType DataSlice
|
||||
type Request struct {
|
||||
Client requestgen.AuthenticatedAPIClient
|
||||
|
||||
Asset string `param:"a,required,query"`
|
||||
Since *time.Time `param:"s,query,seconds"`
|
||||
Until *time.Time `param:"u,query,seconds"`
|
||||
Interval Interval `param:"i,query"`
|
||||
Format Format `param:"f,query"`
|
||||
TimestampFormat string `param:"timestamp_format,query"`
|
||||
|
||||
Category string `param:"category,slug"`
|
||||
Metric string `param:"metric,slug"`
|
||||
}
|
262
pkg/datasource/glassnode/glassnodeapi/request_requestgen.go
Normal file
262
pkg/datasource/glassnode/glassnodeapi/request_requestgen.go
Normal file
|
@ -0,0 +1,262 @@
|
|||
// Code generated by "requestgen -method GET -type Request -url /v1/metrics/:category/:metric -responseType DataSlice"; DO NOT EDIT.
|
||||
|
||||
package glassnodeapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (r *Request) SetAsset(Asset string) *Request {
|
||||
r.Asset = Asset
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) SetSince(Since time.Time) *Request {
|
||||
r.Since = &Since
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) SetUntil(Until time.Time) *Request {
|
||||
r.Until = &Until
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) SetInterval(Interval Interval) *Request {
|
||||
r.Interval = Interval
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) SetFormat(Format Format) *Request {
|
||||
r.Format = Format
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) SetTimestampFormat(TimestampFormat string) *Request {
|
||||
r.TimestampFormat = TimestampFormat
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) SetCategory(Category string) *Request {
|
||||
r.Category = Category
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Request) SetMetric(Metric string) *Request {
|
||||
r.Metric = Metric
|
||||
return r
|
||||
}
|
||||
|
||||
// GetQueryParameters builds and checks the query parameters and returns url.Values
|
||||
func (r *Request) GetQueryParameters() (url.Values, error) {
|
||||
var params = map[string]interface{}{}
|
||||
// check Asset field -> json key a
|
||||
Asset := r.Asset
|
||||
|
||||
// TEMPLATE check-required
|
||||
if len(Asset) == 0 {
|
||||
return nil, fmt.Errorf("a is required, empty string given")
|
||||
}
|
||||
// END TEMPLATE check-required
|
||||
|
||||
// assign parameter of Asset
|
||||
params["a"] = Asset
|
||||
// check Since field -> json key s
|
||||
if r.Since != nil {
|
||||
Since := *r.Since
|
||||
|
||||
// assign parameter of Since
|
||||
// convert time.Time to seconds time stamp
|
||||
params["s"] = strconv.FormatInt(Since.Unix(), 10)
|
||||
} else {
|
||||
}
|
||||
// check Until field -> json key u
|
||||
if r.Until != nil {
|
||||
Until := *r.Until
|
||||
|
||||
// assign parameter of Until
|
||||
// convert time.Time to seconds time stamp
|
||||
params["u"] = strconv.FormatInt(Until.Unix(), 10)
|
||||
} else {
|
||||
}
|
||||
// check Interval field -> json key i
|
||||
Interval := r.Interval
|
||||
|
||||
// TEMPLATE check-valid-values
|
||||
switch Interval {
|
||||
case Interval1h, Interval24h, Interval10m, Interval1w, Interval1m:
|
||||
params["i"] = Interval
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("i value %v is invalid", Interval)
|
||||
|
||||
}
|
||||
// END TEMPLATE check-valid-values
|
||||
|
||||
// assign parameter of Interval
|
||||
params["i"] = Interval
|
||||
// check Format field -> json key f
|
||||
Format := r.Format
|
||||
|
||||
// TEMPLATE check-valid-values
|
||||
switch Format {
|
||||
case FormatJSON, FormatCSV:
|
||||
params["f"] = Format
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("f value %v is invalid", Format)
|
||||
|
||||
}
|
||||
// END TEMPLATE check-valid-values
|
||||
|
||||
// assign parameter of Format
|
||||
params["f"] = Format
|
||||
// check TimestampFormat field -> json key timestamp_format
|
||||
TimestampFormat := r.TimestampFormat
|
||||
|
||||
// assign parameter of TimestampFormat
|
||||
params["timestamp_format"] = TimestampFormat
|
||||
|
||||
query := url.Values{}
|
||||
for _k, _v := range params {
|
||||
query.Add(_k, fmt.Sprintf("%v", _v))
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// GetParameters builds and checks the parameters and return the result in a map object
|
||||
func (r *Request) GetParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
// GetParametersQuery converts the parameters from GetParameters into the url.Values format
|
||||
func (r *Request) GetParametersQuery() (url.Values, error) {
|
||||
query := url.Values{}
|
||||
|
||||
params, err := r.GetParameters()
|
||||
if err != nil {
|
||||
return query, err
|
||||
}
|
||||
|
||||
for _k, _v := range params {
|
||||
if r.isVarSlice(_v) {
|
||||
r.iterateSlice(_v, func(it interface{}) {
|
||||
query.Add(_k+"[]", fmt.Sprintf("%v", it))
|
||||
})
|
||||
} else {
|
||||
query.Add(_k, fmt.Sprintf("%v", _v))
|
||||
}
|
||||
}
|
||||
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// GetParametersJSON converts the parameters from GetParameters into the JSON format
|
||||
func (r *Request) GetParametersJSON() ([]byte, error) {
|
||||
params, err := r.GetParameters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(params)
|
||||
}
|
||||
|
||||
// GetSlugParameters builds and checks the slug parameters and return the result in a map object
|
||||
func (r *Request) GetSlugParameters() (map[string]interface{}, error) {
|
||||
var params = map[string]interface{}{}
|
||||
// check Category field -> json key category
|
||||
Category := r.Category
|
||||
|
||||
// assign parameter of Category
|
||||
params["category"] = Category
|
||||
// check Metric field -> json key metric
|
||||
Metric := r.Metric
|
||||
|
||||
// assign parameter of Metric
|
||||
params["metric"] = Metric
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func (r *Request) applySlugsToUrl(url string, slugs map[string]string) string {
|
||||
for _k, _v := range slugs {
|
||||
needleRE := regexp.MustCompile(":" + _k + "\\b")
|
||||
url = needleRE.ReplaceAllString(url, _v)
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
func (r *Request) iterateSlice(slice interface{}, _f func(it interface{})) {
|
||||
sliceValue := reflect.ValueOf(slice)
|
||||
for _i := 0; _i < sliceValue.Len(); _i++ {
|
||||
it := sliceValue.Index(_i).Interface()
|
||||
_f(it)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) isVarSlice(_v interface{}) bool {
|
||||
rt := reflect.TypeOf(_v)
|
||||
switch rt.Kind() {
|
||||
case reflect.Slice:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *Request) GetSlugsMap() (map[string]string, error) {
|
||||
slugs := map[string]string{}
|
||||
params, err := r.GetSlugParameters()
|
||||
if err != nil {
|
||||
return slugs, nil
|
||||
}
|
||||
|
||||
for _k, _v := range params {
|
||||
slugs[_k] = fmt.Sprintf("%v", _v)
|
||||
}
|
||||
|
||||
return slugs, nil
|
||||
}
|
||||
|
||||
func (r *Request) Do(ctx context.Context) (DataSlice, error) {
|
||||
|
||||
// no body params
|
||||
var params interface{}
|
||||
query, err := r.GetQueryParameters()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiURL := "/v1/metrics/:category/:metric"
|
||||
slugs, err := r.GetSlugsMap()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiURL = r.applySlugsToUrl(apiURL, slugs)
|
||||
|
||||
req, err := r.Client.NewAuthenticatedRequest(ctx, "GET", apiURL, query, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := r.Client.SendRequest(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var apiResponse DataSlice
|
||||
if err := response.DecodeJSON(&apiResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apiResponse, nil
|
||||
}
|
|
@ -72,50 +72,50 @@ and
|
|||
...
|
||||
]
|
||||
|
||||
both can be stored into the Response structure.
|
||||
both can be stored into the DataSlice structure.
|
||||
|
||||
Note: use `HasOptions` to verify the type of response.
|
||||
*/
|
||||
type Response []Data
|
||||
type DataSlice []Data
|
||||
type Data struct {
|
||||
Timestamp Timestamp `json:"t"`
|
||||
Value float64 `json:"v"`
|
||||
Options map[string]float64 `json:"o"`
|
||||
}
|
||||
|
||||
func (s Response) IsEmpty() bool {
|
||||
func (s DataSlice) IsEmpty() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
|
||||
func (s Response) First() Data {
|
||||
func (s DataSlice) First() Data {
|
||||
if s.IsEmpty() {
|
||||
return Data{}
|
||||
}
|
||||
return s[0]
|
||||
}
|
||||
func (s Response) FirstValue() float64 {
|
||||
func (s DataSlice) FirstValue() float64 {
|
||||
return s.First().Value
|
||||
}
|
||||
|
||||
func (s Response) FirstOptions() map[string]float64 {
|
||||
func (s DataSlice) FirstOptions() map[string]float64 {
|
||||
return s.First().Options
|
||||
}
|
||||
|
||||
func (s Response) Last() Data {
|
||||
func (s DataSlice) Last() Data {
|
||||
if s.IsEmpty() {
|
||||
return Data{}
|
||||
}
|
||||
return s[len(s)-1]
|
||||
}
|
||||
|
||||
func (s Response) LastValue() float64 {
|
||||
func (s DataSlice) LastValue() float64 {
|
||||
return s.Last().Value
|
||||
}
|
||||
|
||||
func (s Response) LastOptions() map[string]float64 {
|
||||
func (s DataSlice) LastOptions() map[string]float64 {
|
||||
return s.Last().Options
|
||||
}
|
||||
|
||||
func (s Response) HasOptions() bool {
|
||||
func (s DataSlice) HasOptions() bool {
|
||||
return len(s.First().Options) != 0
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user