mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
228 lines
6.1 KiB
Go
228 lines
6.1 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"runtime"
|
|
"strconv"
|
|
"syscall"
|
|
|
|
"github.com/thrasher-/gocryptotrader/common"
|
|
"github.com/thrasher-/gocryptotrader/config"
|
|
"github.com/thrasher-/gocryptotrader/currency"
|
|
"github.com/thrasher-/gocryptotrader/exchanges"
|
|
"github.com/thrasher-/gocryptotrader/portfolio"
|
|
"github.com/thrasher-/gocryptotrader/smsglobal"
|
|
)
|
|
|
|
// Bot contains configuration, portfolio, exchange & ticker data and is the
|
|
// overarching type across this code base.
|
|
type Bot struct {
|
|
config *config.Config
|
|
smsglobal *smsglobal.Base
|
|
portfolio *portfolio.Base
|
|
exchanges []exchange.IBotExchange
|
|
shutdown chan bool
|
|
configFile string
|
|
}
|
|
|
|
var bot Bot
|
|
|
|
func main() {
|
|
HandleInterrupt()
|
|
|
|
//Handle flags
|
|
flag.StringVar(&bot.configFile, "config", config.GetFilePath(""), "config file to load")
|
|
version := flag.Bool("version", false, "retrieves current GoCryptoTrader version")
|
|
flag.Parse()
|
|
|
|
if *version {
|
|
fmt.Printf(BuildVersion(true))
|
|
os.Exit(0)
|
|
}
|
|
|
|
bot.config = &config.Cfg
|
|
fmt.Println(BuildVersion(false))
|
|
log.Printf("Loading config file %s..\n", bot.configFile)
|
|
|
|
err := bot.config.LoadConfig(bot.configFile)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
AdjustGoMaxProcs()
|
|
log.Printf("Bot '%s' started.\n", bot.config.Name)
|
|
log.Printf("Fiat display currency: %s.", bot.config.FiatDisplayCurrency)
|
|
|
|
if bot.config.SMS.Enabled {
|
|
bot.smsglobal = smsglobal.New(bot.config.SMS.Username, bot.config.SMS.Password,
|
|
bot.config.Name, bot.config.SMS.Contacts)
|
|
log.Printf(
|
|
"SMS support enabled. Number of SMS contacts %d.\n",
|
|
bot.smsglobal.GetEnabledContacts(),
|
|
)
|
|
} else {
|
|
log.Println("SMS support disabled.")
|
|
}
|
|
|
|
log.Printf(
|
|
"Available Exchanges: %d. Enabled Exchanges: %d.\n",
|
|
len(bot.config.Exchanges), bot.config.GetConfigEnabledExchanges(),
|
|
)
|
|
|
|
SetupExchanges()
|
|
if len(bot.exchanges) == 0 {
|
|
log.Fatalf("No exchanges were able to be loaded. Exiting")
|
|
}
|
|
|
|
if bot.config.CurrencyExchangeProvider == "yahoo" {
|
|
currency.SetProvider(true)
|
|
} else {
|
|
currency.SetProvider(false)
|
|
}
|
|
|
|
log.Printf("Using %s as currency exchange provider.", bot.config.CurrencyExchangeProvider)
|
|
|
|
bot.config.RetrieveConfigCurrencyPairs()
|
|
err = currency.SeedCurrencyData(currency.BaseCurrencies)
|
|
if err != nil {
|
|
currency.SwapProvider()
|
|
log.Printf("'%s' currency exchange provider failed, swapping to %s and testing..",
|
|
bot.config.CurrencyExchangeProvider, currency.GetProvider())
|
|
err = currency.SeedCurrencyData(currency.BaseCurrencies)
|
|
if err != nil {
|
|
log.Fatalf("Fatal error retrieving config currencies. Error: %s", err)
|
|
}
|
|
}
|
|
|
|
log.Println("Successfully retrieved config currencies.")
|
|
|
|
bot.portfolio = &portfolio.Portfolio
|
|
bot.portfolio.SeedPortfolio(bot.config.Portfolio)
|
|
SeedExchangeAccountInfo(GetAllEnabledExchangeAccountInfo().Data)
|
|
go portfolio.StartPortfolioWatcher()
|
|
|
|
log.Println("Starting websocket handler")
|
|
go WebsocketHandler()
|
|
|
|
go TickerUpdaterRoutine()
|
|
go OrderbookUpdaterRoutine()
|
|
|
|
if bot.config.Webserver.Enabled {
|
|
listenAddr := bot.config.Webserver.ListenAddress
|
|
log.Printf(
|
|
"HTTP Webserver support enabled. Listen URL: http://%s:%d/\n",
|
|
common.ExtractHost(listenAddr), common.ExtractPort(listenAddr),
|
|
)
|
|
router := NewRouter(bot.exchanges)
|
|
log.Fatal(http.ListenAndServe(listenAddr, router))
|
|
} else {
|
|
log.Println("HTTP RESTful Webserver support disabled.")
|
|
}
|
|
|
|
<-bot.shutdown
|
|
Shutdown()
|
|
}
|
|
|
|
// AdjustGoMaxProcs adjusts the maximum processes that the CPU can handle.
|
|
func AdjustGoMaxProcs() {
|
|
log.Println("Adjusting bot runtime performance..")
|
|
maxProcsEnv := os.Getenv("GOMAXPROCS")
|
|
maxProcs := runtime.NumCPU()
|
|
log.Println("Number of CPU's detected:", maxProcs)
|
|
|
|
if maxProcsEnv != "" {
|
|
log.Println("GOMAXPROCS env =", maxProcsEnv)
|
|
env, err := strconv.Atoi(maxProcsEnv)
|
|
if err != nil {
|
|
log.Println("Unable to convert GOMAXPROCS to int, using", maxProcs)
|
|
} else {
|
|
maxProcs = env
|
|
}
|
|
}
|
|
if i := runtime.GOMAXPROCS(maxProcs); i != maxProcs {
|
|
log.Fatal("Go Max Procs were not set correctly.")
|
|
}
|
|
log.Println("Set GOMAXPROCS to:", maxProcs)
|
|
}
|
|
|
|
// HandleInterrupt monitors and captures the SIGTERM in a new goroutine then
|
|
// shuts down bot
|
|
func HandleInterrupt() {
|
|
c := make(chan os.Signal, 1)
|
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
|
go func() {
|
|
sig := <-c
|
|
log.Printf("Captured %v.", sig)
|
|
Shutdown()
|
|
}()
|
|
}
|
|
|
|
// Shutdown correctly shuts down bot saving configuration files
|
|
func Shutdown() {
|
|
log.Println("Bot shutting down..")
|
|
bot.config.Portfolio = portfolio.Portfolio
|
|
err := bot.config.SaveConfig(bot.configFile)
|
|
|
|
if err != nil {
|
|
log.Println("Unable to save config.")
|
|
} else {
|
|
log.Println("Config file saved successfully.")
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|