mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
Merge remote-tracking branch 'origin/v1.50'
This commit is contained in:
commit
afc5dbb951
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
|
@ -4,7 +4,9 @@ on:
|
|||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches:
|
||||
- "main"
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
@ -288,36 +288,19 @@ func convertWebSocketTrade(t max.TradeUpdate) (*types.Trade, error) {
|
|||
// trade time
|
||||
mts := time.Unix(0, t.Timestamp*int64(time.Millisecond))
|
||||
|
||||
price, err := fixedpoint.NewFromString(t.Price)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
quantity, err := fixedpoint.NewFromString(t.Volume)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
quoteQuantity := price.Mul(quantity)
|
||||
|
||||
fee, err := fixedpoint.NewFromString(t.Fee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.Trade{
|
||||
ID: t.ID,
|
||||
OrderID: t.OrderID,
|
||||
Symbol: toGlobalSymbol(t.Market),
|
||||
Exchange: types.ExchangeMax,
|
||||
Price: price,
|
||||
Quantity: quantity,
|
||||
Price: t.Price,
|
||||
Quantity: t.Volume,
|
||||
Side: side,
|
||||
IsBuyer: side == types.SideTypeBuy,
|
||||
IsMaker: t.Maker,
|
||||
Fee: fee,
|
||||
Fee: t.Fee,
|
||||
FeeCurrency: toGlobalCurrency(t.FeeCurrency),
|
||||
QuoteQuantity: quoteQuantity,
|
||||
QuoteQuantity: t.Price.Mul(t.Volume),
|
||||
Time: types.Time(mts),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -94,74 +94,46 @@ func parserOrderSnapshotEvent(v *fastjson.Value) *OrderSnapshotEvent {
|
|||
}
|
||||
|
||||
type TradeUpdate struct {
|
||||
ID uint64 `json:"i"`
|
||||
Side string `json:"sd"`
|
||||
Price string `json:"p"`
|
||||
Volume string `json:"v"`
|
||||
Market string `json:"M"`
|
||||
ID uint64 `json:"i"`
|
||||
Side string `json:"sd"`
|
||||
Price fixedpoint.Value `json:"p"`
|
||||
Volume fixedpoint.Value `json:"v"`
|
||||
Market string `json:"M"`
|
||||
|
||||
Fee string `json:"f"`
|
||||
FeeCurrency string `json:"fc"`
|
||||
Timestamp int64 `json:"T"`
|
||||
UpdateTime int64 `json:"TU"`
|
||||
Fee fixedpoint.Value `json:"f"`
|
||||
FeeCurrency string `json:"fc"`
|
||||
FeeDiscounted bool `json:"fd"`
|
||||
|
||||
Timestamp int64 `json:"T"`
|
||||
UpdateTime int64 `json:"TU"`
|
||||
|
||||
OrderID uint64 `json:"oi"`
|
||||
|
||||
Maker bool `json:"m"`
|
||||
}
|
||||
|
||||
func parseTradeUpdate(v *fastjson.Value) TradeUpdate {
|
||||
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"),
|
||||
UpdateTime: v.GetInt64("TU"),
|
||||
OrderID: v.GetUint64("oi"),
|
||||
Maker: v.GetBool("m"),
|
||||
}
|
||||
}
|
||||
|
||||
type TradeUpdateEvent struct {
|
||||
BaseEvent
|
||||
|
||||
Trades []TradeUpdate `json:"t"`
|
||||
}
|
||||
|
||||
func parseTradeUpdateEvent(v *fastjson.Value) *TradeUpdateEvent {
|
||||
var e TradeUpdateEvent
|
||||
e.Event = string(v.GetStringBytes("e"))
|
||||
e.Timestamp = v.GetInt64("T")
|
||||
|
||||
for _, tv := range v.GetArray("t") {
|
||||
e.Trades = append(e.Trades, parseTradeUpdate(tv))
|
||||
}
|
||||
|
||||
return &e
|
||||
}
|
||||
|
||||
type TradeSnapshot []TradeUpdate
|
||||
|
||||
type TradeSnapshotEvent struct {
|
||||
BaseEvent
|
||||
|
||||
Trades []TradeUpdate `json:"t"`
|
||||
}
|
||||
|
||||
func parseTradeSnapshotEvent(v *fastjson.Value) *TradeSnapshotEvent {
|
||||
func parseTradeUpdateEvent(v *fastjson.Value) (*TradeUpdateEvent, error) {
|
||||
jsonBytes := v.String()
|
||||
var e TradeUpdateEvent
|
||||
err := json.Unmarshal([]byte(jsonBytes), &e)
|
||||
return &e, err
|
||||
}
|
||||
|
||||
func parseTradeSnapshotEvent(v *fastjson.Value) (*TradeSnapshotEvent, error) {
|
||||
jsonBytes := v.String()
|
||||
var e TradeSnapshotEvent
|
||||
e.Event = string(v.GetStringBytes("e"))
|
||||
e.Timestamp = v.GetInt64("T")
|
||||
|
||||
for _, tv := range v.GetArray("t") {
|
||||
e.Trades = append(e.Trades, parseTradeUpdate(tv))
|
||||
}
|
||||
|
||||
return &e
|
||||
err := json.Unmarshal([]byte(jsonBytes), &e)
|
||||
return &e, err
|
||||
}
|
||||
|
||||
type BalanceMessage struct {
|
||||
|
@ -252,10 +224,10 @@ func ParseUserEvent(v *fastjson.Value) (interface{}, error) {
|
|||
return parseOrderUpdateEvent(v), nil
|
||||
|
||||
case "trade_snapshot", "mwallet_trade_snapshot":
|
||||
return parseTradeSnapshotEvent(v), nil
|
||||
return parseTradeSnapshotEvent(v)
|
||||
|
||||
case "trade_update", "mwallet_trade_update":
|
||||
return parseTradeUpdateEvent(v), nil
|
||||
return parseTradeUpdateEvent(v)
|
||||
|
||||
case "ad_ratio_snapshot", "ad_ratio_update":
|
||||
return parseADRatioEvent(v)
|
||||
|
|
45
pkg/exchange/max/maxapi/userdata_test.go
Normal file
45
pkg/exchange/max/maxapi/userdata_test.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package max
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/valyala/fastjson"
|
||||
)
|
||||
|
||||
func Test_parseTradeSnapshotEvent(t *testing.T) {
|
||||
fv, err := fastjson.Parse(`{
|
||||
"c": "user",
|
||||
"e": "trade_snapshot",
|
||||
"t": [{
|
||||
"i": 68444,
|
||||
"p": "21499.0",
|
||||
"v": "0.2658",
|
||||
"M": "ethtwd",
|
||||
"T": 1521726960357,
|
||||
"sd": "bid",
|
||||
"f": "3.2",
|
||||
"fc": "twd",
|
||||
"fd": false,
|
||||
"m": true,
|
||||
"oi": 7423,
|
||||
"ci": "client-oid-1",
|
||||
"gi": 123
|
||||
}],
|
||||
"T": 1591786735192
|
||||
}`)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, fv)
|
||||
|
||||
evt, err := parseTradeSnapshotEvent(fv)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, evt)
|
||||
assert.Equal(t, "trade_snapshot", evt.Event)
|
||||
assert.Equal(t, int64(1591786735192), evt.Timestamp)
|
||||
assert.Equal(t, 1, len(evt.Trades))
|
||||
assert.Equal(t, "bid", evt.Trades[0].Side)
|
||||
assert.Equal(t, "ethtwd", evt.Trades[0].Market)
|
||||
assert.Equal(t, int64(1521726960357), evt.Trades[0].Timestamp)
|
||||
assert.Equal(t, "3.2", evt.Trades[0].Fee.String())
|
||||
assert.Equal(t, "twd", evt.Trades[0].FeeCurrency)
|
||||
}
|
|
@ -35,28 +35,48 @@ type Grid struct {
|
|||
|
||||
type Pin fixedpoint.Value
|
||||
|
||||
// filterPrice filters price with the given precision
|
||||
func filterPrice(p fixedpoint.Value, prec int) fixedpoint.Value {
|
||||
var pow10 = math.Pow10(prec)
|
||||
pp := math.Round(p.Float64()*pow10*10.0) / 10.0
|
||||
pp = math.Trunc(pp) / pow10
|
||||
|
||||
pps := strconv.FormatFloat(pp, 'f', prec, 64)
|
||||
price := fixedpoint.MustNewFromString(pps)
|
||||
return price
|
||||
}
|
||||
|
||||
func removeDuplicatedPins(pins []Pin) []Pin {
|
||||
var buckets = map[string]struct{}{}
|
||||
var out []Pin
|
||||
|
||||
for _, pin := range pins {
|
||||
p := fixedpoint.Value(pin)
|
||||
|
||||
if _, exists := buckets[p.String()]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, pin)
|
||||
buckets[p.String()] = struct{}{}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func calculateArithmeticPins(lower, upper, spread, tickSize fixedpoint.Value) []Pin {
|
||||
var pins []Pin
|
||||
|
||||
// tickSize number is like 0.01, 0.1, 0.001
|
||||
var ts = tickSize.Float64()
|
||||
var prec = int(math.Round(math.Log10(ts) * -1.0))
|
||||
var pow10 = math.Pow10(prec)
|
||||
for p := lower; p.Compare(upper.Sub(spread)) <= 0; p = p.Add(spread) {
|
||||
pp := math.Round(p.Float64()*pow10*10.0) / 10.0
|
||||
pp = math.Trunc(pp) / pow10
|
||||
|
||||
pps := strconv.FormatFloat(pp, 'f', prec, 64)
|
||||
price := fixedpoint.MustNewFromString(pps)
|
||||
price := filterPrice(p, prec)
|
||||
pins = append(pins, Pin(price))
|
||||
}
|
||||
|
||||
// this makes sure there is no error at the upper price
|
||||
pp := math.Round(upper.Float64()*pow10*10.0) / 10.0
|
||||
pp = math.Trunc(pp) / pow10
|
||||
|
||||
pps := strconv.FormatFloat(pp, 'f', prec, 64)
|
||||
upperPrice := fixedpoint.MustNewFromString(pps)
|
||||
upperPrice := filterPrice(upper, prec)
|
||||
pins = append(pins, Pin(upperPrice))
|
||||
|
||||
return pins
|
||||
|
@ -94,7 +114,7 @@ func (g *Grid) CalculateGeometricPins() {
|
|||
return nil
|
||||
}
|
||||
|
||||
g.addPins(g.calculator())
|
||||
g.addPins(removeDuplicatedPins(g.calculator()))
|
||||
}
|
||||
|
||||
func (g *Grid) CalculateArithmeticPins() {
|
||||
|
|
|
@ -214,3 +214,54 @@ func Test_calculateArithmeticPins(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_filterPrice1(t *testing.T) {
|
||||
type args struct {
|
||||
p fixedpoint.Value
|
||||
prec int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "basic",
|
||||
args: args{p: number("31.2222"), prec: 3},
|
||||
want: "31.222",
|
||||
},
|
||||
{
|
||||
name: "roundup",
|
||||
args: args{p: number("31.22295"), prec: 3},
|
||||
want: "31.223",
|
||||
},
|
||||
{
|
||||
name: "roundup2",
|
||||
args: args{p: number("31.22290"), prec: 3},
|
||||
want: "31.222",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rst := filterPrice(tt.args.p, tt.args.prec)
|
||||
assert.Equalf(t, tt.want, rst.String(), "filterPrice(%v, %v)", tt.args.p, tt.args.prec)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_removeDuplicatedPins(t *testing.T) {
|
||||
pins := []Pin{
|
||||
Pin(number("31.222")),
|
||||
Pin(number("31.222")),
|
||||
Pin(number("31.223")),
|
||||
Pin(number("31.224")),
|
||||
Pin(number("31.224")),
|
||||
}
|
||||
out := removeDuplicatedPins(pins)
|
||||
assert.Equal(t, []Pin{
|
||||
Pin(number("31.222")),
|
||||
Pin(number("31.223")),
|
||||
Pin(number("31.224")),
|
||||
}, out)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user