mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-25 16:25:16 +00:00
Merge pull request #944 from c9s/fix/net-asset-calc
fix: fix net asset calculation
This commit is contained in:
commit
53059824a6
|
@ -115,32 +115,36 @@ func (c *AccountValueCalculator) MarketValue(ctx context.Context) (fixedpoint.Va
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AccountValueCalculator) NetValue(ctx context.Context) (fixedpoint.Value, error) {
|
func (c *AccountValueCalculator) NetValue(ctx context.Context) (fixedpoint.Value, error) {
|
||||||
accountValue := fixedpoint.Zero
|
|
||||||
|
|
||||||
if len(c.prices) == 0 {
|
if len(c.prices) == 0 {
|
||||||
if err := c.UpdatePrices(ctx); err != nil {
|
if err := c.UpdatePrices(ctx); err != nil {
|
||||||
return accountValue, err
|
return fixedpoint.Zero, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
balances := c.session.Account.Balances()
|
balances := c.session.Account.Balances()
|
||||||
|
accountValue := calculateNetValueInQuote(balances, c.prices, c.quoteCurrency)
|
||||||
|
return accountValue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateNetValueInQuote(balances types.BalanceMap, prices types.PriceMap, quoteCurrency string) (accountValue fixedpoint.Value) {
|
||||||
|
accountValue = fixedpoint.Zero
|
||||||
|
|
||||||
for _, b := range balances {
|
for _, b := range balances {
|
||||||
if b.Currency == c.quoteCurrency {
|
if b.Currency == quoteCurrency {
|
||||||
accountValue = accountValue.Add(b.Net())
|
accountValue = accountValue.Add(b.Net())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol := b.Currency + c.quoteCurrency // for BTC/USDT, ETH/USDT pairs
|
symbol := b.Currency + quoteCurrency // for BTC/USDT, ETH/USDT pairs
|
||||||
symbolReverse := c.quoteCurrency + b.Currency // for USDT/USDC or USDT/TWD pairs
|
symbolReverse := quoteCurrency + b.Currency // for USDT/USDC or USDT/TWD pairs
|
||||||
if price, ok := c.prices[symbol]; ok {
|
if price, ok := prices[symbol]; ok {
|
||||||
accountValue = accountValue.Add(b.Net().Mul(price))
|
accountValue = accountValue.Add(b.Net().Mul(price))
|
||||||
} else if priceReverse, ok2 := c.prices[symbolReverse]; ok2 {
|
} else if priceReverse, ok2 := prices[symbolReverse]; ok2 {
|
||||||
price2 := one.Div(priceReverse)
|
accountValue = accountValue.Add(b.Net().Div(priceReverse))
|
||||||
accountValue = accountValue.Add(b.Net().Mul(price2))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return accountValue, nil
|
return accountValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *AccountValueCalculator) AvailableQuote(ctx context.Context) (fixedpoint.Value, error) {
|
func (c *AccountValueCalculator) AvailableQuote(ctx context.Context) (fixedpoint.Value, error) {
|
||||||
|
@ -189,7 +193,7 @@ func (c *AccountValueCalculator) MarginLevel(ctx context.Context) (fixedpoint.Va
|
||||||
return marginLevel, nil
|
return marginLevel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func aggregateUsdValue(balances types.BalanceMap) fixedpoint.Value {
|
func aggregateUsdNetValue(balances types.BalanceMap) fixedpoint.Value {
|
||||||
totalUsdValue := fixedpoint.Zero
|
totalUsdValue := fixedpoint.Zero
|
||||||
// get all usd value if any
|
// get all usd value if any
|
||||||
for currency, balance := range balances {
|
for currency, balance := range balances {
|
||||||
|
@ -247,7 +251,7 @@ func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price,
|
||||||
// for isolated margin we can calculate from these two pair
|
// for isolated margin we can calculate from these two pair
|
||||||
totalUsdValue := fixedpoint.Zero
|
totalUsdValue := fixedpoint.Zero
|
||||||
if len(restBalances) == 1 && types.IsUSDFiatCurrency(market.QuoteCurrency) {
|
if len(restBalances) == 1 && types.IsUSDFiatCurrency(market.QuoteCurrency) {
|
||||||
totalUsdValue = aggregateUsdValue(balances)
|
totalUsdValue = aggregateUsdNetValue(balances)
|
||||||
} else if len(restBalances) > 1 {
|
} else if len(restBalances) > 1 {
|
||||||
accountValue := NewAccountValueCalculator(session, "USDT")
|
accountValue := NewAccountValueCalculator(session, "USDT")
|
||||||
netValue, err := accountValue.NetValue(context.Background())
|
netValue, err := accountValue.NetValue(context.Background())
|
||||||
|
@ -258,7 +262,7 @@ func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price,
|
||||||
totalUsdValue = netValue
|
totalUsdValue = netValue
|
||||||
} else {
|
} else {
|
||||||
// TODO: translate quote currency like BTC of ETH/BTC to usd value
|
// TODO: translate quote currency like BTC of ETH/BTC to usd value
|
||||||
totalUsdValue = aggregateUsdValue(usdBalances)
|
totalUsdValue = aggregateUsdNetValue(usdBalances)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !quantity.IsZero() {
|
if !quantity.IsZero() {
|
||||||
|
@ -270,7 +274,7 @@ func CalculateBaseQuantity(session *ExchangeSession, market types.Market, price,
|
||||||
}
|
}
|
||||||
|
|
||||||
// using leverage -- starts from here
|
// using leverage -- starts from here
|
||||||
log.Infof("calculating available leveraged base quantity: base balance = %+v, quote balance = %+v", baseBalance, quoteBalance)
|
log.Infof("calculating available leveraged base quantity: base balance = %+v, total usd value %f", baseBalance, totalUsdValue.Float64())
|
||||||
|
|
||||||
// calculate the quantity automatically
|
// calculate the quantity automatically
|
||||||
if session.Margin || session.IsolatedMargin {
|
if session.Margin || session.IsolatedMargin {
|
||||||
|
|
|
@ -184,7 +184,7 @@ func Test_aggregateUsdValue(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
assert.Equalf(t, tt.want, aggregateUsdValue(tt.args.balances), "aggregateUsdValue(%v)", tt.args.balances)
|
assert.Equalf(t, tt.want, aggregateUsdNetValue(tt.args.balances), "aggregateUsdNetValue(%v)", tt.args.balances)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,3 +226,98 @@ func Test_usdFiatBalances(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_calculateNetValueInQuote(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
balances types.BalanceMap
|
||||||
|
prices types.PriceMap
|
||||||
|
quoteCurrency string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantAccountValue fixedpoint.Value
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "positive asset",
|
||||||
|
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)},
|
||||||
|
},
|
||||||
|
prices: types.PriceMap{
|
||||||
|
"USDCUSDT": number(1.0),
|
||||||
|
"BUSDUSDT": number(1.0),
|
||||||
|
"BTCUSDT": number(19000.0),
|
||||||
|
},
|
||||||
|
quoteCurrency: "USDT",
|
||||||
|
},
|
||||||
|
wantAccountValue: number(19000.0*0.01 + 100.0 + 80.0 + 70.0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reversed usdt price",
|
||||||
|
args: args{
|
||||||
|
balances: types.BalanceMap{
|
||||||
|
"USDC": types.Balance{Currency: "USDC", Available: number(70.0)},
|
||||||
|
"TWD": types.Balance{Currency: "TWD", Available: number(3000.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)},
|
||||||
|
},
|
||||||
|
prices: types.PriceMap{
|
||||||
|
"USDTTWD": number(30.0),
|
||||||
|
"USDCUSDT": number(1.0),
|
||||||
|
"BUSDUSDT": number(1.0),
|
||||||
|
"BTCUSDT": number(19000.0),
|
||||||
|
},
|
||||||
|
quoteCurrency: "USDT",
|
||||||
|
},
|
||||||
|
wantAccountValue: number(19000.0*0.01 + 100.0 + 80.0 + 70.0 + (3000.0 / 30.0)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "borrow base asset",
|
||||||
|
args: args{
|
||||||
|
balances: types.BalanceMap{
|
||||||
|
"USDT": types.Balance{Currency: "USDT", Available: number(20000.0 * 2)},
|
||||||
|
"USDC": types.Balance{Currency: "USDC", Available: number(70.0)},
|
||||||
|
"BUSD": types.Balance{Currency: "BUSD", Available: number(80.0)},
|
||||||
|
"BTC": types.Balance{Currency: "BTC", Available: number(0), Borrowed: number(2.0)},
|
||||||
|
},
|
||||||
|
prices: types.PriceMap{
|
||||||
|
"USDCUSDT": number(1.0),
|
||||||
|
"BUSDUSDT": number(1.0),
|
||||||
|
"BTCUSDT": number(19000.0),
|
||||||
|
},
|
||||||
|
quoteCurrency: "USDT",
|
||||||
|
},
|
||||||
|
wantAccountValue: number(19000.0*-2.0 + 20000.0*2 + 80.0 + 70.0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "multi base asset",
|
||||||
|
args: args{
|
||||||
|
balances: types.BalanceMap{
|
||||||
|
"USDT": types.Balance{Currency: "USDT", Available: number(20000.0 * 2)},
|
||||||
|
"USDC": types.Balance{Currency: "USDC", Available: number(70.0)},
|
||||||
|
"BUSD": types.Balance{Currency: "BUSD", Available: number(80.0)},
|
||||||
|
"ETH": types.Balance{Currency: "ETH", Available: number(10.0)},
|
||||||
|
"BTC": types.Balance{Currency: "BTC", Available: number(0), Borrowed: number(2.0)},
|
||||||
|
},
|
||||||
|
prices: types.PriceMap{
|
||||||
|
"USDCUSDT": number(1.0),
|
||||||
|
"BUSDUSDT": number(1.0),
|
||||||
|
"ETHUSDT": number(1700.0),
|
||||||
|
"BTCUSDT": number(19000.0),
|
||||||
|
},
|
||||||
|
quoteCurrency: "USDT",
|
||||||
|
},
|
||||||
|
wantAccountValue: number(19000.0*-2.0 + 1700.0*10.0 + 20000.0*2 + 80.0 + 70.0),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equalf(t, tt.wantAccountValue, calculateNetValueInQuote(tt.args.balances, tt.args.prices, tt.args.quoteCurrency), "calculateNetValueInQuote(%v, %v, %v)", tt.args.balances, tt.args.prices, tt.args.quoteCurrency)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@ type FailedBreakHigh struct {
|
||||||
// Ratio is a number less than 1.0, price * ratio will be the price triggers the short order.
|
// Ratio is a number less than 1.0, price * ratio will be the price triggers the short order.
|
||||||
Ratio fixedpoint.Value `json:"ratio"`
|
Ratio fixedpoint.Value `json:"ratio"`
|
||||||
|
|
||||||
|
// EarlyStopRatio adjusts the break high price with the given ratio
|
||||||
|
// this is for stop loss earlier if the price goes above the previous price
|
||||||
|
EarlyStopRatio fixedpoint.Value `json:"earlyStopRatio"`
|
||||||
|
|
||||||
VWMA *types.IntervalWindow `json:"vwma"`
|
VWMA *types.IntervalWindow `json:"vwma"`
|
||||||
|
|
||||||
StopEMA *bbgo.StopEMA `json:"stopEMA"`
|
StopEMA *bbgo.StopEMA `json:"stopEMA"`
|
||||||
|
@ -123,7 +127,7 @@ func (s *FailedBreakHigh) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
bbgo.Notify("%s new pivot low: %f", s.Symbol, s.pivotHigh.Last())
|
bbgo.Notify("%s new pivot high: %f", s.Symbol, s.pivotHigh.Last())
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -149,9 +153,16 @@ func (s *FailedBreakHigh) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastHigh := s.lastFastHigh
|
||||||
|
|
||||||
|
if !s.EarlyStopRatio.IsZero() {
|
||||||
|
lastHigh = lastHigh.Mul(one.Add(s.EarlyStopRatio))
|
||||||
|
}
|
||||||
|
|
||||||
// the kline opened below the last break low, and closed above the last break low
|
// the kline opened below the last break low, and closed above the last break low
|
||||||
if k.Open.Compare(s.lastFailedBreakHigh) < 0 && k.Close.Compare(s.lastFailedBreakHigh) > 0 {
|
if k.Open.Compare(lastHigh) < 0 && k.Close.Compare(lastHigh) > 0 && k.Open.Compare(k.Close) > 0 {
|
||||||
bbgo.Notify("kLine closed above the last break high, triggering stop earlier")
|
bbgo.Notify("kLine closed %f above the last break high %f (ratio %f), triggering stop earlier", k.Close.Float64(), lastHigh.Float64(), s.EarlyStopRatio.Float64())
|
||||||
|
|
||||||
if err := s.orderExecutor.ClosePosition(context.Background(), one, "failedBreakHighStop"); err != nil {
|
if err := s.orderExecutor.ClosePosition(context.Background(), one, "failedBreakHighStop"); err != nil {
|
||||||
log.WithError(err).Error("position close error")
|
log.WithError(err).Error("position close error")
|
||||||
}
|
}
|
||||||
|
@ -182,13 +193,13 @@ func (s *FailedBreakHigh) Bind(session *bbgo.ExchangeSession, orderExecutor *bbg
|
||||||
// we need few conditions:
|
// we need few conditions:
|
||||||
// 1) kline.High is higher than the previous high
|
// 1) kline.High is higher than the previous high
|
||||||
// 2) kline.Close is lower than the previous high
|
// 2) kline.Close is lower than the previous high
|
||||||
// 3) kline.Close is lower than kline.Open
|
|
||||||
if kline.High.Compare(breakPrice) < 0 || closePrice.Compare(breakPrice) >= 0 {
|
if kline.High.Compare(breakPrice) < 0 || closePrice.Compare(breakPrice) >= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3) kline.Close is lower than kline.Open
|
||||||
if closePrice.Compare(openPrice) > 0 {
|
if closePrice.Compare(openPrice) > 0 {
|
||||||
bbgo.Notify("the closed price is higher than the open price, skip failed break high short")
|
bbgo.Notify("the %s closed price %f is higher than the open price %f, skip failed break high short", s.Symbol, closePrice.Float64(), openPrice.Float64())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ func (s *Strategy) recordNetAssetValue(ctx context.Context, sessions map[string]
|
||||||
|
|
||||||
for currency, asset := range totalAssets {
|
for currency, asset := range totalAssets {
|
||||||
// calculated if it's dust only when InUSD (usd value) is defined.
|
// calculated if it's dust only when InUSD (usd value) is defined.
|
||||||
if s.IgnoreDusts && !asset.InUSD.IsZero() && asset.InUSD.Compare(Ten) < 0 {
|
if s.IgnoreDusts && !asset.InUSD.IsZero() && asset.InUSD.Compare(Ten) < 0 && asset.InUSD.Compare(Ten.Neg()) > 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@ import (
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PriceMap map[string]fixedpoint.Value
|
||||||
|
|
||||||
type Balance struct {
|
type Balance struct {
|
||||||
Currency string `json:"currency"`
|
Currency string `json:"currency"`
|
||||||
Available fixedpoint.Value `json:"available"`
|
Available fixedpoint.Value `json:"available"`
|
||||||
|
@ -50,7 +52,7 @@ func (b Balance) Debt() fixedpoint.Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Balance) ValueString() (o string) {
|
func (b Balance) ValueString() (o string) {
|
||||||
o = b.Available.String()
|
o = b.Net().String()
|
||||||
|
|
||||||
if b.Locked.Sign() > 0 {
|
if b.Locked.Sign() > 0 {
|
||||||
o += fmt.Sprintf(" (locked %v)", b.Locked)
|
o += fmt.Sprintf(" (locked %v)", b.Locked)
|
||||||
|
@ -64,7 +66,7 @@ func (b Balance) ValueString() (o string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Balance) String() (o string) {
|
func (b Balance) String() (o string) {
|
||||||
o = fmt.Sprintf("%s: %s", b.Currency, b.Available.String())
|
o = fmt.Sprintf("%s: %s", b.Currency, b.Net().String())
|
||||||
|
|
||||||
if b.Locked.Sign() > 0 {
|
if b.Locked.Sign() > 0 {
|
||||||
o += fmt.Sprintf(" (locked %v)", b.Locked)
|
o += fmt.Sprintf(" (locked %v)", b.Locked)
|
||||||
|
@ -74,6 +76,10 @@ func (b Balance) String() (o string) {
|
||||||
o += fmt.Sprintf(" (borrowed: %v)", b.Borrowed)
|
o += fmt.Sprintf(" (borrowed: %v)", b.Borrowed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b.Interest.Sign() > 0 {
|
||||||
|
o += fmt.Sprintf(" (interest: %v)", b.Interest)
|
||||||
|
}
|
||||||
|
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +161,7 @@ func (m BalanceMap) Copy() (d BalanceMap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assets converts balances into assets with the given prices
|
// Assets converts balances into assets with the given prices
|
||||||
func (m BalanceMap) Assets(prices map[string]fixedpoint.Value, priceTime time.Time) AssetMap {
|
func (m BalanceMap) Assets(prices PriceMap, priceTime time.Time) AssetMap {
|
||||||
assets := make(AssetMap)
|
assets := make(AssetMap)
|
||||||
|
|
||||||
_, btcInUSD, hasBtcPrice := findUSDMarketPrice("BTC", prices)
|
_, btcInUSD, hasBtcPrice := findUSDMarketPrice("BTC", prices)
|
||||||
|
@ -163,6 +169,7 @@ func (m BalanceMap) Assets(prices map[string]fixedpoint.Value, priceTime time.Ti
|
||||||
for currency, b := range m {
|
for currency, b := range m {
|
||||||
total := b.Total()
|
total := b.Total()
|
||||||
netAsset := b.Net()
|
netAsset := b.Net()
|
||||||
|
|
||||||
if total.IsZero() && netAsset.IsZero() {
|
if total.IsZero() && netAsset.IsZero() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -178,7 +185,7 @@ func (m BalanceMap) Assets(prices map[string]fixedpoint.Value, priceTime time.Ti
|
||||||
NetAsset: netAsset,
|
NetAsset: netAsset,
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(currency, "USD") { // for usd
|
if IsUSDFiatCurrency(currency) { // for usd
|
||||||
asset.InUSD = netAsset
|
asset.InUSD = netAsset
|
||||||
asset.PriceInUSD = fixedpoint.One
|
asset.PriceInUSD = fixedpoint.One
|
||||||
if hasBtcPrice && !asset.InUSD.IsZero() {
|
if hasBtcPrice && !asset.InUSD.IsZero() {
|
||||||
|
@ -187,7 +194,7 @@ func (m BalanceMap) Assets(prices map[string]fixedpoint.Value, priceTime time.Ti
|
||||||
} else { // for crypto
|
} else { // for crypto
|
||||||
if market, usdPrice, ok := findUSDMarketPrice(currency, prices); ok {
|
if market, usdPrice, ok := findUSDMarketPrice(currency, prices); ok {
|
||||||
// this includes USDT, USD, USDC and so on
|
// this includes USDT, USD, USDC and so on
|
||||||
if strings.HasPrefix(market, "USD") { // for prices like USDT/TWD
|
if strings.HasPrefix(market, "USD") || strings.HasPrefix(market, "BUSD") { // for prices like USDT/TWD, BUSD/USDT
|
||||||
if !asset.NetAsset.IsZero() {
|
if !asset.NetAsset.IsZero() {
|
||||||
asset.InUSD = asset.NetAsset.Div(usdPrice)
|
asset.InUSD = asset.NetAsset.Div(usdPrice)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
@ -37,3 +38,61 @@ func TestBalanceMap_Add(t *testing.T) {
|
||||||
assert.Len(t, bm3, 2)
|
assert.Len(t, bm3, 2)
|
||||||
assert.Equal(t, fixedpoint.MustNewFromString("11.0"), bm3["BTC"].Available)
|
assert.Equal(t, fixedpoint.MustNewFromString("11.0"), bm3["BTC"].Available)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBalanceMap_Assets(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
prices PriceMap
|
||||||
|
priceTime time.Time
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
m BalanceMap
|
||||||
|
args args
|
||||||
|
want AssetMap
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
m: BalanceMap{
|
||||||
|
"USDT": Balance{Currency: "USDT", Available: number(100.0)},
|
||||||
|
"BTC": Balance{Currency: "BTC", Borrowed: number(2.0)},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
prices: PriceMap{
|
||||||
|
"BTCUSDT": number(19000.0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: AssetMap{
|
||||||
|
"USDT": {
|
||||||
|
Currency: "USDT",
|
||||||
|
Total: number(100),
|
||||||
|
NetAsset: number(100.0),
|
||||||
|
Interest: number(0),
|
||||||
|
InUSD: number(100.0),
|
||||||
|
InBTC: number(100.0 / 19000.0),
|
||||||
|
Time: time.Time{},
|
||||||
|
Locked: number(0),
|
||||||
|
Available: number(100.0),
|
||||||
|
Borrowed: number(0),
|
||||||
|
PriceInUSD: number(1.0),
|
||||||
|
},
|
||||||
|
"BTC": {
|
||||||
|
Currency: "BTC",
|
||||||
|
Total: number(0),
|
||||||
|
NetAsset: number(-2),
|
||||||
|
Interest: number(0),
|
||||||
|
InUSD: number(-2 * 19000.0),
|
||||||
|
InBTC: number(-2),
|
||||||
|
Time: time.Time{},
|
||||||
|
Locked: number(0),
|
||||||
|
Available: number(0),
|
||||||
|
Borrowed: number(2),
|
||||||
|
PriceInUSD: number(19000.0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equalf(t, tt.want, tt.m.Assets(tt.args.prices, tt.args.priceTime), "Assets(%v, %v)", tt.args.prices, tt.args.priceTime)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user