gitlab.com/SkynetLabs/skyd@v1.6.9/cmd/skyc/cryptowatch.go (about)

     1  package main
     2  
     3  // This code pulls SC data from crypto watch for historical pricing information.
     4  //
     5  // There is a go SDK https://github.com/cryptowatch/cw-sdk-go but the last
     6  // version release was 2019 and the one method we would use doesn't support the
     7  // necessary arguments. So much of the code is copied from the SDK here to add
     8  // the functionality we need.
     9  //
    10  // ref: https://docs.cryptowat.ch/
    11  
    12  import (
    13  	"encoding/json"
    14  	"fmt"
    15  	"net/http"
    16  	"time"
    17  
    18  	"gitlab.com/NebulousLabs/errors"
    19  )
    20  
    21  type (
    22  	// ohlcResponse is the data type for the response body of the OHLC
    23  	// request. This is copied from the cryptowatch go sdk
    24  	ohlcResponse struct {
    25  		Result map[string][][]json.Number `json:"result"`
    26  	}
    27  
    28  	// SCPrice defines the response data for an OHLC interval
    29  	SCPrice struct {
    30  		// High and Low Price for the interval
    31  		Average float64
    32  		High    float64
    33  		Low     float64
    34  
    35  		// EndTime is the end of the interval.
    36  		EndTime time.Time
    37  
    38  		// StartTime is the beginning of the interval.
    39  		StartTime time.Time
    40  	}
    41  )
    42  
    43  // scUSDPrices returns the SCUSD price information
    44  func scUSDPrices(start, end int64) ([]SCPrice, error) {
    45  	return scPrices(start, end, "scusd")
    46  }
    47  
    48  // scPrices pulls the historical SC Price information
    49  //
    50  // ref: https://docs.cryptowat.ch/rest-api/markets/ohlc
    51  func scPrices(start, end int64, pair string) (priceInfo []SCPrice, err error) {
    52  	client := &http.Client{}
    53  	var period int64 = 86400 // one day in seconds
    54  	query := fmt.Sprintf("https://api.cryptowat.ch/markets/kraken/%v/ohlc?periods=%v&before=%v&after=%v", pair, period, end, start)
    55  	req, err := http.NewRequest("GET", query, nil)
    56  	if err != nil {
    57  		return nil, errors.AddContext(err, "unable to build request")
    58  	}
    59  	resp, err := client.Do(req)
    60  	if err != nil {
    61  		return nil, errors.AddContext(err, "unable to fetch historical price info")
    62  	}
    63  	defer func() {
    64  		err = errors.Compose(err, resp.Body.Close())
    65  	}()
    66  
    67  	srv := ohlcResponse{}
    68  
    69  	dec := json.NewDecoder(resp.Body)
    70  	if err := dec.Decode(&srv); err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	// Grab the period info
    75  	periodResults, ok := srv.Result[fmt.Sprint(period)]
    76  	if !ok {
    77  		return nil, errors.New("period not found in map")
    78  	}
    79  
    80  	priceInfo = make([]SCPrice, 0, len(periodResults))
    81  	for _, pr := range periodResults {
    82  		if len(pr) < 7 {
    83  			return nil, fmt.Errorf("unexpected response from the server: wanted 7 elements, got %v", pr)
    84  		}
    85  
    86  		ts, err := pr[0].Int64()
    87  		if err != nil {
    88  			return nil, errors.AddContext(err, fmt.Sprintf("getting timestamp %q", pr[0].String()))
    89  		}
    90  		high, err := pr[2].Float64()
    91  		if err != nil {
    92  			return nil, err
    93  		}
    94  		low, err := pr[3].Float64()
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  		priceInfo = append(priceInfo, SCPrice{
    99  			Average: (high + low) / 2,
   100  			High:    high,
   101  			Low:     low,
   102  
   103  			EndTime:   time.Unix(ts, 0),
   104  			StartTime: time.Unix(ts-period, 0),
   105  		})
   106  	}
   107  	return priceInfo, nil
   108  }