Parse UserData websocket events
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.
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))
}
Why don't we merge this? Could you make a PR?
If you don't mind, I'll restructure them in an appropriate place and make a PR.
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.