-
Notifications
You must be signed in to change notification settings - Fork 103
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
client/mm: CEX balance tracking and auto-rebalancing #2568
Conversation
martonp
commented
Oct 13, 2023
client/mm/wrapped_cex.go
Outdated
ticker := time.NewTicker(time.Second * 20) | ||
giveUp := time.NewTimer(time.Minute * 10) |
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.
Missed deferring Stop() for both tickers.
client/mm/wrapped_cex.go
Outdated
|
||
w.tradesMtx.Lock() | ||
defer w.tradesMtx.Unlock() | ||
|
||
w.subscriptionIDMtx.RLock() | ||
defer w.subscriptionIDMtx.RUnlock() |
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 we'd want to avoid nested locks.
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.
subscriptionID could be atomic actually.. but what's wrong with locking two things at once?
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.
Nothing really wrong since they are protecting different data. But might lead to unexpected issues, I think.
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.
Yeah it could cause a deadlock if in another location the locks are acquired in the reverse order.
client/mm/config.go
Outdated
@@ -63,6 +74,10 @@ func (c *BotConfig) requiresPriceOracle() bool { | |||
return false | |||
} | |||
|
|||
func (c *BotConfig) requiresCEX() bool { | |||
return c.SimpleArbConfig != nil || c.MMWithCEXConfig != 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.
Why not just make BotCEXCfg
a field of, or embedded in, SimpleArbConfig
and MMWithCEXConfig
?
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 did it like this because the strategy doesn't need to know anything about the CEX it's trading on. Creating the CEXes and allocating the balances is the purview of the level above the strategies. I was kind of split on this, thought it could go either way.
@@ -550,6 +633,56 @@ func (m *MarketMaker) botBalance(botID string, assetID uint32) uint64 { | |||
return 0 | |||
} | |||
|
|||
func (m *MarketMaker) modifyBotCEXBalance(botID string, assetID uint32, amount uint64, increase bool) { |
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.
Delta-based value tracking tends to be fragile. Much better to find an idempotent pattern, such that we track the server's reported balance and pending deposits/withdraws to calculate 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.
The server's balance doesn't really tell us much because the balance of the CEX will be split between multiple bots. Also, not just deposits/withdrawals change the balance, but also trades. Maybe a better pattern would be to keep track of each of the actions which changed the balance and how much it changed it by. Then we could definitely avoid any double counting. Is this kind of what you're suggesting?
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'll leave it up to you. Just wanted to point out the scary pattern.
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're probably right, I'll think of something. The balance management for the DEX should be updated then too.
// Assign to balance to the bot as long as the wallet | ||
// knows about the transaction. | ||
w.mm.modifyBotBalance(w.botID, []*balanceMod{{balanceModIncrease, assetID, balTypeAvailable, withdrawnAmt}}) | ||
onConfirm() |
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.
Confirmed to exist from the point of view of our node but not confirmed really if 0 confs. Should this wait for some amount of confs?
} | ||
|
||
if !trade.sell && calc.BaseToQuote(trade.rate, trade.qty) > trade.quoteFilled { | ||
unfilledQty := calc.BaseToQuote(trade.rate, trade.qty) - trade.quoteFilled |
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.
Could this trade have been completed at different rates? If taker maybe some quote was taken at a better rate?
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.
The original reserved amount was calc.BaseToQuote(trade.rate, trade.qty)
. The amount of quote that was used is trade.quoteFilled
. quoteFilled
is the amount of quote that was used to buy the base in this trade, regardless of what the rate was.
Send and Withdraw are updated to return a transaction ID. Also, a TransactionConfirmations function is added to the wallet interface which allows callers to determine the amount of confirmations a wallet transaction has.
- Deposit and Withdraw functionality is added to the CEX interface and is implemented in Binance. - The CEX interface is updated to take uint32 assetIDs instead of strings to represent assets. - The "weth.polygon" and "wbtc.polygon" assets are renamed to be "eth.polygon" and "btc.polygon". This makes it clear that "btc" and "btc.polygon" are the same asset, just on different networks.
Tracking of CEX balances for each bot is implemented in a similar fashion to tracking bot balances on the DEX. A `wrappedCEX` is created for each bot which behaves as if the entire balance of the CEX is the amount that is allocated for each bot.
This implements auto-rebalancing in the simple arbitrage strategy. This is an optional functionality that allows the user to specify a minimum balance of each asset that should be on both the DEX and the CEX. If the balance dips below this amount, then either a deposit or withdrawal will be done to have an equal amount of the asset on both exchanges.
b96b239
to
6d22e0c
Compare
6d22e0c
to
996b2a6
Compare
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.
Partial review. I'll get back into this tomorrow.
I'll just drop this diff here. buck54321/dcrdex@996b2a6...buck54321:dcrdex:cexbalances. Do with it what you will.
client/mm/mm_simple_arb.go
Outdated
MinBaseAmt uint64 `json:"minBaseAmt"` | ||
MinBaseTransfer uint64 `json:"minBaseTransfer"` | ||
MinQuoteAmt uint64 `json:"minQuoteAmt"` | ||
MinQuoteTransfer uint64 `json:"minQuoteTransfer"` |
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 feel like none of these should need to be manually set. We should know when to trigger an auto-rebalance based on lot size and bot setttings. Min transfers too.
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 some people would want to be more aggressive with rebalancing and some people less. If someone allocates 4 lots on both sides of a market for simple arb, when should this be rebalanced? For Arb+mm, if there are a few matches in one direction, and there's not enough balance for all the placements on one side of the market, maybe someone would want to rebalance ASAP, while others would want to give it some time because the market may move in the other direction. I don't think there's a one size fits all.
client/mm/mm_arb_market_maker.go
Outdated
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.
Arb+mm doesn't get auto-rebalance?
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'm not going to add anything to this now. I know you were looking at some refactoring of the balance tracking anyway. If you can just address outstanding comments, we'll get this in.
@buck54321 I've made the changes. Adding rebalancing to mm+arb required some new logic, so that could still use a review. |