diff --git a/examples/okex-book/main.go b/examples/okex-book/main.go index 0f17bf74e..9d846b065 100644 --- a/examples/okex-book/main.go +++ b/examples/okex-book/main.go @@ -47,6 +47,15 @@ var rootCmd = &cobra.Command{ client := okexapi.NewClient() client.Auth(key, secret, passphrase) + instruments, err := client.PublicDataService.NewGetInstrumentsRequest(). + InstrumentType("SPOT").Do(ctx) + if err != nil { + return err + } + + log.Infof("instruments: %+v", instruments) + return nil + log.Infof("ACCOUNT BALANCES:") balanceSummaries, err := client.AccountBalances() if err != nil { diff --git a/pkg/exchange/okex/okexapi/client.go b/pkg/exchange/okex/okexapi/client.go index 8e5f579c8..58473f845 100644 --- a/pkg/exchange/okex/okexapi/client.go +++ b/pkg/exchange/okex/okexapi/client.go @@ -40,6 +40,15 @@ const ( OrderTypeIOC OrderType = "ioc" ) +type InstrumentType string + +const ( + InstrumentTypeSpot InstrumentType = "SPOT" + InstrumentTypeSwap InstrumentType = "SWAP" + InstrumentTypeFutures InstrumentType = "FUTURES" + InstrumentTypeOption InstrumentType = "OPTION" +) + type OrderState string const ( @@ -56,7 +65,8 @@ type RestClient struct { Key, Secret, Passphrase string - TradeService *TradeService + TradeService *TradeService + PublicDataService *PublicDataService } func NewClient() *RestClient { @@ -73,6 +83,7 @@ func NewClient() *RestClient { } client.TradeService = &TradeService{client: client} + client.PublicDataService = &PublicDataService{client: client} return client } @@ -94,13 +105,7 @@ func (c *RestClient) newRequest(method, refURL string, params url.Values, body [ } pathURL := c.BaseURL.ResolveReference(rel) - - req, err := http.NewRequest(method, pathURL.String(), bytes.NewReader(body)) - if err != nil { - return nil, err - } - - return req, nil + return http.NewRequest(method, pathURL.String(), bytes.NewReader(body)) } // sendRequest sends the request to the API server and handle the response diff --git a/pkg/exchange/okex/okexapi/public.go b/pkg/exchange/okex/okexapi/public.go index b18b2822c..e158d6c32 100644 --- a/pkg/exchange/okex/okexapi/public.go +++ b/pkg/exchange/okex/okexapi/public.go @@ -1 +1,89 @@ package okexapi + +import ( + "context" + "net/url" + + "github.com/c9s/bbgo/pkg/fixedpoint" + "github.com/c9s/bbgo/pkg/types" +) + +type PublicDataService struct { + client *RestClient +} + +func (s *PublicDataService) NewGetInstrumentsRequest() *GetInstrumentsRequest { + return &GetInstrumentsRequest{ + client: s.client, + } +} + +type Instrument struct { + InstrumentType string `json:"instType"` + InstrumentID string `json:"instId"` + BaseCurrency string `json:"baseCcy"` + QuoteCurrency string `json:"quoteCcy"` + SettleCurrency string `json:"settleCcy"` + ContractValue string `json:"ctVal"` + ContractMultiplier string `json:"ctMult"` + ContractValueCurrency string `json:"ctValCcy"` + ListTime types.MillisecondTimestamp `json:"listTime"` + ExpiryTime types.MillisecondTimestamp `json:"expTime"` + TickSize fixedpoint.Value `json:"tickSz"` + LotSize fixedpoint.Value `json:"lotSz"` + + // MinSize = min order size + MinSize fixedpoint.Value `json:"minSz"` + + // instrument status + State string `json:"state"` +} + +type GetInstrumentsRequest struct { + client *RestClient + + instType InstrumentType + + instId *string +} + +func (r *GetInstrumentsRequest) InstrumentType(instType InstrumentType) *GetInstrumentsRequest { + r.instType = instType + return r +} + +func (r *GetInstrumentsRequest) InstrumentID(instId string) *GetInstrumentsRequest { + r.instId = &instId + return r +} + +func (r *GetInstrumentsRequest) Do(ctx context.Context) ([]Instrument, error) { + // SPOT, SWAP, FUTURES, OPTION + var params = url.Values{} + params.Add("instType", string(r.instType)) + + if r.instId != nil { + params.Add("instId", *r.instId) + } + + req, err := r.client.newRequest("GET", "/api/v5/public/instruments", params, nil) + if err != nil { + return nil, err + } + + response, err := r.client.sendRequest(req) + if err != nil { + return nil, err + } + + var apiResponse struct { + Code string `json:"code"` + Message string `json:"msg"` + Data []Instrument `json:"data"` + } + if err := response.DecodeJSON(&apiResponse); err != nil { + return nil, err + } + + return apiResponse.Data, nil +} diff --git a/pkg/exchange/okex/okexapi/trade.go b/pkg/exchange/okex/okexapi/trade.go index 624ab4795..3d8e20339 100644 --- a/pkg/exchange/okex/okexapi/trade.go +++ b/pkg/exchange/okex/okexapi/trade.go @@ -439,14 +439,14 @@ func (r *GetOrderDetailsRequest) Do(ctx context.Context) (*OrderDetails, error) type GetPendingOrderRequest struct { client *RestClient - instType *string + instType *InstrumentType orderTypes []string state *OrderState } -func (r *GetPendingOrderRequest) InstrumentType(instType string) *GetPendingOrderRequest { +func (r *GetPendingOrderRequest) InstrumentType(instType InstrumentType) *GetPendingOrderRequest { r.instType = &instType return r } @@ -511,14 +511,14 @@ func (r *GetPendingOrderRequest) Do(ctx context.Context) ([]OrderDetails, error) type GetTransactionDetailsRequest struct { client *RestClient - instType *string + instType *InstrumentType instId *string ordId *string } -func (r *GetTransactionDetailsRequest) InstrumentType(instType string) *GetTransactionDetailsRequest { +func (r *GetTransactionDetailsRequest) InstrumentType(instType InstrumentType) *GetTransactionDetailsRequest { r.instType = &instType return r } diff --git a/pkg/types/time.go b/pkg/types/time.go index 30404b3b1..5781dd865 100644 --- a/pkg/types/time.go +++ b/pkg/types/time.go @@ -24,6 +24,12 @@ func (t *MillisecondTimestamp) UnmarshalJSON(data []byte) error { switch vt := v.(type) { case string: + if vt == "" { + // treat empty string as 0 + *t = MillisecondTimestamp(time.Time{}) + return nil + } + i, err := strconv.ParseInt(vt, 10, 64) if err == nil { *t = MillisecondTimestamp(time.Unix(0, i*int64(time.Millisecond)))