mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
refactor balance, asset and remove price cache check
This commit is contained in:
parent
f33e8a3de2
commit
36c764efa9
|
@ -649,9 +649,10 @@ func (session *ExchangeSession) FormatOrder(order types.SubmitOrder) (types.Subm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *ExchangeSession) UpdatePrices(ctx context.Context, currencies []string, fiat string) (err error) {
|
func (session *ExchangeSession) UpdatePrices(ctx context.Context, currencies []string, fiat string) (err error) {
|
||||||
if session.lastPriceUpdatedAt.After(time.Now().Add(-time.Hour)) {
|
// TODO: move this cache check to the http routes
|
||||||
return nil
|
// if session.lastPriceUpdatedAt.After(time.Now().Add(-time.Hour)) {
|
||||||
}
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
var symbols []string
|
var symbols []string
|
||||||
for _, c := range currencies {
|
for _, c := range currencies {
|
||||||
|
|
|
@ -78,7 +78,6 @@ var Ten = fixedpoint.NewFromInt(10)
|
||||||
func (s *Strategy) CrossSubscribe(sessions map[string]*bbgo.ExchangeSession) {}
|
func (s *Strategy) CrossSubscribe(sessions map[string]*bbgo.ExchangeSession) {}
|
||||||
|
|
||||||
func (s *Strategy) recordNetAssetValue(ctx context.Context, sessions map[string]*bbgo.ExchangeSession) {
|
func (s *Strategy) recordNetAssetValue(ctx context.Context, sessions map[string]*bbgo.ExchangeSession) {
|
||||||
totalAssets := types.AssetMap{}
|
|
||||||
totalBalances := types.BalanceMap{}
|
totalBalances := types.BalanceMap{}
|
||||||
allPrices := map[string]fixedpoint.Value{}
|
allPrices := map[string]fixedpoint.Value{}
|
||||||
sessionBalances := map[string]types.BalanceMap{}
|
sessionBalances := map[string]types.BalanceMap{}
|
||||||
|
@ -113,19 +112,20 @@ func (s *Strategy) recordNetAssetValue(ctx context.Context, sessions map[string]
|
||||||
s.Environment.RecordAsset(priceTime, session, assets)
|
s.Environment.RecordAsset(priceTime, session, assets)
|
||||||
}
|
}
|
||||||
|
|
||||||
allAssets := totalBalances.Assets(allPrices, priceTime)
|
displayAssets := types.AssetMap{}
|
||||||
for currency, asset := range allAssets {
|
totalAssets := totalBalances.Assets(allPrices, priceTime)
|
||||||
|
s.Environment.RecordAsset(priceTime, &bbgo.ExchangeSession{Name: "ALL"}, 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 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
totalAssets[currency] = asset
|
displayAssets[currency] = asset
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Environment.RecordAsset(priceTime, &bbgo.ExchangeSession{Name: "ALL"}, totalAssets)
|
s.Notifiability.Notify(displayAssets)
|
||||||
|
|
||||||
s.Notifiability.Notify(totalAssets)
|
|
||||||
|
|
||||||
if s.state != nil {
|
if s.state != nil {
|
||||||
if s.state.IsOver24Hours() {
|
if s.state.IsOver24Hours() {
|
||||||
|
@ -196,7 +196,7 @@ func (s *Strategy) CrossRun(ctx context.Context, _ bbgo.OrderExecutionRouter, se
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: if interval is supported, we can use kline as the ticker
|
// TODO: if interval is supported, we can use kline as the ticker
|
||||||
if _, ok := types.SupportedIntervals[s.Interval] ; ok {
|
if _, ok := types.SupportedIntervals[s.Interval]; ok {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,7 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/slack-go/slack"
|
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -21,253 +16,12 @@ func init() {
|
||||||
debugBalance = viper.GetBool("debug-balance")
|
debugBalance = viper.GetBool("debug-balance")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Balance struct {
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Available fixedpoint.Value `json:"available"`
|
|
||||||
Locked fixedpoint.Value `json:"locked,omitempty"`
|
|
||||||
|
|
||||||
// margin related fields
|
|
||||||
Borrowed fixedpoint.Value `json:"borrowed,omitempty"`
|
|
||||||
Interest fixedpoint.Value `json:"interest,omitempty"`
|
|
||||||
|
|
||||||
// NetAsset = (Available + Locked) - Borrowed - Interest
|
|
||||||
NetAsset fixedpoint.Value `json:"net,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Balance) Total() fixedpoint.Value {
|
|
||||||
return b.Available.Add(b.Locked)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Balance) String() (o string) {
|
|
||||||
|
|
||||||
o = fmt.Sprintf("%s: %s", b.Currency, b.Available.String())
|
|
||||||
|
|
||||||
if b.Locked.Sign() > 0 {
|
|
||||||
o += fmt.Sprintf(" (locked %v)", b.Locked)
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.Borrowed.Sign() > 0 {
|
|
||||||
o += fmt.Sprintf(" (borrowed: %v)", b.Borrowed)
|
|
||||||
}
|
|
||||||
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
type Asset struct {
|
|
||||||
Currency string `json:"currency" db:"currency"`
|
|
||||||
Total fixedpoint.Value `json:"total" db:"total"`
|
|
||||||
InUSD fixedpoint.Value `json:"inUSD" db:"in_usd"`
|
|
||||||
InBTC fixedpoint.Value `json:"inBTC" db:"in_btc"`
|
|
||||||
Time time.Time `json:"time" db:"time"`
|
|
||||||
Locked fixedpoint.Value `json:"lock" db:"lock" `
|
|
||||||
Available fixedpoint.Value `json:"available" db:"available"`
|
|
||||||
Borrowed fixedpoint.Value `json:"borrowed" db:"borrowed"`
|
|
||||||
NetAsset fixedpoint.Value `json:"netAsset" db:"net_asset"`
|
|
||||||
PriceInUSD fixedpoint.Value `json:"priceInUSD" db:"price_in_usd"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AssetMap map[string]Asset
|
|
||||||
|
|
||||||
func (m AssetMap) PlainText() (o string) {
|
|
||||||
var assets = m.Slice()
|
|
||||||
|
|
||||||
// sort assets
|
|
||||||
sort.Slice(assets, func(i, j int) bool {
|
|
||||||
return assets[i].InUSD.Compare(assets[j].InUSD) > 0
|
|
||||||
})
|
|
||||||
|
|
||||||
sumUsd := fixedpoint.Zero
|
|
||||||
sumBTC := fixedpoint.Zero
|
|
||||||
for _, a := range assets {
|
|
||||||
usd := a.InUSD
|
|
||||||
btc := a.InBTC
|
|
||||||
if !a.InUSD.IsZero() {
|
|
||||||
o += fmt.Sprintf(" %s: %s (≈ %s) (≈ %s)",
|
|
||||||
a.Currency,
|
|
||||||
a.Total.String(),
|
|
||||||
USD.FormatMoney(usd),
|
|
||||||
BTC.FormatMoney(btc),
|
|
||||||
) + "\n"
|
|
||||||
sumUsd = sumUsd.Add(usd)
|
|
||||||
sumBTC = sumBTC.Add(btc)
|
|
||||||
} else {
|
|
||||||
o += fmt.Sprintf(" %s: %s",
|
|
||||||
a.Currency,
|
|
||||||
a.Total.String(),
|
|
||||||
) + "\n"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
o += fmt.Sprintf(" Summary: (≈ %s) (≈ %s)",
|
|
||||||
USD.FormatMoney(sumUsd),
|
|
||||||
BTC.FormatMoney(sumBTC),
|
|
||||||
) + "\n"
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m AssetMap) Slice() (assets []Asset) {
|
|
||||||
for _, a := range m {
|
|
||||||
assets = append(assets, a)
|
|
||||||
}
|
|
||||||
return assets
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m AssetMap) SlackAttachment() slack.Attachment {
|
|
||||||
var fields []slack.AttachmentField
|
|
||||||
var totalBTC, totalUSD fixedpoint.Value
|
|
||||||
|
|
||||||
var assets = m.Slice()
|
|
||||||
|
|
||||||
// sort assets
|
|
||||||
sort.Slice(assets, func(i, j int) bool {
|
|
||||||
return assets[i].InUSD.Compare(assets[j].InUSD) > 0
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, a := range assets {
|
|
||||||
totalUSD = totalUSD.Add(a.InUSD)
|
|
||||||
totalBTC = totalBTC.Add(a.InBTC)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, a := range assets {
|
|
||||||
if !a.InUSD.IsZero() {
|
|
||||||
fields = append(fields, slack.AttachmentField{
|
|
||||||
Title: a.Currency,
|
|
||||||
Value: fmt.Sprintf("%s (≈ %s) (≈ %s) (%s)",
|
|
||||||
a.Total.String(),
|
|
||||||
USD.FormatMoney(a.InUSD),
|
|
||||||
BTC.FormatMoney(a.InBTC),
|
|
||||||
a.InUSD.Div(totalUSD).FormatPercentage(2),
|
|
||||||
),
|
|
||||||
Short: false,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
fields = append(fields, slack.AttachmentField{
|
|
||||||
Title: a.Currency,
|
|
||||||
Value: fmt.Sprintf("%s", a.Total.String()),
|
|
||||||
Short: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return slack.Attachment{
|
|
||||||
Title: fmt.Sprintf("Net Asset Value %s (≈ %s)",
|
|
||||||
USD.FormatMoney(totalUSD),
|
|
||||||
BTC.FormatMoney(totalBTC),
|
|
||||||
),
|
|
||||||
Fields: fields,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type BalanceMap map[string]Balance
|
|
||||||
type PositionMap map[string]Position
|
type PositionMap map[string]Position
|
||||||
type IsolatedMarginAssetMap map[string]IsolatedMarginAsset
|
type IsolatedMarginAssetMap map[string]IsolatedMarginAsset
|
||||||
type MarginAssetMap map[string]MarginUserAsset
|
type MarginAssetMap map[string]MarginUserAsset
|
||||||
type FuturesAssetMap map[string]FuturesUserAsset
|
type FuturesAssetMap map[string]FuturesUserAsset
|
||||||
type FuturesPositionMap map[string]FuturesPosition
|
type FuturesPositionMap map[string]FuturesPosition
|
||||||
|
|
||||||
func (m BalanceMap) Currencies() (currencies []string) {
|
|
||||||
for _, b := range m {
|
|
||||||
currencies = append(currencies, b.Currency)
|
|
||||||
}
|
|
||||||
return currencies
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m BalanceMap) Add(bm BalanceMap) BalanceMap {
|
|
||||||
var total = BalanceMap{}
|
|
||||||
for _, b := range bm {
|
|
||||||
tb := total[b.Currency]
|
|
||||||
tb.Available = tb.Available.Add(b.Available)
|
|
||||||
tb.Locked = tb.Locked.Add(b.Locked)
|
|
||||||
tb.Borrowed = tb.Borrowed.Add(b.Borrowed)
|
|
||||||
tb.NetAsset = tb.NetAsset.Add(b.NetAsset)
|
|
||||||
tb.Interest = tb.Interest.Add(b.Interest)
|
|
||||||
total[b.Currency] = tb
|
|
||||||
}
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m BalanceMap) String() string {
|
|
||||||
var ss []string
|
|
||||||
for _, b := range m {
|
|
||||||
ss = append(ss, b.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return "BalanceMap[" + strings.Join(ss, ", ") + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m BalanceMap) Copy() (d BalanceMap) {
|
|
||||||
d = make(BalanceMap)
|
|
||||||
for c, b := range m {
|
|
||||||
d[c] = b
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assets converts balances into assets with the given prices
|
|
||||||
func (m BalanceMap) Assets(prices map[string]fixedpoint.Value, priceTime time.Time) AssetMap {
|
|
||||||
assets := make(AssetMap)
|
|
||||||
btcusdt, hasBtcPrice := prices["BTCUSDT"]
|
|
||||||
for currency, b := range m {
|
|
||||||
if b.Locked.IsZero() && b.Available.IsZero() && b.Borrowed.IsZero() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
total := b.Available.Add(b.Locked)
|
|
||||||
netAsset := b.NetAsset
|
|
||||||
if netAsset.IsZero() {
|
|
||||||
netAsset = total.Sub(b.Borrowed)
|
|
||||||
}
|
|
||||||
|
|
||||||
asset := Asset{
|
|
||||||
Currency: currency,
|
|
||||||
Total: total,
|
|
||||||
Time: priceTime,
|
|
||||||
Locked: b.Locked,
|
|
||||||
Available: b.Available,
|
|
||||||
Borrowed: b.Borrowed,
|
|
||||||
NetAsset: netAsset,
|
|
||||||
}
|
|
||||||
|
|
||||||
usdMarkets := []string{currency + "USDT", currency + "USDC", currency + "USD", "USDT" + currency}
|
|
||||||
for _, market := range usdMarkets {
|
|
||||||
if usdPrice, ok := prices[market] ; ok {
|
|
||||||
// this includes USDT, USD, USDC and so on
|
|
||||||
if strings.HasPrefix(market, "USD") {
|
|
||||||
if !asset.Total.IsZero() {
|
|
||||||
asset.InUSD = asset.Total.Div(usdPrice)
|
|
||||||
}
|
|
||||||
asset.PriceInUSD = usdPrice
|
|
||||||
} else {
|
|
||||||
if !asset.Total.IsZero() {
|
|
||||||
asset.InUSD = asset.Total.Mul(usdPrice)
|
|
||||||
}
|
|
||||||
asset.PriceInUSD = fixedpoint.One.Div(usdPrice)
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasBtcPrice && !asset.InUSD.IsZero() {
|
|
||||||
asset.InBTC = asset.InUSD.Div(btcusdt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assets[currency] = asset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return assets
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m BalanceMap) Print() {
|
|
||||||
for _, balance := range m {
|
|
||||||
if balance.Available.IsZero() && balance.Locked.IsZero() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if balance.Locked.Sign() > 0 {
|
|
||||||
logrus.Infof(" %s: %v (locked %v)", balance.Currency, balance.Available, balance.Locked)
|
|
||||||
} else {
|
|
||||||
logrus.Infof(" %s: %v", balance.Currency, balance.Available)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountType string
|
type AccountType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
115
pkg/types/asset.go
Normal file
115
pkg/types/asset.go
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/slack-go/slack"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Asset struct {
|
||||||
|
Currency string `json:"currency" db:"currency"`
|
||||||
|
Total fixedpoint.Value `json:"total" db:"total"`
|
||||||
|
InUSD fixedpoint.Value `json:"inUSD" db:"in_usd"`
|
||||||
|
InBTC fixedpoint.Value `json:"inBTC" db:"in_btc"`
|
||||||
|
Time time.Time `json:"time" db:"time"`
|
||||||
|
Locked fixedpoint.Value `json:"lock" db:"lock" `
|
||||||
|
Available fixedpoint.Value `json:"available" db:"available"`
|
||||||
|
Borrowed fixedpoint.Value `json:"borrowed" db:"borrowed"`
|
||||||
|
NetAsset fixedpoint.Value `json:"netAsset" db:"net_asset"`
|
||||||
|
PriceInUSD fixedpoint.Value `json:"priceInUSD" db:"price_in_usd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssetMap map[string]Asset
|
||||||
|
|
||||||
|
func (m AssetMap) PlainText() (o string) {
|
||||||
|
var assets = m.Slice()
|
||||||
|
|
||||||
|
// sort assets
|
||||||
|
sort.Slice(assets, func(i, j int) bool {
|
||||||
|
return assets[i].InUSD.Compare(assets[j].InUSD) > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
sumUsd := fixedpoint.Zero
|
||||||
|
sumBTC := fixedpoint.Zero
|
||||||
|
for _, a := range assets {
|
||||||
|
usd := a.InUSD
|
||||||
|
btc := a.InBTC
|
||||||
|
if !a.InUSD.IsZero() {
|
||||||
|
o += fmt.Sprintf(" %s: %s (≈ %s) (≈ %s)",
|
||||||
|
a.Currency,
|
||||||
|
a.Total.String(),
|
||||||
|
USD.FormatMoney(usd),
|
||||||
|
BTC.FormatMoney(btc),
|
||||||
|
) + "\n"
|
||||||
|
sumUsd = sumUsd.Add(usd)
|
||||||
|
sumBTC = sumBTC.Add(btc)
|
||||||
|
} else {
|
||||||
|
o += fmt.Sprintf(" %s: %s",
|
||||||
|
a.Currency,
|
||||||
|
a.Total.String(),
|
||||||
|
) + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o += fmt.Sprintf(" Summary: (≈ %s) (≈ %s)",
|
||||||
|
USD.FormatMoney(sumUsd),
|
||||||
|
BTC.FormatMoney(sumBTC),
|
||||||
|
) + "\n"
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m AssetMap) Slice() (assets []Asset) {
|
||||||
|
for _, a := range m {
|
||||||
|
assets = append(assets, a)
|
||||||
|
}
|
||||||
|
return assets
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m AssetMap) SlackAttachment() slack.Attachment {
|
||||||
|
var fields []slack.AttachmentField
|
||||||
|
var totalBTC, totalUSD fixedpoint.Value
|
||||||
|
|
||||||
|
var assets = m.Slice()
|
||||||
|
|
||||||
|
// sort assets
|
||||||
|
sort.Slice(assets, func(i, j int) bool {
|
||||||
|
return assets[i].InUSD.Compare(assets[j].InUSD) > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, a := range assets {
|
||||||
|
totalUSD = totalUSD.Add(a.InUSD)
|
||||||
|
totalBTC = totalBTC.Add(a.InBTC)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range assets {
|
||||||
|
if !a.InUSD.IsZero() {
|
||||||
|
fields = append(fields, slack.AttachmentField{
|
||||||
|
Title: a.Currency,
|
||||||
|
Value: fmt.Sprintf("%s (≈ %s) (≈ %s) (%s)",
|
||||||
|
a.Total.String(),
|
||||||
|
USD.FormatMoney(a.InUSD),
|
||||||
|
BTC.FormatMoney(a.InBTC),
|
||||||
|
a.InUSD.Div(totalUSD).FormatPercentage(2),
|
||||||
|
),
|
||||||
|
Short: false,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
fields = append(fields, slack.AttachmentField{
|
||||||
|
Title: a.Currency,
|
||||||
|
Value: fmt.Sprintf("%s", a.Total.String()),
|
||||||
|
Short: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slack.Attachment{
|
||||||
|
Title: fmt.Sprintf("Net Asset Value %s (≈ %s)",
|
||||||
|
USD.FormatMoney(totalUSD),
|
||||||
|
BTC.FormatMoney(totalBTC),
|
||||||
|
),
|
||||||
|
Fields: fields,
|
||||||
|
}
|
||||||
|
}
|
150
pkg/types/balance.go
Normal file
150
pkg/types/balance.go
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Balance struct {
|
||||||
|
Currency string `json:"currency"`
|
||||||
|
Available fixedpoint.Value `json:"available"`
|
||||||
|
Locked fixedpoint.Value `json:"locked,omitempty"`
|
||||||
|
|
||||||
|
// margin related fields
|
||||||
|
Borrowed fixedpoint.Value `json:"borrowed,omitempty"`
|
||||||
|
Interest fixedpoint.Value `json:"interest,omitempty"`
|
||||||
|
|
||||||
|
// NetAsset = (Available + Locked) - Borrowed - Interest
|
||||||
|
NetAsset fixedpoint.Value `json:"net,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Balance) Total() fixedpoint.Value {
|
||||||
|
return b.Available.Add(b.Locked)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Balance) String() (o string) {
|
||||||
|
o = fmt.Sprintf("%s: %s", b.Currency, b.Available.String())
|
||||||
|
|
||||||
|
if b.Locked.Sign() > 0 {
|
||||||
|
o += fmt.Sprintf(" (locked %v)", b.Locked)
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Borrowed.Sign() > 0 {
|
||||||
|
o += fmt.Sprintf(" (borrowed: %v)", b.Borrowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type BalanceMap map[string]Balance
|
||||||
|
|
||||||
|
func (m BalanceMap) Currencies() (currencies []string) {
|
||||||
|
for _, b := range m {
|
||||||
|
currencies = append(currencies, b.Currency)
|
||||||
|
}
|
||||||
|
return currencies
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m BalanceMap) Add(bm BalanceMap) BalanceMap {
|
||||||
|
var total = BalanceMap{}
|
||||||
|
for _, b := range bm {
|
||||||
|
tb := total[b.Currency]
|
||||||
|
tb.Available = tb.Available.Add(b.Available)
|
||||||
|
tb.Locked = tb.Locked.Add(b.Locked)
|
||||||
|
tb.Borrowed = tb.Borrowed.Add(b.Borrowed)
|
||||||
|
tb.NetAsset = tb.NetAsset.Add(b.NetAsset)
|
||||||
|
tb.Interest = tb.Interest.Add(b.Interest)
|
||||||
|
total[b.Currency] = tb
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m BalanceMap) String() string {
|
||||||
|
var ss []string
|
||||||
|
for _, b := range m {
|
||||||
|
ss = append(ss, b.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return "BalanceMap[" + strings.Join(ss, ", ") + "]"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m BalanceMap) Copy() (d BalanceMap) {
|
||||||
|
d = make(BalanceMap)
|
||||||
|
for c, b := range m {
|
||||||
|
d[c] = b
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assets converts balances into assets with the given prices
|
||||||
|
func (m BalanceMap) Assets(prices map[string]fixedpoint.Value, priceTime time.Time) AssetMap {
|
||||||
|
assets := make(AssetMap)
|
||||||
|
btcusdt, hasBtcPrice := prices["BTCUSDT"]
|
||||||
|
for currency, b := range m {
|
||||||
|
if b.Locked.IsZero() && b.Available.IsZero() && b.Borrowed.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
total := b.Available.Add(b.Locked)
|
||||||
|
netAsset := b.NetAsset
|
||||||
|
if netAsset.IsZero() {
|
||||||
|
netAsset = total.Sub(b.Borrowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
asset := Asset{
|
||||||
|
Currency: currency,
|
||||||
|
Total: total,
|
||||||
|
Time: priceTime,
|
||||||
|
Locked: b.Locked,
|
||||||
|
Available: b.Available,
|
||||||
|
Borrowed: b.Borrowed,
|
||||||
|
NetAsset: netAsset,
|
||||||
|
}
|
||||||
|
|
||||||
|
usdMarkets := []string{currency + "USDT", currency + "USDC", currency + "USD", "USDT" + currency}
|
||||||
|
for _, market := range usdMarkets {
|
||||||
|
if usdPrice, ok := prices[market]; ok {
|
||||||
|
// this includes USDT, USD, USDC and so on
|
||||||
|
if strings.HasPrefix(market, "USD") {
|
||||||
|
if !asset.Total.IsZero() {
|
||||||
|
asset.InUSD = asset.Total.Div(usdPrice)
|
||||||
|
}
|
||||||
|
asset.PriceInUSD = usdPrice
|
||||||
|
} else {
|
||||||
|
if !asset.Total.IsZero() {
|
||||||
|
asset.InUSD = asset.Total.Mul(usdPrice)
|
||||||
|
}
|
||||||
|
asset.PriceInUSD = fixedpoint.One.Div(usdPrice)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasBtcPrice && !asset.InUSD.IsZero() {
|
||||||
|
asset.InBTC = asset.InUSD.Div(btcusdt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assets[currency] = asset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return assets
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m BalanceMap) Print() {
|
||||||
|
for _, balance := range m {
|
||||||
|
if balance.Available.IsZero() && balance.Locked.IsZero() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if balance.Locked.Sign() > 0 {
|
||||||
|
logrus.Infof(" %s: %v (locked %v)", balance.Currency, balance.Available, balance.Locked)
|
||||||
|
} else {
|
||||||
|
logrus.Infof(" %s: %v", balance.Currency, balance.Available)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user