diff --git a/client/cmd/testbinance/main.go b/client/cmd/testbinance/main.go
index 1459f2f198..174ed651ed 100644
--- a/client/cmd/testbinance/main.go
+++ b/client/cmd/testbinance/main.go
@@ -12,6 +12,7 @@ import (
"encoding/json"
"flag"
"fmt"
+ "io"
"math"
"math/rand"
"net/http"
@@ -150,15 +151,50 @@ func makeCoinpapAsset(assetID uint32, symbol, name string) *fiatrates.Coinpaprik
}
}
+// sendBalanceUpdateRequest sends a balance update request to the testbinance server
+// running in another process.
+func sendBalanceUpdateRequest(coin string, balanceUpdate float64) {
+ if coin == "" || balanceUpdate == 0 {
+ fmt.Printf("Invalid balance update request: coin = %q, balanceUpdate = %f\n", coin, balanceUpdate)
+ return
+ }
+
+ url := fmt.Sprintf("http://localhost:37346/testbinance/updatebalance?coin=%s&amt=%f",
+ coin, balanceUpdate)
+ resp, err := http.Get(url)
+ if err != nil {
+ log.Errorf("Error sending balance update request: %v", err)
+ return
+ }
+
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ body, _ := io.ReadAll(resp.Body)
+ fmt.Println("Balance update request failed:", string(body))
+ return
+ }
+
+ fmt.Println("Balance update request sent")
+}
+
func main() {
var logDebug, logTrace bool
+ var coin string
+ var balanceUpdate float64
flag.Float64Var(&walkingSpeedAdj, "walkspeed", 1.0, "scale the maximum walking speed. default scale of 1.0 is about 3%")
flag.Float64Var(&gapRange, "gaprange", 0.04, "a ratio of how much the gap can vary. default is 0.04 => 4%")
flag.BoolVar(&logDebug, "debug", false, "use debug logging")
flag.BoolVar(&logTrace, "trace", false, "use trace logging")
flag.BoolVar(&flappyWS, "flappyws", false, "periodically drop websocket clients and delete subscriptions")
+ flag.Float64Var(&balanceUpdate, "balupdate", 0, "update the balance of an asset on a testbinance server running as another process")
+ flag.StringVar(&coin, "coin", "", "coin for testbinance admin update")
flag.Parse()
+ if balanceUpdate != 0 {
+ sendBalanceUpdateRequest(coin, balanceUpdate)
+ return
+ }
+
switch {
case logTrace:
log = dex.StdOutLogger("TB", dex.LevelTrace)
@@ -312,10 +348,32 @@ func newFakeBinanceServer(ctx context.Context) (*fakeBinance, error) {
mux.Get("/ws/{listenKey}", f.handleAccountSubscription)
mux.Get("/stream", f.handleMarketStream)
+ mux.Route("/testbinance", func(r chi.Router) {
+ r.Get("/updatebalance", f.handleUpdateBalance)
+ })
return f, nil
}
+func (f *fakeBinance) handleUpdateBalance(w http.ResponseWriter, r *http.Request) {
+ coin := r.URL.Query().Get("coin")
+ amtStr := r.URL.Query().Get("amt")
+ amt, err := strconv.ParseFloat(amtStr, 64)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("invalid amt %q: %v", amtStr, err), http.StatusBadRequest)
+ return
+ }
+
+ balUpdate := f.updateBalance(coin, amt)
+ if balUpdate == nil {
+ http.Error(w, fmt.Sprintf("no balance to update for %q", coin), http.StatusBadRequest)
+ return
+ }
+
+ f.sendBalanceUpdates([]*bntypes.WSBalance{balUpdate})
+ w.WriteHeader(http.StatusOK)
+}
+
func (f *fakeBinance) run(ctx context.Context) {
// Start a ticker to do book shuffles.
@@ -779,6 +837,27 @@ func (f *fakeBinance) handleGetDepositAddress(w http.ResponseWriter, r *http.Req
writeJSONWithStatus(w, resp, http.StatusOK)
}
+func (f *fakeBinance) updateBalance(coin string, amt float64) *bntypes.WSBalance {
+ f.balancesMtx.Lock()
+ defer f.balancesMtx.Unlock()
+
+ var balUpdate *bntypes.WSBalance
+
+ for _, b := range f.balances {
+ if b.Asset == coin {
+ if amt+b.Free < 0 {
+ b.Free = 0
+ } else {
+ b.Free += amt
+ }
+ balUpdate = (*bntypes.WSBalance)(b)
+ break
+ }
+ }
+
+ return balUpdate
+}
+
func (f *fakeBinance) handleWithdrawal(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
apiKey := extractAPIKey(r)
@@ -814,24 +893,7 @@ func (f *fakeBinance) handleWithdrawal(w http.ResponseWriter, r *http.Request) {
}
f.withdrawalHistoryMtx.Unlock()
- var balUpdate *bntypes.WSBalance
- debitBalance := func(coin string, amt float64) {
- for _, b := range f.balances {
- if b.Asset == coin {
- if amt > b.Free {
- b.Free = 0
- } else {
- b.Free -= amt
- }
- }
- balUpdate = (*bntypes.WSBalance)(b)
- }
- }
-
- f.balancesMtx.Lock()
- debitBalance(coin, amt)
- f.balancesMtx.Unlock()
-
+ balUpdate := f.updateBalance(coin, -amt)
f.sendBalanceUpdates([]*bntypes.WSBalance{balUpdate})
resp := struct {
diff --git a/client/mm/libxc/binance.go b/client/mm/libxc/binance.go
index 5f30c3690a..739d8621bf 100644
--- a/client/mm/libxc/binance.go
+++ b/client/mm/libxc/binance.go
@@ -663,11 +663,11 @@ func (bnc *binance) Connect(ctx context.Context) (*sync.WaitGroup, error) {
wg := new(sync.WaitGroup)
if err := bnc.getCoinInfo(ctx); err != nil {
- return nil, fmt.Errorf("error getting coin info: %v", err)
+ return nil, fmt.Errorf("error getting coin info: %w", err)
}
if _, err := bnc.getMarkets(ctx); err != nil {
- return nil, fmt.Errorf("error getting markets: %v", err)
+ return nil, fmt.Errorf("error getting markets: %w", err)
}
if err := bnc.setBalances(ctx); err != nil {
diff --git a/client/mm/mm.go b/client/mm/mm.go
index f06ba59653..b9c3cba0dd 100644
--- a/client/mm/mm.go
+++ b/client/mm/mm.go
@@ -510,21 +510,21 @@ func (m *MarketMaker) connectCEX(ctx context.Context, c *centralizedExchange) er
if !cm.On() {
c.connectErr = ""
if err := cm.ConnectOnce(ctx); err != nil {
- c.connectErr = err.Error()
- return fmt.Errorf("failed to connect to CEX: %v", err)
+ c.connectErr = core.UnwrapErr(err).Error()
+ return fmt.Errorf("failed to connect to CEX: %w", err)
}
mkts, err := c.Markets(ctx)
if err != nil {
// Probably can't get here if we didn't error on connect, but
// checking anyway.
- c.connectErr = err.Error()
- return fmt.Errorf("error refreshing markets: %v", err)
+ c.connectErr = core.UnwrapErr(err).Error()
+ return fmt.Errorf("error refreshing markets: %w", err)
}
c.mkts = mkts
bals, err := c.Balances(ctx)
if err != nil {
- c.connectErr = err.Error()
- return fmt.Errorf("error getting balances: %v", err)
+ c.connectErr = core.UnwrapErr(err).Error()
+ return fmt.Errorf("error getting balances: %w", err)
}
c.balances = bals
}
@@ -590,12 +590,12 @@ func (m *MarketMaker) loadCEX(ctx context.Context, cfg *CEXConfig) (*centralized
if err != nil {
m.log.Errorf("Failed to get markets for %s: %v", cfg.Name, err)
c.mkts = make(map[string]*libxc.Market)
- c.connectErr = err.Error()
+ c.connectErr = core.UnwrapErr(err).Error()
}
if c.balances, err = c.Balances(ctx); err != nil {
m.log.Errorf("Failed to get balances for %s: %v", cfg.Name, err)
c.balances = make(map[uint32]*libxc.ExchangeBalance)
- c.connectErr = err.Error()
+ c.connectErr = core.UnwrapErr(err).Error()
}
m.cexes[cfg.Name] = c
success = true
@@ -1390,7 +1390,7 @@ func (m *MarketMaker) connectedCEX(cexName string) (*centralizedExchange, error)
err := m.connectCEX(m.ctx, cex)
if err != nil {
- return nil, fmt.Errorf("error connecting to CEX: %v", err)
+ return nil, fmt.Errorf("error connecting to CEX: %w", err)
}
return cex, nil
diff --git a/client/webserver/jsintl.go b/client/webserver/jsintl.go
index acc13a4ae8..22555a8e87 100644
--- a/client/webserver/jsintl.go
+++ b/client/webserver/jsintl.go
@@ -217,6 +217,8 @@ const (
idOrderReportTitle = "ORDER_REPORT_TITLE"
idCEXBalances = "CEX_BALANCES"
idCausesSelfMatch = "CAUSES_SELF_MATCH"
+ idCexNotConnected = "CEX_NOT_CONNECTED"
+ idRemovingBotConfig = "REMOVING_BOT_CONFIG"
)
var enUS = map[string]*intl.Translation{
@@ -433,6 +435,8 @@ var enUS = map[string]*intl.Translation{
idOrderReportTitle: {T: "{{ side }} orders report for epoch #{{ epochNum }}"},
idCEXBalances: {T: "{{ cexName }} Balances"},
idCausesSelfMatch: {T: "This order would cause a self-match"},
+ idCexNotConnected: {T: "{{ cexName }} not connected"},
+ idRemovingBotConfig: {T: "Are you sure you want to remove the config for the {{ baseSymbol }}-{{ quoteSymbol }} market on {{ host }}?"},
}
var ptBR = map[string]*intl.Translation{
diff --git a/client/webserver/locales/en-us.go b/client/webserver/locales/en-us.go
index 2db4ce7c0a..b8c996d1a1 100644
--- a/client/webserver/locales/en-us.go
+++ b/client/webserver/locales/en-us.go
@@ -678,4 +678,5 @@ var EnUS = map[string]*intl.Translation{
"Priority": {T: "Priority"},
"Wallet Balances": {T: "Wallet Balances"},
"Placements": {T: "Placements"},
+ "removing_bot_config": {T: "Removing Bot Config"},
}
diff --git a/client/webserver/site/src/html/mm.tmpl b/client/webserver/site/src/html/mm.tmpl
index b7dac7d5d6..03abf8e128 100644
--- a/client/webserver/site/src/html/mm.tmpl
+++ b/client/webserver/site/src/html/mm.tmpl
@@ -151,8 +151,12 @@
+
+
{{- /* PROJECTED ALLOCATIONS */ -}}
{{- /* END FORMS */ -}}
{{template "bottom"}}
diff --git a/client/webserver/site/src/js/doc.ts b/client/webserver/site/src/js/doc.ts
index 7be2a2d583..4934e526ca 100644
--- a/client/webserver/site/src/js/doc.ts
+++ b/client/webserver/site/src/js/doc.ts
@@ -245,6 +245,17 @@ export default class Doc {
for (const el of els) el.classList.remove('d-hide')
}
+ /*
+ * showTemporarily shows the specified elements for the specified time, then
+ * hides it again.
+ */
+ static showTemporarily (timeout: number, ...els: Element[]) {
+ this.show(...els)
+ setTimeout(() => {
+ this.hide(...els)
+ }, timeout)
+ }
+
/*
* show or hide the specified elements, based on value of the truthiness of
* vis.
diff --git a/client/webserver/site/src/js/forms.ts b/client/webserver/site/src/js/forms.ts
index 631f207d96..6c5ea715cd 100644
--- a/client/webserver/site/src/js/forms.ts
+++ b/client/webserver/site/src/js/forms.ts
@@ -2151,14 +2151,13 @@ export class TokenApprovalForm {
export class CEXConfigurationForm {
form: PageElement
page: Record
- success: (cexName: string) => void
+ updated: (cexName: string, success: boolean) => void
cexName: string
- constructor (form: PageElement, success: (cexName: string) => void) {
+ constructor (form: PageElement, updated: (cexName: string, success: boolean) => void) {
this.form = form
- this.success = success
+ this.updated = updated
this.page = Doc.parseTemplate(form)
-
Doc.bind(this.page.cexSubmit, 'click', () => this.submit())
}
@@ -2202,12 +2201,11 @@ export class CEXConfigurationForm {
apiSecret: apiSecret
})
if (!app().checkResponse(res)) throw res
- await app().fetchMMStatus()
- this.success(cexName)
+ this.updated(cexName, true)
} catch (e) {
Doc.show(page.cexFormErr)
page.cexFormErr.textContent = intl.prep(intl.ID_API_ERROR, { msg: e.msg ?? String(e) })
- return
+ this.updated(cexName, false)
} finally {
loaded()
}
diff --git a/client/webserver/site/src/js/locales.ts b/client/webserver/site/src/js/locales.ts
index 7c4ca1b7a6..11521164c2 100644
--- a/client/webserver/site/src/js/locales.ts
+++ b/client/webserver/site/src/js/locales.ts
@@ -217,6 +217,8 @@ export const ID_CEX_TRADE_ERROR = 'CEX_TRADE_ERROR'
export const ID_ORDER_REPORT_TITLE = 'ORDER_REPORT_TITLE'
export const ID_CEX_BALANCES = 'CEX_BALANCES'
export const ID_CAUSES_SELF_MATCH = 'CAUSES_SELF_MATCH'
+export const ID_CEX_NOT_CONNECTED = 'CEX_NOT_CONNECTED'
+export const ID_REMOVING_BOT_CONFIG = 'REMOVING_BOT_CONFIG'
let locale: Locale
diff --git a/client/webserver/site/src/js/mm.ts b/client/webserver/site/src/js/mm.ts
index a5b048239b..df5f68fcfd 100644
--- a/client/webserver/site/src/js/mm.ts
+++ b/client/webserver/site/src/js/mm.ts
@@ -4,13 +4,13 @@ import {
MMBotStatus,
RunStatsNote,
RunEventNote,
- ExchangeBalance,
StartConfig,
OrderPlacement,
AutoRebalanceConfig,
CEXNotification,
EpochReportNote,
- CEXProblemsNote
+ CEXProblemsNote,
+ MarketWithHost
} from './registry'
import {
MM,
@@ -185,6 +185,7 @@ export default class MarketMakerPage extends BasePage {
cexes: Record
twoColumn: boolean
runningMMDisplayElements: RunningMMDisplayElements
+ removingCfg: MarketWithHost | undefined
constructor (main: HTMLElement) {
super()
@@ -198,7 +199,7 @@ export default class MarketMakerPage extends BasePage {
Doc.cleanTemplates(page.botTmpl, page.botRowTmpl, page.exchangeRowTmpl)
this.forms = new Forms(page.forms)
- this.cexConfigForm = new CEXConfigurationForm(page.cexConfigForm, (cexName: string) => this.cexConfigured(cexName))
+ this.cexConfigForm = new CEXConfigurationForm(page.cexConfigForm, (cexName: string, success: boolean) => this.cexConfigured(cexName, success))
this.runningMMDisplayElements = {
orderReportForm: page.orderReportForm,
dexBalancesRowTmpl: page.dexBalancesRowTmpl,
@@ -209,6 +210,7 @@ export default class MarketMakerPage extends BasePage {
Doc.bind(page.newBot, 'click', () => { this.newBot() })
Doc.bind(page.archivedLogsBtn, 'click', () => { app().loadPage('mmarchives') })
+ Doc.bind(page.confirmRemoveConfigBttn, 'click', () => { this.removeCfg() })
this.twoColumn = window.innerWidth >= mediumBreakpoint
const ro = new ResizeObserver(() => { this.resized() })
@@ -279,9 +281,7 @@ export default class MarketMakerPage extends BasePage {
return (b.runStats?.startTime ?? 0) - (a.runStats?.startTime ?? 0)
})
- const startupBalanceCache: Record> = {}
-
- for (const botStatus of sortedBots) this.addBot(botStatus, startupBalanceCache)
+ for (const botStatus of sortedBots) this.addBot(botStatus)
}
async handleCEXNote (n: CEXNotification) {
@@ -307,20 +307,45 @@ export default class MarketMakerPage extends BasePage {
Doc.unbind(document, 'keyup', this.keyup)
}
- addBot (botStatus: MMBotStatus, startupBalanceCache?: Record>) {
+ addBot (botStatus: MMBotStatus) {
const { page, bots, sortedBots } = this
// Make sure the market still exists.
const { config: { baseID, quoteID, host } } = botStatus
const [baseSymbol, quoteSymbol] = [app().assets[baseID].symbol, app().assets[quoteID].symbol]
const mktID = `${baseSymbol}_${quoteSymbol}`
if (!app().exchanges[host]?.markets[mktID]) return
- const bot = new Bot(this, this.runningMMDisplayElements, botStatus, startupBalanceCache)
+ const bot = new Bot(this, this.runningMMDisplayElements, botStatus)
page.botRows.appendChild(bot.row.tr)
sortedBots.push(bot)
bots[bot.id] = bot
this.appendBotBox(bot.div)
}
+ confirmRemoveCfg (mwh: MarketWithHost) {
+ const page = this.page
+ this.removingCfg = mwh
+ Doc.hide(page.removeCfgErr)
+ const baseAsset = app().assets[mwh.baseID]
+ const quoteAsset = app().assets[mwh.quoteID]
+ const baseSymbol = baseAsset.symbol.toUpperCase()
+ const quoteSymbol = quoteAsset.symbol.toUpperCase()
+ page.confirmRemoveCfgMsg.textContent = intl.prep(intl.ID_REMOVING_BOT_CONFIG, { host: mwh.host, baseSymbol, quoteSymbol })
+ this.forms.show(this.page.confirmRemoveForm)
+ }
+
+ async removeCfg () {
+ const page = this.page
+ if (!this.removingCfg) { this.forms.close(); return }
+ const resp = await MM.removeBotConfig(this.removingCfg.host, this.removingCfg.baseID, this.removingCfg.quoteID)
+ if (!app().checkResponse(resp)) {
+ page.removeCfgErr.textContent = intl.prep(intl.ID_API_ERROR, { msg: resp.msg })
+ Doc.show(page.removeCfgErr)
+ return
+ }
+ await app().fetchMMStatus()
+ app().loadPage('mm')
+ }
+
appendBotBox (div: PageElement) {
const { page: { boxZero, boxOne }, twoColumn } = this
const useZeroth = !twoColumn || (boxZero.children.length + boxOne.children.length) % 2 === 0
@@ -352,10 +377,10 @@ export default class MarketMakerPage extends BasePage {
app().loadPage('mmsettings')
}
- async cexConfigured (cexName: string) {
+ async cexConfigured (cexName: string, success: boolean) {
await app().fetchMMStatus()
this.updateCexRow(this.cexes[cexName])
- this.forms.close()
+ if (success) this.forms.close()
}
updateCexRow (row: CEXRow) {
@@ -419,9 +444,8 @@ class Bot extends BotMarket {
row: BotRow
runDisplay: RunningMarketMakerDisplay
- constructor (pg: MarketMakerPage, runningMMElements: RunningMMDisplayElements, status: MMBotStatus, startupBalanceCache?: Record>) {
+ constructor (pg: MarketMakerPage, runningMMElements: RunningMMDisplayElements, status: MMBotStatus) {
super(status.config)
- startupBalanceCache = startupBalanceCache ?? {}
this.pg = pg
const { baseID, quoteID, host, botType, nBuyPlacements, nSellPlacements, cexName } = this
this.id = hostedMarketID(host, baseID, quoteID)
@@ -452,6 +476,7 @@ class Bot extends BotMarket {
Doc.bind(page.startBttn, 'click', () => this.start())
Doc.bind(page.allocationBttn, 'click', () => this.allocate())
Doc.bind(page.reconfigureBttn, 'click', () => this.reconfigure())
+ Doc.bind(page.removeBttn, 'click', () => this.pg.confirmRemoveCfg(status.config))
Doc.bind(page.goBackFromAllocation, 'click', () => this.hideAllocationDialog())
Doc.bind(page.marketLink, 'click', () => app().loadPage('markets', { host, baseID, quoteID }))
@@ -469,11 +494,11 @@ class Bot extends BotMarket {
})
Doc.bind(tr, 'click', () => pg.showBot(this.id))
- this.initialize(startupBalanceCache)
+ this.initialize()
}
- async initialize (startupBalanceCache: Record>) {
- await super.initialize(startupBalanceCache)
+ async initialize () {
+ await super.initialize()
this.runDisplay.setBotMarket(this)
const {
page, host, cexName, botType, div,
@@ -632,13 +657,23 @@ class Bot extends BotMarket {
* confirm allocations and start the bot.
*/
allocate () {
- const f = this.fundingState()
const {
page, marketReport: { baseFiatRate, quoteFiatRate }, baseID, quoteID,
baseFeeID, quoteFeeID, baseFeeFiatRate, quoteFeeFiatRate, cexName,
baseFactor, quoteFactor, baseFeeFactor, quoteFeeFactor, host, mktID
} = this
+ if (cexName) {
+ const cex = app().mmStatus.cexes[cexName]
+ if (!cex || !cex.connected) {
+ page.offError.textContent = intl.prep(intl.ID_CEX_NOT_CONNECTED, { cexName })
+ Doc.showTemporarily(3000, page.offError)
+ return
+ }
+ }
+
+ const f = this.fundingState()
+
const [proposedDexBase, proposedCexBase, baseSlider] = parseFundingOptions(f.base)
const [proposedDexQuote, proposedCexQuote, quoteSlider] = parseFundingOptions(f.quote)
@@ -823,7 +858,15 @@ class Bot extends BotMarket {
}
reconfigure () {
- const { host, baseID, quoteID, cexName, botType } = this
+ const { host, baseID, quoteID, cexName, botType, page } = this
+ if (cexName) {
+ const cex = app().mmStatus.cexes[cexName]
+ if (!cex || !cex.connected) {
+ page.offError.textContent = intl.prep(intl.ID_CEX_NOT_CONNECTED, { cexName })
+ Doc.showTemporarily(3000, page.offError)
+ return
+ }
+ }
app().loadPage('mmsettings', { host, baseID, quoteID, cexName, botType })
}
diff --git a/client/webserver/site/src/js/mmutil.ts b/client/webserver/site/src/js/mmutil.ts
index da1a282c16..f3d951bf26 100644
--- a/client/webserver/site/src/js/mmutil.ts
+++ b/client/webserver/site/src/js/mmutil.ts
@@ -423,8 +423,6 @@ export class BotMarket {
baseLots: number
quoteLots: number
marketReport: MarketReport
- cexBaseBalance?: ExchangeBalance
- cexQuoteBalance?: ExchangeBalance
nBuyPlacements: number
nSellPlacements: number
@@ -499,20 +497,13 @@ export class BotMarket {
}
}
- async initialize (startupBalanceCache: Record>) {
- const { host, baseID, quoteID, lotSizeConv, quoteLotConv, cexName } = this
+ async initialize () {
+ const { host, baseID, quoteID, lotSizeConv, quoteLotConv } = this
const res = await MM.report(host, baseID, quoteID)
const r = this.marketReport = res.report as MarketReport
this.lotSizeUSD = lotSizeConv * r.baseFiatRate
this.quoteLotUSD = quoteLotConv * r.quoteFiatRate
this.proj = this.projectedAllocations()
-
- if (cexName) {
- const b = startupBalanceCache[baseID] = startupBalanceCache[baseID] || MM.cexBalance(cexName, baseID)
- const q = startupBalanceCache[quoteID] = startupBalanceCache[quoteID] || MM.cexBalance(cexName, quoteID)
- this.cexBaseBalance = await b
- this.cexQuoteBalance = await q
- }
}
status () {
@@ -529,16 +520,25 @@ export class BotMarket {
*/
adjustedBalances () {
const {
- baseID, quoteID, baseFeeID, quoteFeeID, cexBaseBalance, cexQuoteBalance,
+ baseID, quoteID, baseFeeID, quoteFeeID, cexName,
baseFactor, quoteFactor, baseFeeFactor, quoteFeeFactor
} = this
const [baseWallet, quoteWallet] = [app().walletMap[baseID], app().walletMap[quoteID]]
const [bInv, qInv] = [runningBotInventory(baseID), runningBotInventory(quoteID)]
+
// In these available balance calcs, only subtract the available balance of
// running bots, since the locked/reserved/immature is already subtracted
// from the wallet's total available balance.
let cexBaseAvail = 0
let cexQuoteAvail = 0
+ let cexBaseBalance: ExchangeBalance | undefined
+ let cexQuoteBalance: ExchangeBalance | undefined
+ if (cexName) {
+ const cex = app().mmStatus.cexes[cexName]
+ if (!cex) throw Error('where\'s the cex status?')
+ cexBaseBalance = cex.balances[baseID]
+ cexQuoteBalance = cex.balances[quoteID]
+ }
if (cexBaseBalance) cexBaseAvail = (cexBaseBalance.available || 0) - bInv.cex.avail
if (cexQuoteBalance) cexQuoteAvail = (cexQuoteBalance.available || 0) - qInv.cex.avail
const [dexBaseAvail, dexQuoteAvail] = [baseWallet.balance.available - bInv.dex.avail, quoteWallet.balance.available - qInv.dex.avail]
@@ -823,7 +823,7 @@ export class RunningMarketMakerDisplay {
const botStatus = app().mmStatus.bots.find(({ config: c }: MMBotStatus) => c.baseID === baseID && c.quoteID === quoteID && c.host === host)
if (!botStatus) return
const mkt = new BotMarket(botStatus.config)
- await mkt.initialize({})
+ await mkt.initialize()
this.setBotMarket(mkt)
}