Code Monkey home page Code Monkey logo

go-deribit's Introduction

Build Status Go Report Card codebeat badge

go-deribit

No longer maintained

I do not have the time to look after this project. It was good fun but all good things must end. If you wish to carry on then please fork this repo and go your own way.

V3

This project is now using go1.13 with Go Modules, but should remain compatible with dep. Also, as there are some breaking changes introduced by the latest schema changes from the remote API, I have decided to carry on development in the new v3 namespace with the project root containing the code tagged v2.x.

import "github.com/adampointer/go-deribit/v3"

We now have the latest API methods which were recently released such as public/get_tradingview_chart_data.

I recommend using the v3 project in your projects as all onward development will now be within this project.

GoDoc API Documentation

Overview

Go library for using the Deribit's v2 Websocket API.

Deribit is a modern, fast BitCoin derivatives exchange.

This library is a port of the official wrapper libraries to Go.

If you wish to try it out, be kind and use my affiliate link https://www.deribit.com/reg-3027.8327

Or tip me!

btc: 3HmLfHJvrJuM48zHFY6HstUCxbuwV3dvxd

eth: 0x9Dc9129185E79211534D0039Af1C6f1ff585F5e3

ltc: MEpFjCdR3uXd6QjuJTSu3coLtcSWY3S2Hg

p.s. If you want a good BitMEX client library then try go-bitmex

V2 API Documentation

Example Usage

Look at cmd/example/main.go

make build
example --access-key XXX --secret-key YYYYYY

Reconnect Behaviour

There is a heartbeat which triggers every 10 seconds to keep the websocket connection alive. In the event of a connection error, the library will automatically attempt to reconnect, re-authenticate and reestablish subscriptions.

This behaviour is overrideable with the SetDisconnectHandler method.

// Example reconnect code
exchange.SetDisconnectHandler(func (core *deribit.RPCCore) {
    exg := &deribit.NewExchangeFromCore(true, core)
	log.Warn("Disconnected from exchange. Attempting reconnection...")
	if err := exg.Connect(); err != nil {
		log.Fatalf("Error re-connecting to exchange: %s", err)
	}
	log.Info("Reconnected")
})

Logging

The standard logger has been used within the library. You can plug this into your own application's logger by overriding the output io.Writer.

logger := logrus.New()
exchange.SetLogOutput(logger.Writer())

Development

The models and client directories are where all the requests and responses are stored. The contents is automatically generated from the schema directory by go-swagger.

If you need to rebuild these use make generate-models.

The RPC subscriptions are also auto-generated. Use make generate-methods to rebuild these. They are in rpc_subscriptions.go.

go-deribit's People

Contributors

adampointer avatar adampointer-form3 avatar kprimice avatar krisa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

go-deribit's Issues

Returning the pointer to the channel is having race issues

Prerequisite:
1- Subscribe to the orders, e.g. with SubscribeUserOrdersKind

Reproduction steps:
1- create 2 or more limits order in an open position (so that an array is returned and not a single value)
2- click on "Cancel All"

An array of cancelled orders is returned in a websocket by Deribit. This code https://github.com/adampointer/go-deribit/blob/master/v3/rpc_subscriptions.go#L759 handles the array and sends each element to the channel here https://github.com/adampointer/go-deribit/blob/master/v3/rpc_subscriptions.go#L765. For some reasons, which I'm not aware of due to my limited knowledge in Go, the channel receives the same pointer address for the first two elements. The third element (if there were 3 open orders) is another order.

Solution found: I'm not sure it's ideal, I also don't know why a pointer was returned instead of the value (again my Go knowledge are a bit limited) but my solution was simply to not return a pointer, just its value, it seems to do the trick. But whether there are other consequences?..

Stop order placement marshal error

When a stop order is placed, it fails because the remote sets price as a string and we expect a model.Price (float64).

{
  ...
  "price": "market_price",
  ...
}

API Bug: subscribe orderbook failed with `options` instrument name

Example from API Console:
API Request:

