Skip to content
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

FEATURE: Implement Coinbase API client and order management features #1903

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

dboyliao
Copy link
Collaborator

@dboyliao dboyliao commented Feb 12, 2025

Implement following exchange interfaces:

  • ExchangeMinimal
  • ExchangeTradeService
  • ExchangeOrderQueryService
  • ExchangeMarketDataService is WIP (Impl. for NewStream will be in another PR)

TODO: unit tests

@dboyliao dboyliao requested review from c9s and kbearXD February 12, 2025 09:56
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


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.

@dboyliao dboyliao force-pushed the dboy/coinbase branch 2 times, most recently from c353e97 to 43a6476 Compare February 13, 2025 01:25
// 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"`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be fixedpoint.Value

Copy link
Collaborator Author

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{
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@echo "Generate symbols.go" && go run ./generate_symbol_map.go

go-generate:
@echo "Running \`go generate\`" && go generate ./...
Copy link
Owner

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

Copy link
Collaborator Author

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

QuoteQuantity: cbTrade.Size.Mul(cbTrade.Price),
Symbol: cbTrade.ProductID,
Side: cbTrade.Side.GlobalSideType(),
IsBuyer: cbTrade.Liquidity == "T",
Copy link
Collaborator

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?

Copy link
Collaborator Author

@dboyliao dboyliao Feb 14, 2025

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

Copy link
Collaborator

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Will do.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

cur := strings.ToUpper(b.Currency)
balances[cur] = types.Balance{
Currency: cur,
Available: b.Available,
Copy link
Collaborator

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?

Copy link
Collaborator Author

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.

QuoteQuantity: cbTrade.Size.Mul(cbTrade.Price),
Symbol: cbTrade.ProductID,
Side: cbTrade.Side.GlobalSideType(),
IsBuyer: cbTrade.Liquidity == "T",
Copy link
Collaborator

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

Comment on lines 124 to 127
done := false
if len(cbOrders) < 1000 || len(cbOrders) == 0 {
done = true
}
Copy link
Collaborator

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines 223 to 225
if len(cbTrades) < paginationLimit || len(cbTrades) == 0 {
done = true
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it removable?

Copy link
Collaborator Author

@dboyliao dboyliao Feb 14, 2025

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:

productID string `param:"product_id,required"`
granularity *string `param:"granularity" validValues:"60,300,900,3600,21600,86400"`
start *string `param:"start"`
end *string `param:"end"`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

orderID string `param:"order_id,required"`
limit int `param:"limit"`
before *string `param:"before"`
after *string `param:"after"`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startDate *time.Time `param:"start_date" timeFormat:"RFC3339"`
endDate *time.Time `param:"end_date" timeFormat:"RFC3339"`
before *time.Time `param:"before" timeFormat:"RFC3339"`
after *time.Time `param:"after" timeFormat:"RFC3339"`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pagination, it's a number, not a date string?
https://docs.cdp.coinbase.com/exchange/docs/rest-pagination

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pagination id used for GET /orders are before and after which are timestamp string in RFC3339.
See:
https://docs.cdp.coinbase.com/exchange/reference/exchangerestapi_getorders

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants