2020-10-01 08:48:08 +00:00
|
|
|
package max
|
|
|
|
|
|
|
|
import (
|
2022-01-02 04:20:38 +00:00
|
|
|
"encoding/json"
|
2022-05-25 12:34:25 +00:00
|
|
|
"fmt"
|
2020-11-17 06:24:26 +00:00
|
|
|
"strings"
|
|
|
|
|
2020-10-01 08:48:08 +00:00
|
|
|
"github.com/pkg/errors"
|
2022-05-27 11:20:45 +00:00
|
|
|
log "github.com/sirupsen/logrus"
|
2020-10-01 08:48:08 +00:00
|
|
|
"github.com/valyala/fastjson"
|
2020-10-03 03:11:59 +00:00
|
|
|
|
2020-11-10 06:19:33 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
2020-10-11 08:46:15 +00:00
|
|
|
"github.com/c9s/bbgo/pkg/types"
|
2020-10-01 08:48:08 +00:00
|
|
|
)
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
type BaseEvent struct {
|
2020-10-02 13:29:56 +00:00
|
|
|
Event string `json:"e"`
|
|
|
|
Timestamp int64 `json:"T"`
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type OrderUpdate struct {
|
2020-11-10 06:19:33 +00:00
|
|
|
Event string `json:"e"`
|
|
|
|
ID uint64 `json:"i"`
|
|
|
|
Side string `json:"sd"`
|
2020-10-29 14:53:04 +00:00
|
|
|
OrderType OrderType `json:"ot"`
|
2020-10-01 09:08:12 +00:00
|
|
|
|
2022-05-27 11:20:45 +00:00
|
|
|
Price fixedpoint.Value `json:"p"`
|
|
|
|
StopPrice fixedpoint.Value `json:"sp"`
|
2020-10-01 09:08:12 +00:00
|
|
|
|
2022-05-27 11:20:45 +00:00
|
|
|
Volume fixedpoint.Value `json:"v"`
|
|
|
|
AveragePrice fixedpoint.Value `json:"ap"`
|
|
|
|
State OrderState `json:"S"`
|
|
|
|
Market string `json:"M"`
|
2020-10-01 08:48:08 +00:00
|
|
|
|
2022-05-27 11:20:45 +00:00
|
|
|
RemainingVolume fixedpoint.Value `json:"rv"`
|
|
|
|
ExecutedVolume fixedpoint.Value `json:"ev"`
|
2020-10-01 08:48:08 +00:00
|
|
|
|
|
|
|
TradesCount int64 `json:"tc"`
|
|
|
|
|
2021-03-22 09:25:43 +00:00
|
|
|
GroupID uint32 `json:"gi"`
|
2020-10-01 08:48:08 +00:00
|
|
|
ClientOID string `json:"ci"`
|
|
|
|
CreatedAtMs int64 `json:"T"`
|
2022-05-25 11:52:29 +00:00
|
|
|
UpdateTime int64 `json:"TU"`
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
type OrderUpdateEvent struct {
|
|
|
|
BaseEvent
|
|
|
|
|
|
|
|
Orders []OrderUpdate `json:"o"`
|
|
|
|
}
|
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
func parseOrderUpdateEvent(v *fastjson.Value) *OrderUpdateEvent {
|
|
|
|
var e OrderUpdateEvent
|
2020-10-01 09:05:46 +00:00
|
|
|
e.Event = string(v.GetStringBytes("e"))
|
|
|
|
e.Timestamp = v.GetInt64("T")
|
|
|
|
|
|
|
|
for _, ov := range v.GetArray("o") {
|
2022-05-27 11:20:45 +00:00
|
|
|
var o = ov.String()
|
|
|
|
var u OrderUpdate
|
|
|
|
if err := json.Unmarshal([]byte(o), &u); err != nil {
|
|
|
|
log.WithError(err).Error("parse error")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
e.Orders = append(e.Orders, u)
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
return &e
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
type OrderSnapshotEvent struct {
|
|
|
|
BaseEvent
|
2020-10-01 08:48:08 +00:00
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
Orders []OrderUpdate `json:"o"`
|
2020-10-01 09:05:46 +00:00
|
|
|
}
|
2020-10-01 08:48:08 +00:00
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
func parserOrderSnapshotEvent(v *fastjson.Value) *OrderSnapshotEvent {
|
|
|
|
var e OrderSnapshotEvent
|
2020-10-01 09:05:46 +00:00
|
|
|
e.Event = string(v.GetStringBytes("e"))
|
|
|
|
e.Timestamp = v.GetInt64("T")
|
2020-10-01 08:48:08 +00:00
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
for _, ov := range v.GetArray("o") {
|
2022-05-27 11:20:45 +00:00
|
|
|
var o = ov.String()
|
|
|
|
var u OrderUpdate
|
|
|
|
if err := json.Unmarshal([]byte(o), &u); err != nil {
|
|
|
|
log.WithError(err).Error("parse error")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
e.Orders = append(e.Orders, u)
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
return &e
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type TradeUpdate struct {
|
|
|
|
ID uint64 `json:"i"`
|
|
|
|
Side string `json:"sd"`
|
|
|
|
Price string `json:"p"`
|
|
|
|
Volume string `json:"v"`
|
|
|
|
Market string `json:"M"`
|
|
|
|
|
|
|
|
Fee string `json:"f"`
|
|
|
|
FeeCurrency string `json:"fc"`
|
|
|
|
Timestamp int64 `json:"T"`
|
2022-05-25 11:52:29 +00:00
|
|
|
UpdateTime int64 `json:"TU"`
|
2020-10-01 08:48:08 +00:00
|
|
|
|
|
|
|
OrderID uint64 `json:"oi"`
|
2020-10-19 14:23:49 +00:00
|
|
|
|
|
|
|
Maker bool `json:"m"`
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
func parseTradeUpdate(v *fastjson.Value) TradeUpdate {
|
2020-10-01 08:48:08 +00:00
|
|
|
return TradeUpdate{
|
|
|
|
ID: v.GetUint64("i"),
|
|
|
|
Side: string(v.GetStringBytes("sd")),
|
|
|
|
Price: string(v.GetStringBytes("p")),
|
|
|
|
Volume: string(v.GetStringBytes("v")),
|
|
|
|
Market: string(v.GetStringBytes("M")),
|
|
|
|
Fee: string(v.GetStringBytes("f")),
|
|
|
|
FeeCurrency: string(v.GetStringBytes("fc")),
|
|
|
|
Timestamp: v.GetInt64("T"),
|
2022-05-25 11:52:29 +00:00
|
|
|
UpdateTime: v.GetInt64("TU"),
|
2020-10-01 08:48:08 +00:00
|
|
|
OrderID: v.GetUint64("oi"),
|
2020-10-19 14:23:49 +00:00
|
|
|
Maker: v.GetBool("m"),
|
2020-10-01 09:05:46 +00:00
|
|
|
}
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
type TradeUpdateEvent struct {
|
|
|
|
BaseEvent
|
|
|
|
|
|
|
|
Trades []TradeUpdate `json:"t"`
|
|
|
|
}
|
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
func parseTradeUpdateEvent(v *fastjson.Value) *TradeUpdateEvent {
|
|
|
|
var e TradeUpdateEvent
|
2020-10-01 09:05:46 +00:00
|
|
|
e.Event = string(v.GetStringBytes("e"))
|
|
|
|
e.Timestamp = v.GetInt64("T")
|
|
|
|
|
|
|
|
for _, tv := range v.GetArray("t") {
|
|
|
|
e.Trades = append(e.Trades, parseTradeUpdate(tv))
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
return &e
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type TradeSnapshot []TradeUpdate
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
type TradeSnapshotEvent struct {
|
|
|
|
BaseEvent
|
2020-10-01 08:48:08 +00:00
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
Trades []TradeUpdate `json:"t"`
|
|
|
|
}
|
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
func parseTradeSnapshotEvent(v *fastjson.Value) *TradeSnapshotEvent {
|
|
|
|
var e TradeSnapshotEvent
|
2020-10-01 09:05:46 +00:00
|
|
|
e.Event = string(v.GetStringBytes("e"))
|
|
|
|
e.Timestamp = v.GetInt64("T")
|
|
|
|
|
|
|
|
for _, tv := range v.GetArray("t") {
|
|
|
|
e.Trades = append(e.Trades, parseTradeUpdate(tv))
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 13:29:56 +00:00
|
|
|
return &e
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 02:10:59 +00:00
|
|
|
type BalanceMessage struct {
|
2022-01-02 04:20:38 +00:00
|
|
|
Currency string `json:"cu"`
|
|
|
|
Available fixedpoint.Value `json:"av"`
|
|
|
|
Locked fixedpoint.Value `json:"l"`
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-03 03:11:59 +00:00
|
|
|
func (m *BalanceMessage) Balance() (*types.Balance, error) {
|
|
|
|
return &types.Balance{
|
2020-11-17 06:24:26 +00:00
|
|
|
Currency: strings.ToUpper(m.Currency),
|
2022-01-02 04:20:38 +00:00
|
|
|
Locked: m.Locked,
|
|
|
|
Available: m.Available,
|
2020-10-03 03:11:59 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
type AccountUpdateEvent struct {
|
|
|
|
BaseEvent
|
2020-10-02 02:10:59 +00:00
|
|
|
Balances []BalanceMessage `json:"B"`
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 09:05:46 +00:00
|
|
|
type AccountSnapshotEvent struct {
|
|
|
|
BaseEvent
|
2020-10-02 02:10:59 +00:00
|
|
|
Balances []BalanceMessage `json:"B"`
|
2020-10-01 09:05:46 +00:00
|
|
|
}
|
|
|
|
|
2022-01-02 04:20:38 +00:00
|
|
|
func parseAuthEvent(v *fastjson.Value) (*AuthEvent, error) {
|
|
|
|
var e AuthEvent
|
|
|
|
var err = json.Unmarshal([]byte(v.String()), &e)
|
|
|
|
return &e, err
|
2020-10-01 09:05:46 +00:00
|
|
|
}
|
|
|
|
|
2022-05-25 12:06:17 +00:00
|
|
|
type ADRatio struct {
|
|
|
|
ADRatio fixedpoint.Value `json:"ad"`
|
|
|
|
AssetInUSDT fixedpoint.Value `json:"as"`
|
|
|
|
DebtInUSDT fixedpoint.Value `json:"db"`
|
|
|
|
IndexPrices []struct {
|
|
|
|
Market string `json:"M"`
|
|
|
|
Price fixedpoint.Value `json:"p"`
|
|
|
|
} `json:"idxp"`
|
|
|
|
TU types.MillisecondTimestamp `json:"TU"`
|
|
|
|
}
|
|
|
|
|
2022-05-25 12:34:25 +00:00
|
|
|
func (r *ADRatio) String() string {
|
|
|
|
return fmt.Sprintf("ADRatio: %v Asset: %v USDT, Debt: %v USDT (Mark Prices: %+v)", r.ADRatio, r.AssetInUSDT, r.DebtInUSDT, r.IndexPrices)
|
|
|
|
}
|
2022-05-25 12:12:16 +00:00
|
|
|
|
2022-05-25 12:34:25 +00:00
|
|
|
type ADRatioEvent struct {
|
|
|
|
ADRatio ADRatio `json:"ad"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseADRatioEvent(v *fastjson.Value) (*ADRatioEvent, error) {
|
|
|
|
o := v.String()
|
|
|
|
e := ADRatioEvent{}
|
|
|
|
err := json.Unmarshal([]byte(o), &e)
|
|
|
|
return &e, err
|
2022-05-25 12:12:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Debt struct {
|
|
|
|
Currency string `json:"cu"`
|
|
|
|
DebtPrincipal fixedpoint.Value `json:"dbp"`
|
|
|
|
DebtInterest fixedpoint.Value `json:"dbi"`
|
|
|
|
TU types.MillisecondTimestamp `json:"TU"`
|
|
|
|
}
|
|
|
|
|
2022-05-26 10:07:17 +00:00
|
|
|
func (d *Debt) String() string {
|
|
|
|
return fmt.Sprintf("Debt %s %v (Interest %v)", d.Currency, d.DebtPrincipal, d.DebtInterest)
|
|
|
|
}
|
|
|
|
|
2022-05-25 12:34:25 +00:00
|
|
|
type DebtEvent struct {
|
|
|
|
Debts []Debt `json:"db"`
|
|
|
|
}
|
2022-05-25 12:12:16 +00:00
|
|
|
|
2022-05-25 12:34:25 +00:00
|
|
|
func parseDebts(v *fastjson.Value) (*DebtEvent, error) {
|
|
|
|
o := v.String()
|
|
|
|
e := DebtEvent{}
|
|
|
|
err := json.Unmarshal([]byte(o), &e)
|
|
|
|
return &e, err
|
2022-05-25 12:06:17 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 04:43:14 +00:00
|
|
|
func ParseUserEvent(v *fastjson.Value) (interface{}, error) {
|
2020-10-01 09:05:46 +00:00
|
|
|
eventType := string(v.GetStringBytes("e"))
|
|
|
|
switch eventType {
|
2022-05-25 06:42:45 +00:00
|
|
|
case "order_snapshot", "mwallet_order_snapshot":
|
2020-10-01 09:05:46 +00:00
|
|
|
return parserOrderSnapshotEvent(v), nil
|
|
|
|
|
2022-05-25 06:42:45 +00:00
|
|
|
case "order_update", "mwallet_order_update":
|
2020-10-01 09:05:46 +00:00
|
|
|
return parseOrderUpdateEvent(v), nil
|
|
|
|
|
2022-05-25 06:42:45 +00:00
|
|
|
case "trade_snapshot", "mwallet_trade_snapshot":
|
2020-10-01 09:05:46 +00:00
|
|
|
return parseTradeSnapshotEvent(v), nil
|
|
|
|
|
2022-05-25 06:42:45 +00:00
|
|
|
case "trade_update", "mwallet_trade_update":
|
2020-10-01 09:05:46 +00:00
|
|
|
return parseTradeUpdateEvent(v), nil
|
|
|
|
|
2022-05-25 12:06:51 +00:00
|
|
|
case "ad_ratio_snapshot", "ad_ratio_update":
|
2022-05-25 12:34:25 +00:00
|
|
|
return parseADRatioEvent(v)
|
2022-05-25 12:06:17 +00:00
|
|
|
|
2022-05-25 12:12:16 +00:00
|
|
|
case "borrowing_snapshot", "borrowing_update":
|
|
|
|
return parseDebts(v)
|
|
|
|
|
2022-05-25 06:42:45 +00:00
|
|
|
case "account_snapshot", "account_update", "mwallet_account_snapshot", "mwallet_account_update":
|
2022-01-02 04:20:38 +00:00
|
|
|
var e AccountUpdateEvent
|
2022-05-25 12:34:25 +00:00
|
|
|
o := v.String()
|
|
|
|
err := json.Unmarshal([]byte(o), &e)
|
2022-01-02 04:20:38 +00:00
|
|
|
return &e, err
|
2020-10-01 09:05:46 +00:00
|
|
|
|
|
|
|
case "error":
|
2020-10-02 04:43:14 +00:00
|
|
|
logger.Errorf("error %s", v.MarshalTo(nil))
|
2020-10-01 09:05:46 +00:00
|
|
|
}
|
|
|
|
|
2020-10-02 04:43:14 +00:00
|
|
|
return nil, errors.Wrapf(ErrMessageTypeNotSupported, "private message %s", v.MarshalTo(nil))
|
2020-10-01 08:48:08 +00:00
|
|
|
}
|