Merge branch 'master' into engine

This commit is contained in:
Adrian Gallagher
2019-09-03 08:57:21 +10:00
11 changed files with 267 additions and 174 deletions

View File

@@ -8,8 +8,8 @@ import (
"errors"
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/communications/base"
@@ -39,9 +39,16 @@ const (
talkRoot = "GoCryptoTrader bot"
)
var (
// ErrWaiter is the default timer to wait if an err occurs
// before retrying after successfully connecting
ErrWaiter = time.Second * 30
)
// Telegram is the overarching type across this package
type Telegram struct {
base.Base
initConnected bool
Token string
Offset int64
AuthorisedClients []int64
@@ -63,6 +70,8 @@ func (t *Telegram) Connect() error {
if err := t.TestConnection(); err != nil {
return err
}
log.Debugln(log.CommunicationMgr, "Telegram: Connected successfully!")
t.Connected = true
go t.PollerStart()
return nil
@@ -70,9 +79,10 @@ func (t *Telegram) Connect() error {
// PushEvent sends an event to a supplied recipient list via telegram
func (t *Telegram) PushEvent(event base.Event) error {
msg := fmt.Sprintf("Type: %s Message: %s",
event.Type, event.Message)
for i := range t.AuthorisedClients {
err := t.SendMessage(fmt.Sprintf("Type: %s Message: %s",
event.Type, event.Message), t.AuthorisedClients[i])
err := t.SendMessage(msg, t.AuthorisedClients[i])
if err != nil {
return err
}
@@ -82,12 +92,25 @@ func (t *Telegram) PushEvent(event base.Event) error {
// PollerStart starts the long polling sequence
func (t *Telegram) PollerStart() {
t.InitialConnect()
errWait := func(err error) {
log.Errorln(log.CommunicationMgr, err)
time.Sleep(ErrWaiter)
}
for {
if !t.initConnected {
err := t.InitialConnect()
if err != nil {
errWait(err)
continue
}
t.initConnected = true
}
resp, err := t.GetUpdates()
if err != nil {
log.Errorln(log.CommunicationMgr, err)
errWait(err)
continue
}
for i := range resp.Result {
@@ -95,7 +118,8 @@ func (t *Telegram) PollerStart() {
if string(resp.Result[i].Message.Text[0]) == "/" {
err = t.HandleMessages(resp.Result[i].Message.Text, resp.Result[i].Message.From.ID)
if err != nil {
log.Errorln(log.CommunicationMgr, err)
log.Errorf(log.CommunicationMgr, "Telegram: Unable to HandleMessages. Error: %s\n", err)
continue
}
}
t.Offset = resp.Result[i].UpdateID
@@ -106,16 +130,14 @@ func (t *Telegram) PollerStart() {
// InitialConnect sets offset, and sends a welcome greeting to any associated
// IDs
func (t *Telegram) InitialConnect() {
func (t *Telegram) InitialConnect() error {
resp, err := t.GetUpdates()
if err != nil {
log.Errorln(log.CommunicationMgr, err)
os.Exit(1)
return err
}
if !resp.Ok {
log.Errorln(log.CommunicationMgr, resp.Description)
os.Exit(1)
return errors.New(resp.Description)
}
warmWelcomeList := make(map[string]int64)
@@ -128,18 +150,25 @@ func (t *Telegram) InitialConnect() {
for userName, ID := range warmWelcomeList {
err = t.SendMessage(fmt.Sprintf("GoCryptoTrader bot has connected: Hello, %s!", userName), ID)
if err != nil {
log.Errorln(log.CommunicationMgr, err)
os.Exit(1)
log.Errorf(log.CommunicationMgr, "Telegram: Unable to send welcome message. Error: %s\n", err)
continue
}
}
if len(resp.Result) == 0 {
return
return nil
}
t.Offset = resp.Result[len(resp.Result)-1].UpdateID
return nil
}
// HandleMessages handles incoming message from the long polling routine
func (t *Telegram) HandleMessages(text string, chatID int64) error {
if t.Verbose {
log.Debugf(log.CommunicationMgr, "Telegram: Received message: %s\n", text)
}
switch {
case strings.Contains(text, cmdHelp):
return t.SendMessage(fmt.Sprintf("%s: %s", talkRoot, cmdHelpReply), chatID)
@@ -151,7 +180,7 @@ func (t *Telegram) HandleMessages(text string, chatID int64) error {
return t.SendMessage(fmt.Sprintf("%s: %s", talkRoot, t.GetStatus()), chatID)
default:
return t.SendMessage(fmt.Sprintf("command %s not recognized", text), chatID)
return t.SendMessage(fmt.Sprintf("Command %s not recognized", text), chatID)
}
}
@@ -204,6 +233,10 @@ func (t *Telegram) SendMessage(text string, chatID int64) error {
if !resp.Ok {
return errors.New(resp.Description)
}
if t.Verbose {
log.Debugf(log.CommunicationMgr, "Telegram: Sent '%s'\n", text)
}
return nil
}

File diff suppressed because one or more lines are too long

View File

@@ -16,7 +16,6 @@ import (
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
log "github.com/thrasher-corp/gocryptotrader/logger"
)
// Coinmarketcap account plan bitmasks, url and enpoint consts
@@ -80,19 +79,16 @@ func (c *Coinmarketcap) SetDefaults() {
}
// Setup sets user configuration
func (c *Coinmarketcap) Setup(conf Settings) {
func (c *Coinmarketcap) Setup(conf Settings) error {
if !conf.Enabled {
c.Enabled = false
} else {
err := c.SetAccountPlan(conf.AccountPlan)
if err != nil {
log.Errorf(log.Global, "CoinMarketCap enabled but SetAccountPlan failed. Err: %s\n", err)
return
}
c.Enabled = true
c.Verbose = conf.Verbose
c.APIkey = conf.APIkey
return nil
}
c.Enabled = true
c.Verbose = conf.Verbose
c.APIkey = conf.APIkey
return c.SetAccountPlan(conf.AccountPlan)
}
// GetCryptocurrencyInfo returns all static metadata for one or more

View File

@@ -41,7 +41,14 @@ func TestSetup(t *testing.T) {
cfg.Enabled = true
cfg.AccountPlan = "basic"
c.Setup(cfg)
if err := c.Setup(cfg); err != nil {
t.Error(err)
}
cfg.AccountPlan = "meow"
if err := c.Setup(cfg); err == nil {
t.Error("expected err when invalid account plan is specified")
}
}
func TestCheckAccountPlan(t *testing.T) {

View File

@@ -122,15 +122,21 @@ func (s *Storage) RunUpdater(overrides BotOverrides, settings *MainConfiguration
"Setting up currency analysis system with Coinmarketcap...")
c := &coinmarketcap.Coinmarketcap{}
c.SetDefaults()
c.Setup(coinmarketcap.Settings{
err := c.Setup(coinmarketcap.Settings{
Name: settings.CryptocurrencyProvider.Name,
Enabled: true,
AccountPlan: settings.CryptocurrencyProvider.AccountPlan,
APIkey: settings.CryptocurrencyProvider.APIkey,
Verbose: settings.CryptocurrencyProvider.Verbose,
})
s.currencyAnalysis = c
if err != nil {
log.Errorf(log.Global,
"Unable to setup CoinMarketCap analysis. Error: %s", err)
c = nil
settings.CryptocurrencyProvider.Enabled = false
} else {
s.currencyAnalysis = c
}
}
if filePath == "" {

View File

@@ -257,6 +257,7 @@ func PrintSettings(s *Settings) {
// Start starts the engine
func (e *Engine) Start() {
// TO-DO: move this out of here
if e == nil {
log.Errorln(log.Global, "Engine instance is nil")
os.Exit(1)
@@ -301,6 +302,11 @@ func (e *Engine) Start() {
log.Debugln(log.Global, "Setting up exchanges..")
SetupExchanges()
// TO-DO: move this out of here
if len(Bot.Exchanges) == 0 {
log.Errorln(log.Global, "No exchanges were able to be loaded. Exiting")
os.Exit(1)
}
if e.Settings.EnableCommsRelayer {
if err := e.CommsManager.Start(); err != nil {

View File

@@ -2,7 +2,6 @@ package engine
import (
"errors"
"os"
"strings"
"sync"
@@ -313,8 +312,4 @@ func SetupExchanges() {
)
}
wg.Wait()
if len(Bot.Exchanges) == 0 {
log.Errorln(log.Global, "No exchanges were able to be loaded. Exiting")
os.Exit(1)
}
}

View File

@@ -58,7 +58,6 @@ const (
// Bitstamp is the overarching type across the bitstamp package
type Bitstamp struct {
exchange.Base
Balance Balances
WebsocketConn *wshandler.WebsocketConnection
}
@@ -68,15 +67,15 @@ func (b *Bitstamp) GetFee(feeBuilder *exchange.FeeBuilder) (float64, error) {
switch feeBuilder.FeeType {
case exchange.CryptocurrencyTradeFee:
var err error
b.Balance, err = b.GetBalance()
balance, err := b.GetBalance()
if err != nil {
return 0, err
}
fee = b.CalculateTradingFee(feeBuilder.Pair.Base,
feeBuilder.Pair.Quote,
feeBuilder.PurchasePrice,
feeBuilder.Amount)
feeBuilder.Amount,
balance)
case exchange.CyptocurrencyDepositFee:
fee = 0
case exchange.InternationalBankDepositFee:
@@ -121,20 +120,20 @@ func getInternationalBankDepositFee(amount float64) float64 {
}
// CalculateTradingFee returns fee on a currency pair
func (b *Bitstamp) CalculateTradingFee(base, quote currency.Code, purchasePrice, amount float64) float64 {
func (b *Bitstamp) CalculateTradingFee(base, quote currency.Code, purchasePrice, amount float64, balances *Balances) float64 {
var fee float64
switch base.String() + quote.String() {
case currency.BTC.String() + currency.USD.String():
fee = b.Balance.BTCUSDFee
fee = balances.BTCUSDFee
case currency.BTC.String() + currency.EUR.String():
fee = b.Balance.BTCEURFee
fee = balances.BTCEURFee
case currency.XRP.String() + currency.EUR.String():
fee = b.Balance.XRPEURFee
fee = balances.XRPEURFee
case currency.XRP.String() + currency.USD.String():
fee = b.Balance.XRPUSDFee
fee = balances.XRPUSDFee
case currency.EUR.String() + currency.USD.String():
fee = b.Balance.EURUSDFee
fee = balances.EURUSDFee
default:
fee = 0
}
@@ -259,9 +258,9 @@ func (b *Bitstamp) GetEURUSDConversionRate() (EURUSDConversionRate, error) {
}
// GetBalance returns full balance of currency held on the exchange
func (b *Bitstamp) GetBalance() (Balances, error) {
func (b *Bitstamp) GetBalance() (*Balances, error) {
var balance Balances
return balance,
return &balance,
b.SendAuthenticatedHTTPRequest(bitstampAPIBalance, true, nil, &balance)
}

View File

@@ -141,21 +141,23 @@ func TestGetFee(t *testing.T) {
func TestCalculateTradingFee(t *testing.T) {
t.Parallel()
b.Balance.BTCUSDFee = 1
b.Balance.BTCEURFee = 0
if resp := b.CalculateTradingFee(currency.BTC, currency.USD, 0, 0); resp != 0 {
var newBalance = new(Balances)
newBalance.BTCUSDFee = 1
newBalance.BTCEURFee = 0
if resp := b.CalculateTradingFee(currency.BTC, currency.USD, 0, 0, newBalance); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
if resp := b.CalculateTradingFee(currency.BTC, currency.USD, 2, 2); resp != float64(4) {
if resp := b.CalculateTradingFee(currency.BTC, currency.USD, 2, 2, newBalance); resp != float64(4) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(4), resp)
}
if resp := b.CalculateTradingFee(currency.BTC, currency.EUR, 2, 2); resp != float64(0) {
if resp := b.CalculateTradingFee(currency.BTC, currency.EUR, 2, 2, newBalance); resp != float64(0) {
t.Errorf("Test Failed - GetFee() error. Expected: %f, Received: %f", float64(0), resp)
}
dummy1, dummy2 := currency.NewCode(""), currency.NewCode("")
if resp := b.CalculateTradingFee(dummy1, dummy2, 0, 0); resp != 0 {
if resp := b.CalculateTradingFee(dummy1, dummy2, 0, 0, newBalance); resp != 0 {
t.Error("Test Failed - GetFee() error")
}
}

View File

@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
@@ -164,7 +163,7 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
mockRespVals, urlErr := url.ParseQuery(mockResponses[i].BodyParams)
if urlErr != nil {
log.Fatal(urlErr)
return urlErr
}
if MatchURLVals(respQueryVals, mockRespVals) {

File diff suppressed because one or more lines are too long