mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
first max token market maker
This commit is contained in:
parent
cd80a68e50
commit
a8c972dfb1
|
@ -32,20 +32,20 @@ type OrderService struct {
|
||||||
type Order struct {
|
type Order struct {
|
||||||
ID uint64 `json:"id,omitempty" db:"exchange_id"`
|
ID uint64 `json:"id,omitempty" db:"exchange_id"`
|
||||||
Side string `json:"side" db:"side"`
|
Side string `json:"side" db:"side"`
|
||||||
OrderType string `json:"ord_type" db:"order_type"`
|
OrderType string `json:"ord_type,omitempty" db:"order_type"`
|
||||||
Price string `json:"price" db:"price"`
|
Price string `json:"price" db:"price"`
|
||||||
AveragePrice string `json:"avg_price,omitempty" db:"average_price"`
|
AveragePrice string `json:"avg_price,omitempty" db:"average_price"`
|
||||||
State string `json:"state,omitempty" db:"state"`
|
State string `json:"state,omitempty" db:"state"`
|
||||||
Market string `json:"market" db:"market"`
|
Market string `json:"market,omitempty" db:"market"`
|
||||||
Volume string `json:"volume" db:"volume"`
|
Volume string `json:"volume" db:"volume"`
|
||||||
RemainingVolume string `json:"remaining_volume,omitempty" db:"remaining_volume"`
|
RemainingVolume string `json:"remaining_volume,omitempty" db:"remaining_volume"`
|
||||||
ExecutedVolume string `json:"executed_volume,omitempty" db:"executed_volume"`
|
ExecutedVolume string `json:"executed_volume,omitempty" db:"executed_volume"`
|
||||||
TradesCount int64 `json:"trades_count,omitempty" db:"trades_count"`
|
TradesCount int64 `json:"trades_count,omitempty" db:"trades_count"`
|
||||||
GroupID int64 `json:"group_id,omitempty" db:"group_id"`
|
GroupID int64 `json:"group_id,omitempty" db:"group_id"`
|
||||||
ClientOID string `json:"client_oid,omitempty" db:"client_oid"`
|
ClientOID string `json:"client_oid,omitempty" db:"client_oid"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `json:"-" db:"created_at"`
|
||||||
CreatedAtMs int64 `json:"created_at_in_ms,omitempty"`
|
CreatedAtMs int64 `json:"created_at_in_ms,omitempty"`
|
||||||
InsertedAt time.Time `db:"inserted_at"`
|
InsertedAt time.Time `json:"-" db:"inserted_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// All returns all orders for the authenticated account.
|
// All returns all orders for the authenticated account.
|
||||||
|
@ -182,20 +182,22 @@ func (s *OrderService) Get(orderID uint64) (*Order, error) {
|
||||||
// Create multiple order in a single request
|
// Create multiple order in a single request
|
||||||
func (s *OrderService) CreateMulti(market string, orders []Order) ([]Order, error) {
|
func (s *OrderService) CreateMulti(market string, orders []Order) ([]Order, error) {
|
||||||
var returnOrders []Order
|
var returnOrders []Order
|
||||||
req, err := s.client.newAuthenticatedRequest("POST", "v2/orders/multi", map[string]interface{}{
|
req, err := s.client.newAuthenticatedRequest("POST", "v2/orders/multi/onebyone", map[string]interface{}{
|
||||||
"market": market,
|
"market": market,
|
||||||
"orders": orders,
|
"orders": orders,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return returnOrders, errors.Wrapf(err, "failed to create %s orders", market)
|
return returnOrders, errors.Wrapf(err, "failed to create %s orders", market)
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := s.client.sendRequest(req)
|
response, err := s.client.sendRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return returnOrders, err
|
return returnOrders, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if errJson := response.DecodeJSON(&returnOrders); errJson != nil {
|
if errJson := response.DecodeJSON(&returnOrders); errJson != nil {
|
||||||
return returnOrders, errJson
|
return returnOrders, errJson
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnOrders, err
|
return returnOrders, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@ package max
|
||||||
import (
|
import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/bbgo/types"
|
||||||
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BaseEvent struct {
|
type BaseEvent struct {
|
||||||
|
@ -165,6 +168,24 @@ type BalanceMessage struct {
|
||||||
Locked string `json:"l"`
|
Locked string `json:"l"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *BalanceMessage) Balance() (*types.Balance, error) {
|
||||||
|
available, err := util.ParseFloat(m.Available)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
locked, err := util.ParseFloat(m.Locked)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Balance{
|
||||||
|
Currency: m.Currency,
|
||||||
|
Locked: locked,
|
||||||
|
Available: available,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseBalance(v *fastjson.Value) BalanceMessage {
|
func parseBalance(v *fastjson.Value) BalanceMessage {
|
||||||
return BalanceMessage{
|
return BalanceMessage{
|
||||||
Currency: string(v.GetStringBytes("cu")),
|
Currency: string(v.GetStringBytes("cu")),
|
||||||
|
|
|
@ -15,6 +15,10 @@ func (v Value) Float64() float64 {
|
||||||
return float64(v) / DefaultPow
|
return float64(v) / DefaultPow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v Value) Int64() int64 {
|
||||||
|
return int64(v)
|
||||||
|
}
|
||||||
|
|
||||||
func (v Value) Mul(v2 Value) Value {
|
func (v Value) Mul(v2 Value) Value {
|
||||||
return NewFromFloat(v.Float64() * v2.Float64())
|
return NewFromFloat(v.Float64() * v2.Float64())
|
||||||
}
|
}
|
||||||
|
@ -43,3 +47,11 @@ func NewFromString(input string) (Value, error) {
|
||||||
func NewFromFloat(val float64) Value {
|
func NewFromFloat(val float64) Value {
|
||||||
return Value(int64(math.Round(val * DefaultPow)))
|
return Value(int64(math.Round(val * DefaultPow)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewFromInt(val int) Value {
|
||||||
|
return Value(int64(val * DefaultPow))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFromInt64(val int64) Value {
|
||||||
|
return Value(val * DefaultPow)
|
||||||
|
}
|
||||||
|
|
|
@ -13,3 +13,13 @@ type Account struct {
|
||||||
AccountType string
|
AccountType string
|
||||||
Balances map[string]Balance
|
Balances map[string]Balance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Account) UpdateBalance(b Balance) {
|
||||||
|
a.Balances[b.Currency] = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAccount() *Account {
|
||||||
|
return &Account{
|
||||||
|
Balances: make(map[string]Balance),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package types
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo/fixedpoint"
|
"github.com/c9s/bbgo/pkg/bbgo/fixedpoint"
|
||||||
)
|
)
|
||||||
|
@ -34,14 +35,27 @@ func (slice PriceVolumeSlice) Trim() (pvs PriceVolumeSlice) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slice PriceVolumeSlice) Copy() PriceVolumeSlice {
|
func (slice PriceVolumeSlice) Copy() PriceVolumeSlice {
|
||||||
// this is faster than make
|
// this is faster than make (however it's only for simple types)
|
||||||
return append(slice[:0:0], slice...)
|
return append(slice[:0:0], slice...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (slice PriceVolumeSlice) IndexByVolumeDepth(requiredVolume fixedpoint.Value) int {
|
||||||
|
var tv int64 = 0
|
||||||
|
for x, el := range slice {
|
||||||
|
tv += el.Volume.Int64()
|
||||||
|
if tv >= requiredVolume.Int64() {
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not deep enough
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
func (slice PriceVolumeSlice) InsertAt(idx int, pv PriceVolume) PriceVolumeSlice {
|
func (slice PriceVolumeSlice) InsertAt(idx int, pv PriceVolume) PriceVolumeSlice {
|
||||||
rear := append([]PriceVolume{}, slice[idx:]...)
|
rear := append([]PriceVolume{}, slice[idx:]...)
|
||||||
slice = append(slice[:idx], pv)
|
newSlice := append(slice[:idx], pv)
|
||||||
return append(slice, rear...)
|
return append(newSlice, rear...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slice PriceVolumeSlice) Remove(price fixedpoint.Value, descending bool) PriceVolumeSlice {
|
func (slice PriceVolumeSlice) Remove(price fixedpoint.Value, descending bool) PriceVolumeSlice {
|
||||||
|
@ -89,13 +103,26 @@ func (slice PriceVolumeSlice) Upsert(pv PriceVolume, descending bool) PriceVolum
|
||||||
return slice
|
return slice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:generate callbackgen -type OrderBook
|
||||||
type OrderBook struct {
|
type OrderBook struct {
|
||||||
Symbol string
|
Symbol string
|
||||||
Bids PriceVolumeSlice
|
Bids PriceVolumeSlice
|
||||||
Asks PriceVolumeSlice
|
Asks PriceVolumeSlice
|
||||||
|
|
||||||
|
loadCallbacks []func(book *OrderBook)
|
||||||
|
updateCallbacks []func(book *OrderBook)
|
||||||
|
bidsChangeCallbacks []func(pvs PriceVolumeSlice)
|
||||||
|
asksChangeCallbacks []func(pvs PriceVolumeSlice)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *OrderBook) UpdateAsks(pvs PriceVolumeSlice) {
|
func (b *OrderBook) Copy() (book OrderBook) {
|
||||||
|
book = *b
|
||||||
|
book.Bids = b.Bids.Copy()
|
||||||
|
book.Asks = b.Asks.Copy()
|
||||||
|
return book
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) updateAsks(pvs PriceVolumeSlice) {
|
||||||
for _, pv := range pvs {
|
for _, pv := range pvs {
|
||||||
if pv.Volume == 0 {
|
if pv.Volume == 0 {
|
||||||
b.Asks = b.Asks.Remove(pv.Price, false)
|
b.Asks = b.Asks.Remove(pv.Price, false)
|
||||||
|
@ -103,9 +130,11 @@ func (b *OrderBook) UpdateAsks(pvs PriceVolumeSlice) {
|
||||||
b.Asks = b.Asks.Upsert(pv, false)
|
b.Asks = b.Asks.Upsert(pv, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.EmitAsksChange(b.Asks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *OrderBook) UpdateBids(pvs PriceVolumeSlice) {
|
func (b *OrderBook) updateBids(pvs PriceVolumeSlice) {
|
||||||
for _, pv := range pvs {
|
for _, pv := range pvs {
|
||||||
if pv.Volume == 0 {
|
if pv.Volume == 0 {
|
||||||
b.Bids = b.Bids.Remove(pv.Price, true)
|
b.Bids = b.Bids.Remove(pv.Price, true)
|
||||||
|
@ -113,17 +142,29 @@ func (b *OrderBook) UpdateBids(pvs PriceVolumeSlice) {
|
||||||
b.Bids = b.Bids.Upsert(pv, true)
|
b.Bids = b.Bids.Upsert(pv, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.EmitBidsChange(b.Bids)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) update(book OrderBook) {
|
||||||
|
b.updateBids(book.Bids)
|
||||||
|
b.updateAsks(book.Asks)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) Reset() {
|
||||||
|
b.Bids = nil
|
||||||
|
b.Asks = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *OrderBook) Load(book OrderBook) {
|
func (b *OrderBook) Load(book OrderBook) {
|
||||||
b.Bids = nil
|
b.Reset()
|
||||||
b.Asks = nil
|
b.update(book)
|
||||||
b.Update(book)
|
b.EmitLoad(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *OrderBook) Update(book OrderBook) {
|
func (b *OrderBook) Update(book OrderBook) {
|
||||||
b.UpdateBids(book.Bids)
|
b.update(book)
|
||||||
b.UpdateAsks(book.Asks)
|
b.EmitUpdate(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *OrderBook) Print() {
|
func (b *OrderBook) Print() {
|
||||||
|
@ -138,3 +179,36 @@ func (b *OrderBook) Print() {
|
||||||
fmt.Printf("- BID: %s\n", bid.String())
|
fmt.Printf("- BID: %s\n", bid.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MutexOrderBook struct {
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
|
*OrderBook
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMutexOrderBook(symbol string) *MutexOrderBook {
|
||||||
|
return &MutexOrderBook{
|
||||||
|
OrderBook: &OrderBook{Symbol: symbol},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *MutexOrderBook) Load(book OrderBook) {
|
||||||
|
b.Lock()
|
||||||
|
defer b.Unlock()
|
||||||
|
|
||||||
|
b.Reset()
|
||||||
|
b.update(book)
|
||||||
|
b.EmitLoad(b.OrderBook)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *MutexOrderBook) Get() OrderBook {
|
||||||
|
return b.OrderBook.Copy()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *MutexOrderBook) Update(book OrderBook) {
|
||||||
|
b.Lock()
|
||||||
|
defer b.Unlock()
|
||||||
|
|
||||||
|
b.update(book)
|
||||||
|
b.EmitUpdate(b.OrderBook)
|
||||||
|
}
|
||||||
|
|
45
bbgo/types/orderbook_callbacks.go
Normal file
45
bbgo/types/orderbook_callbacks.go
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Code generated by "callbackgen -type OrderBook"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package types
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
func (b *OrderBook) OnLoad(cb func(book *OrderBook)) {
|
||||||
|
b.loadCallbacks = append(b.loadCallbacks, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) EmitLoad(book *OrderBook) {
|
||||||
|
for _, cb := range b.loadCallbacks {
|
||||||
|
cb(book)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) OnUpdate(cb func(book *OrderBook)) {
|
||||||
|
b.updateCallbacks = append(b.updateCallbacks, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) EmitUpdate(book *OrderBook) {
|
||||||
|
for _, cb := range b.updateCallbacks {
|
||||||
|
cb(book)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) OnBidsChange(cb func(pvs PriceVolumeSlice)) {
|
||||||
|
b.bidsChangeCallbacks = append(b.bidsChangeCallbacks, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) EmitBidsChange(pvs PriceVolumeSlice) {
|
||||||
|
for _, cb := range b.bidsChangeCallbacks {
|
||||||
|
cb(pvs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) OnAsksChange(cb func(pvs PriceVolumeSlice)) {
|
||||||
|
b.asksChangeCallbacks = append(b.asksChangeCallbacks, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *OrderBook) EmitAsksChange(pvs PriceVolumeSlice) {
|
||||||
|
for _, cb := range b.asksChangeCallbacks {
|
||||||
|
cb(pvs)
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,15 @@ func FormatFloat(val float64, prec int) string {
|
||||||
return strconv.FormatFloat(val, 'f', prec, 64)
|
return strconv.FormatFloat(val, 'f', prec, 64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseFloat(s string) (float64, error) {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return 0.0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.ParseFloat(s, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func MustParseFloat(s string) float64 {
|
func MustParseFloat(s string) float64 {
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
Loading…
Reference in New Issue
Block a user