-
-
Notifications
You must be signed in to change notification settings - Fork 345
FEATURE: Implement Coinbase API client and order management features #1903
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…d cancel order functionalities
dboy seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
c353e97
to
43a6476
Compare
…ation for API client
// ClientOID must be uuid | ||
ClientOID string `json:"client_oid" db:"client_oid"` | ||
Stop string `json:"stop" db:"stop"` | ||
StopPrice json.Number `json:"stop_price" db:"stop_price"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be fixedpoint.Value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
import "context" | ||
|
||
func (client *RestAPIClient) GetOrderTrades(ctx context.Context, orderID string, limit int, before *string) (TradeSnapshot, error) { | ||
req := GetOrderTradesRequest{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@echo "Generate symbols.go" && go run ./generate_symbol_map.go | ||
|
||
go-generate: | ||
@echo "Running \`go generate\`" && go generate ./... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need the makefile actually? you can embed them in the go:generate comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just want a way to document how I generate the symbols.go
pkg/exchange/coinbase/convert.go
Outdated
QuoteQuantity: cbTrade.Size.Mul(cbTrade.Price), | ||
Symbol: cbTrade.ProductID, | ||
Side: cbTrade.Side.GlobalSideType(), | ||
IsBuyer: cbTrade.Liquidity == "T", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do T
and M
represent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"T"aker and "M"aker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you can use cb Trade.Liquidity == api.Liquidity Maker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. Will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
cur := strings.ToUpper(b.Currency) | ||
balances[cur] = types.Balance{ | ||
Currency: cur, | ||
Available: b.Available, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you missed the Lock
field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not well documented in the CoinBase API which is the right value for Locked
:
https://docs.cdp.coinbase.com/exchange/reference/exchangerestapi_getaccounts
After searching around on the web, I think the reasonable choice would be balance - available
from the CoinBase side.
Let's use balance - available
for Locked
for now.
I'll update the NetAsset
as well.
pkg/exchange/coinbase/convert.go
Outdated
QuoteQuantity: cbTrade.Size.Mul(cbTrade.Price), | ||
Symbol: cbTrade.ProductID, | ||
Side: cbTrade.Side.GlobalSideType(), | ||
IsBuyer: cbTrade.Liquidity == "T", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you can use cb Trade.Liquidity == api.Liquidity Maker
pkg/exchange/coinbase/exchage.go
Outdated
done := false | ||
if len(cbOrders) < 1000 || len(cbOrders) == 0 { | ||
done = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be simplify to
if len(cbOrders) < paginationLimit {
return cbOrders,nil)
}
done := false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
if len(cbTrades) < paginationLimit || len(cbTrades) == 0 { | ||
done = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it removable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to get all trades from Coinbase Exchange API, I believe applying pagination is a must.
See:
4c395e2
to
8cf8461
Compare
} | ||
done := false | ||
for { | ||
if done { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to handle the ctx.Done() in the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
done := false | ||
for { | ||
if done { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to handle the ctx.Done() in the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/convert.go
Outdated
return &ticker | ||
} | ||
|
||
func toGlobalBalance(cur string, cbBalance *api.Balance) *types.Balance { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for this case, you can just return the value struct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
balances := make(types.BalanceMap) | ||
for _, cbBalance := range accounts { | ||
cur := strings.ToUpper(cbBalance.Currency) | ||
balances[cur] = *toGlobalBalance(cur, &cbBalance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using dereferencing the return pointer could be dangerous, so for this function, you can just return value (you always have a value to return)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
} | ||
return &types.Order{ | ||
Exchange: types.ExchangeCoinBase, | ||
UUID: res.ID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to assign SubmitOrder into the SubmitOrder field,
and you might need to query the order details, take a look at bybit or bitget's SubmitOrder() implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
} | ||
orders := make([]types.Order, 0, len(cbOrders)) | ||
for _, cbOrder := range cbOrders { | ||
orders = append(orders, *toGlobalOrder(&cbOrder)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto, avoid de-referencing the value directly from the function call since it's a plain data object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
return orders, nil | ||
} | ||
|
||
func (e *Exchange) queryOrdersByPagination(ctx context.Context, symbol string, status []string) ([]api.Order, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you might need to apply the rate limiter here, or from the request itself. requestgen supports rate limiter's Wait() method call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
} | ||
|
||
func (e *Exchange) CancelOrders(ctx context.Context, orders ...types.Order) error { | ||
failedOrderIDs := make([]string, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is minor, simple form is:
var failedOrderIDs []string
they are equivalent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
log.WithError(err).Errorf("failed to cancel order: %v", order.UUID) | ||
failedOrderIDs = append(failedOrderIDs, order.UUID) | ||
} | ||
log.Infof("order %v has been cancelled", res) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need an "else" for this Infof log?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
// ExchangeMarketDataService | ||
func (e *Exchange) NewStream() types.Stream { | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a TODO mark comment here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
} | ||
marketMap := make(types.MarketMap) | ||
for _, m := range markets { | ||
marketMap[toGlobalSymbol(m.ID)] = *toGlobalMarket(&m) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
} | ||
// default limit is 300, which is the maximum limit of the Coinbase Exchange API | ||
if options.Limit == 0 { | ||
options.Limit = 300 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pull these numbers out to constants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
It has been renamed as DefaultKLineLimit
.
pkg/exchange/coinbase/exchage.go
Outdated
} | ||
if options.Limit > 300 { | ||
log.Warnf("limit %d is greater than the maximum limit 300, set to 300", options.Limit) | ||
options.Limit = 300 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
5215b79
to
ed7d2c1
Compare
pkg/exchange/coinbase/exchage.go
Outdated
if done { | ||
break | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad. Silly rebase error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
pkg/exchange/coinbase/exchage.go
Outdated
if done { | ||
break | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To implement rate limits on each API, refer to the code snippet found in the following link: Cancel Order Request in Bybit API.
…ne, function return pointers)
ed7d2c1
to
d1ad710
Compare
Implement following exchange interfaces:
ExchangeMinimal
ExchangeTradeService
ExchangeOrderQueryService
ExchangeMarketDataService
is WIP (Impl. forNewStream
will be in another PR)TODO: unit tests