go-binance icon indicating copy to clipboard operation
go-binance copied to clipboard

Parse UserData websocket events

Open Denton-L opened this issue 5 years ago • 4 comments

Currently, WsFutureUserDataServe() and WsUserDataServe() both accept generic WsHandler types. However, the response events are known: https://binance-docs.github.io/apidocs/spot/en/#payload-account-update and https://binance-docs.github.io/apidocs/futures/en/#event-user-data-stream-expired

We should parse the data into big Go structs which contain every possible field. It will be up to the users to disambiguate based on the event type field.

Denton-L avatar Nov 29 '20 06:11 Denton-L

This is the struct that I am planning on using for futures events:

package binance

import (
	"encoding/json"

	"github.com/adshao/go-binance/v2"
	"github.com/adshao/go-binance/v2/futures"
)

type FutureUserDataEventType string
type AccountUpdateEventType string

type ExecutionType string
type OrderStatusType string

const (
	FutureUserDataEventTypeListenKeyExpired FutureUserDataEventType = "listenKeyExpired"
	FutureUserDataEventTypeMarginCall       FutureUserDataEventType = "MARGIN_CALL"
	FutureUserDataEventTypeAccountUpdate    FutureUserDataEventType = "ACCOUNT_UPDATE"
	FutureUserDataEventTypeOrderTradeUpdate FutureUserDataEventType = "ORDER_TRADE_UPDATE"

	AccountUpdateEventTypeDeposit             AccountUpdateEventType = "DEPOSIT"
	AccountUpdateEventTypeWithdraw            AccountUpdateEventType = "WITHDRAW"
	AccountUpdateEventTypeOrder               AccountUpdateEventType = "ORDER"
	AccountUpdateEventTypeFundingFee          AccountUpdateEventType = "FUNDING_FEE"
	AccountUpdateEventTypeWithdrawReject      AccountUpdateEventType = "WITHDRAW_REJECT"
	AccountUpdateEventTypeAdjustment          AccountUpdateEventType = "ADJUSTMENT"
	AccountUpdateEventTypeInsuranceClear      AccountUpdateEventType = "INSURANCE_CLEAR"
	AccountUpdateEventTypeAdminDeposit        AccountUpdateEventType = "ADMIN_DEPOSIT"
	AccountUpdateEventTypeAdminWithdraw       AccountUpdateEventType = "ADMIN_WITHDRAW"
	AccountUpdateEventTypeMarginTransfer      AccountUpdateEventType = "MARGIN_TRANSFER"
	AccountUpdateEventTypeMarginTypeChange    AccountUpdateEventType = "MARGIN_TYPE_CHANGE"
	AccountUpdateEventTypeAssetTransfer       AccountUpdateEventType = "ASSET_TRANSFER"
	AccountUpdateEventTypeOptionsPremiumFee   AccountUpdateEventType = "OPTIONS_PREMIUM_FEE"
	AccountUpdateEventTypeOptionsSettleProfit AccountUpdateEventType = "OPTIONS_SETTLE_PROFIT"

	ExecutionTypeNew         ExecutionType = "NEW"
	ExecutionTypePartialFill ExecutionType = "PARTIAL_FILL"
	ExecutionTypeFill        ExecutionType = "FILL"
	ExecutionTypeCanceled    ExecutionType = "CANCELED"
	ExecutionTypeCalculated  ExecutionType = "CALCULATED"
	ExecutionTypeExpired     ExecutionType = "EXPIRED"
	ExecutionTypeTrade       ExecutionType = "TRADE"

	OrderStatusTypeNew             OrderStatusType = "NEW"
	OrderStatusTypePartiallyFilled OrderStatusType = "PARTIALLY_FILLED"
	OrderStatusTypeFilled          OrderStatusType = "FILLED"
	OrderStatusTypeCanceled        OrderStatusType = "CANCELED"
	OrderStatusTypeExpired         OrderStatusType = "EXPIRED"
	OrderStatusTypeNewInsurance    OrderStatusType = "NEW_INSURANCE"
	OrderStatusTypeNewAdl          OrderStatusType = "NEW_ADL"
)