{
    "jsonrpc": "2.0",
    "id": 3997,
    "method": "public/subscribe",
    "params": {
        "channels": [
            "book.BTC-21JUN19-10000-C.none.1.100ms"
        ]
    }
}

API Results and notifications:

{
    "jsonrpc": "2.0",
    "id": 3997,
    "result": [],
    "usIn": 1561053224590810,
    "usOut": 1561053224590859,
    "usDiff": 49,
    "testnet": true
} 

If subscription was subscribed successfully the result tag should contain a confirmation.

NOTE: "result": [] is a fishy way to notify users about unsuccessful subscribe to a channel.

Invalid params when using example

when using for example: getprivatebuy() method, I get:

request failed with code (-32602): Invalid params

generating new models and methods doesnt work since it breaks the Exchange struct.

# github.com/adampointer/go-deribit
./rpc_subscriptions.go:20:3: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:24:4: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:70:3: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:74:4: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:120:3: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:124:4: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:170:3: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:174:4: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:220:3: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:224:4: e.calls undefined (type *Exchange has no field or method calls)
./rpc_subscriptions.go:224:4: too many errors

GetPrivateGetSettlementHistoryByCurrency/Instrument

When trying to get settlement history:

client := e.Client()
// Account settlement history
history, err := client.GetPrivateGetSettlementHistoryByCurrency(&operations.GetPrivateGetSettlementHistoryByCurrencyParams{Currency: "BTC"})
if err != nil {
log.Fatalf("Error getting account settlement: %s", err)
}

retrieves err:
Error getting account settlement: json: cannot unmarshal object into Go struct field PrivateSettlementResponse.result of type []string
Tried to change swaqqer struct. And as a result answer was nil. How to solve the problem?

Setup CI

I need to setup basic CI with linting and security checks etc.

Tests

Find a mocking framework for websockets maybe nock? Need to add basic tests around handling of messages from the remote as some break the type system where we expect objects and they send slices.

Breaking Changes

hi adam,
this package introduced breaking changes in the - I would say - last week.

my whole application is broken. structs are different, strings are not strings anymore, paths dont work anymore (see my other issue), etc.

Subscriptions issues

I'm currently having two issues around subscriptions.

1- It looks like after some inactivity, such as in the SubscribeUser* methods which may more often than not, not returning anything during a while, the listener times out after just a couple of minutes - also any network issue would result in the same. I'm using the basic example provided and I'd expect that following part produces at least an error but it doesn't:

         go func() {
		err := <-errs
		stop <- true
		log.Fatalf("RPC error: %s", err)
	}()

Did I miss something? Is there somewhere some methods which would listen for errors, reconnect automatically (or not), etc. ?

2- I'm also trying to figure out how to close a subscription specifically, and not all of them. *deribit.Exchange, or the stop variable returned during the initialization seem to close all of them

Ability to make JSON-RPC requests over the WS connection

Looks like this library uses WebSockets for subscriptions etc. however all the other requests are made through the JSON-RPC via HTTP. Is this correct? If so, is there a reason beyond the functions to do so being unexported?

I am able to place orders using e.rpcRequest(req) if I patch the library and add:

func (e *Exchange) WriteReqWS(req *RPCRequest) (*RPCResponse, error) {
	return e.rpcRequest(req)
}

This seems to work. Results in lower order latency and also has the benefit of not using up your "request quota".

Am I missing something here? Why was this function not exported? Is there an easier way to actually send these messages over the already alive websocket connection?

My test involves:

func (dbit *DeribitSessionContext) createRPC(method string, args map[string]string) (*deribit.RPCRequest, error) {
	req := deribit.NewRPCRequest(method)
	if args != nil {
		for k, v := range args {
			if err := req.SetQueryParam(k, v); err != nil {
				return nil, err
			}
		}
	}
	return req, nil
}

