-
Notifications
You must be signed in to change notification settings - Fork 146
add Bitget exchange adapter #3430
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
base: master
Are you sure you want to change the base?
Conversation
This commit adds full support for Bitget centralized exchange integration to the market maker, including REST API and WebSocket v2 implementations for trading, orderbook synchronization, balance management, and deposit/ withdrawal operations. Key features: - Complete Bitget CEX adapter implementation (client/mm/libxc/bitget.go) - WebSocket v2 support for real-time orderbook updates and order status - Market data retrieval with proper ticker handling and grouping by Slug - Order placement, cancellation, and status tracking - Balance fetching and deposit/withdrawal operations - Checksum validation for orderbook integrity - Order status check before cancellation to prevent unnecessary API calls Configuration changes: - Add APIPassphrase field to CEXConfig for exchanges requiring passphrase authentication (Bitget requires this in addition to API key/secret) - Extend CEXConfig interface in libxc to support passphrase - Update frontend forms and UI to handle passphrase input for Bitget - Add Bitget logo and display information to UI Bug fixes: - Fix omitempty JSON tag behavior for CEXBaseID and CEXQuoteID in BotConfig to properly handle asset ID 0 (BTC). Previously, these fields were omitted from JSON when their value was 0, causing frontend errors when loading bot configurations for BTC markets. - Add normalization logic in mm.go to ensure CEXBaseID and CEXQuoteID are always set when CEXName is configured, preventing missing config data for assets with ID 0. Normalization is applied: * When loading configs from disk (NewMarketMaker, getMarketMakingConfig) * When accessing default config (defaultConfig) * When retrieving configs for markets (configsForMarket) * Before saving configs (updateDefaultBotConfig) Order status handling: - Implement correct Bitget order status codes (live, partially_filled, filled, cancelled) matching Spot Trading API documentation - Add status check in CancelTrade to verify order completion before attempting cancellation, preventing unnecessary API calls and errors - Fix TradeStatus to handle array response from Bitget API Files changed: - client/mm/libxc/bitget.go (new file - complete adapter implementation) - client/mm/libxc/bgtypes/ (new package - Bitget API types) - client/mm/libxc/interface.go (add Bitget constant and passphrase support) - client/mm/config.go (add APIPassphrase, fix omitempty tags for CEXBaseID/CEXQuoteID) - client/mm/mm.go (add passphrase handling, normalization logic) - client/webserver/site/src/js/registry.ts (add passphrase to CEXConfig) - client/webserver/site/src/js/forms.ts (add passphrase UI handling) - client/webserver/site/src/js/mmutil.ts (add Bitget display info) - client/webserver/site/src/html/forms.tmpl (add passphrase input field) - client/webserver/locales/*.go (add passphrase translations) - client/webserver/site/src/img/bitget.com.png (new file - Bitget logo)
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.
Lots of code to review but looks good to me. A few things that stand out.
-
Saving the book as strings and then parsing many of them many times every update does not seem optimal.
-
I don't think it is necessary to check the checksum. Am I wrong?
-
There are many ignored errors, especially for parsing floats. Please check and log all errors. It prevents alot of headaches later to just stick to that rule, unless absolutely not necessary. Even then best to comment why it is absolutely not needed.
| if !found && qty != "0" { | ||
| sob.asks = sob.insertAsk(price, qty) | ||
| } | ||
| } |
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.
These two could be combined for less code but it's fine not to change.
| // insertBid inserts a bid maintaining descending price order | ||
| func (sob *stringOrderbook) insertBid(price, qty string) [][]string { | ||
| priceFloat, _ := strconv.ParseFloat(price, 64) | ||
| newBid := []string{price, qty} | ||
|
|
||
| for i, level := range sob.bids { | ||
| levelPrice, _ := strconv.ParseFloat(level[0], 64) | ||
| if priceFloat > levelPrice { | ||
| // Insert here | ||
| return append(sob.bids[:i], append([][]string{newBid}, sob.bids[i:]...)...) | ||
| } | ||
| } | ||
| // Append at end | ||
| return append(sob.bids, newBid) | ||
| } |
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.
Seems really inefficient to parse everything every time rather than just converting once and saving as a float.
There's probably a better structure to save these in as well. Unsure atm though. I guess can optimize later.
| bids, asks, err := b.convertBookUpdate(update) | ||
| if err != nil { | ||
| b.log.Errorf("%s: error converting book update: %v", b.symbol, err) | ||
| return false | ||
| } | ||
|
|
||
| // Sanity check: Validate rate > 0 (qty=0 is valid for removals) | ||
| for _, bid := range bids { | ||
| if bid.rate == 0 { | ||
| b.log.Errorf("%s: Invalid bid with zero rate: rate=%d, qty=%d", b.symbol, bid.rate, bid.qty) | ||
| return false | ||
| } | ||
| } | ||
| for _, ask := range asks { | ||
| if ask.rate == 0 { | ||
| b.log.Errorf("%s: Invalid ask with zero rate: rate=%d, qty=%d", b.symbol, ask.rate, ask.qty) | ||
| return 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.
Converting all the books just to look at the rate and then throwing those away seems wild.
| // Mark uint64 cache as dirty (will rebuild on next read) | ||
| b.bookDirty.Store(true) | ||
|
|
||
| // Validate checksum (if provided and non-zero) |
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.
Why do we need to validate the checksum? Doesn't seem to serve a purpose. I think this should be removed. Can leave some comments noting it is possible... Do their docs say you should do this?
| processUpdate := func(update *bgtypes.BookUpdate) bool { | ||
| syncMtx.Lock() | ||
| defer syncMtx.Unlock() | ||
| return acceptUpdate(update, update.IsSnapshot) |
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.
No need to use two arguments if one is part of the update struct.
| price, _ := strconv.ParseFloat(item[0], 64) | ||
| qty, _ := strconv.ParseFloat(item[1], 64) |
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.
Please log errors.
| if err != nil { | ||
| continue | ||
| } |
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 log error?
| high24h, _ := strconv.ParseFloat(ticker.High24h, 64) | ||
| low24h, _ := strconv.ParseFloat(ticker.Low24h, 64) | ||
| close, _ := strconv.ParseFloat(ticker.Close, 64) | ||
| quoteVol, _ := strconv.ParseFloat(ticker.QuoteVol, 64) | ||
| baseVol, _ := strconv.ParseFloat(ticker.BaseVol, 64) | ||
| openUtc, _ := strconv.ParseFloat(ticker.OpenUtc, 64) | ||
| changeUtc24h, _ := strconv.ParseFloat(ticker.ChangeUtc24h, 64) |
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.
Rather not ignore errors.
| size, _ := strconv.ParseFloat(orderDetail.Size, 64) | ||
| baseFilled, _ := strconv.ParseFloat(orderDetail.BaseVolume, 64) | ||
| quoteFilled, _ := strconv.ParseFloat(orderDetail.QuoteVolume, 64) | ||
| priceAvg, _ := strconv.ParseFloat(orderDetail.PriceAvg, 64) |
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.
Rather not ignore errors.
| return 0, "", ErrWithdrawalPending | ||
| } | ||
|
|
||
| sizeFloat, _ := strconv.ParseFloat(status.Size, 64) |
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.
Rather not ignore error.
This commit adds full support for Bitget centralized exchange integration to the market maker, including REST API and WebSocket v2 implementations for trading, orderbook synchronization, balance management, and deposit/ withdrawal operations.
Key features:
Configuration changes:
Bug fixes:
Order status handling:
Files changed: