mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-17 23:16:52 +00:00
* Add exchange manager to engine
* Several improvements for engine and friends
1) New file.Exists func
2) gRPC TLS cert expiration date check and regeneration
3) New donation var for use across the codebase
4) Use Go log package until the logger is initialised
* Add cert tests and create dir tree if it doesn't exist for file.Write
* Link up donation address to documentation tool plus minor adjustments
* Fix remaining donation addrs
* Move non-needed reload exchange funcs
* Revert accidental config_example.json changes 🕯️
* Use go logger for logging until the logger has initiliased, otherwise no output will be seen
* Link up portfolio delay val and other fixes
* Run go mod tidy after dependabot PR
* Address nitterinos
843 lines
27 KiB
Go
843 lines
27 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"text/template"
|
|
|
|
"github.com/thrasher-corp/gocryptotrader/common/file"
|
|
"github.com/thrasher-corp/gocryptotrader/config"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/engine"
|
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/withdraw"
|
|
)
|
|
|
|
func main() {
|
|
log.Println("Loading flags...")
|
|
parseCLFlags()
|
|
var err error
|
|
log.Println("Loading engine...")
|
|
engine.Bot, err = engine.New()
|
|
if err != nil {
|
|
log.Fatalf("Failed to initialise engine. Err: %s", err)
|
|
}
|
|
|
|
engine.Bot.Settings = engine.Settings{
|
|
DisableExchangeAutoPairUpdates: true,
|
|
Verbose: verboseOverride,
|
|
}
|
|
|
|
log.Println("Loading config...")
|
|
wrapperConfig, err := loadConfig()
|
|
if err != nil {
|
|
log.Printf("Error loading config: '%v', generating empty config", err)
|
|
wrapperConfig = Config{
|
|
Exchanges: make(map[string]*config.APICredentialsConfig),
|
|
}
|
|
}
|
|
|
|
log.Println("Loading exchanges..")
|
|
|
|
var wg sync.WaitGroup
|
|
for x := range exchange.Exchanges {
|
|
name := exchange.Exchanges[x]
|
|
if _, ok := wrapperConfig.Exchanges[name]; !ok {
|
|
wrapperConfig.Exchanges[strings.ToLower(name)] = &config.APICredentialsConfig{}
|
|
}
|
|
if shouldLoadExchange(name) {
|
|
err = engine.LoadExchange(name, true, &wg)
|
|
if err != nil {
|
|
log.Printf("Failed to load exchange %s. Err: %s", name, err)
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
wg.Wait()
|
|
log.Println("Done.")
|
|
|
|
if withdrawAddressOverride != "" {
|
|
wrapperConfig.WalletAddress = withdrawAddressOverride
|
|
}
|
|
if orderTypeOverride != "LIMIT" {
|
|
wrapperConfig.OrderSubmission.OrderType = orderTypeOverride
|
|
}
|
|
if orderSideOverride != "BUY" {
|
|
wrapperConfig.OrderSubmission.OrderSide = orderSideOverride
|
|
}
|
|
if orderPriceOverride > 0 {
|
|
wrapperConfig.OrderSubmission.Price = orderPriceOverride
|
|
}
|
|
if orderAmountOverride > 0 {
|
|
wrapperConfig.OrderSubmission.Amount = orderAmountOverride
|
|
}
|
|
|
|
log.Println("Testing exchange wrappers..")
|
|
var exchangeResponses []ExchangeResponses
|
|
|
|
exchs := engine.GetExchanges()
|
|
for x := range exchs {
|
|
base := exchs[x].GetBase()
|
|
if !base.Config.Enabled {
|
|
log.Printf("Exchange %v not enabled, skipping", base.GetName())
|
|
continue
|
|
}
|
|
base.Config.Verbose = verboseOverride
|
|
base.Verbose = verboseOverride
|
|
base.HTTPDebugging = false
|
|
base.Config.HTTPDebugging = false
|
|
wg.Add(1)
|
|
|
|
go func(num int) {
|
|
name := exchs[num].GetName()
|
|
authenticated := setExchangeAPIKeys(name, wrapperConfig.Exchanges, base)
|
|
wrapperResult := ExchangeResponses{
|
|
ID: fmt.Sprintf("Exchange%v", num),
|
|
ExchangeName: name,
|
|
APIKeysSet: authenticated,
|
|
AssetPairResponses: testWrappers(exchs[num], base, &wrapperConfig),
|
|
}
|
|
for i := range wrapperResult.AssetPairResponses {
|
|
wrapperResult.ErrorCount += wrapperResult.AssetPairResponses[i].ErrorCount
|
|
}
|
|
exchangeResponses = append(exchangeResponses, wrapperResult)
|
|
wg.Done()
|
|
}(x)
|
|
}
|
|
wg.Wait()
|
|
|
|
log.Println("Done.")
|
|
log.Println()
|
|
|
|
sort.Slice(exchangeResponses, func(i, j int) bool {
|
|
return exchangeResponses[i].ExchangeName < exchangeResponses[j].ExchangeName
|
|
})
|
|
|
|
if strings.EqualFold(outputOverride, "Console") {
|
|
outputToConsole(exchangeResponses)
|
|
}
|
|
if strings.EqualFold(outputOverride, "JSON") {
|
|
outputToJSON(exchangeResponses)
|
|
}
|
|
if strings.EqualFold(outputOverride, "HTML") {
|
|
outputToHTML(exchangeResponses)
|
|
}
|
|
|
|
saveConfig(&wrapperConfig)
|
|
}
|
|
|
|
func parseCLFlags() {
|
|
flag.StringVar(&exchangesToUseOverride, "exchanges", "", "a + delimited list of exchange names to run tests against eg -exchanges=bitfinex+okex")
|
|
flag.StringVar(&exchangesToExcludeOverride, "excluded-exchanges", "", "a + delimited list of exchange names to ignore when they're being temperamental eg -exchangesToExlude=lbank")
|
|
flag.StringVar(&assetTypeOverride, "asset", "", "the asset type to run tests against (where applicable)")
|
|
flag.StringVar(¤cyPairOverride, "currency", "", "the currency to run tests against (where applicable)")
|
|
flag.StringVar(&outputOverride, "output", "HTML", "JSON, HTML or Console")
|
|
flag.BoolVar(&authenticatedOnly, "auth-only", false, "skip any wrapper function that doesn't require auth")
|
|
flag.BoolVar(&verboseOverride, "verbose", false, "verbose CL output - if console output is selected then wrapper response is included")
|
|
flag.StringVar(&orderSideOverride, "orderside", "BUY", "the order type for all order based wrapper tests")
|
|
flag.StringVar(&orderTypeOverride, "ordertype", "LIMIT", "the order type for all order based wrapper tests")
|
|
flag.Float64Var(&orderAmountOverride, "orderamount", 0, "the order amount for all order based wrapper tests")
|
|
flag.Float64Var(&orderPriceOverride, "orderprice", 0, "the order price for all order based wrapper tests")
|
|
flag.StringVar(&withdrawAddressOverride, "withdraw-wallet", "", "withdraw wallet address")
|
|
flag.StringVar(&outputFileName, "filename", "report", "name of the output file eg 'report'.html or 'report'.json")
|
|
flag.Parse()
|
|
|
|
if exchangesToUseOverride != "" {
|
|
exchangesToUseList = strings.Split(exchangesToUseOverride, "+")
|
|
}
|
|
if exchangesToExcludeOverride != "" {
|
|
exchangesToExcludeList = strings.Split(exchangesToExcludeOverride, "+")
|
|
}
|
|
}
|
|
|
|
func shouldLoadExchange(name string) bool {
|
|
shouldLoadExchange := true
|
|
if len(exchangesToUseList) > 0 {
|
|
var found bool
|
|
for i := range exchangesToUseList {
|
|
if strings.EqualFold(name, exchangesToUseList[i]) {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
shouldLoadExchange = false
|
|
}
|
|
}
|
|
|
|
if len(exchangesToExcludeList) > 0 {
|
|
for i := range exchangesToExcludeList {
|
|
if strings.EqualFold(name, exchangesToExcludeList[i]) {
|
|
if shouldLoadExchange {
|
|
shouldLoadExchange = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return shouldLoadExchange
|
|
}
|
|
|
|
func setExchangeAPIKeys(name string, keys map[string]*config.APICredentialsConfig, base *exchange.Base) bool {
|
|
lowerExchangeName := strings.ToLower(name)
|
|
|
|
if base.API.CredentialsValidator.RequiresKey && keys[lowerExchangeName].Key == "" {
|
|
keys[lowerExchangeName].Key = config.DefaultAPIKey
|
|
}
|
|
if base.API.CredentialsValidator.RequiresSecret && keys[lowerExchangeName].Secret == "" {
|
|
keys[lowerExchangeName].Secret = config.DefaultAPISecret
|
|
}
|
|
if base.API.CredentialsValidator.RequiresPEM && keys[lowerExchangeName].PEMKey == "" {
|
|
keys[lowerExchangeName].PEMKey = "PEM"
|
|
}
|
|
if base.API.CredentialsValidator.RequiresClientID && keys[lowerExchangeName].ClientID == "" {
|
|
keys[lowerExchangeName].ClientID = config.DefaultAPIClientID
|
|
}
|
|
if keys[lowerExchangeName].OTPSecret == "" {
|
|
keys[lowerExchangeName].OTPSecret = "-" // Ensure OTP is available for use
|
|
}
|
|
|
|
base.API.Credentials.Key = keys[lowerExchangeName].Key
|
|
base.Config.API.Credentials.Key = keys[lowerExchangeName].Key
|
|
|
|
base.API.Credentials.Secret = keys[lowerExchangeName].Secret
|
|
base.Config.API.Credentials.Secret = keys[lowerExchangeName].Secret
|
|
|
|
base.API.Credentials.ClientID = keys[lowerExchangeName].ClientID
|
|
base.Config.API.Credentials.ClientID = keys[lowerExchangeName].ClientID
|
|
|
|
if keys[lowerExchangeName].OTPSecret != "-" {
|
|
base.Config.API.Credentials.OTPSecret = keys[lowerExchangeName].OTPSecret
|
|
}
|
|
|
|
base.API.AuthenticatedSupport = true
|
|
base.API.AuthenticatedWebsocketSupport = true
|
|
base.Config.API.AuthenticatedSupport = true
|
|
base.Config.API.AuthenticatedWebsocketSupport = true
|
|
|
|
return base.ValidateAPICredentials()
|
|
}
|
|
|
|
func parseOrderSide(orderSide string) order.Side {
|
|
switch orderSide {
|
|
case order.AnySide.String():
|
|
return order.AnySide
|
|
case order.Buy.String():
|
|
return order.Buy
|
|
case order.Sell.String():
|
|
return order.Sell
|
|
case order.Bid.String():
|
|
return order.Bid
|
|
case order.Ask.String():
|
|
return order.Ask
|
|
default:
|
|
log.Printf("Orderside '%v' not recognised, defaulting to BUY", orderSide)
|
|
return order.Buy
|
|
}
|
|
}
|
|
|
|
func parseOrderType(orderType string) order.Type {
|
|
switch orderType {
|
|
case order.AnyType.String():
|
|
return order.AnyType
|
|
case order.Limit.String():
|
|
return order.Limit
|
|
case order.Market.String():
|
|
return order.Market
|
|
case order.ImmediateOrCancel.String():
|
|
return order.ImmediateOrCancel
|
|
case order.Stop.String():
|
|
return order.Stop
|
|
case order.TrailingStop.String():
|
|
return order.TrailingStop
|
|
case order.Unknown.String():
|
|
return order.Unknown
|
|
default:
|
|
log.Printf("OrderType '%v' not recognised, defaulting to LIMIT",
|
|
orderTypeOverride)
|
|
return order.Limit
|
|
}
|
|
}
|
|
|
|
func testWrappers(e exchange.IBotExchange, base *exchange.Base, config *Config) []ExchangeAssetPairResponses {
|
|
var response []ExchangeAssetPairResponses
|
|
testOrderSide := parseOrderSide(config.OrderSubmission.OrderSide)
|
|
testOrderType := parseOrderType(config.OrderSubmission.OrderType)
|
|
assetTypes := base.GetAssetTypes()
|
|
if assetTypeOverride != "" {
|
|
if asset.IsValid(asset.Item(assetTypeOverride)) {
|
|
assetTypes = asset.Items{asset.Item(assetTypeOverride)}
|
|
} else {
|
|
log.Printf("%v Asset Type '%v' not recognised, defaulting to exchange defaults", base.GetName(), assetTypeOverride)
|
|
}
|
|
}
|
|
for i := range assetTypes {
|
|
var msg string
|
|
var p currency.Pair
|
|
log.Printf("%v %v", base.GetName(), assetTypes[i])
|
|
if _, ok := base.Config.CurrencyPairs.Pairs[assetTypes[i]]; !ok {
|
|
continue
|
|
}
|
|
|
|
switch {
|
|
case currencyPairOverride != "":
|
|
p = currency.NewPairFromString(currencyPairOverride)
|
|
case len(base.Config.CurrencyPairs.Pairs[assetTypes[i]].Enabled) == 0:
|
|
if len(base.Config.CurrencyPairs.Pairs[assetTypes[i]].Available) == 0 {
|
|
log.Printf("%v has no enabled or available currencies. Skipping", base.GetName())
|
|
continue
|
|
}
|
|
p = base.Config.CurrencyPairs.Pairs[assetTypes[i]].Available.GetRandomPair()
|
|
default:
|
|
p = base.Config.CurrencyPairs.Pairs[assetTypes[i]].Enabled.GetRandomPair()
|
|
}
|
|
|
|
responseContainer := ExchangeAssetPairResponses{
|
|
AssetType: assetTypes[i],
|
|
CurrencyPair: p,
|
|
}
|
|
|
|
log.Printf("Setup config for %v %v %v", base.GetName(), assetTypes[i], p)
|
|
err := e.Setup(base.Config)
|
|
if err != nil {
|
|
log.Printf("%v Encountered error reloading config: '%v'", base.GetName(), err)
|
|
}
|
|
log.Printf("Executing wrappers for %v %v %v", base.GetName(), assetTypes[i], p)
|
|
|
|
if !authenticatedOnly {
|
|
var r1 *ticker.Price
|
|
r1, err = e.FetchTicker(p, assetTypes[i])
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
|
|
Function: "FetchTicker",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r1}),
|
|
})
|
|
|
|
var r2 *ticker.Price
|
|
r2, err = e.UpdateTicker(p, assetTypes[i])
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
|
|
Function: "UpdateTicker",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r2}),
|
|
})
|
|
|
|
var r3 *orderbook.Base
|
|
r3, err = e.FetchOrderbook(p, assetTypes[i])
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
|
|
Function: "FetchOrderbook",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r3}),
|
|
})
|
|
|
|
var r4 *orderbook.Base
|
|
r4, err = e.UpdateOrderbook(p, assetTypes[i])
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
|
|
Function: "UpdateOrderbook",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r4}),
|
|
})
|
|
|
|
var r5 []string
|
|
r5, err = e.FetchTradablePairs(assetTypes[i])
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{assetTypes[i]}),
|
|
Function: "FetchTradablePairs",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r5}),
|
|
})
|
|
// r6
|
|
err = e.UpdateTradablePairs(false)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{false}),
|
|
Function: "UpdateTradablePairs",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{nil}),
|
|
})
|
|
}
|
|
|
|
var r7 account.Holdings
|
|
r7, err = e.FetchAccountInfo()
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
Function: "FetchAccountInfo",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r7}),
|
|
})
|
|
|
|
var r8 []exchange.TradeHistory
|
|
r8, err = e.GetExchangeHistory(p, assetTypes[i])
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{p, assetTypes[i]}),
|
|
Function: "GetExchangeHistory",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r8}),
|
|
})
|
|
|
|
var r9 []exchange.FundHistory
|
|
r9, err = e.GetFundingHistory()
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
Function: "GetFundingHistory",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r9}),
|
|
})
|
|
|
|
feeType := exchange.FeeBuilder{
|
|
FeeType: exchange.CryptocurrencyTradeFee,
|
|
Pair: p,
|
|
PurchasePrice: config.OrderSubmission.Price,
|
|
Amount: config.OrderSubmission.Amount,
|
|
}
|
|
var r10 float64
|
|
r10, err = e.GetFeeByType(&feeType)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{feeType}),
|
|
Function: "GetFeeByType-Trade",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r10}),
|
|
})
|
|
|
|
s := &order.Submit{
|
|
Pair: p,
|
|
OrderSide: testOrderSide,
|
|
OrderType: testOrderType,
|
|
Amount: config.OrderSubmission.Amount,
|
|
Price: config.OrderSubmission.Price,
|
|
ClientID: config.OrderSubmission.OrderID,
|
|
}
|
|
var r11 order.SubmitResponse
|
|
r11, err = e.SubmitOrder(s)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{*s}),
|
|
Function: "SubmitOrder",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r11}),
|
|
})
|
|
|
|
modifyRequest := order.Modify{
|
|
OrderID: config.OrderSubmission.OrderID,
|
|
Type: testOrderType,
|
|
Side: testOrderSide,
|
|
CurrencyPair: p,
|
|
Price: config.OrderSubmission.Price,
|
|
Amount: config.OrderSubmission.Amount,
|
|
}
|
|
var r12 string
|
|
r12, err = e.ModifyOrder(&modifyRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{modifyRequest}),
|
|
Function: "ModifyOrder",
|
|
Error: msg,
|
|
Response: r12,
|
|
})
|
|
// r13
|
|
cancelRequest := order.Cancel{
|
|
Side: testOrderSide,
|
|
CurrencyPair: p,
|
|
OrderID: config.OrderSubmission.OrderID,
|
|
}
|
|
err = e.CancelOrder(&cancelRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{cancelRequest}),
|
|
Function: "CancelOrder",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{nil}),
|
|
})
|
|
|
|
var r14 order.CancelAllResponse
|
|
r14, err = e.CancelAllOrders(&cancelRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{cancelRequest}),
|
|
Function: "CancelAllOrders",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r14}),
|
|
})
|
|
|
|
var r15 order.Detail
|
|
r15, err = e.GetOrderInfo(config.OrderSubmission.OrderID)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{config.OrderSubmission.OrderID}),
|
|
Function: "GetOrderInfo",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r15}),
|
|
})
|
|
|
|
historyRequest := order.GetOrdersRequest{
|
|
OrderType: testOrderType,
|
|
OrderSide: testOrderSide,
|
|
Currencies: []currency.Pair{p},
|
|
}
|
|
var r16 []order.Detail
|
|
r16, err = e.GetOrderHistory(&historyRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{historyRequest}),
|
|
Function: "GetOrderHistory",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r16}),
|
|
})
|
|
|
|
orderRequest := order.GetOrdersRequest{
|
|
OrderType: testOrderType,
|
|
OrderSide: testOrderSide,
|
|
Currencies: []currency.Pair{p},
|
|
}
|
|
var r17 []order.Detail
|
|
r17, err = e.GetActiveOrders(&orderRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{orderRequest}),
|
|
Function: "GetActiveOrders",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r17}),
|
|
})
|
|
|
|
var r18 string
|
|
r18, err = e.GetDepositAddress(p.Base, "")
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{p.Base, ""}),
|
|
Function: "GetDepositAddress",
|
|
Error: msg,
|
|
Response: r18,
|
|
})
|
|
|
|
feeType = exchange.FeeBuilder{
|
|
FeeType: exchange.CryptocurrencyWithdrawalFee,
|
|
Pair: p,
|
|
PurchasePrice: config.OrderSubmission.Price,
|
|
Amount: config.OrderSubmission.Amount,
|
|
}
|
|
var r19 float64
|
|
r19, err = e.GetFeeByType(&feeType)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{feeType}),
|
|
Function: "GetFeeByType-Crypto-Withdraw",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r19}),
|
|
})
|
|
|
|
genericWithdrawRequest := withdraw.GenericInfo{
|
|
Amount: config.OrderSubmission.Amount,
|
|
Currency: p.Quote,
|
|
}
|
|
withdrawRequest := withdraw.CryptoRequest{
|
|
GenericInfo: genericWithdrawRequest,
|
|
Address: withdrawAddressOverride,
|
|
}
|
|
var r20 string
|
|
r20, err = e.WithdrawCryptocurrencyFunds(&withdrawRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{withdrawRequest}),
|
|
Function: "WithdrawCryptocurrencyFunds",
|
|
Error: msg,
|
|
Response: r20,
|
|
})
|
|
|
|
feeType = exchange.FeeBuilder{
|
|
FeeType: exchange.InternationalBankWithdrawalFee,
|
|
Pair: p,
|
|
PurchasePrice: config.OrderSubmission.Price,
|
|
Amount: config.OrderSubmission.Amount,
|
|
FiatCurrency: currency.AUD,
|
|
BankTransactionType: exchange.WireTransfer,
|
|
}
|
|
var r21 float64
|
|
r21, err = e.GetFeeByType(&feeType)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{feeType}),
|
|
Function: "GetFeeByType-FIAT-Withdraw",
|
|
Error: msg,
|
|
Response: jsonifyInterface([]interface{}{r21}),
|
|
})
|
|
|
|
fiatWithdrawRequest := withdraw.FiatRequest{
|
|
GenericInfo: genericWithdrawRequest,
|
|
BankAccountName: config.BankDetails.BankAccountName,
|
|
BankAccountNumber: config.BankDetails.BankAccountNumber,
|
|
SwiftCode: config.BankDetails.SwiftCode,
|
|
IBAN: config.BankDetails.Iban,
|
|
BankCity: config.BankDetails.BankCity,
|
|
BankName: config.BankDetails.BankName,
|
|
BankAddress: config.BankDetails.BankAddress,
|
|
BankCountry: config.BankDetails.BankCountry,
|
|
BankPostalCode: config.BankDetails.BankPostalCode,
|
|
BankCode: config.BankDetails.BankCode,
|
|
IsExpressWire: config.BankDetails.IsExpressWire,
|
|
RequiresIntermediaryBank: config.BankDetails.RequiresIntermediaryBank,
|
|
IntermediaryBankName: config.BankDetails.IntermediaryBankName,
|
|
IntermediaryBankAccountNumber: config.BankDetails.IntermediaryBankAccountNumber,
|
|
IntermediarySwiftCode: config.BankDetails.IntermediarySwiftCode,
|
|
IntermediaryIBAN: config.BankDetails.IntermediaryIban,
|
|
IntermediaryBankCity: config.BankDetails.IntermediaryBankCity,
|
|
IntermediaryBankAddress: config.BankDetails.IntermediaryBankAddress,
|
|
IntermediaryBankCountry: config.BankDetails.IntermediaryBankCountry,
|
|
IntermediaryBankPostalCode: config.BankDetails.IntermediaryBankPostalCode,
|
|
IntermediaryBankCode: config.BankDetails.IntermediaryBankCode,
|
|
}
|
|
var r22 string
|
|
r22, err = e.WithdrawFiatFunds(&fiatWithdrawRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{fiatWithdrawRequest}),
|
|
Function: "WithdrawFiatFunds",
|
|
Error: msg,
|
|
Response: r22,
|
|
})
|
|
|
|
var r23 string
|
|
r23, err = e.WithdrawFiatFundsToInternationalBank(&fiatWithdrawRequest)
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
SentParams: jsonifyInterface([]interface{}{fiatWithdrawRequest}),
|
|
Function: "WithdrawFiatFundsToInternationalBank",
|
|
Error: msg,
|
|
Response: r23,
|
|
})
|
|
response = append(response, responseContainer)
|
|
}
|
|
return response
|
|
}
|
|
|
|
func jsonifyInterface(params []interface{}) json.RawMessage {
|
|
response, _ := json.MarshalIndent(params, "", " ")
|
|
return response
|
|
}
|
|
|
|
func loadConfig() (Config, error) {
|
|
var config Config
|
|
file, err := os.OpenFile("wrapperconfig.json", os.O_RDONLY, os.ModePerm)
|
|
if err != nil {
|
|
return config, err
|
|
}
|
|
defer file.Close()
|
|
keys, err := ioutil.ReadAll(file)
|
|
if err != nil {
|
|
return config, err
|
|
}
|
|
|
|
err = json.Unmarshal(keys, &config)
|
|
return config, err
|
|
}
|
|
|
|
func saveConfig(config *Config) {
|
|
log.Println("JSONifying config...")
|
|
jsonOutput, err := json.MarshalIndent(config, "", " ")
|
|
if err != nil {
|
|
log.Fatalf("Encountered error encoding JSON: %v", err)
|
|
}
|
|
|
|
dir, err := os.Getwd()
|
|
if err != nil {
|
|
log.Printf("Encountered error retrieving output directory: %v", err)
|
|
return
|
|
}
|
|
|
|
log.Printf("Outputting to: %v", filepath.Join(dir, "wrapperconfig.json"))
|
|
err = file.Write(filepath.Join(dir, "wrapperconfig.json"), jsonOutput)
|
|
if err != nil {
|
|
log.Printf("Encountered error writing to disk: %v", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func outputToJSON(exchangeResponses []ExchangeResponses) {
|
|
log.Println("JSONifying results...")
|
|
jsonOutput, err := json.MarshalIndent(exchangeResponses, "", " ")
|
|
if err != nil {
|
|
log.Fatalf("Encountered error encoding JSON: %v", err)
|
|
}
|
|
|
|
dir, err := os.Getwd()
|
|
if err != nil {
|
|
log.Printf("Encountered error retrieving output directory: %v", err)
|
|
return
|
|
}
|
|
|
|
log.Printf("Outputting to: %v", filepath.Join(dir, fmt.Sprintf("%v.json", outputFileName)))
|
|
err = file.Write(filepath.Join(dir, fmt.Sprintf("%v.json", outputFileName)), jsonOutput)
|
|
if err != nil {
|
|
log.Printf("Encountered error writing to disk: %v", err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func outputToHTML(exchangeResponses []ExchangeResponses) {
|
|
log.Println("Generating HTML report...")
|
|
dir, err := os.Getwd()
|
|
if err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
|
|
tmpl, err := template.New("report.tmpl").ParseFiles(filepath.Join(dir, "report.tmpl"))
|
|
if err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
|
|
log.Printf("Outputting to: %v", filepath.Join(dir, fmt.Sprintf("%v.html", outputFileName)))
|
|
file, err := os.Create(filepath.Join(dir, fmt.Sprintf("%v.html", outputFileName)))
|
|
if err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
|
|
defer file.Close()
|
|
err = tmpl.Execute(file, exchangeResponses)
|
|
if err != nil {
|
|
log.Print(err)
|
|
return
|
|
}
|
|
}
|
|
|
|
func outputToConsole(exchangeResponses []ExchangeResponses) {
|
|
var totalErrors int64
|
|
for i := range exchangeResponses {
|
|
log.Printf("------------%v Results-------------\n", exchangeResponses[i].ExchangeName)
|
|
for j := range exchangeResponses[i].AssetPairResponses {
|
|
for k := range exchangeResponses[i].AssetPairResponses[j].EndpointResponses {
|
|
log.Printf("%v Result: %v", exchangeResponses[i].ExchangeName, k)
|
|
log.Printf("Function:\t%v", exchangeResponses[i].AssetPairResponses[j].EndpointResponses[k].Function)
|
|
log.Printf("AssetType:\t%v", exchangeResponses[i].AssetPairResponses[j].AssetType)
|
|
log.Printf("Currency:\t%v\n", exchangeResponses[i].AssetPairResponses[j].CurrencyPair)
|
|
log.Printf("Wrapper Params:\t%s\n", exchangeResponses[i].AssetPairResponses[j].EndpointResponses[k].SentParams)
|
|
if exchangeResponses[i].AssetPairResponses[j].EndpointResponses[k].Error != "" {
|
|
totalErrors++
|
|
log.Printf("Error:\t%v", exchangeResponses[i].AssetPairResponses[j].EndpointResponses[k].Error)
|
|
} else {
|
|
log.Print("Error:\tnone")
|
|
}
|
|
if verboseOverride {
|
|
log.Printf("Wrapper Response:\t%s", exchangeResponses[i].AssetPairResponses[j].EndpointResponses[k].Response)
|
|
}
|
|
log.Println()
|
|
}
|
|
}
|
|
log.Println()
|
|
}
|
|
}
|