Skip to content

Commit 6055d5c

Browse files
Patrick BanksPatrick Banks
authored andcommitted
Added cache for balances
1 parent 70abd39 commit 6055d5c

File tree

2 files changed

+51
-21
lines changed

2 files changed

+51
-21
lines changed

src/trader/apis/binance.ts

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ const sandbox = process.env.NODE_ENV === "staging"
1313

1414
// Used to track when the last buy / sell / borrow / repay occurred to allow for balance sync
1515
// This should always be updated before and after the transaction is executed on Binance
16-
let lastChangeTime = 0
16+
const lastChangeTimes: Dictionary<Number> = {}
17+
18+
// Cached balances for better performance, especially for the fall back wallet that is not used often
19+
const balances: Dictionary<ccxt.Balances> = {}
20+
const balanceTimestamps: Dictionary<Number> = {}
1721

1822
if (process.env.NODE_ENV !== "test") {
1923
binanceClient = new ccxt.binance({
@@ -56,13 +60,24 @@ export async function fetchBalance(type: WalletType): Promise<ccxt.Balances> {
5660
// Hack, as you can't look up margin balances on testnet (NotSupported error), but this is only for testing
5761
if (sandbox) type = WalletType.SPOT
5862

63+
// If a wallet has been touched then it will already be cleared from the cache
64+
if (balances.hasOwnProperty(type)) {
65+
// Check that the cached balances are less than 24 hours old
66+
const elapsed = Date.now() - (balanceTimestamps[type] as number)
67+
if (elapsed >=0 && elapsed < 24 * 60 * 60 * 1000) {
68+
// Use the cache
69+
logger.debug(`Using cached ${type} balances.`)
70+
return balances[type]
71+
}
72+
}
73+
5974
// According to Binance support it can take from 1 to 10 seconds for the balances to sync after making a trade
6075
// Therefore if there are a lot of signals happening at the same time it can give the wrong results, so we're just going to slow it down a bit
6176
// The recommended subscribing to the web socket for user updates, but that would be more work, and hopefully this won't happen too often
6277
// Just in case another trade happens while waiting, check again after waiting
63-
while (timeSinceLastChange() < env().BALANCE_SYNC_DELAY) {
78+
while (timeSinceLastChange(type) < env().BALANCE_SYNC_DELAY) {
6479
// Add an extra 10ms just so we don't go around again
65-
const delay = (env().BALANCE_SYNC_DELAY - timeSinceLastChange()) + 10
80+
const delay = (env().BALANCE_SYNC_DELAY - timeSinceLastChange(type)) + 10
6681

6782
logger.debug(`Waiting ${delay} milliseconds to allow balances to synchronise.`)
6883

@@ -112,65 +127,83 @@ export function getMarginLoans(marginBalance: ccxt.Balances): Dictionary<Loan> {
112127
}
113128
}
114129

115-
// Calculate how much time has elapsed since the balances were changed in Binance
116-
function timeSinceLastChange(): number {
130+
// Calculate how much time has elapsed since the balances were changed in Binance for the specified wallet
131+
function timeSinceLastChange(type: WalletType): number {
117132
const now = Date.now()
118133

134+
// Initialise
135+
if (!lastChangeTimes.hasOwnProperty(type)) lastChangeTimes[type] = 0
136+
119137
// Maybe a time update, so we can't trust it anymore
120-
if (now < lastChangeTime) lastChangeTime = 0
138+
if (now < lastChangeTimes[type]) lastChangeTimes[type] = 0
121139

122-
return now - lastChangeTime
140+
return now - (lastChangeTimes[type] as number)
123141
}
124142

143+
// Update the time of last change and reset the balances for a specified wallet
144+
function balanceChanged(type: WalletType) {
145+
lastChangeTimes[type] = Date.now()
146+
147+
if (balances.hasOwnProperty(type)) {
148+
delete balances[type]
149+
delete balanceTimestamps[type]
150+
}
151+
}
152+
153+
// Places a market order for a symbol pair on the specified wallet
125154
export async function createMarketOrder(
126155
symbol: string,
127156
side: "buy" | "sell",
128157
amount: BigNumber,
129-
price?: BigNumber,
130-
params?: ccxt.Params
158+
walletType: WalletType,
159+
price?: BigNumber
131160
): Promise<ccxt.Order> {
132161
if (!binanceClient) return Promise.reject(logBinanceUndefined)
133-
lastChangeTime = Date.now()
162+
balanceChanged(walletType)
134163
return binanceClient.createMarketOrder(
135164
symbol,
136165
side,
137166
amount.toNumber(),
138167
price?.toNumber(),
139-
params
168+
{
169+
type: walletType
170+
}
140171
).then((result) => {
141-
lastChangeTime = Date.now()
172+
balanceChanged(walletType)
142173
return result
143174
})
144175
}
145176

177+
// Borrows an asset on the cross margin wallet
146178
export async function marginBorrow(
147179
asset: string,
148180
amount: BigNumber
149181
): Promise<LoanTransaction> {
150182
if (!binanceClient) return Promise.reject(logBinanceUndefined)
151-
lastChangeTime = Date.now()
183+
balanceChanged(WalletType.MARGIN)
152184
return binanceClient.sapiPostMarginLoan({
153185
asset,
154186
//isIsolated: 'FALSE', // "FALSE" for cross margin borrow without specification of a symbol.
155187
amount: amount.toFixed()
156188
}).then((result: LoanTransaction) => {
157-
lastChangeTime = Date.now()
189+
balanceChanged(WalletType.MARGIN)
158190
return result
159191
})
160192
}
161193

194+
// Repays an asset on the cross margin wallet
162195
export async function marginRepay(
163196
asset: string,
164197
amount: BigNumber
165198
): Promise<LoanTransaction> {
166199
if (!binanceClient) return Promise.reject(logBinanceUndefined)
167-
lastChangeTime = Date.now()
200+
balanceChanged(WalletType.MARGIN)
168201
return binanceClient.sapiPostMarginRepay({
169202
asset,
170203
//isIsolated: 'FALSE', // "FALSE" for cross margin repay without specification of a symbol.
171204
amount: amount.toFixed()
172205
}).then((result: LoanTransaction) => {
173-
lastChangeTime = Date.now()
206+
balanceChanged(WalletType.MARGIN)
174207
return result
175208
})
176209
}

src/trader/trader.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,10 +1039,7 @@ async function executeTradeAction(
10391039
symbolAsset,
10401040
action,
10411041
quantity,
1042-
undefined,
1043-
{
1044-
type: tradeOpen.wallet!,
1045-
}
1042+
tradeOpen.wallet!
10461043
)
10471044
:
10481045
createVirtualOrder(
@@ -2413,7 +2410,7 @@ async function sellEverything(base: string, fraction: number) {
24132410
if (market && balances[quote].free) {
24142411
const qty = balances[quote].free * fraction
24152412
logger.debug(`Selling ${qty} ${quote}.`)
2416-
logger.debug(await createMarketOrder(quote + "/" + base, "sell", new BigNumber(qty)).then(order => `${order.status} ${order.cost}`).catch(e => e.name))
2413+
logger.debug(await createMarketOrder(quote + "/" + base, "sell", new BigNumber(qty), WalletType.SPOT).then(order => `${order.status} ${order.cost}`).catch(e => e.name))
24172414
}
24182415
}
24192416
await fetchBalance(WalletType.SPOT)

0 commit comments

Comments
 (0)