type WsFutureUserData struct {
	EventType FutureUserDataEventType `json:"e"`
	Time      int64                   `json:"E"`

	CrossWalletBalance string `json:"cw"`
	Positions          []struct {
		Symbol                    string                   `json:"s"`
		Side                      futures.PositionSideType `json:"ps"`
		Amount                    string                   `json:"pa"`
		MarginType                futures.MarginType       `json:"mt"`
		IsolatedWallet            string                   `json:"iw"`
		MarkPrice                 string                   `json:"mp"`
		UnrealizedPnL             string                   `json:"up"`
		MaintenanceMarginRequired string                   `json:"mm"`
	} `json:"p"`

	TransactionTime int64 `json:"T"`

	AccountUpdate struct {
		Event    AccountUpdateEventType `json:"m"`
		Balances []struct {
			Asset              string `json:"a"`
			Balance            string `json:"wb"`
			CrossWalletBalance string `json:"cw"`
		} `json:"B"`
		Positions []struct {
			Symbol              string                   `json:"s"`
			PositionAmt         string                   `json:"pa"`
			EntryPrice          string                   `json:"ep"`
			AccumulatedRealized string                   `json:"cr"`
			UnRealizedProfit    string                   `json:"up"`
			MarginType          string                   `json:"mt"`
			IsolatedWallet      string                   `json:"iw"`
			PositionSide        futures.PositionSideType `json:""ps"`
		} `json:"P"`
	} `json:"a"`

	OrderTradeUpdate struct {
		Symbol               string                   `json:"s"`
		ClientOrderID        string                   `json:"c"`
		Side                 futures.SideType         `json:"S"`
		Type                 futures.OrderType        `json:"o"`
		TimeInForce          futures.TimeInForceType  `json:"f"`
		OrigQuantity         string                   `json:"q"`
		Price                string                   `json:"p"`
		AvgPrice             string                   `json:"ap"`
		StopPrice            string                   `json:"sp"`
		ExecutionType        ExecutionType            `json:"x"`
		Status               OrderStatusType          `json:"X"`
		OrderID              int64                    `json:"i"`
		LastFilledQty        string                   `json:"l"`
		AccumulatedFilledQty string                   `json:"z"`
		FilledPrice          string                   `json:"L"`
		CommissionAsset      string                   `json:"N"`
		Commission           string                   `json:"n"`
		TradeTime            int64                    `json:"T"`
		TradeId              int64                    `json:"t"`
		BidsNotional         string                   `json:"b"`
		AsksNotional         string                   `json:"a"`
		IsMaker              bool                     `json:"m"`
		ReduceOnly           bool                     `json:"R"`
		WorkingType          futures.WorkingType      `json:"wt"`
		OriginalType         futures.OrderType        `json:"ot"`
		PositionSide         futures.PositionSideType `json:"ps"`
		ClosePosition        bool                     `json:"cp"`
		ActivatePrice        string                   `json:"AP"`
		CallbackRate         string                   `json:"cr"`
		RealizedProfit       string                   `json:"rp"`
	} `json:"o"`
}

type WsFutureUserDataHandler func(event *WsFutureUserData)

func WsFutureUserDataServe(listenKey string, handler WsFutureUserDataHandler, errHandler futures.ErrHandler) (doneC, stopC chan struct{}, err error) {
	wsHandler := func(message []byte) {
		event := new(WsFutureUserData)
		err := json.Unmarshal(message, event)
		if err != nil {
			errHandler(err)
			return
		}
		handler(event)
	}

	return binance.WsFutureUserDataServe(listenKey, wsHandler, binance.ErrHandler(errHandler))
}

Denton-L avatar Nov 30 '20 01:11 Denton-L

Why don't we merge this? Could you make a PR?

dohki avatar Jan 26 '21 05:01 dohki

If you don't mind, I'll restructure them in an appropriate place and make a PR.

dohki avatar Jan 26 '21 06:01 dohki

Yes, please do. I don't have the time to push this all the way to the finish line so I'd love it if someone took over.

Denton-L avatar Jan 26 '21 06:01 Denton-L