func (dbit *DeribitSessionContext) LimitOrder(dir models.Direction, total uint64, price float64, postOnly bool, label *string) error {
	args := map[string]string{
		"instrument_name": DeribitBtcPerpInstrument,
		"type":            "limit",
		"price":           fmt.Sprintf("%.2f", price),
		"amount":          fmt.Sprintf("%d", total),
	}
	if postOnly {
		args["post_only"] = "true"
	}
	if label != nil {
		args["label"] = *label
	}

	req, err := dbit.createRPC(fmt.Sprintf("private/%s", dir), args)
	if err != nil {
		return err
	}
	resp, err := dbit.ctx.WriteReqWS(req)
	if err != nil {
		return err
	}
	if resp == nil {
		return ErrNilResponse
	}
	return nil
}

This actually has significantly lower latency than the standard way of using the client (which seems to use JSON-RPC over a new HTTP request).

Websocket Concurrency

From gorilla/websocket documentation:

Concurrency ¶

Connections support one concurrent reader and one concurrent writer.

Applications are responsible for ensuring that no more than one goroutine calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and that no more than one goroutine calls the read methods (NextReader, SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) concurrently.

The Close and WriteControl methods can be called concurrently with all other methods.

The library currently does not prevent concurrent writes and I have add panics because of this.

Suggest adding a mutex to protect it.

panic: runtime error: slice bounds out of range [:6477] with capacity 4096

After running for a few hours I got this error:

panic: runtime error: slice bounds out of range [:6477] with capacity 4096

goroutine 237 [running]:
bufio.(*Reader).Read(0xc000205aa0, 0xc0002be000, 0x22, 0x2000, 0x0, 0x0, 0x0)
        /usr/local/go/src/bufio/bufio.go:237 +0x3f0
io.(*LimitedReader).Read(0xc0005c0400, 0xc0002be000, 0x2000, 0x2000, 0x7, 0x40c48b, 0xc000012000)
        /usr/local/go/src/io/io.go:448 +0x63
io/ioutil.devNull.ReadFrom(0x0, 0xb581e0, 0xc0005c0400, 0x9fcec0, 0x1, 0x7f9866c8c2e0)
        /usr/local/go/src/io/ioutil/ioutil.go:147 +0x92
io.copyBuffer(0xb58da0, 0xf87c00, 0xb581e0, 0xc0005c0400, 0x0, 0x0, 0x0, 0x568262, 0x9a5d40, 0x0)
        /usr/local/go/src/io/io.go:388 +0x2ed
io.Copy(...)
        /usr/local/go/src/io/io.go:364
io.CopyN(0xb58da0, 0xf87c00, 0xb563a0, 0xc000205aa0, 0x22, 0x0, 0xc00062fe48, 0x55743a)
        /usr/local/go/src/io/io.go:340 +0x9a
github.com/gorilla/websocket.(*Conn).advanceFrame(0xc00020e6e0, 0x0, 0x0, 0x80)
        /go/pkg/mod/github.com/gorilla/[email protected]/conn.go:791 +0xe28
github.com/gorilla/websocket.(*Conn).NextReader(0xc00020e6e0, 0xc000350900, 0xc0002f2480, 0x0, 0xc00062ff70, 0x40fe68)
        /go/pkg/mod/github.com/gorilla/[email protected]/conn.go:980 +0xa0
github.com/gorilla/websocket.(*Conn).ReadJSON(0xc00020e6e0, 0xa29ee0, 0xc0002f2680, 0x0, 0x0)
        /go/pkg/mod/github.com/gorilla/[email protected]/json.go:50 +0x2f
github.com/adampointer/go-deribit/v3.(*connManager).readJSON(...)
        /go/pkg/mod/github.com/adampointer/go-deribit/[email protected]/rpc_core.go:123
github.com/adampointer/go-deribit/v3.(*RPCCore).read(0xc000562110)
        /go/pkg/mod/github.com/adampointer/go-deribit/[email protected]/rpc_core.go:190 +0x96
created by github.com/adampointer/go-deribit/v3.(*Exchange).Reconnect
        /go/pkg/mod/github.com/adampointer/go-deribit/[email protected]/exchange.go:105 +0xed

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.