bbgo: fix reverse pair price lookup and add tests

This commit is contained in:
c9s 2022-09-12 00:05:22 +08:00
parent 3b1725014b
commit 53c4178ae2
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
2 changed files with 103 additions and 8 deletions

View File

@ -130,13 +130,14 @@ func (c *AccountValueCalculator) NetValue(ctx context.Context) (fixedpoint.Value
continue
}
symbol := b.Currency + c.quoteCurrency
price, ok := c.prices[symbol]
if !ok {
continue
symbol := b.Currency + c.quoteCurrency // for BTC/USDT, ETH/USDT pairs
symbolReverse := c.quoteCurrency + b.Currency // for USDT/USDC or USDT/TWD pairs
if price, ok := c.prices[symbol]; ok {
accountValue = accountValue.Add(b.Net().Mul(price))
} else if priceReverse, ok2 := c.prices[symbolReverse]; ok2 {
price2 := one.Div(priceReverse)
accountValue = accountValue.Add(b.Net().Mul(price2))
}
accountValue = accountValue.Add(b.Net().Mul(price))
}
return accountValue, nil
@ -200,6 +201,20 @@ func aggregateUsdValue(balances types.BalanceMap) fixedpoint.Value {
return totalUsdValue
}
func usdFiatBalances(balances types.BalanceMap) (fiats types.BalanceMap, rest types.BalanceMap) {
rest = make(types.BalanceMap)
fiats = make(types.BalanceMap)
for currency, balance := range balances {
if types.IsUSDFiatCurrency(currency) {
fiats[currency] = balance
} else {
rest[currency] = balance
}
}
return fiats, rest
}
func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price, quantity, leverage fixedpoint.Value) (fixedpoint.Value, error) {
// default leverage guard
if leverage.IsZero() {
@ -227,14 +242,23 @@ func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price,
baseBalance, _ := session.Account.Balance(market.BaseCurrency)
quoteBalance, _ := session.Account.Balance(market.QuoteCurrency)
balances := session.Account.Balances()
usdBalances, restBalances := usdFiatBalances(balances)
// for isolated margin we can calculate from these two pair
totalUsdValue := fixedpoint.Zero
if types.IsUSDFiatCurrency(market.QuoteCurrency) {
if len(restBalances) == 1 && types.IsUSDFiatCurrency(market.QuoteCurrency) {
totalUsdValue = aggregateUsdValue(balances)
} else if len(restBalances) > 1 {
accountValue := NewAccountValueCalculator(session, "USDT")
netValue, err := accountValue.NetValue(context.Background())
if err != nil {
return quantity, err
}
totalUsdValue = netValue
} else {
// TODO: translate quote currency like BTC of ETH/BTC to usd value
totalUsdValue = quoteBalance.Net()
totalUsdValue = aggregateUsdValue(usdBalances)
}
if !quantity.IsZero() {

View File

@ -155,3 +155,74 @@ func TestNewAccountValueCalculator_MarginLevel(t *testing.T) {
fixedpoint.NewFromFloat(21000.0).Div(fixedpoint.NewFromFloat(19000.0).Mul(fixedpoint.NewFromFloat(1.003))).FormatString(6),
marginLevel.FormatString(6))
}
func number(n float64) fixedpoint.Value {
return fixedpoint.NewFromFloat(n)
}
func Test_aggregateUsdValue(t *testing.T) {
type args struct {
balances types.BalanceMap
}
tests := []struct {
name string
args args
want fixedpoint.Value
}{
{
name: "mixed",
args: args{
balances: types.BalanceMap{
"USDC": types.Balance{Currency: "USDC", Available: number(70.0)},
"USDT": types.Balance{Currency: "USDT", Available: number(100.0)},
"BUSD": types.Balance{Currency: "BUSD", Available: number(80.0)},
"BTC": types.Balance{Currency: "BTC", Available: number(0.01)},
},
},
want: number(250.0),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, aggregateUsdValue(tt.args.balances), "aggregateUsdValue(%v)", tt.args.balances)
})
}
}
func Test_usdFiatBalances(t *testing.T) {
type args struct {
balances types.BalanceMap
}
tests := []struct {
name string
args args
wantFiats types.BalanceMap
wantRest types.BalanceMap
}{
{
args: args{
balances: types.BalanceMap{
"USDC": types.Balance{Currency: "USDC", Available: number(70.0)},
"USDT": types.Balance{Currency: "USDT", Available: number(100.0)},
"BUSD": types.Balance{Currency: "BUSD", Available: number(80.0)},
"BTC": types.Balance{Currency: "BTC", Available: number(0.01)},
},
},
wantFiats: types.BalanceMap{
"USDC": types.Balance{Currency: "USDC", Available: number(70.0)},
"USDT": types.Balance{Currency: "USDT", Available: number(100.0)},
"BUSD": types.Balance{Currency: "BUSD", Available: number(80.0)},
},
wantRest: types.BalanceMap{
"BTC": types.Balance{Currency: "BTC", Available: number(0.01)},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotFiats, gotRest := usdFiatBalances(tt.args.balances)
assert.Equalf(t, tt.wantFiats, gotFiats, "usdFiatBalances(%v)", tt.args.balances)
assert.Equalf(t, tt.wantRest, gotRest, "usdFiatBalances(%v)", tt.args.balances)
})
}
}