mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Reorganise portfolio and prevent saving nil portfolio if not seeded
This commit is contained in:
File diff suppressed because one or more lines are too long
50
helpers.go
50
helpers.go
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/thrasher-/gocryptotrader/currency"
|
||||
"github.com/thrasher-/gocryptotrader/currency/pair"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/stats"
|
||||
"github.com/thrasher-/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-/gocryptotrader/portfolio"
|
||||
)
|
||||
|
||||
// GetAllAvailablePairs returns a list of all available pairs on either enabled
|
||||
@@ -311,3 +313,51 @@ func GetExchangeLowestPriceByCurrencyPair(p pair.CurrencyPair, assetType string)
|
||||
|
||||
return result[0].Exchange, nil
|
||||
}
|
||||
|
||||
// SeedExchangeAccountInfo seeds account info
|
||||
func SeedExchangeAccountInfo(data []exchange.AccountInfo) {
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
port := portfolio.GetPortfolio()
|
||||
|
||||
for i := 0; i < len(data); i++ {
|
||||
exchangeName := data[i].ExchangeName
|
||||
for j := 0; j < len(data[i].Currencies); j++ {
|
||||
currencyName := data[i].Currencies[j].CurrencyName
|
||||
onHold := data[i].Currencies[j].Hold
|
||||
avail := data[i].Currencies[j].TotalValue
|
||||
total := onHold + avail
|
||||
|
||||
if !port.ExchangeAddressExists(exchangeName, currencyName) {
|
||||
if total <= 0 {
|
||||
continue
|
||||
}
|
||||
log.Printf("Portfolio: Adding new exchange address: %s, %s, %f, %s\n",
|
||||
exchangeName, currencyName, total, portfolio.PortfolioAddressExchange)
|
||||
port.Addresses = append(
|
||||
port.Addresses,
|
||||
portfolio.Address{Address: exchangeName, CoinType: currencyName,
|
||||
Balance: total, Description: portfolio.PortfolioAddressExchange},
|
||||
)
|
||||
} else {
|
||||
if total <= 0 {
|
||||
log.Printf("Portfolio: Removing %s %s entry.\n", exchangeName,
|
||||
currencyName)
|
||||
port.RemoveExchangeAddress(exchangeName, currencyName)
|
||||
} else {
|
||||
balance, ok := port.GetAddressBalance(exchangeName, currencyName, portfolio.PortfolioAddressExchange)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if balance != total {
|
||||
log.Printf("Portfolio: Updating %s %s entry with balance %f.\n",
|
||||
exchangeName, currencyName, total)
|
||||
port.UpdateExchangeAddressBalance(exchangeName, currencyName, total)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
main.go
60
main.go
@@ -43,6 +43,7 @@ const banner = `
|
||||
var bot Bot
|
||||
|
||||
func main() {
|
||||
bot.shutdown = make(chan bool)
|
||||
HandleInterrupt()
|
||||
|
||||
//Handle flags
|
||||
@@ -181,15 +182,18 @@ func HandleInterrupt() {
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
go func() {
|
||||
sig := <-c
|
||||
log.Printf("Captured %v.", sig)
|
||||
Shutdown()
|
||||
log.Printf("Captured %v, shutdown requested.", sig)
|
||||
bot.shutdown <- true
|
||||
}()
|
||||
}
|
||||
|
||||
// Shutdown correctly shuts down bot saving configuration files
|
||||
func Shutdown() {
|
||||
log.Println("Bot shutting down..")
|
||||
bot.config.Portfolio = portfolio.Portfolio
|
||||
|
||||
if len(portfolio.Portfolio.Addresses) != 0 {
|
||||
bot.config.Portfolio = portfolio.Portfolio
|
||||
}
|
||||
|
||||
if !bot.dryRun {
|
||||
err := bot.config.SaveConfig(bot.configFile)
|
||||
@@ -202,53 +206,5 @@ func Shutdown() {
|
||||
}
|
||||
|
||||
log.Println("Exiting.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// SeedExchangeAccountInfo seeds account info
|
||||
func SeedExchangeAccountInfo(data []exchange.AccountInfo) {
|
||||
if len(data) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
port := portfolio.GetPortfolio()
|
||||
|
||||
for i := 0; i < len(data); i++ {
|
||||
exchangeName := data[i].ExchangeName
|
||||
for j := 0; j < len(data[i].Currencies); j++ {
|
||||
currencyName := data[i].Currencies[j].CurrencyName
|
||||
onHold := data[i].Currencies[j].Hold
|
||||
avail := data[i].Currencies[j].TotalValue
|
||||
total := onHold + avail
|
||||
|
||||
if !port.ExchangeAddressExists(exchangeName, currencyName) {
|
||||
if total <= 0 {
|
||||
continue
|
||||
}
|
||||
log.Printf("Portfolio: Adding new exchange address: %s, %s, %f, %s\n",
|
||||
exchangeName, currencyName, total, portfolio.PortfolioAddressExchange)
|
||||
port.Addresses = append(
|
||||
port.Addresses,
|
||||
portfolio.Address{Address: exchangeName, CoinType: currencyName,
|
||||
Balance: total, Description: portfolio.PortfolioAddressExchange},
|
||||
)
|
||||
} else {
|
||||
if total <= 0 {
|
||||
log.Printf("Portfolio: Removing %s %s entry.\n", exchangeName,
|
||||
currencyName)
|
||||
port.RemoveExchangeAddress(exchangeName, currencyName)
|
||||
} else {
|
||||
balance, ok := port.GetAddressBalance(exchangeName, currencyName, portfolio.PortfolioAddressExchange)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if balance != total {
|
||||
log.Printf("Portfolio: Updating %s %s entry with balance %f.\n",
|
||||
exchangeName, currencyName, total)
|
||||
port.UpdateExchangeAddressBalance(exchangeName, currencyName, total)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@@ -12,9 +12,6 @@ import (
|
||||
const (
|
||||
cryptoIDAPIURL = "https://chainz.cryptoid.info"
|
||||
|
||||
etherchainAPIURL = "https://etherchain.org/api"
|
||||
etherchainAccountMultiple = "account/multiple"
|
||||
|
||||
ethplorerAPIURL = "https://api.ethplorer.io"
|
||||
ethplorerAddressInfo = "getAddressInfo"
|
||||
|
||||
@@ -27,89 +24,6 @@ const (
|
||||
// Portfolio is variable store holding an array of portfolioAddress
|
||||
var Portfolio Base
|
||||
|
||||
// Base holds the portfolio base addresses
|
||||
type Base struct {
|
||||
Addresses []Address
|
||||
}
|
||||
|
||||
// Address sub type holding address information for portfolio
|
||||
type Address struct {
|
||||
Address string
|
||||
CoinType string
|
||||
Balance float64
|
||||
Description string
|
||||
}
|
||||
|
||||
// EtherchainBalanceResponse holds JSON incoming and outgoing data for
|
||||
// Etherchain
|
||||
type EtherchainBalanceResponse struct {
|
||||
Status int `json:"status"`
|
||||
Data []struct {
|
||||
Address string `json:"address"`
|
||||
Balance float64 `json:"balance"`
|
||||
Nonce interface{} `json:"nonce"`
|
||||
Code string `json:"code"`
|
||||
Name interface{} `json:"name"`
|
||||
Storage interface{} `json:"storage"`
|
||||
FirstSeen interface{} `json:"firstSeen"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// EthplorerResponse holds JSON address data for Ethplorer
|
||||
type EthplorerResponse struct {
|
||||
Address string `json:"address"`
|
||||
ETH struct {
|
||||
Balance float64 `json:"balance"`
|
||||
TotalIn float64 `json:"totalIn"`
|
||||
TotalOut float64 `json:"totalOut"`
|
||||
} `json:"ETH"`
|
||||
CountTxs int `json:"countTxs"`
|
||||
ContractInfo struct {
|
||||
CreatorAddress string `json:"creatorAddress"`
|
||||
TransactionHash string `json:"transactionHash"`
|
||||
Timestamp int `json:"timestamp"`
|
||||
} `json:"contractInfo"`
|
||||
TokenInfo struct {
|
||||
Address string `json:"address"`
|
||||
Name string `json:"name"`
|
||||
Decimals int `json:"decimals"`
|
||||
Symbol string `json:"symbol"`
|
||||
TotalSupply string `json:"totalSupply"`
|
||||
Owner string `json:"owner"`
|
||||
LastUpdated int `json:"lastUpdated"`
|
||||
TotalIn int64 `json:"totalIn"`
|
||||
TotalOut int64 `json:"totalOut"`
|
||||
IssuancesCount int `json:"issuancesCount"`
|
||||
HoldersCount int `json:"holdersCount"`
|
||||
Image string `json:"image"`
|
||||
Description string `json:"description"`
|
||||
Price struct {
|
||||
Rate int `json:"rate"`
|
||||
Diff int `json:"diff"`
|
||||
Ts int `json:"ts"`
|
||||
Currency string `json:"currency"`
|
||||
} `json:"price"`
|
||||
} `json:"tokenInfo"`
|
||||
Error struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
// ExchangeAccountInfo : Generic type to hold each exchange's holdings in all
|
||||
// enabled currencies
|
||||
type ExchangeAccountInfo struct {
|
||||
ExchangeName string
|
||||
Currencies []ExchangeAccountCurrencyInfo
|
||||
}
|
||||
|
||||
// ExchangeAccountCurrencyInfo : Sub type to store currency name and value
|
||||
type ExchangeAccountCurrencyInfo struct {
|
||||
CurrencyName string
|
||||
TotalValue float64
|
||||
Hold float64
|
||||
}
|
||||
|
||||
// GetEthereumBalance single or multiple address information as
|
||||
// EtherchainBalanceResponse
|
||||
func GetEthereumBalance(address string) (EthplorerResponse, error) {
|
||||
@@ -361,39 +275,6 @@ func getPercentageSpecific(input float64, target string, totals map[string]float
|
||||
return percentage
|
||||
}
|
||||
|
||||
// Coin stores a coin type, balance, address and percentage relative to the total
|
||||
// amount.
|
||||
type Coin struct {
|
||||
Coin string `json:"coin"`
|
||||
Balance float64 `json:"balance"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Percentage float64 `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
// OfflineCoinSummary stores a coin types address, balance and percentage
|
||||
// relative to the total amount.
|
||||
type OfflineCoinSummary struct {
|
||||
Address string `json:"address"`
|
||||
Balance float64 `json:"balance"`
|
||||
Percentage float64 `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
// OnlineCoinSummary stores a coin types balance and percentage relative to the
|
||||
// total amount.
|
||||
type OnlineCoinSummary struct {
|
||||
Balance float64 `json:"balance"`
|
||||
Percentage float64 `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
// Summary Stores the entire portfolio summary
|
||||
type Summary struct {
|
||||
Totals []Coin `json:"coin_totals"`
|
||||
Offline []Coin `json:"coins_offline"`
|
||||
OfflineSummary map[string][]OfflineCoinSummary `json:"offline_summary"`
|
||||
Online []Coin `json:"coins_online"`
|
||||
OnlineSummary map[string]map[string]OnlineCoinSummary `json:"online_summary"`
|
||||
}
|
||||
|
||||
// GetPortfolioSummary returns the complete portfolio summary, showing
|
||||
// coin totals, offline and online summaries with their relative percentages.
|
||||
func (p *Base) GetPortfolioSummary() Summary {
|
||||
|
||||
@@ -3,6 +3,7 @@ package portfolio
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGetEthereumBalance(t *testing.T) {
|
||||
@@ -201,6 +202,8 @@ func TestUpdatePortfolio(t *testing.T) {
|
||||
if value {
|
||||
t.Error("Test Failed - portfolio_test.go - UpdatePortfolio error")
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 5)
|
||||
value = portfolio.UpdatePortfolio(
|
||||
[]string{"0xb794f5ea0ba39494ce839613fffba74279579268",
|
||||
"0xe853c56864a2ebe4576a807d26fdc4a0ada51919"}, "ETH",
|
||||
|
||||
117
portfolio/portfolio_types.go
Normal file
117
portfolio/portfolio_types.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package portfolio
|
||||
|
||||
// Base holds the portfolio base addresses
|
||||
type Base struct {
|
||||
Addresses []Address
|
||||
}
|
||||
|
||||
// Address sub type holding address information for portfolio
|
||||
type Address struct {
|
||||
Address string
|
||||
CoinType string
|
||||
Balance float64
|
||||
Description string
|
||||
}
|
||||
|
||||
// EtherchainBalanceResponse holds JSON incoming and outgoing data for
|
||||
// Etherchain
|
||||
type EtherchainBalanceResponse struct {
|
||||
Status int `json:"status"`
|
||||
Data []struct {
|
||||
Address string `json:"address"`
|
||||
Balance float64 `json:"balance"`
|
||||
Nonce interface{} `json:"nonce"`
|
||||
Code string `json:"code"`
|
||||
Name interface{} `json:"name"`
|
||||
Storage interface{} `json:"storage"`
|
||||
FirstSeen interface{} `json:"firstSeen"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// EthplorerResponse holds JSON address data for Ethplorer
|
||||
type EthplorerResponse struct {
|
||||
Address string `json:"address"`
|
||||
ETH struct {
|
||||
Balance float64 `json:"balance"`
|
||||
TotalIn float64 `json:"totalIn"`
|
||||
TotalOut float64 `json:"totalOut"`
|
||||
} `json:"ETH"`
|
||||
CountTxs int `json:"countTxs"`
|
||||
ContractInfo struct {
|
||||
CreatorAddress string `json:"creatorAddress"`
|
||||
TransactionHash string `json:"transactionHash"`
|
||||
Timestamp int `json:"timestamp"`
|
||||
} `json:"contractInfo"`
|
||||
TokenInfo struct {
|
||||
Address string `json:"address"`
|
||||
Name string `json:"name"`
|
||||
Decimals int `json:"decimals"`
|
||||
Symbol string `json:"symbol"`
|
||||
TotalSupply string `json:"totalSupply"`
|
||||
Owner string `json:"owner"`
|
||||
LastUpdated int `json:"lastUpdated"`
|
||||
TotalIn int64 `json:"totalIn"`
|
||||
TotalOut int64 `json:"totalOut"`
|
||||
IssuancesCount int `json:"issuancesCount"`
|
||||
HoldersCount int `json:"holdersCount"`
|
||||
Image string `json:"image"`
|
||||
Description string `json:"description"`
|
||||
Price struct {
|
||||
Rate int `json:"rate"`
|
||||
Diff int `json:"diff"`
|
||||
Ts int `json:"ts"`
|
||||
Currency string `json:"currency"`
|
||||
} `json:"price"`
|
||||
} `json:"tokenInfo"`
|
||||
Error struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
// ExchangeAccountInfo : Generic type to hold each exchange's holdings in all
|
||||
// enabled currencies
|
||||
type ExchangeAccountInfo struct {
|
||||
ExchangeName string
|
||||
Currencies []ExchangeAccountCurrencyInfo
|
||||
}
|
||||
|
||||
// ExchangeAccountCurrencyInfo : Sub type to store currency name and value
|
||||
type ExchangeAccountCurrencyInfo struct {
|
||||
CurrencyName string
|
||||
TotalValue float64
|
||||
Hold float64
|
||||
}
|
||||
|
||||
// Coin stores a coin type, balance, address and percentage relative to the total
|
||||
// amount.
|
||||
type Coin struct {
|
||||
Coin string `json:"coin"`
|
||||
Balance float64 `json:"balance"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Percentage float64 `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
// OfflineCoinSummary stores a coin types address, balance and percentage
|
||||
// relative to the total amount.
|
||||
type OfflineCoinSummary struct {
|
||||
Address string `json:"address"`
|
||||
Balance float64 `json:"balance"`
|
||||
Percentage float64 `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
// OnlineCoinSummary stores a coin types balance and percentage relative to the
|
||||
// total amount.
|
||||
type OnlineCoinSummary struct {
|
||||
Balance float64 `json:"balance"`
|
||||
Percentage float64 `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
// Summary Stores the entire portfolio summary
|
||||
type Summary struct {
|
||||
Totals []Coin `json:"coin_totals"`
|
||||
Offline []Coin `json:"coins_offline"`
|
||||
OfflineSummary map[string][]OfflineCoinSummary `json:"offline_summary"`
|
||||
Online []Coin `json:"coins_online"`
|
||||
OnlineSummary map[string]map[string]OnlineCoinSummary `json:"online_summary"`
|
||||
}
|
||||
Reference in New Issue
Block a user