Skip to content

Latest commit

 

History

History
258 lines (224 loc) · 6.88 KB

README.md

File metadata and controls

258 lines (224 loc) · 6.88 KB

golang-binance-service

Setup, Build, and Run

You might need to update go.mod:

go mod tidy
go mod vendor

Create an .env file with:

PORT=4200
USE_TESTNET=true
DEBUG=true

Start the server on port 4200 with:

make build run PORT=4200

Testing

Go to https://testnet.binancefuture.com/ and create an account. After creating an account, you can make an API key and API secret below the candlestick chart. You will use these in postman and unit tests.

Postman

The postman collection is under postman/collections and the postman environment is under postman/environments. There are example requests for each endpoint.

I suggest having the https://testnet.binancefuture.com/ open in one window to close any positions you open or cancel any orders made while testing the endpoints.

The set up is basically the same as https://github.com/binance/binance-api-postman

Unit tests

In order to run tests, create an .env.test file with:

FUTURES_API_KEY="XXXXXXX"
FUTURES_API_SECRET="XXXXXX"

in the ./libs/binancewrapper, ./libs/test, and ./controllers/v1/user directories.

To run all tests:

godotenv -f .env.test go test -v ./...

To run a specific test not cached:

godotenv -f .env.test go test -count=1 -run TestCreateLimitOrder -v ./libs/binancewrapper

Viewing Go Doc of code

go get -v  golang.org/x/tools/cmd/godoc
godoc -http:6060

Then go to http://localhost:6060/pkg/github.com/bosdhill/golang-binance-service/ (its kind of fucked up rn)

Endpoints

GET /v1/user/balance

Returns the user's perpetual futures usdtBalance.

Example request body:

{
    "api_key": "{{binance-api-key}}",
    "api_secret": "{{binance-api-secret}}"
}

Example response body:

{
    "accountAlias": "sRmYFzoCuXFz",
    "asset": "USDT",
    "balance": "98076.98393216",
    "crossWalletBalance": "98076.98393216",
    "crossUnPnl": "0.00000000",
    "availableBalance": "98076.98393216",
    "maxWithdrawAmount": "98076.98393216"
}

GET /v1/user/account

Returns the user's perpetual futures account info.

Example request body:

{
    "api_key": "{{binance-api-key}}",
    "api_secret": "{{binance-api-secret}}"
}

Example response body:

{
    "assets": [
        {
            "asset": "BNB",
            "initialMargin": "0.00000000",
            "maintMargin": "0.00000000",
            "marginBalance": "0.00000000",
            "maxWithdrawAmount": "0.00000000",
            "openOrderInitialMargin": "0.00000000",
            "positionInitialMargin": "0.00000000",
            "unrealizedProfit": "0.00000000",
            "walletBalance": "0.00000000"
        },
        {
            "asset": "USDT",
            "initialMargin": "0.00000000",
            "maintMargin": "0.00000000",
            "marginBalance": "98076.98393216",
            "maxWithdrawAmount": "98076.98393216",
            "openOrderInitialMargin": "0.00000000",
            "positionInitialMargin": "0.00000000",
            "unrealizedProfit": "0.00000000",
            "walletBalance": "98076.98393216"
        },
        {
            "asset": "BUSD",
            "initialMargin": "0.00000000",
            "maintMargin": "0.00000000",
            "marginBalance": "0.00000000",
            "maxWithdrawAmount": "0.00000000",
            "openOrderInitialMargin": "0.00000000",
            "positionInitialMargin": "0.00000000",
            "unrealizedProfit": "0.00000000",
            "walletBalance": "0.00000000"
        }
    ],
    "canDeposit": true,
    "canTrade": true,
    "canWithdraw": true,
    "feeTier": 0,
    "maxWithdrawAmount": "98076.98393216",
    "positions": [
        {
            "isolated": false,
            "leverage": "20",
            "initialMargin": "0",
            "maintMargin": "0",
            "openOrderInitialMargin": "0",
            "positionInitialMargin": "0",
            "symbol": "RAYUSDT",
            "unrealizedProfit": "0.00000000",
            "entryPrice": "0.0",
            "maxNotional": "25000",
            "positionSide": "BOTH",
            "positionAmt": "0.0",
            "notional": "0",
            "isolatedWallet": "0",
            "updateTime": 0
        },
        ...
        {
            "isolated": false,
            "leverage": "20",
            "initialMargin": "0",
            "maintMargin": "0",
            "openOrderInitialMargin": "0",
            "positionInitialMargin": "0",
            "symbol": "CTSIUSDT",
            "unrealizedProfit": "0.00000000",
            "entryPrice": "0.0",
            "maxNotional": "25000",
            "positionSide": "BOTH",
            "positionAmt": "0",
            "notional": "0",
            "isolatedWallet": "0",
            "updateTime": 0
        }
    ],
    "totalInitialMargin": "0.00000000",
    "totalMaintMargin": "0.00000000",
    "totalMarginBalance": "98076.98393216",
    "totalOpenOrderInitialMargin": "0.00000000",
    "totalPositionInitialMargin": "0.00000000",
    "totalUnrealizedProfit": "0.00000000",
    "totalWalletBalance": "98076.98393216",
    "updateTime": 0
}

POST /v1/user/order

Creates either a LIMIT, MARKET, or STOP_MARKET order, depending on the order type provided.

Example request body:

{
    "user": {
        "api_key": "{{binance-api-key}}",
        "api_secret": "{{binance-api-secret}}"
    },
    "order": {
        "type": "MARKET",
        "symbol": "BTCUSDT",
        "side": "BUY",
        "percentage": 0.01
    }
}

Example response body:

{
    "symbol": "BTCUSDT",
    "orderId": 2869718120,
    "clientOrderId": "G9Wqjy1RisSjYLDhR4rzYi",
    "price": "0",
    "origQty": "0.152",
    "executedQty": "0",
    "cumQuote": "0",
    "reduceOnly": false,
    "status": "NEW",
    "stopPrice": "0",
    "timeInForce": "GTC",
    "type": "MARKET",
    "side": "BUY",
    "updateTime": 1636705431064,
    "workingType": "CONTRACT_PRICE",
    "activatePrice": "",
    "priceRate": "",
    "avgPrice": "0.00000",
    "positionSide": "BOTH",
    "closePosition": false,
    "priceProtect": false
}

Examples for LIMIT and STOP_MARKET are in the postman collection.

Issue with Buy limit and Take Profit

If order is not filled, take profit might be triggered immediately. Fill or kill. If order not filled, don't execute

Issue with Binance server time synchronization

Sometimes the system time can fall out of sync with the binance server time, for example:

--- FAIL: TestChangeSymbolLeverage (36.89s)
    leverage_test.go:68: <APIError> code=-1021, msg=Timestamp for this request is outside of the recvWindow.

There is a fix implemented for this in the go-binance sdk: adshao/go-binance#127

This would require querying the binance server time once when creating a client and using as a time offset it in each request.

Since it will eventually get out of sync again, we will retry a failed request (one with error code -1021) with the updated time offset after quering the binance server time.