mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
* Initial commit which runs through all wrapper funcs for one of each currency pair for each asset type for each exchange and then outputs it all into a JSON file * Fixes up data holding responses to allow for good json output after completion * Starting work for reading credentials from a config. Some variable names are more appropriate * Keys can now be read from keys.json and applied to exchanges. Fixes naming bug for console output * Cleans up implementation. Uses templating to output some pretty html report * Changes config to include a bank account to customise for withdrawals. Updates template for warnings for not implemented. Updates template to include jsonified parameters that are sent to the wrapper. Jsonifies the response so you actually understand whats returned. * Adds bank for withdrawals. Adds wallet address for crypto withdrawals * Adds ordersubmission configuration to config. Sets command line overrides. Adds lbank to config. Adds okgroup clientid to config. * Adds missing comma * Adds config to gitignore * Removes because thats not how it works... * Revert go mod changes * Formatting for prettiness * Adds asset type override * Adds verbose, exchangesToExclude, filename CL flags. Removes wg redeclaration. Creates func to check to load exchange before its loaded. Removes double variables and uses flag.Stringvar instead * Prettifies the JSON output * Stringifies the []byteified jsonified wrapper response in the template * Puts types in their own EXCLUSIVE types.go. LOWERCASES COMMAND LINE ARGUMENTS. Wraps vars in var so theres less vars to look at. * Generates wrapperconfig.json on the fly if not present. Adds missing config fields and exchanges when not present. Saves config file on finish. Fixes some formatting on output when its just a number * micro format update * Changes printfs to printlns. Handles config error. Comments on types. Fixes lint issue with shadow err declaration * Fixes linting issue, removes returns after fatals, evaluates assetType, formats template * Stringifies byte output when console output is selected. Verbose mode now includes wrapper responses in console output
840 lines
27 KiB
Go
840 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"
|
|
"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/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
|
)
|
|
|
|
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
|
|
|
|
for x := range engine.Bot.Exchanges {
|
|
base := engine.Bot.Exchanges[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 := engine.Bot.Exchanges[num].GetName()
|
|
authenticated := setExchangeAPIKeys(name, wrapperConfig.Exchanges, base)
|
|
wrapperResult := ExchangeResponses{
|
|
ID: fmt.Sprintf("Exchange%v", num),
|
|
ExchangeName: name,
|
|
APIKeysSet: authenticated,
|
|
AssetPairResponses: testWrappers(engine.Bot.Exchanges[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+anx")
|
|
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) exchange.OrderSide {
|
|
switch orderSide {
|
|
case exchange.AnyOrderSide.ToString():
|
|
return exchange.AnyOrderSide
|
|
case exchange.BuyOrderSide.ToString():
|
|
return exchange.BuyOrderSide
|
|
case exchange.SellOrderSide.ToString():
|
|
return exchange.SellOrderSide
|
|
case exchange.BidOrderSide.ToString():
|
|
return exchange.BidOrderSide
|
|
case exchange.AskOrderSide.ToString():
|
|
return exchange.AskOrderSide
|
|
default:
|
|
log.Printf("Orderside '%v' not recognised, defaulting to BUY", orderSide)
|
|
return exchange.BuyOrderSide
|
|
}
|
|
}
|
|
|
|
func parseOrderType(orderType string) exchange.OrderType {
|
|
switch orderType {
|
|
case exchange.AnyOrderType.ToString():
|
|
return exchange.AnyOrderType
|
|
case exchange.LimitOrderType.ToString():
|
|
return exchange.LimitOrderType
|
|
case exchange.MarketOrderType.ToString():
|
|
return exchange.MarketOrderType
|
|
case exchange.ImmediateOrCancelOrderType.ToString():
|
|
return exchange.ImmediateOrCancelOrderType
|
|
case exchange.StopOrderType.ToString():
|
|
return exchange.StopOrderType
|
|
case exchange.TrailingStopOrderType.ToString():
|
|
return exchange.TrailingStopOrderType
|
|
case exchange.UnknownOrderType.ToString():
|
|
return exchange.UnknownOrderType
|
|
default:
|
|
log.Printf("OrderType '%v' not recognised, defaulting to LIMIT", orderTypeOverride)
|
|
return exchange.LimitOrderType
|
|
}
|
|
}
|
|
|
|
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 exchange.AccountInfo
|
|
r7, err = e.GetAccountInfo()
|
|
msg = ""
|
|
if err != nil {
|
|
msg = err.Error()
|
|
responseContainer.ErrorCount++
|
|
}
|
|
responseContainer.EndpointResponses = append(responseContainer.EndpointResponses, EndpointResponse{
|
|
Function: "GetAccountInfo",
|
|
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 := &exchange.OrderSubmission{
|
|
Pair: p,
|
|
OrderSide: testOrderSide,
|
|
OrderType: testOrderType,
|
|
Amount: config.OrderSubmission.Amount,
|
|
Price: config.OrderSubmission.Price,
|
|
ClientID: config.OrderSubmission.OrderID,
|
|
}
|
|
var r11 exchange.SubmitOrderResponse
|
|
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 := exchange.ModifyOrder{
|
|
OrderID: config.OrderSubmission.OrderID,
|
|
OrderType: testOrderType,
|
|
OrderSide: 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 := exchange.OrderCancellation{
|
|
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 exchange.CancelAllOrdersResponse
|
|
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 exchange.OrderDetail
|
|
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 := exchange.GetOrdersRequest{
|
|
OrderType: testOrderType,
|
|
OrderSide: testOrderSide,
|
|
Currencies: []currency.Pair{p},
|
|
}
|
|
var r16 []exchange.OrderDetail
|
|
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 := exchange.GetOrdersRequest{
|
|
OrderType: testOrderType,
|
|
OrderSide: testOrderSide,
|
|
Currencies: []currency.Pair{p},
|
|
}
|
|
var r17 []exchange.OrderDetail
|
|
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 := exchange.GenericWithdrawRequestInfo{
|
|
Amount: config.OrderSubmission.Amount,
|
|
Currency: p.Quote,
|
|
}
|
|
withdrawRequest := exchange.CryptoWithdrawRequest{
|
|
GenericWithdrawRequestInfo: 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 := exchange.FiatWithdrawRequest{
|
|
GenericWithdrawRequestInfo: 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 = common.JSONDecode(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 = common.WriteFile(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 = common.WriteFile(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()
|
|
}
|
|
}
|