daily progress build

This commit is contained in:
Adrian Gallagher
2019-06-06 17:20:40 +10:00
parent 26795508ff
commit bd8dc47c38
14 changed files with 261 additions and 121 deletions

View File

@@ -158,7 +158,7 @@ func (c *Config) UpdateClientBankAccounts(bankCfg *BankAccount) error {
}
// CheckClientBankAccounts checks client bank details
func (c *Config) CheckClientBankAccounts() error {
func (c *Config) CheckClientBankAccounts() {
m.Lock()
defer m.Unlock()
@@ -175,24 +175,30 @@ func (c *Config) CheckClientBankAccounts() error {
SupportedExchanges: "ANX,Kraken",
},
)
return nil
return
}
for i := range c.BankAccounts {
if c.BankAccounts[i].Enabled {
if c.BankAccounts[i].BankName == "" || c.BankAccounts[i].BankAddress == "" {
return fmt.Errorf("banking details for %s is enabled but variables not set correctly",
c.BankAccounts[i].Enabled = false
log.Warnf("banking details for %s is enabled but variables not set correctly",
c.BankAccounts[i].BankName)
continue
}
if c.BankAccounts[i].AccountName == "" || c.BankAccounts[i].AccountNumber == "" {
return fmt.Errorf("banking account details for %s variables not set correctly",
c.BankAccounts[i].Enabled = false
log.Warnf("banking account details for %s variables not set correctly",
c.BankAccounts[i].BankName)
continue
}
if c.BankAccounts[i].IBAN == "" && c.BankAccounts[i].SWIFTCode == "" && c.BankAccounts[i].BSBNumber == "" {
return fmt.Errorf("critical banking numbers not set for %s in %s account",
c.BankAccounts[i].Enabled = false
log.Warnf("critical banking numbers not set for %s in %s account",
c.BankAccounts[i].BankName,
c.BankAccounts[i].AccountName)
continue
}
if c.BankAccounts[i].SupportedExchanges == "" {
@@ -200,7 +206,6 @@ func (c *Config) CheckClientBankAccounts() error {
}
}
}
return nil
}
// PurgeExchangeAPICredentials purges the stored API credentials
@@ -1254,7 +1259,7 @@ func (c *Config) CheckNTPConfig() {
}
if len(c.NTPClient.Pool) < 1 {
log.Warn("NTPClient enabled with no servers configured enabling default pool")
log.Warn("NTPClient enabled with no servers configured, enabling default pool.")
c.NTPClient.Pool = []string{"pool.ntp.org:123"}
}
}
@@ -1265,8 +1270,8 @@ func (c *Config) DisableNTPCheck(input io.Reader) (string, error) {
defer m.Unlock()
reader := bufio.NewReader(input)
log.Warn("Your system time is out of sync this may cause issues with trading")
log.Warn("How would you like to show future notifications? (a)lert / (w)arn / (d)isable \n")
log.Warn("Your system time is out of sync, this may cause issues with trading.")
log.Warn("How would you like to show future notifications? (a)lert / (w)arn / (d)isable. \n")
var answered = false
for ok := true; ok; ok = (!answered) {
@@ -1291,7 +1296,7 @@ func (c *Config) DisableNTPCheck(input io.Reader) (string, error) {
return "Future notications for out time sync have been disabled", nil
}
}
return "", errors.New("something went wrong NTPCheck should never make it this far")
return "", errors.New("something went wrong, NTPCheck should never make it this far")
}
// CheckConnectionMonitorConfig checks and if zero value assigns default values
@@ -1502,15 +1507,11 @@ func (c *Config) SaveConfig(configPath string) error {
return common.WriteFile(defaultPath, payload)
}
// CheckConfig checks all config settings
func (c *Config) CheckConfig() error {
err := c.CheckExchangeConfigValues()
if err != nil {
return fmt.Errorf(ErrCheckingConfigValues, err)
}
c.CheckConnectionMonitorConfig()
c.CheckCommunicationsConfig()
// CheckRemoteControlConfig checks to see if the old c.Webserver field is used
// and migrates the existing settings to the new RemoteControl struct
func (c *Config) CheckRemoteControlConfig() {
m.Lock()
defer m.Unlock()
if c.Webserver != nil {
port := common.ExtractPort(c.Webserver.ListenAddress)
@@ -1548,6 +1549,25 @@ func (c *Config) CheckConfig() error {
c.Webserver = nil
}
}
// CheckConfig checks all config settings
func (c *Config) CheckConfig() error {
err := c.CheckLoggerConfig()
if err != nil {
log.Errorf("Failed to configure logger. Err: %s", err)
}
err = c.CheckExchangeConfigValues()
if err != nil {
return fmt.Errorf(ErrCheckingConfigValues, err)
}
c.CheckConnectionMonitorConfig()
c.CheckCommunicationsConfig()
c.CheckClientBankAccounts()
c.CheckRemoteControlConfig()
err = c.CheckCurrencyConfigValues()
if err != nil {
return err
@@ -1558,7 +1578,11 @@ func (c *Config) CheckConfig() error {
c.GlobalHTTPTimeout = configDefaultHTTPTimeout
}
return c.CheckClientBankAccounts()
if c.NTPClient.Level != 0 {
c.CheckNTPConfig()
}
return nil
}
// LoadConfig loads your configuration file into your configuration object

View File

@@ -130,7 +130,7 @@ func TestCheckClientBankAccounts(t *testing.T) {
}
cfg.BankAccounts = nil
err = cfg.CheckClientBankAccounts()
cfg.CheckClientBankAccounts()
if err != nil || len(cfg.BankAccounts) == 0 {
t.Error("Test failed. CheckClientBankAccounts error:", err)
}
@@ -140,33 +140,7 @@ func TestCheckClientBankAccounts(t *testing.T) {
Enabled: true,
BankName: "test",
})
err = cfg.CheckClientBankAccounts()
if err.Error() != "banking details for test is enabled but variables not set correctly" {
t.Error("Test failed. CheckClientBankAccounts unexpected error:", err)
}
cfg.BankAccounts[0].BankAddress = "test"
err = cfg.CheckClientBankAccounts()
if err.Error() != "banking account details for test variables not set correctly" {
t.Error("Test failed. CheckClientBankAccounts unexpected error:", err)
}
cfg.BankAccounts[0].AccountName = "Thrasher"
cfg.BankAccounts[0].AccountNumber = "1337"
err = cfg.CheckClientBankAccounts()
if err.Error() != "critical banking numbers not set for test in Thrasher account" {
t.Error("Test failed. CheckClientBankAccounts unexpected error:", err)
}
cfg.BankAccounts[0].IBAN = "12345678"
err = cfg.CheckClientBankAccounts()
if err != nil {
t.Error("Test failed. CheckClientBankAccounts error:", err)
}
if cfg.BankAccounts[0].SupportedExchanges == "" {
t.Error("Test failed. CheckClientBankAccounts SupportedExchanges unexpectedly nil, data:",
cfg.BankAccounts[0])
}
// TO-DO: Complete test coverage
}
func TestGetCommunicationsConfig(t *testing.T) {

View File

@@ -86,7 +86,7 @@ func (c *Checker) Shutdown() {
// Monitor determines internet connectivity via a DNS lookup
func (c *Checker) Monitor(wg *sync.WaitGroup) {
c.wg.Add(1)
tick := time.NewTicker(time.Second)
tick := time.NewTicker(c.CheckInterval)
defer func() { tick.Stop(); c.wg.Done() }()
wg.Done()
for {

View File

@@ -343,7 +343,7 @@ func (s *Storage) SeedCurrencyAnalysisData() error {
// loads it into memory
func (s *Storage) FetchCurrencyAnalysisData() error {
if s.currencyAnalysis == nil {
log.Warn("Currency analysis system offline please set api keys for coinmarketcap")
log.Warn("Currency analysis system offline, please set api keys for coinmarketcap if you wish to use this feature.")
return errors.New("currency analysis system offline")
}

View File

@@ -33,6 +33,7 @@ type Engine struct {
Exchanges []exchange.IBotExchange
ExchangeCurrencyPairManager *ExchangeCurrencyPairSyncer
OrderManager *OrderManager
PortfolioManager portfolioManager
CommsRelayer *communications.Communications
Connectivity *connchecker.Checker
Shutdown chan bool
@@ -86,11 +87,6 @@ func NewFromSettings(settings *Settings) (*Engine, error) {
return nil, fmt.Errorf("failed to open/create data directory: %s. Err: %s", settings.DataDir, err)
}
err = b.Config.CheckLoggerConfig()
if err != nil {
log.Errorf("Failed to configure logger. Err: %s", err)
}
err = log.SetupLogger()
if err != nil {
log.Errorf("Failed to setup logger. Err: %s", err)
@@ -119,7 +115,7 @@ func ValidateSettings(b *Engine, s *Settings) {
b.Settings.EnableDryRun = s.EnableDryRun
b.Settings.EnableAllExchanges = s.EnableAllExchanges
b.Settings.EnableAllPairs = s.EnableAllPairs
b.Settings.EnablePortfolioWatcher = s.EnablePortfolioWatcher
b.Settings.EnablePortfolioManager = s.EnablePortfolioManager
b.Settings.EnableCoinmarketcapAnalysis = s.EnableCoinmarketcapAnalysis
// TO-DO: FIXME
@@ -159,10 +155,11 @@ func ValidateSettings(b *Engine, s *Settings) {
}
}
b.Settings.EnableConnectivityMonitor = s.EnableConnectivityMonitor
b.Settings.EnableNTPClient = s.EnableNTPClient
b.Settings.EnableTickerRoutine = s.EnableTickerRoutine
b.Settings.EnableOrderbookRoutine = s.EnableOrderbookRoutine
b.Settings.EnableWebsocketRoutine = s.EnableWebsocketRoutine
b.Settings.EnableExchangeSyncManager = s.EnableExchangeSyncManager
b.Settings.EnableTickerSyncing = s.EnableTickerSyncing
b.Settings.EnableOrderbookSyncing = s.EnableOrderbookSyncing
b.Settings.EnableExchangeAutoPairUpdates = s.EnableExchangeAutoPairUpdates
b.Settings.EnableExchangeWebsocketSupport = s.EnableExchangeWebsocketSupport
b.Settings.EnableExchangeRESTSupport = s.EnableExchangeRESTSupport
@@ -222,7 +219,7 @@ func PrintSettings(s *Settings) {
log.Debugf("\t Enable all exchanges: %v", s.EnableAllExchanges)
log.Debugf("\t Enable all pairs: %v", s.EnableAllPairs)
log.Debugf("\t Enable coinmarketcap analaysis: %v", s.EnableCoinmarketcapAnalysis)
log.Debugf("\t Enable portfolio watcher: %v", s.EnablePortfolioWatcher)
log.Debugf("\t Enable portfolio watcher: %v", s.EnablePortfolioManager)
log.Debugf("\t Enable gPRC: %v", s.EnableGRPC)
log.Debugf("\t Enable gRPC Proxy: %v", s.EnableGRPCProxy)
log.Debugf("\t Enable websocket RPC: %v", s.EnableWebsocketRPC)
@@ -230,8 +227,10 @@ func PrintSettings(s *Settings) {
log.Debugf("\t Enable comms relayer: %v", s.EnableCommsRelayer)
log.Debugf("\t Enable event manager: %v", s.EnableEventManager)
log.Debugf("\t Event manager sleep delay: %v", s.EventManagerDelay)
log.Debugf("\t Enable ticker routine: %v", s.EnableTickerRoutine)
log.Debugf("\t Enable orderbook routine: %v", s.EnableOrderbookRoutine)
log.Debugf("\t Enable order manager: %v", s.EnableOrderManager)
log.Debugf("\t Enable exchange sync manager: %v", s.EnableExchangeSyncManager)
log.Debugf("\t Enable ticker syncing: %v", s.EnableTickerSyncing)
log.Debugf("\t Enable orderbook syncing: %v", s.EnableOrderbookSyncing)
log.Debugf("\t Enable websocket routine: %v\n", s.EnableWebsocketRoutine)
log.Debugf("\t Enable NTP client: %v", s.EnableNTPClient)
log.Debugf("- FOREX SETTINGS:")
@@ -266,16 +265,17 @@ func (e *Engine) Start() {
// Sets up internet connectivity monitor
var err error
e.Connectivity, err = connchecker.New(e.Config.ConnectionMonitor.DNSList,
e.Config.ConnectionMonitor.PublicDomainList,
e.Config.ConnectionMonitor.CheckInterval)
if err != nil {
log.Fatalf("Connectivity checker failure: %s", err)
if e.Settings.EnableConnectivityMonitor {
e.Connectivity, err = connchecker.New(e.Config.ConnectionMonitor.DNSList,
e.Config.ConnectionMonitor.PublicDomainList,
e.Config.ConnectionMonitor.CheckInterval)
if err != nil {
log.Fatalf("Connectivity checker failure: %s", err)
}
}
if e.Settings.EnableNTPClient {
if e.Config.NTPClient.Level != -1 {
e.Config.CheckNTPConfig()
NTPTime, errNTP := ntpclient.NTPClient(e.Config.NTPClient.Pool)
currentTime := time.Now()
if errNTP != nil {
@@ -356,10 +356,6 @@ func (e *Engine) Start() {
log.Warn("currency updater system failed to start", err)
}
e.Portfolio = &portfolio.Portfolio
e.Portfolio.Seed(e.Config.Portfolio)
SeedExchangeAccountInfo(GetAllEnabledExchangeAccountInfo().Data)
e.CryptocurrencyDepositAddresses = GetExchangeCryptocurrencyDepositAddresses()
if e.Settings.EnableGRPC {
@@ -375,42 +371,31 @@ func (e *Engine) Start() {
StartWebsocketHandler()
}
if e.Settings.EnablePortfolioWatcher {
go portfolio.StartPortfolioWatcher()
if e.Settings.EnablePortfolioManager {
if err = e.PortfolioManager.Start(); err != nil {
log.Errorf("Fund manager unable to start: %v", err)
}
}
/*
if e.Settings.EnableExchangeSyncManager {
exchangeSyncCfg := CurrencyPairSyncerConfig{
SyncTicker: true,
SyncOrderbook: true,
SyncTicker: e.Settings.EnableTickerSyncing,
SyncOrderbook: e.Settings.EnableOrderbookSyncing,
SyncContinuously: true,
NumWorkers: 15,
}
e.ExchangeCurrencyPairManager, err = NewCurrencyPairSyncer(exchangeSyncCfg)
if err != nil {
log.Warnf("Unable to initialise exchange currency pair syncer. Err: %s", err)
} else {
e.ExchangeCurrencyPairManager.Start()
}
*/
go StartOrderManagerRoutine()
if e.Settings.EnableTickerRoutine {
go TickerUpdaterRoutine()
e.ExchangeCurrencyPairManager, err = NewCurrencyPairSyncer(exchangeSyncCfg)
if err != nil {
log.Warnf("Unable to initialise exchange currency pair syncer. Err: %s", err)
} else {
go e.ExchangeCurrencyPairManager.Start()
}
}
/*
if e.Settings.EnableOrderbookRoutine {
go OrderbookUpdaterRoutine()
}
if e.Settings.EnableWebsocketRoutine {
go WebsocketRoutine()
}
*/
if e.Settings.EnableOrderManager {
go StartOrderManagerRoutine()
}
if e.Settings.EnableEventManager {
go events.EventManger()
@@ -428,9 +413,14 @@ func (e *Engine) Stop() {
e.Config.Portfolio = portfolio.Portfolio
}
if e.PortfolioManager.Started() {
if err := e.PortfolioManager.Stop(); err != nil {
log.Errorf("Fund manager unable to stop. Error: %v", err)
}
}
if !e.Settings.EnableDryRun {
err := e.Config.SaveConfig(e.Settings.ConfigFile)
if err != nil {
log.Error("Unable to save config.")
} else {

View File

@@ -14,17 +14,20 @@ type Settings struct {
EnableAllExchanges bool
EnableAllPairs bool
EnableCoinmarketcapAnalysis bool
EnablePortfolioWatcher bool
EnablePortfolioManager bool
EnableGRPC bool
EnableGRPCProxy bool
EnableWebsocketRPC bool
EnableDeprecatedRPC bool
EnableTickerRoutine bool
EnableOrderbookRoutine bool
EnableWebsocketRoutine bool
EnableCommsRelayer bool
EnableExchangeSyncManager bool
EnableTickerSyncing bool
EnableOrderbookSyncing bool
EnableEventManager bool
EnableOrderManager bool
EnableConnectivityMonitor bool
EnableNTPClient bool
EnableWebsocketRoutine bool
EventManagerDelay time.Duration
Verbose bool

View File

@@ -269,8 +269,9 @@ func LoadExchange(name string, useWG bool, wg *sync.WaitGroup) error {
// SetupExchanges sets up the exchanges used by the Bot
func SetupExchanges() {
var wg sync.WaitGroup
for x := range Bot.Config.Exchanges {
exch := &Bot.Config.Exchanges[x]
exchanges := Bot.Config.GetAllExchangeConfigs()
for x := range exchanges {
exch := exchanges[x]
if CheckExchangeExists(exch.Name) {
e := GetExchangeByName(exch.Name)
if e == nil {

View File

@@ -26,6 +26,14 @@ import (
"github.com/thrasher-/gocryptotrader/utils"
)
// IsOnline returns whether or not the engine has Internet connectivity
func IsOnline() bool {
if Bot.Connectivity == nil {
log.Warnf("IsOnline called but Bot.Connectivity is nil")
}
return Bot.Connectivity.IsConnected()
}
// GetAvailableExchanges returns a list of enabled exchanges
func GetAvailableExchanges() []string {
var enExchanges []string

81
engine/portfolio.go Normal file
View File

@@ -0,0 +1,81 @@
package engine
import (
"errors"
"sync/atomic"
"time"
log "github.com/thrasher-/gocryptotrader/logger"
"github.com/thrasher-/gocryptotrader/portfolio"
)
// vars for the fund manager package
var (
PortfolioSleepDelay = time.Minute
)
type portfolioManager struct {
started int32
stopped int32
shutdown chan struct{}
}
func (p *portfolioManager) Started() bool {
return atomic.LoadInt32(&p.started) == 1
}
func (p *portfolioManager) Start() error {
if atomic.AddInt32(&p.started, 1) != 1 {
return errors.New("portfolio manager already started")
}
log.Debugln("Portfolio manager starting...")
Bot.Portfolio = &portfolio.Portfolio
Bot.Portfolio.Seed(Bot.Config.Portfolio)
p.shutdown = make(chan struct{})
go p.run()
return nil
}
func (p *portfolioManager) Stop() error {
if atomic.AddInt32(&p.stopped, 1) != 1 {
return errors.New("portfolio manager is already stopped")
}
log.Debugln("Portfolio manager shutting down...")
close(p.shutdown)
return nil
}
func (p *portfolioManager) run() {
log.Debugln("Portfolio manager started.")
tick := time.NewTicker(PortfolioSleepDelay)
defer func() {
log.Debugf("Portfolio manager shutdown.")
tick.Stop()
}()
for {
select {
case <-p.shutdown:
return
case <-tick.C:
p.processPortfolio()
}
}
}
func (p *portfolioManager) processPortfolio() {
pf := portfolio.GetPortfolio()
data := pf.GetPortfolioGroupedCoin()
for key, value := range data {
success := pf.UpdatePortfolio(value, key)
if success {
log.Debugf(
"Portfolio manager: Successfully updated address balance for %s address(es) %s\n",
key, value,
)
}
}
SeedExchangeAccountInfo(GetAllEnabledExchangeAccountInfo().Data)
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/thrasher-/gocryptotrader/config"
log "github.com/thrasher-/gocryptotrader/logger"
"github.com/thrasher-/gocryptotrader/portfolio"
)
// RESTfulJSONResponse outputs a JSON response of the response interface
@@ -100,7 +101,8 @@ func RESTGetAllActiveOrderbooks(w http.ResponseWriter, r *http.Request) {
// RESTGetPortfolio returns the Bot portfolio
func RESTGetPortfolio(w http.ResponseWriter, r *http.Request) {
result := Bot.Portfolio.GetPortfolioSummary()
p := portfolio.GetPortfolio()
result := p.GetPortfolioSummary()
err := RESTfulJSONResponse(w, result)
if err != nil {
RESTfulError(r.Method, err)

View File

@@ -466,14 +466,14 @@ func (s *RPCServer) GetPortfolioSummary(ctx context.Context, r *gctrpc.GetPortfo
// AddPortfolioAddress adds an address to the portfolio manager
func (s *RPCServer) AddPortfolioAddress(ctx context.Context, r *gctrpc.AddPortfolioAddressRequest) (*gctrpc.AddPortfolioAddressResponse, error) {
Bot.Portfolio.AddAddress(r.Address, r.Description, currency.NewCode(r.CoinType), r.Balance)
return &gctrpc.AddPortfolioAddressResponse{}, nil
err := Bot.Portfolio.AddAddress(r.Address, r.Description, currency.NewCode(r.CoinType), r.Balance)
return &gctrpc.AddPortfolioAddressResponse{}, err
}
// RemovePortfolioAddress removes an address from the portfolio manager
func (s *RPCServer) RemovePortfolioAddress(ctx context.Context, r *gctrpc.RemovePortfolioAddressRequest) (*gctrpc.RemovePortfolioAddressResponse, error) {
Bot.Portfolio.RemoveAddress(r.Address, r.Description, currency.NewCode(r.CoinType))
return &gctrpc.RemovePortfolioAddressResponse{}, nil
err := Bot.Portfolio.RemoveAddress(r.Address, r.Description, currency.NewCode(r.CoinType))
return &gctrpc.RemovePortfolioAddressResponse{}, err
}
// GetForexProviders returns a list of available forex providers

11
main.go
View File

@@ -32,18 +32,21 @@ func main() {
flag.BoolVar(&settings.EnableDryRun, "dryrun", false, "dry runs bot, doesn't save config file")
flag.BoolVar(&settings.EnableAllExchanges, "enableallexchanges", false, "enables all exchanges")
flag.BoolVar(&settings.EnableAllPairs, "enableallpairs", false, "enables all pairs for enabled exchanges")
flag.BoolVar(&settings.EnablePortfolioWatcher, "portfoliowatcher", true, "enables the portfolio watcher")
flag.BoolVar(&settings.EnablePortfolioManager, "portfoliomanager", true, "enables the portfolio manager")
flag.BoolVar(&settings.EnableGRPC, "grpc", true, "enables the grpc server")
flag.BoolVar(&settings.EnableGRPCProxy, "grpcproxy", true, "enables the grpc proxy server")
flag.BoolVar(&settings.EnableWebsocketRPC, "websocketrpc", true, "enables the websocket RPC server")
flag.BoolVar(&settings.EnableDeprecatedRPC, "deprecatedrpc", true, "enables the deprecated RPC server")
flag.BoolVar(&settings.EnableCommsRelayer, "enablecommsrelayer", true, "enables available communications relayer")
flag.BoolVar(&settings.Verbose, "verbose", false, "increases logging verbosity for GoCryptoTrader")
flag.BoolVar(&settings.EnableTickerRoutine, "tickerroutine", true, "enables the ticker routine for all loaded exchanges")
flag.BoolVar(&settings.EnableOrderbookRoutine, "orderbookroutine", true, "enables the orderbook routine for all loaded exchanges")
flag.BoolVar(&settings.EnableExchangeSyncManager, "syncmanager", true, "enables to exchange sync manager")
flag.BoolVar(&settings.EnableTickerSyncing, "tickersync", true, "enables ticker syncing for all enabled exchanges")
flag.BoolVar(&settings.EnableOrderbookSyncing, "orderbooksync", true, "enables orderbook syncing for all enabled exchanges")
flag.BoolVar(&settings.EnableWebsocketRoutine, "websocketroutine", true, "enables the websocket routine for all loaded exchanges")
flag.BoolVar(&settings.EnableCoinmarketcapAnalysis, "coinmarketcap", false, "overrides config and runs currency analysis")
flag.BoolVar(&settings.EnableEventManager, "enableeventmanager", true, "enables the event manager")
flag.BoolVar(&settings.EnableEventManager, "eventmanager", true, "enables the event manager")
flag.BoolVar(&settings.EnableOrderManager, "ordermanager", true, "enables the order manager")
flag.BoolVar(&settings.EnableConnectivityMonitor, "connectivitymonitor", true, "enables the connectivity monitor")
flag.DurationVar(&settings.EventManagerDelay, "eventmanagerdelay", time.Duration(0), "sets the event managers sleep delay between event checking")
flag.BoolVar(&settings.EnableNTPClient, "ntpclient", true, "enables the NTP client to check system clock drift")

View File

@@ -149,10 +149,17 @@ func (p *Base) UpdateExchangeAddressBalance(exchangeName string, coinType curren
}
// AddAddress adds an address to the portfolio base
func (p *Base) AddAddress(address, description string, coinType currency.Code, balance float64) {
func (p *Base) AddAddress(address, description string, coinType currency.Code, balance float64) error {
if address == "" {
return errors.New("address is empty")
}
if coinType.String() == "" {
return errors.New("coin type is empty")
}
if description == PortfolioAddressExchange {
p.AddExchangeAddress(address, coinType, balance)
return
}
if !p.AddressExists(address) {
p.Addresses = append(
@@ -166,19 +173,30 @@ func (p *Base) AddAddress(address, description string, coinType currency.Code, b
p.UpdateAddressBalance(address, balance)
}
}
return nil
}
// RemoveAddress removes an address when checked against the correct address and
// coinType
func (p *Base) RemoveAddress(address, description string, coinType currency.Code) {
func (p *Base) RemoveAddress(address, description string, coinType currency.Code) error {
if address == "" {
return errors.New("address is empty")
}
if coinType.String() == "" {
return errors.New("coin type is empty")
}
for x := range p.Addresses {
if p.Addresses[x].Address == address &&
p.Addresses[x].CoinType == coinType &&
p.Addresses[x].Description == description {
p.Addresses = append(p.Addresses[:x], p.Addresses[x+1:]...)
return
return nil
}
}
return errors.New("portfolio item does not exist")
}
// UpdatePortfolio adds to the portfolio addresses by coin type

View File

@@ -138,7 +138,19 @@ func TestUpdateAddressBalance(t *testing.T) {
}
func TestRemoveAddress(t *testing.T) {
newbase := Base{}
var newbase Base
if err := newbase.RemoveAddress("", "MEOW", currency.LTC); err == nil {
t.Error("invalid address should throw an error")
}
if err := newbase.RemoveAddress("Gibson", "", currency.NewCode("")); err == nil {
t.Error("invalid coin type should throw an error")
}
if err := newbase.RemoveAddress("HIDDENERINO", "MEOW", currency.LTC); err == nil {
t.Error("non-existent address should throw an error")
}
newbase.AddAddress("someaddr",
currency.LTC.String(),
currency.NewCode("LTCWALLETTEST"),
@@ -187,12 +199,36 @@ func TestUpdateExchangeAddressBalance(t *testing.T) {
}
func TestAddAddress(t *testing.T) {
newbase := Base{}
var newbase Base
if err := newbase.AddAddress("", "MEOW", currency.LTC, 1); err == nil {
t.Error("invalid address should throw an error")
}
if err := newbase.AddAddress("Gibson", "", currency.NewCode(""), 1); err == nil {
t.Error("invalid coin type should throw an error")
}
// test adding an exchange address
err := newbase.AddAddress("COINUT", PortfolioAddressExchange, currency.LTC, 0)
if err != nil {
t.Errorf("failed to add address: %v", err)
}
// add a test portfolio address and amount
newbase.AddAddress("Gibson",
currency.LTC.String(),
currency.NewCode("LTCWALLETTEST"),
0.02)
// test updating the balance and make sure it's reflected
newbase.AddAddress("Gibson", currency.LTC.String(),
currency.NewCode("LTCWALLETTEST"), 0.05)
b, _ := newbase.GetAddressBalance("Gibson", "LTC",
currency.NewCode("LTCWALLETTEST"))
if b != 0.05 {
t.Error("invalid portfolio amount")
}
portfolio := GetPortfolio()
portfolio.Seed(newbase)
if !portfolio.AddressExists("Gibson") {