diff --git a/.appveyor.yml b/.appveyor.yml
index 03edc788..e982c2ae 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -13,15 +13,35 @@ environment:
GO111MODULE: on
NODEJS_VER: 10.15.3
APPVEYOR_SAVE_CACHE_ON_ERROR: true
+ POSTGRES_PATH: C:\Program Files\PostgreSQL\9.6
+ PGUSER: postgres
+ PGPASSWORD: Password12!
+ POSTGRES_ENV_POSTGRES_USER: postgres
+ POSTGRES_ENV_POSTGRES_PASSWORD: Password12!
+ POSTGRES_ENV_POSTGRES_DB: gct_dev_ci
+ PSQL_USER: postgres
+ PSQL_HOST: localhost
+ PSQL_PASS: Password12!
+ PSQL_DBNAME: gct_dev_ci
+ PSQL_SSLMODE: disable
stack: go 1.13.x
+services:
+ - postgresql96
+
+init:
+ - SET PATH=%POSTGRES_PATH%\bin;%PATH%
+
install:
- set Path=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%Path%
- ps: Install-Product node $env:NODEJS_VER
- cd c:\gopath\src\github.com\thrasher-corp\gocryptotrader\web
- npm install
+build_script:
+ - createdb gct_dev_ci
+
before_test:
- cd c:\gopath\src\github.com\thrasher-corp\gocryptotrader
- go get
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..4fea60b9
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+go.mod text eol=lf
+go.sum text eol=lf
\ No newline at end of file
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index cd01660e..6c539d02 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -17,6 +17,7 @@ In order to maintain a consistent style across the codebase, the following codin
- In line with gofmt, for loops and if statements don't require parenthesis.
Block style example:
+
```go
func SendHTTPRequest(method, path string, headers map[string]string, body io.Reader) (string, error) {
result := strings.ToUpper(method)
@@ -38,51 +39,51 @@ func SendHTTPRequest(method, path string, headers map[string]string, body io.Rea
```
## Effective Go Guidelines
+
[CodeLingo](https://codelingo.io) automatically checks every pull request against the following guidelines from [Effective Go](https://golang.org/doc/effective_go.html).
-
### Comment First Word as Subject
+
Doc comments work best as complete sentences, which allow a wide variety of automated presentations.
The first sentence should be a one-sentence summary that starts with the name being declared.
-
### Good Package Name
-It's helpful if everyone using the package can use the same name
-to refer to its contents, which implies that the package name should
-be good: short, concise, evocative. By convention, packages are
-given lower case, single-word names; there should be no need for
-underscores or mixedCaps. Err on the side of brevity, since everyone
-using your package will be typing that name. And don't worry about
-collisions a priori. The package name is only the default name for
-imports; it need not be unique across all source code, and in the
-rare case of a collision the importing package can choose a different
-name to use locally. In any case, confusion is rare because the file
+
+It's helpful if everyone using the package can use the same name
+to refer to its contents, which implies that the package name should
+be good: short, concise, evocative. By convention, packages are
+given lower case, single-word names; there should be no need for
+underscores or mixedCaps. Err on the side of brevity, since everyone
+using your package will be typing that name. And don't worry about
+collisions a priori. The package name is only the default name for
+imports; it need not be unique across all source code, and in the
+rare case of a collision the importing package can choose a different
+name to use locally. In any case, confusion is rare because the file
name in the import determines just which package is being used.
-
### Package Comment
-Every package should have a package comment, a block comment preceding the package clause.
-For multi-file packages, the package comment only needs to be present in one file, and any one will do.
-The package comment should introduce the package and provide information relevant to the package as a
+
+Every package should have a package comment, a block comment preceding the package clause.
+For multi-file packages, the package comment only needs to be present in one file, and any one will do.
+The package comment should introduce the package and provide information relevant to the package as a
whole. It will appear first on the godoc page and should set up the detailed documentation that follows.
-
### Single Method Interface Name
-By convention, one-method interfaces are named by the method name plus an -er suffix
+
+By convention, one-method interfaces are named by the method name plus an -er suffix
or similar modification to construct an agent noun: Reader, Writer, Formatter, CloseNotifier etc.
-There are a number of such names and it's productive to honor them and the function names they capture.
-Read, Write, Close, Flush, String and so on have canonical signatures and meanings. To avoid confusion,
-don't give your method one of those names unless it has the same signature and meaning. Conversely,
-if your type implements a method with the same meaning as a method on a well-known type, give it the
+There are a number of such names and it's productive to honor them and the function names they capture.
+Read, Write, Close, Flush, String and so on have canonical signatures and meanings. To avoid confusion,
+don't give your method one of those names unless it has the same signature and meaning. Conversely,
+if your type implements a method with the same meaning as a method on a well-known type, give it the
same name and signature; call your string-converter method String not ToString.
-
### Avoid Annotations in Comments
-Comments do not need extra formatting such as banners of stars. The generated output
-may not even be presented in a fixed-width font, so don't depend on spacing for alignment—godoc,
-like gofmt, takes care of that. The comments are uninterpreted plain text, so HTML and other
-annotations such as _this_ will reproduce verbatim and should not be used. One adjustment godoc
-does do is to display indented text in a fixed-width font, suitable for program snippets.
-The package comment for the fmt package uses this to good effect.
+Comments do not need extra formatting such as banners of stars. The generated output
+may not even be presented in a fixed-width font, so don't depend on spacing for alignment—godoc,
+like gofmt, takes care of that. The comments are uninterpreted plain text, so HTML and other
+annotations such as _this_ will reproduce verbatim and should not be used. One adjustment godoc
+does do is to display indented text in a fixed-width font, suitable for program snippets.
+The package comment for the fmt package uses this to good effect.
diff --git a/.github/CONTRIBUTING_TEMPLATE.md b/.github/CONTRIBUTING_TEMPLATE.md
index f4aecf7c..cff2cb3f 100644
--- a/.github/CONTRIBUTING_TEMPLATE.md
+++ b/.github/CONTRIBUTING_TEMPLATE.md
@@ -17,6 +17,7 @@ In order to maintain a consistent style across the codebase, the following codin
- In line with gofmt, for loops and if statements don't require parenthesis.
Block style example:
+
```go
func SendHTTPRequest(method, path string, headers map[string]string, body io.Reader) (string, error) {
result := strings.ToUpper(method)
@@ -38,9 +39,12 @@ func SendHTTPRequest(method, path string, headers map[string]string, body io.Rea
```
## Effective Go Guidelines
+
[CodeLingo](https://codelingo.io) automatically checks every pull request against the following guidelines from [Effective Go](https://golang.org/doc/effective_go.html).
{{range .}}
+
### {{.title}}
+
{{.body}}
-{{end}}
\ No newline at end of file
+{{end}}
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index cbf11442..75073df6 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -30,4 +30,4 @@ Please provide detailed steps for reproducing the issue.
### Failure Logs
-By default, GoCryptoTrader stores its `debug.log` file in `%APPDATA%\GoCryptoTrader` on Windows and `~/.gocryptotrader` on Linux/Unix/macOS. Raw text or a link to a pastebin type site is preferred.
\ No newline at end of file
+By default and if file logging is enabled, GoCryptoTrader stores its `log.txt` file in `%APPDATA%\GoCryptoTrader\logs` on Windows and `~/.gocryptotrader/logs` on Linux/Unix/macOS. Raw text or a link to a pastebin type site is preferred.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index d3ddb8a0..edabdd52 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,6 @@
-# Description
+# PR Description
-Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
+Please include a summary of the change, feature or issue which this pull request addresses. Please also include relevant motivation and context. List any dependencies that are required for this change.
Fixes # (issue)
@@ -13,22 +13,22 @@ Please delete options that are not relevant and add an `x` in `[]` as item is co
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] This change requires a documentation update
-# How Has This Been Tested?
+## How has this been tested
-Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
+Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration and
+also consider improving test coverage whilst working on a certain feature or package.
-## Please also consider improving test coverage whilst working on a certain package
+- [ ] go test ./... -race
+- [ ] golangci-lint run
+- [ ] Test X
-- [ ] Test A
-- [ ] Test B
-
-# Checklist:
+## Checklist
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
-- [ ] I have made corresponding changes to the documentation and regenerated documentation via the documentation tool
+- [ ] I have made corresponding changes to the documentation and regenerated documentation via the documentation tool
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally and on Travis with my changes
-- [ ] Any dependent changes have been merged and published in downstream modules
\ No newline at end of file
+- [ ] Any dependent changes have been merged and published in downstream modules
diff --git a/.gitignore b/.gitignore
index c3baa137..09c57015 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ lib
.vscode
testdata/dump
+testdata/preengine_config.json
testdata/writefiletest
# InteliJ
@@ -25,3 +26,5 @@ gocryptotrader
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
+sqlboiler.toml
+sqlboiler.json
diff --git a/.travis.yml b/.travis.yml
index e04d4cf7..f41e6b4c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,21 +16,54 @@ matrix:
- language: go
dist: xenial
- name: 'GoCryptoTrader [back-end] [linux]'
+ name: 'GoCryptoTrader [back-end] [linux] [64-bit]'
go:
- 1.13.x
env:
- GO111MODULE=on
+ - PSQL_USER=postgres
+ - PSQL_HOST=localhost
+ - PSQL_DBNAME=gct_dev_ci
install: true
cache:
directories:
- $GOPATH/pkg/mod
-
+ services:
+ - postgresql
+ before_script:
+ - psql -c 'create database gct_dev_ci;' -U postgres
script:
- make check
after_success:
- bash <(curl -s https://codecov.io/bash)
+ - language: go
+ dist: xenial
+ name: 'GoCryptoTrader [back-end] [linux] [32-bit]'
+ go:
+ - 1.13.x
+ env:
+ - GO111MODULE=on
+ - NO_RACE_TEST=1
+ - PSQL_USER=postgres
+ - PSQL_HOST=localhost
+ - PSQL_DBNAME=gct_dev_ci
+ install: true
+ cache:
+ directories:
+ - $GOPATH/pkg/mod
+ services:
+ - postgresql
+ before_script:
+ - psql -c 'create database gct_dev_ci;' -U postgres
+ script:
+ - export GOARCH=386
+ - export CGO_ENABLED=1
+ - sudo apt-get install gcc-multilib
+ - make test
+ after_success:
+ - bash <(curl -s https://codecov.io/bash)
+
- language: go
os: osx
name: 'GoCryptoTrader [back-end] [darwin]'
@@ -38,11 +71,22 @@ matrix:
- 1.13.x
env:
- GO111MODULE=on
+ - PSQL_USER=postgres
+ - PSQL_HOST=localhost
+ - PSQL_DBNAME=gct_dev_ci
+ - PSQL_SSLMODE=disable
+ - PSQL_SKIPSQLCMD=true
+ - PSQL_TESTDBNAME=gct_dev_ci
install: true
cache:
directories:
- $GOPATH/pkg/mod
-
+ before_install:
+ - rm -rf /usr/local/var/postgres
+ - initdb /usr/local/var/postgres
+ - pg_ctl start --pgdata /usr/local/var/postgres
+ - createuser -s postgres
+ - psql -c 'create database gct_dev_ci;' -U postgres
script:
- make check
after_success:
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 3f7eeb20..3453fc18 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -8,8 +8,8 @@ ermalguni | https://github.com/ermalguni
vadimzhukck | https://github.com/vadimzhukck
140am | https://github.com/140am
marcofranssen | https://github.com/marcofranssen
-cranktakular | https://github.com/cranktakular
MadCozBadd | https://github.com/MadCozBadd
+cranktakular | https://github.com/cranktakular
leilaes | https://github.com/leilaes
crackcomm | https://github.com/crackcomm
andreygrehov | https://github.com/andreygrehov
@@ -30,8 +30,9 @@ frankzougc | https://github.com/frankzougc
starit | https://github.com/starit
Jimexist | https://github.com/Jimexist
lookfirst | https://github.com/lookfirst
+idoall | https://github.com/idoall
mattkanwisher | https://github.com/mattkanwisher
mKurrels | https://github.com/mKurrels
m1kola | https://github.com/m1kola
cavapoo2 | https://github.com/cavapoo2
-zeldrinn | https://github.com/zeldrinn
\ No newline at end of file
+zeldrinn | https://github.com/zeldrinn
diff --git a/Dockerfile b/Dockerfile
index a82cff59..2524f16b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,14 +1,18 @@
-FROM golang:1.12 as build
+FROM golang:1.13 as build
WORKDIR /go/src/github.com/thrasher-corp/gocryptotrader
COPY . .
RUN GO111MODULE=on go mod vendor
RUN mv -vn config_example.json config.json \
- && GOARCH=386 GOOS=linux CGO_ENABLED=0 go build . \
- && mv gocryptotrader /go/bin/gocryptotrader
+ && GOARCH=386 GOOS=linux go build . \
+ && GOARCH=386 GOOS=linux go build ./cmd/gctcli \
+ && mv gocryptotrader /go/bin/gocryptotrader \
+ && mv gctcli /go/bin/gctcli
FROM alpine:latest
-RUN apk update && apk add --no-cache ca-certificates
+VOLUME /root/.gocryptotrader
+RUN apk update && apk add --no-cache ca-certificates bash
COPY --from=build /go/bin/gocryptotrader /app/
+COPY --from=build /go/bin/gctcli /app/
COPY --from=build /go/src/github.com/thrasher-corp/gocryptotrader/config.json /app/
-EXPOSE 9050
-CMD ["/app/gocryptotrader"]
+EXPOSE 9050-9053
+ENTRYPOINT [ "/app/gocryptotrader" ]
diff --git a/Makefile b/Makefile
index 6a5c7eff..7094b991 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,8 @@ LINTBIN = $(GOPATH)/bin/golangci-lint
GCTLISTENPORT=9050
GCTPROFILERLISTENPORT=8085
CRON = $(TRAVIS_EVENT_TYPE)
+DRIVER ?= psql
+RACE_FLAG := $(if $(NO_RACE_TEST),,-race)
get:
GO111MODULE=on go get $(GCTPKG)
@@ -18,9 +20,9 @@ check: linter test
test:
ifeq ($(CRON), cron)
- go test -race -tags=mock_test_off -coverprofile=coverage.txt -covermode=atomic ./...
+ go test $(RACE_FLAG) -tags=mock_test_off -coverprofile=coverage.txt -covermode=atomic ./...
else
- go test -race -coverprofile=coverage.txt -covermode=atomic ./...
+ go test $(RACE_FLAG) -coverprofile=coverage.txt -covermode=atomic ./...
endif
build:
@@ -41,7 +43,14 @@ update_deps:
.PHONY: profile_heap
profile_heap:
go tool pprof -http "localhost:$(GCTPROFILERLISTENPORT)" 'http://localhost:$(GCTLISTENPORT)/debug/pprof/heap'
-
+
.PHONY: profile_cpu
profile_cpu:
- go tool pprof -http "localhost:$(GCTPROFILERLISTENPORT)" 'http://localhost:$(GCTLISTENPORT)/debug/pprof/profile'
\ No newline at end of file
+ go tool pprof -http "localhost:$(GCTPROFILERLISTENPORT)" 'http://localhost:$(GCTLISTENPORT)/debug/pprof/profile'
+
+gen_db_models:
+ifeq ($(DRIVER), psql)
+ sqlboiler -o database/models/postgres -p postgres --no-auto-timestamps --wipe $(DRIVER)
+else
+ sqlboiler -o database/models/sqlite3 -p sqlite3 --no-auto-timestamps --wipe $(DRIVER)
+endif
diff --git a/README.md b/README.md
index 76104bbc..5aee76a4 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| COINUT | Yes | Yes | NA |
| Exmo | Yes | NA | NA |
| CoinbasePro | Yes | Yes | No|
+| Coinbene | Yes | No | No |
| GateIO | Yes | Yes | NA |
| Gemini | Yes | Yes | No |
| HitBTC | Yes | Yes | No |
@@ -53,19 +54,26 @@ We are aiming to support the top 20 highest volume exchanges based off the [Coin
## Current Features
-+ Support for all Exchange fiat and digital currencies, with the ability to individually toggle them on/off.
++ Support for all exchange fiat and digital currencies, with the ability to individually toggle them on/off.
+ AES256 encrypted config file.
+ REST API support for all exchanges.
+ Websocket support for applicable exchanges.
+ Ability to turn off/on certain exchanges.
-+ Ability to adjust manual polling timer for exchanges.
+ Communication packages (Slack, SMS via SMSGlobal, Telegram and SMTP)
+ HTTP rate limiter package.
++ Unified API for exchange usage.
++ Customisation of HTTP client features including setting a proxy, user agent and adjusting transport settings.
++ NTP client package.
++ Database support (Postgres and SQLite3). See [database](/database/README.md).
++ OTP generation tool. See [gen otp](/cmd/gen_otp).
++ Connection monitor package.
++ gRPC service and JSON RPC proxy. See [gRPC service](/gctrpc/README.md).
++ gRPC client. See [gctcli](/cmd/gctcli/README.md).
+ Forex currency converter packages (CurrencyConverterAPI, CurrencyLayer, Fixer.io, OpenExchangeRates)
+ Packages for handling currency pairs, tickers and orderbooks.
+ Portfolio management tool; fetches balances from supported exchanges and allows for custom address tracking.
+ Basic event trigger system.
-+ WebGUI.
++ WebGUI (discontinued).
## Planned Features
@@ -128,42 +136,41 @@ Binaries will be published once the codebase reaches a stable condition.
### A very special thank you to all who have contributed to this program:
-|User|Github|Contribution Amount|
-|--|--|--|
-| thrasher- | https://github.com/thrasher- | 548 |
-| shazbert | https://github.com/shazbert | 176 |
-| gloriousCode | https://github.com/gloriousCode | 155 |
-| xtda | https://github.com/xtda | 18 |
-| ermalguni | https://github.com/ermalguni | 14 |
-| vadimzhukck | https://github.com/vadimzhukck | 10 |
-| 140am | https://github.com/140am | 8 |
-| marcofranssen | https://github.com/marcofranssen | 8 |
-| cranktakular | https://github.com/cranktakular | 5 |
-| MadCozBadd | https://github.com/MadCozBadd | 3 |
-| leilaes | https://github.com/leilaes | 3 |
-| crackcomm | https://github.com/crackcomm | 3 |
-| andreygrehov | https://github.com/andreygrehov | 2 |
-| bretep | https://github.com/bretep | 2 |
-| woshidama323 | https://github.com/woshidama323 | 2 |
-| gam-phon | https://github.com/gam-phon | 2 |
-| cornelk | https://github.com/cornelk | 2 |
-| if1live | https://github.com/if1live | 2 |
-| soxipy | https://github.com/soxipy | 2 |
-| herenow | https://github.com/herenow | 2 |
-| blombard | https://github.com/blombard | 1 |
-| CodeLingoBot | https://github.com/CodeLingoBot | 1 |
-| CodeLingoTeam | https://github.com/CodeLingoTeam | 1 |
-| Daanikus | https://github.com/Daanikus | 1 |
-| daniel-cohen | https://github.com/daniel-cohen | 1 |
-| DirectX | https://github.com/DirectX | 1 |
-| frankzougc | https://github.com/frankzougc | 1 |
-| starit | https://github.com/starit | 1 |
-| Jimexist | https://github.com/Jimexist | 1 |
-| lookfirst | https://github.com/lookfirst | 1 |
-| mattkanwisher | https://github.com/mattkanwisher | 1 |
-| mKurrels | https://github.com/mKurrels | 1 |
-| m1kola | https://github.com/m1kola | 1 |
-| cavapoo2 | https://github.com/cavapoo2 | 1 |
-| zeldrinn | https://github.com/zeldrinn | 1 |
-
-
+|User|Contribution Amount|
+|--|--|
+| [thrasher-](https://github.com/thrasher-) | 551 |
+| [shazbert](https://github.com/shazbert) | 176 |
+| [gloriousCode](https://github.com/gloriousCode) | 155 |
+| [xtda](https://github.com/xtda) | 18 |
+| [ermalguni](https://github.com/ermalguni) | 14 |
+| [vadimzhukck](https://github.com/vadimzhukck) | 10 |
+| [140am](https://github.com/140am) | 8 |
+| [marcofranssen](https://github.com/marcofranssen) | 8 |
+| [MadCozBadd](https://github.com/MadCozBadd) | 6 |
+| [cranktakular](https://github.com/cranktakular) | 5 |
+| [leilaes](https://github.com/leilaes) | 3 |
+| [crackcomm](https://github.com/crackcomm) | 3 |
+| [andreygrehov](https://github.com/andreygrehov) | 2 |
+| [bretep](https://github.com/bretep) | 2 |
+| [woshidama323](https://github.com/woshidama323) | 2 |
+| [gam-phon](https://github.com/gam-phon) | 2 |
+| [cornelk](https://github.com/cornelk) | 2 |
+| [if1live](https://github.com/if1live) | 2 |
+| [soxipy](https://github.com/soxipy) | 2 |
+| [herenow](https://github.com/herenow) | 2 |
+| [blombard](https://github.com/blombard) | 1 |
+| [CodeLingoBot](https://github.com/CodeLingoBot) | 1 |
+| [CodeLingoTeam](https://github.com/CodeLingoTeam) | 1 |
+| [Daanikus](https://github.com/Daanikus) | 1 |
+| [daniel-cohen](https://github.com/daniel-cohen) | 1 |
+| [DirectX](https://github.com/DirectX) | 1 |
+| [frankzougc](https://github.com/frankzougc) | 1 |
+| [starit](https://github.com/starit) | 1 |
+| [Jimexist](https://github.com/Jimexist) | 1 |
+| [lookfirst](https://github.com/lookfirst) | 1 |
+| [idoall](https://github.com/idoall) | 1 |
+| [mattkanwisher](https://github.com/mattkanwisher) | 1 |
+| [mKurrels](https://github.com/mKurrels) | 1 |
+| [m1kola](https://github.com/m1kola) | 1 |
+| [cavapoo2](https://github.com/cavapoo2) | 1 |
+| [zeldrinn](https://github.com/zeldrinn) | 1 |
diff --git a/tools/config/config.go b/cmd/config/config.go
similarity index 80%
rename from tools/config/config.go
rename to cmd/config/config.go
index 74f23b15..3274b9ed 100644
--- a/tools/config/config.go
+++ b/cmd/config/config.go
@@ -2,9 +2,10 @@ package main
import (
"flag"
+ "io/ioutil"
"log"
- "github.com/thrasher-corp/gocryptotrader/common"
+ "github.com/thrasher-corp/gocryptotrader/common/file"
"github.com/thrasher-corp/gocryptotrader/config"
)
@@ -42,19 +43,19 @@ func main() {
key = string(result)
}
- file, err := common.ReadFile(inFile)
+ fileData, err := ioutil.ReadFile(inFile)
if err != nil {
log.Fatalf("Unable to read input file %s. Error: %s.", inFile, err)
}
- if config.ConfirmECS(file) && encrypt {
+ if config.ConfirmECS(fileData) && encrypt {
log.Println("File is already encrypted. Decrypting..")
encrypt = false
}
- if !config.ConfirmECS(file) && !encrypt {
+ if !config.ConfirmECS(fileData) && !encrypt {
var result interface{}
- errf := config.ConfirmConfigJSON(file, result)
+ errf := config.ConfirmConfigJSON(fileData, result)
if errf != nil {
log.Fatal("File isn't in JSON format")
}
@@ -64,18 +65,18 @@ func main() {
var data []byte
if encrypt {
- data, err = config.EncryptConfigFile(file, []byte(key))
+ data, err = config.EncryptConfigFile(fileData, []byte(key))
if err != nil {
log.Fatalf("Unable to encrypt config data. Error: %s.", err)
}
} else {
- data, err = config.DecryptConfigFile(file, []byte(key))
+ data, err = config.DecryptConfigFile(fileData, []byte(key))
if err != nil {
log.Fatalf("Unable to decrypt config data. Error: %s.", err)
}
}
- err = common.WriteFile(outFile, data)
+ err = file.Write(outFile, data)
if err != nil {
log.Fatalf("Unable to write output file %s. Error: %s", outFile, err)
}
diff --git a/tools/config/config_test.go b/cmd/config/config_test.go
similarity index 62%
rename from tools/config/config_test.go
rename to cmd/config/config_test.go
index cd266ae5..7542cc09 100644
--- a/tools/config/config_test.go
+++ b/cmd/config/config_test.go
@@ -6,13 +6,13 @@ func TestEncryptOrDecrypt(t *testing.T) {
reValue := EncryptOrDecrypt(true)
if reValue != "encrypted" {
t.Error(
- "Test failed - Tools/Config/Config_test.go - EncryptOrDecrypt Error",
+ "Tools/Config/Config_test.go - EncryptOrDecrypt Error",
)
}
reValue = EncryptOrDecrypt(false)
if reValue != "decrypted" {
t.Error(
- "Test failed - Tools/Config/Config_test.go - EncryptOrDecrypt Error",
+ "Tools/Config/Config_test.go - EncryptOrDecrypt Error",
)
}
}
diff --git a/cmd/config_builder/builder.go b/cmd/config_builder/builder.go
new file mode 100644
index 00000000..8c15b5ba
--- /dev/null
+++ b/cmd/config_builder/builder.go
@@ -0,0 +1,51 @@
+package main
+
+import (
+ "encoding/json"
+ "log"
+ "sync"
+
+ "github.com/thrasher-corp/gocryptotrader/config"
+ "github.com/thrasher-corp/gocryptotrader/engine"
+ exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
+)
+
+func main() {
+ var err error
+ engine.Bot, err = engine.New()
+ if err != nil {
+ log.Fatalf("Failed to initialise engine. Err: %s", err)
+ }
+
+ log.Printf("Loading exchanges..")
+ var wg sync.WaitGroup
+ for x := range exchange.Exchanges {
+ name := exchange.Exchanges[x]
+ 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.")
+
+ var cfgs []config.ExchangeConfig
+ for x := range engine.Bot.Exchanges {
+ var cfg *config.ExchangeConfig
+ cfg, err = engine.Bot.Exchanges[x].GetDefaultConfig()
+ if err != nil {
+ log.Printf("Failed to get exchanges default config. Err: %s", err)
+ continue
+ }
+ log.Printf("Adding %s", engine.Bot.Exchanges[x].GetName())
+ cfgs = append(cfgs, *cfg)
+ }
+
+ data, err := json.MarshalIndent(cfgs, "", " ")
+ if err != nil {
+ log.Fatalf("Unable to marshal cfgs. Err: %s", err)
+ }
+
+ log.Println(string(data))
+}
diff --git a/cmd/dbmigrate/main.go b/cmd/dbmigrate/main.go
new file mode 100644
index 00000000..496daadd
--- /dev/null
+++ b/cmd/dbmigrate/main.go
@@ -0,0 +1,102 @@
+package main
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "os"
+ "runtime"
+
+ "github.com/thrasher-corp/gocryptotrader/common"
+ "github.com/thrasher-corp/gocryptotrader/config"
+ "github.com/thrasher-corp/gocryptotrader/core"
+ "github.com/thrasher-corp/gocryptotrader/database"
+ dbPSQL "github.com/thrasher-corp/gocryptotrader/database/drivers/postgres"
+ dbsqlite3 "github.com/thrasher-corp/gocryptotrader/database/drivers/sqlite3"
+ "github.com/thrasher-corp/gocryptotrader/database/repository"
+ "github.com/thrasher-corp/goose"
+)
+
+var (
+ dbConn *database.Db
+ configFile string
+ defaultDataDir string
+ migrationDir string
+ command string
+ args string
+)
+
+func openDbConnection(driver string) (err error) {
+ if driver == database.DBPostgreSQL {
+ dbConn, err = dbPSQL.Connect()
+ if err != nil {
+ return fmt.Errorf("database failed to connect: %v Some features that utilise a database will be unavailable", err)
+ }
+ return nil
+ } else if driver == database.DBSQLite || driver == database.DBSQLite3 {
+ dbConn, err = dbsqlite3.Connect()
+ if err != nil {
+ return fmt.Errorf("database failed to connect: %v Some features that utilise a database will be unavailable", err)
+ }
+ return nil
+ }
+ return errors.New("no connection established")
+}
+
+func main() {
+ fmt.Println("GoCryptoTrader database migration tool")
+ fmt.Println(core.Copyright)
+ fmt.Println()
+
+ defaultPath, err := config.GetFilePath("")
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ flag.StringVar(&command, "command", "", "command to run status|up|up-by-one|up-to|down|create")
+ flag.StringVar(&args, "args", "", "arguments to pass to goose")
+
+ flag.StringVar(&configFile, "config", defaultPath, "config file to load")
+ flag.StringVar(&defaultDataDir, "datadir", common.GetDefaultDataDir(runtime.GOOS), "default data directory for GoCryptoTrader files")
+ flag.StringVar(&migrationDir, "migrationdir", database.MigrationDir, "override migration folder")
+
+ flag.Parse()
+
+ conf := config.GetConfig()
+
+ err = conf.LoadConfig(configFile, true)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ if !conf.Database.Enabled {
+ fmt.Println("Database support is disabled")
+ os.Exit(1)
+ }
+ err = openDbConnection(conf.Database.Driver)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ drv := repository.GetSQLDialect()
+
+ if drv == database.DBSQLite || drv == database.DBSQLite3 {
+ fmt.Printf("Database file: %s\n", conf.Database.Database)
+ } else {
+ fmt.Printf("Connected to: %s\n", conf.Database.Host)
+ }
+
+ if command == "" {
+ _ = goose.Run("status", dbConn.SQL, drv, migrationDir, "")
+ fmt.Println()
+ flag.Usage()
+ return
+ }
+
+ if err = goose.Run(command, dbConn.SQL, drv, migrationDir, args); err != nil {
+ fmt.Println(err)
+ }
+}
diff --git a/cmd/documentation/README.md b/cmd/documentation/README.md
new file mode 100644
index 00000000..e6fb031f
--- /dev/null
+++ b/cmd/documentation/README.md
@@ -0,0 +1,97 @@
+# GoCryptoTrader package Documentation
+
+
+
+
+[](https://travis-ci.org/thrasher-corp/gocryptotrader)
+[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
+[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/cmd/documentation)
+[](http://codecov.io/github/thrasher-corp/gocryptotrader?branch=master)
+[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
+
+
+This documentation package is part of the GoCryptoTrader codebase.
+
+## This is still in active development
+
+You can track ideas, planned features and what's in progresss on this Trello board: [https://trello.com/b/ZAhMhpOy/gocryptotrader](https://trello.com/b/ZAhMhpOy/gocryptotrader).
+
+Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/enQtNTQ5NDAxMjA2Mjc5LTc5ZDE1ZTNiOGM3ZGMyMmY1NTAxYWZhODE0MWM5N2JlZDk1NDU0YTViYzk4NTk3OTRiMDQzNGQ1YTc4YmRlMTk)
+
+## Current Features for documentation
+
+#### This tool allows for the generation of new documentation through templating
+
+From the `gocryptotrader/cmd/documentation/` folder, using the go command: **go run documentation.go** this will auto-generate and regenerate documentation across the **GoCryptoTrader** code base.
+>Using the -v command will, ie **go run documentation.go -v** put the tool into verbose mode allowing you to see what is happening with a little more depth.
+
+Be aware, this tool will:
+- Works off a configuration JSON file located at ``gocryptotrader/cmd/documentation/`` for future use with multiple repositories.
+- Automatically find the directory and file tree for the GoCryptoTrader source code and alert you of undocumented file systems which **need** to be updated.
+- Automatically find the template folder tree.
+- Fetch an updated contributor list and rank on pull request commit amount
+- Sets up core folder docs for the root directory tree including **LICENSE** and **CONTRIBUTORS**
+
+### config.json example
+
+```json
+{
+"githubRepo": "https://api.github.com/repos/thrasher-corp/gocryptotrader", This is your current repo
+"exclusionList": { This allows for excluded directories and files
+"Files": null,
+"Directories": [
+"_templates",
+".git",
+"web"
+]
+},
+"rootReadmeActive": true, allows a root directory README.md
+"licenseFileActive": true, allows for a license file to be generated
+"contributorFileActive": true, fetches a new contributor list
+"referencePathToRepo": "../../"
+}
+```
+### Template example
+>place a new template **example_file.tmpl** located in the current gocryptotrader/cmd/documentation/ folder; when the documentation tool finishes it will give you the define template associated name e.g. ``Template not found for path ../../cmd/documentation create new template with \{\{define "cmd documentation" -\}\} TEMPLATE HERE \{\{end}}`` so you can replace the below example with ``\{\{define "cmd documentation" -}}``
+
+```
+\{\{\define "example_definition_created_by_documentation_tool" -}}
+\{\{\template "header" .}}
+## Current Features for documentation
+
+#### A concise blurb about the package or tool system
+
++ Coding examples
+import "github.com/thrasher-corp/gocryptotrader/something"
+testString := "aAaAa"
+upper := strings.ToUpper(testString)
+// upper == "AAAAA"
+
+{\{\template "contributions"}}
+{\{\template "donations"}}
+{\{\end}}
+```
+
+### ALL NEW UPDATES AND FILE SYSTEM ADDITIONS NEED A DOCUMENTATION UPDATE USING THIS TOOL OR PR MERGE REQUEST MAY BE POSTPONED.
+
+
+### Please click GoDocs chevron above to view current GoDoc information for this package
+
+## Contribution
+
+Please feel free to submit any pull requests or suggest any desired features to be added.
+
+When submitting a PR, please abide by our coding guidelines:
+
++ Code must adhere to the official Go [formatting](https://golang.org/doc/effective_go.html#formatting) guidelines (i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
++ Code must be documented adhering to the official Go [commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
++ Code must adhere to our [coding style](https://github.com/thrasher-corp/gocryptotrader/blob/master/doc/coding_style.md).
++ Pull requests need to be based on and opened against the `master` branch.
+
+## Donations
+
+
+
+If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
+
+***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
diff --git a/cmd/documentation/cmd_templates/documentation.tmpl b/cmd/documentation/cmd_templates/documentation.tmpl
new file mode 100644
index 00000000..1f6d4956
--- /dev/null
+++ b/cmd/documentation/cmd_templates/documentation.tmpl
@@ -0,0 +1,63 @@
+{{define "cmd documentation" -}}
+{{template "header" .}}
+## Current Features for {{.Name}}
+
+#### This tool allows for the generation of new documentation through templating
+
+From the `gocryptotrader/cmd/documentation/` folder, using the go command: **go run documentation.go** this will auto-generate and regenerate documentation across the **GoCryptoTrader** code base.
+>Using the -v command will, ie **go run documentation.go -v** put the tool into verbose mode allowing you to see what is happening with a little more depth.
+
+Be aware, this tool will:
+- Works off a configuration JSON file located at ``gocryptotrader/cmd/documentation/`` for future use with multiple repositories.
+- Automatically find the directory and file tree for the GoCryptoTrader source code and alert you of undocumented file systems which **need** to be updated.
+- Automatically find the template folder tree.
+- Fetch an updated contributor list and rank on pull request commit amount
+- Sets up core folder docs for the root directory tree including **LICENSE** and **CONTRIBUTORS**
+
+### config.json example
+
+```json
+{
+"githubRepo": "https://api.github.com/repos/thrasher-corp/gocryptotrader", This is your current repo
+"exclusionList": { This allows for excluded directories and files
+"Files": null,
+"Directories": [
+"_templates",
+".git",
+"web"
+]
+},
+"rootReadmeActive": true, allows a root directory README.md
+"licenseFileActive": true, allows for a license file to be generated
+"contributorFileActive": true, fetches a new contributor list
+"referencePathToRepo": "../../"
+}
+```
+### Template example
+>place a new template **example_file.tmpl** located in the current gocryptotrader/cmd/documentation/ folder; when the documentation tool finishes it will give you the define template associated name e.g. ``Template not found for path ../../cmd/documentation create new template with \{\{define "cmd documentation" -\}\} TEMPLATE HERE \{\{end}}`` so you can replace the below example with ``\{\{define "cmd documentation" -}}``
+
+```
+\{\{\define "example_definition_created_by_documentation_tool" -}}
+\{\{\template "header" .}}
+## Current Features for {{.Name}}
+
+#### A concise blurb about the package or tool system
+
++ Coding examples
+import "github.com/thrasher-corp/gocryptotrader/something"
+testString := "aAaAa"
+upper := strings.ToUpper(testString)
+// upper == "AAAAA"
+
+{\{\template "contributions"}}
+{\{\template "donations"}}
+{\{\end}}
+```
+
+### ALL NEW UPDATES AND FILE SYSTEM ADDITIONS NEED A DOCUMENTATION UPDATE USING THIS TOOL OR PR MERGE REQUEST MAY BE POSTPONED.
+
+
+### Please click GoDocs chevron above to view current GoDoc information for this package
+{{template "contributions"}}
+{{template "donations"}}
+{{end}}
diff --git a/tools/documentation/common_templates/common_readme.tmpl b/cmd/documentation/common_templates/common_readme.tmpl
similarity index 91%
rename from tools/documentation/common_templates/common_readme.tmpl
rename to cmd/documentation/common_templates/common_readme.tmpl
index e91f1daa..64200f7c 100644
--- a/tools/documentation/common_templates/common_readme.tmpl
+++ b/cmd/documentation/common_templates/common_readme.tmpl
@@ -11,7 +11,7 @@ import "github.com/thrasher-corp/gocryptotrader/common"
testString := "aAaAa"
-upper := common.StringToUpper(testString)
+upper := strings.ToUpper(testString)
// upper == "AAAAA"
```
diff --git a/tools/documentation/communications_templates/base.tmpl b/cmd/documentation/communications_templates/base.tmpl
similarity index 100%
rename from tools/documentation/communications_templates/base.tmpl
rename to cmd/documentation/communications_templates/base.tmpl
diff --git a/tools/documentation/communications_templates/comms.tmpl b/cmd/documentation/communications_templates/comms.tmpl
similarity index 100%
rename from tools/documentation/communications_templates/comms.tmpl
rename to cmd/documentation/communications_templates/comms.tmpl
diff --git a/tools/documentation/communications_templates/slack.tmpl b/cmd/documentation/communications_templates/slack.tmpl
similarity index 100%
rename from tools/documentation/communications_templates/slack.tmpl
rename to cmd/documentation/communications_templates/slack.tmpl
diff --git a/tools/documentation/communications_templates/smsglobal.tmpl b/cmd/documentation/communications_templates/smsglobal.tmpl
similarity index 100%
rename from tools/documentation/communications_templates/smsglobal.tmpl
rename to cmd/documentation/communications_templates/smsglobal.tmpl
diff --git a/tools/documentation/communications_templates/smtp.tmpl b/cmd/documentation/communications_templates/smtp.tmpl
similarity index 100%
rename from tools/documentation/communications_templates/smtp.tmpl
rename to cmd/documentation/communications_templates/smtp.tmpl
diff --git a/tools/documentation/communications_templates/telegram.tmpl b/cmd/documentation/communications_templates/telegram.tmpl
similarity index 100%
rename from tools/documentation/communications_templates/telegram.tmpl
rename to cmd/documentation/communications_templates/telegram.tmpl
diff --git a/tools/documentation/config_templates/config_readme.tmpl b/cmd/documentation/config_templates/config_readme.tmpl
similarity index 100%
rename from tools/documentation/config_templates/config_readme.tmpl
rename to cmd/documentation/config_templates/config_readme.tmpl
diff --git a/tools/documentation/currency_templates/currency_pair_readme.tmpl b/cmd/documentation/currency_templates/currency_pair_readme.tmpl
similarity index 100%
rename from tools/documentation/currency_templates/currency_pair_readme.tmpl
rename to cmd/documentation/currency_templates/currency_pair_readme.tmpl
diff --git a/tools/documentation/currency_templates/currency_readme.tmpl b/cmd/documentation/currency_templates/currency_readme.tmpl
similarity index 100%
rename from tools/documentation/currency_templates/currency_readme.tmpl
rename to cmd/documentation/currency_templates/currency_readme.tmpl
diff --git a/tools/documentation/currency_templates/currency_symbol_readme.tmpl b/cmd/documentation/currency_templates/currency_symbol_readme.tmpl
similarity index 100%
rename from tools/documentation/currency_templates/currency_symbol_readme.tmpl
rename to cmd/documentation/currency_templates/currency_symbol_readme.tmpl
diff --git a/tools/documentation/currency_templates/currency_translation_readme.tmpl b/cmd/documentation/currency_templates/currency_translation_readme.tmpl
similarity index 100%
rename from tools/documentation/currency_templates/currency_translation_readme.tmpl
rename to cmd/documentation/currency_templates/currency_translation_readme.tmpl
diff --git a/tools/documentation/currency_templates/fx.tmpl b/cmd/documentation/currency_templates/fx.tmpl
similarity index 100%
rename from tools/documentation/currency_templates/fx.tmpl
rename to cmd/documentation/currency_templates/fx.tmpl
diff --git a/tools/documentation/currency_templates/fx_base.tmpl b/cmd/documentation/currency_templates/fx_base.tmpl
similarity index 100%
rename from tools/documentation/currency_templates/fx_base.tmpl
rename to cmd/documentation/currency_templates/fx_base.tmpl
diff --git a/tools/documentation/currency_templates/fx_currencyconverterapi.tmpl b/cmd/documentation/currency_templates/fx_currencyconverterapi.tmpl
similarity index 77%
rename from tools/documentation/currency_templates/fx_currencyconverterapi.tmpl
rename to cmd/documentation/currency_templates/fx_currencyconverterapi.tmpl
index bad1a573..d6da5a20 100644
--- a/tools/documentation/currency_templates/fx_currencyconverterapi.tmpl
+++ b/cmd/documentation/currency_templates/fx_currencyconverterapi.tmpl
@@ -1,4 +1,4 @@
-{{define "currency forexprovider currencyconverter" -}}
+{{define "currency forexprovider currencyconverterapi" -}}
{{template "header" .}}
## Current Features for {{.Name}}
@@ -11,15 +11,15 @@
+ Individual package example below:
```go
import (
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/currencyconverter"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/currencyconverter"
)
c := currencyconverter.CurrencyConverter{}
// Define configuration
newSettings := base.Settings{
- Name: "CurrencyConverter",
+ Name: "CurrencyConverter",
Enabled: true,
Verbose: false,
RESTPollingDelay: time.Duration,
diff --git a/tools/documentation/currency_templates/fx_currencylayer.tmpl b/cmd/documentation/currency_templates/fx_currencylayer.tmpl
similarity index 83%
rename from tools/documentation/currency_templates/fx_currencylayer.tmpl
rename to cmd/documentation/currency_templates/fx_currencylayer.tmpl
index e96a1513..b2654fd9 100644
--- a/tools/documentation/currency_templates/fx_currencylayer.tmpl
+++ b/cmd/documentation/currency_templates/fx_currencylayer.tmpl
@@ -11,15 +11,15 @@
+ Individual package example below:
```go
import (
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/currencylayer"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/currencylayer"
)
c := currencylayer.CurrencyLayer{}
// Define configuration
newSettings := base.Settings{
- Name: "CurrencyLayer",
+ Name: "CurrencyLayer",
Enabled: true,
Verbose: false,
RESTPollingDelay: time.Duration,
diff --git a/cmd/documentation/currency_templates/fx_exchangeratesapi.tmpl b/cmd/documentation/currency_templates/fx_exchangeratesapi.tmpl
new file mode 100644
index 00000000..49830305
--- /dev/null
+++ b/cmd/documentation/currency_templates/fx_exchangeratesapi.tmpl
@@ -0,0 +1,40 @@
+{{define "currency forexprovider exchangeratesapi.io" -}}
+{{template "header" .}}
+## Current Features for {{.Name}}
+
++ Fetches up to date curency data from [Exchange rates API]("http://exchangeratesapi.io")
+
+### How to enable
+
++ [Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-currency-via-config-example)
+
++ Individual package example below:
+```go
+import (
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/exchangerates"
+)
+
+c := exchangerates.ExchangeRates{}
+
+// Define configuration
+newSettings := base.Settings{
+ Name: "ExchangeRates",
+ Enabled: true,
+ Verbose: false,
+ RESTPollingDelay: time.Duration,
+ APIKey: "key",
+ APIKeyLvl: "keylvl",
+ PrimaryProvider: true,
+}
+
+c.Setup(newSettings)
+
+mapstringfloat, err := c.GetRates("USD", "EUR,CHY")
+// Handle error
+```
+
+### Please click GoDocs chevron above to view current GoDoc information for this package
+{{template "contributions"}}
+{{template "donations"}}
+{{- end}}
\ No newline at end of file
diff --git a/tools/documentation/currency_templates/fx_fixer.tmpl b/cmd/documentation/currency_templates/fx_fixer.tmpl
similarity index 78%
rename from tools/documentation/currency_templates/fx_fixer.tmpl
rename to cmd/documentation/currency_templates/fx_fixer.tmpl
index 346e9b31..60a1e4dd 100644
--- a/tools/documentation/currency_templates/fx_fixer.tmpl
+++ b/cmd/documentation/currency_templates/fx_fixer.tmpl
@@ -1,4 +1,4 @@
-{{define "currency forexprovider fixer" -}}
+{{define "currency forexprovider fixer.io" -}}
{{template "header" .}}
## Current Features for {{.Name}}
@@ -11,15 +11,15 @@
+ Individual package example below:
```go
import (
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/fixer.io"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/fixer.io"
)
c := fixer.Fixer{}
// Define configuration
newSettings := base.Settings{
- Name: "Fixer",
+ Name: "Fixer",
Enabled: true,
Verbose: false,
RESTPollingDelay: time.Duration,
diff --git a/tools/documentation/currency_templates/fx_openexchangerates.tmpl b/cmd/documentation/currency_templates/fx_openexchangerates.tmpl
similarity index 82%
rename from tools/documentation/currency_templates/fx_openexchangerates.tmpl
rename to cmd/documentation/currency_templates/fx_openexchangerates.tmpl
index 72dbd7c3..372e1936 100644
--- a/tools/documentation/currency_templates/fx_openexchangerates.tmpl
+++ b/cmd/documentation/currency_templates/fx_openexchangerates.tmpl
@@ -11,15 +11,15 @@
+ Individual package example below:
```go
import (
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
-"github.com/thrasher-corp/gocryptotrader/currency/forexprovider/openexchangerates"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/base"
+ "github.com/thrasher-corp/gocryptotrader/currency/forexprovider/openexchangerates"
)
c := openexchangerates.OXR{}
// Define configuration
newSettings := base.Settings{
- Name: "openexchangerates",
+ Name: "openexchangerates",
Enabled: true,
Verbose: false,
RESTPollingDelay: time.Duration,
diff --git a/cmd/documentation/documentation.go b/cmd/documentation/documentation.go
new file mode 100644
index 00000000..1b7fe352
--- /dev/null
+++ b/cmd/documentation/documentation.go
@@ -0,0 +1,487 @@
+package main
+
+import (
+ "encoding/json"
+ "errors"
+ "flag"
+ "fmt"
+ "html/template"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/thrasher-corp/gocryptotrader/common"
+ "github.com/thrasher-corp/gocryptotrader/core"
+)
+
+const (
+ // DefaultRepo is the main example repository
+ DefaultRepo = "https://api.github.com/repos/thrasher-corp/gocryptotrader"
+
+ // GithubAPIEndpoint allows the program to query your repository
+ // contributor list
+ GithubAPIEndpoint = "/contributors"
+
+ // LicenseFile defines a license file
+ LicenseFile = "LICENSE"
+
+ // ContributorFile defines contributor file
+ ContributorFile = "CONTRIBUTORS"
+)
+
+var (
+ // DefaultExcludedDirectories defines the basic directory exclusion list for GCT
+ DefaultExcludedDirectories = []string{".github",
+ ".git",
+ "node_modules",
+ ".vscode",
+ ".idea",
+ "cmd_templates",
+ "common_templates",
+ "communications_templates",
+ "config_templates",
+ "currency_templates",
+ "events_templates",
+ "exchanges_templates",
+ "portfolio_templates",
+ "root_templates",
+ "sub_templates",
+ "testdata_templates",
+ "tools_templates",
+ "web_templates",
+ }
+
+ // global flag for verbosity
+ verbose bool
+ // current tool directory to specify working templates
+ toolDir string
+ // exposes root directory if outside of document tool directory
+ repoDir string
+ // is a broken down version of the documentation tool dir for cross platform
+ // checking
+ ref = []string{"gocryptotrader", "cmd", "documentation"}
+)
+
+// Contributor defines an account associated with this code base by doing
+// contributions
+type Contributor struct {
+ Login string `json:"login"`
+ URL string `json:"html_url"`
+ Contributions int `json:"contributions"`
+}
+
+// Config defines the running config to deploy documentation across a github
+// repository including exclusion lists for files and directories
+type Config struct {
+ GithubRepo string `json:"githubRepo"`
+ Exclusions Exclusions `json:"exclusionList"`
+ RootReadme bool `json:"rootReadmeActive"`
+ LicenseFile bool `json:"licenseFileActive"`
+ ContributorFile bool `json:"contributorFileActive"`
+}
+
+// Exclusions defines the exclusion list so documents are not generated
+type Exclusions struct {
+ Files []string `json:"Files"`
+ Directories []string `json:"Directories"`
+}
+
+// DocumentationDetails defines parameters to update documentation
+type DocumentationDetails struct {
+ Directories []string
+ Tmpl *template.Template
+ Contributors []Contributor
+ Config *Config
+}
+
+// Attributes defines specific documentation attributes when a template is
+// executed
+type Attributes struct {
+ Name string
+ Contributors []Contributor
+ NameURL string
+ Year int
+ CapitalName string
+}
+
+func main() {
+ flag.BoolVar(&verbose, "v", false, "Verbose output")
+ flag.StringVar(&toolDir, "tooldir", "", "Pass in the documentation tool directory if outside tool folder")
+ flag.Parse()
+
+ wd, err := os.Getwd()
+ if err != nil {
+ fmt.Println("Documentation tool error cannot get working dir:", err)
+ os.Exit(1)
+ }
+
+ if strings.Contains(wd, filepath.Join(ref...)) {
+ rootdir := filepath.Dir(filepath.Dir(wd))
+ repoDir = rootdir
+ toolDir = wd
+ } else {
+ if toolDir == "" {
+ fmt.Println("Please set documentation tool directory via the tooldir flag if working outside of tool directory")
+ os.Exit(1)
+ }
+ repoDir = wd
+ }
+
+ fmt.Println(core.Banner)
+ fmt.Println("This will update and regenerate documentation for the different packages in your repo.")
+ fmt.Println()
+
+ if verbose {
+ fmt.Println("Fetching configuration...")
+ }
+
+ config, err := GetConfiguration()
+ if err != nil {
+ log.Fatalf("Documentation Generation Tool - GetConfiguration error %s",
+ err)
+ }
+
+ if verbose {
+ fmt.Println("Fetching project directory tree...")
+ }
+
+ dirList, err := GetProjectDirectoryTree(&config)
+ if err != nil {
+ log.Fatalf("Documentation Generation Tool - GetProjectDirectoryTree error %s",
+ err)
+ }
+
+ var contributors []Contributor
+ if config.ContributorFile {
+ if verbose {
+ fmt.Println("Fetching repository contributor list...")
+ }
+ contributors, err = GetContributorList(config.GithubRepo)
+ if err != nil {
+ log.Fatalf("Documentation Generation Tool - GetContributorList error %s",
+ err)
+ }
+
+ // Github API missing contributors
+ contributors = append(contributors, []Contributor{
+ // idoall's contributors were forked and merged, so his contributions
+ // aren't automatically retrievable
+ {
+ Login: "idoall",
+ URL: "https://github.com/idoall",
+ Contributions: 1,
+ },
+ {
+ Login: "mattkanwisher",
+ URL: "https://github.com/mattkanwisher",
+ Contributions: 1,
+ },
+ {
+ Login: "mKurrels",
+ URL: "https://github.com/mKurrels",
+ Contributions: 1,
+ },
+ {
+ Login: "m1kola",
+ URL: "https://github.com/m1kola",
+ Contributions: 1,
+ },
+ {
+ Login: "cavapoo2",
+ URL: "https://github.com/cavapoo2",
+ Contributions: 1,
+ },
+ {
+ Login: "zeldrinn",
+ URL: "https://github.com/zeldrinn",
+ Contributions: 1,
+ },
+ }...)
+
+ if verbose {
+ fmt.Println("Contributor List Fetched")
+ for i := range contributors {
+ fmt.Println(contributors[i].Login)
+ }
+ }
+ } else {
+ fmt.Println("Contributor list file disabled skipping fetching details")
+ }
+
+ if verbose {
+ fmt.Println("Fetching template files...")
+ }
+
+ tmpl, err := GetTemplateFiles()
+ if err != nil {
+ log.Fatalf("Documentation Generation Tool - GetTemplateFiles error %s",
+ err)
+ }
+
+ if verbose {
+ fmt.Println("All core systems fetched, updating documentation...")
+ }
+
+ err = UpdateDocumentation(DocumentationDetails{
+ dirList,
+ tmpl,
+ contributors,
+ &config})
+ if err != nil {
+ log.Fatalf("Documentation Generation Tool - UpdateDocumentation error %s",
+ err)
+ }
+
+ fmt.Println("\nDocumentation Generation Tool - Finished")
+}
+
+// GetConfiguration retrieves the documentation configuration
+func GetConfiguration() (Config, error) {
+ var c Config
+ configFilePath := filepath.Join([]string{toolDir, "config.json"}...)
+ file, err := os.OpenFile(configFilePath, os.O_RDWR, os.ModePerm)
+ if err != nil {
+ fmt.Println("Creating configuration file, please check to add a different github repository path and change preferences")
+
+ file, err = os.Create(configFilePath)
+ if err != nil {
+ return c, err
+ }
+
+ // Set default params for configuration
+ c.GithubRepo = DefaultRepo
+ c.ContributorFile = true
+ c.LicenseFile = true
+ c.RootReadme = true
+ c.Exclusions.Directories = DefaultExcludedDirectories
+
+ data, mErr := json.MarshalIndent(c, "", " ")
+ if mErr != nil {
+ return c, mErr
+ }
+
+ _, err = file.WriteAt(data, 0)
+ if err != nil {
+ return c, err
+ }
+ }
+
+ defer file.Close()
+
+ config, err := ioutil.ReadAll(file)
+ if err != nil {
+ return c, err
+ }
+
+ err = json.Unmarshal(config, &c)
+ if err != nil {
+ return c, err
+ }
+
+ if c.GithubRepo == "" {
+ return c, errors.New("repository not set in config.json file, please change")
+ }
+
+ return c, nil
+}
+
+// IsExcluded returns if the file path is included in the exclusion list
+func IsExcluded(path string, exclusion []string) bool {
+ for i := range exclusion {
+ if path == exclusion[i] {
+ return true
+ }
+ }
+ return false
+}
+
+// GetProjectDirectoryTree uses filepath walk functions to get each individual
+// directory name and path to match templates with
+func GetProjectDirectoryTree(c *Config) ([]string, error) {
+ var directoryData []string
+ if c.RootReadme { // Projects root README.md
+ directoryData = append(directoryData, repoDir)
+ }
+
+ if c.LicenseFile { // Standard license file
+ directoryData = append(directoryData, filepath.Join(repoDir, LicenseFile))
+ }
+
+ if c.ContributorFile { // Standard contributor file
+ directoryData = append(directoryData, filepath.Join(repoDir, ContributorFile))
+ }
+
+ walkfn := func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ // Bypass what is contained in config.json directory exclusion
+ if IsExcluded(info.Name(), c.Exclusions.Directories) {
+ if verbose {
+ fmt.Println("Excluding Directory:", info.Name())
+ }
+ return filepath.SkipDir
+ }
+ // Don't append parent directory
+ if strings.EqualFold(info.Name(), "..") {
+ return nil
+ }
+ directoryData = append(directoryData, path)
+ }
+ return nil
+ }
+
+ return directoryData, filepath.Walk(repoDir, walkfn)
+}
+
+// GetTemplateFiles parses and returns all template files in the documentation
+// tree
+func GetTemplateFiles() (*template.Template, error) {
+ tmpl := template.New("")
+
+ walkfn := func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ if path == "." || path == ".." {
+ return nil
+ }
+
+ var parseError error
+ tmpl, parseError = tmpl.ParseGlob(filepath.Join(path, "*.tmpl"))
+ if parseError != nil {
+ if strings.Contains(parseError.Error(), "pattern matches no files") {
+ return nil
+ }
+ return parseError
+ }
+ return filepath.SkipDir
+ }
+ return nil
+ }
+
+ return tmpl, filepath.Walk(toolDir, walkfn)
+}
+
+// GetContributorList fetches a list of contributors from the github api
+// endpoint
+func GetContributorList(repo string) ([]Contributor, error) {
+ var resp []Contributor
+ return resp, common.SendHTTPGetRequest(repo+GithubAPIEndpoint, true, false, &resp)
+}
+
+// GetDocumentationAttributes returns specific attributes for a file template
+func GetDocumentationAttributes(packageName string, contributors []Contributor) Attributes {
+ return Attributes{
+ Name: GetPackageName(packageName, false),
+ Contributors: contributors,
+ NameURL: GetGoDocURL(packageName),
+ Year: time.Now().Year(),
+ CapitalName: GetPackageName(packageName, true),
+ }
+}
+
+// GetPackageName returns the package name after cleaning path as a string
+func GetPackageName(name string, capital bool) string {
+ newStrings := strings.Split(name, " ")
+ var i int
+ if len(newStrings) > 1 {
+ i = 1
+ }
+ if capital {
+ return strings.Title(newStrings[i])
+ }
+ return newStrings[i]
+}
+
+// GetGoDocURL returns a string for godoc package names
+func GetGoDocURL(name string) string {
+ if strings.Contains(name, " ") {
+ return strings.Join(strings.Split(name, " "), "/")
+ }
+ if name == "testdata" ||
+ name == "tools" ||
+ name == ContributorFile ||
+ name == LicenseFile {
+ return ""
+ }
+ return name
+}
+
+// UpdateDocumentation generates or updates readme/documentation files across
+// the codebase
+func UpdateDocumentation(details DocumentationDetails) error {
+ for i := range details.Directories {
+ cutset := details.Directories[i][len(repoDir):]
+ if cutset != "" && cutset[0] == os.PathSeparator {
+ cutset = cutset[1:]
+ }
+
+ data := strings.Split(cutset, string(os.PathSeparator))
+
+ var temp []string
+ for x := range data {
+ if data[x] == ".." {
+ continue
+ }
+ if data[x] == "" {
+ break
+ }
+ temp = append(temp, data[x])
+ }
+
+ var name string
+ if len(temp) == 0 {
+ name = "root"
+ } else {
+ name = strings.Join(temp, " ")
+ }
+
+ if IsExcluded(name, details.Config.Exclusions.Files) {
+ if verbose {
+ fmt.Println("Excluding file:", name)
+ }
+ continue
+ }
+
+ if details.Tmpl.Lookup(name) == nil {
+ fmt.Printf("Template not found for path %s create new template with {{define \"%s\" -}} TEMPLATE HERE {{end}}\n",
+ details.Directories[i],
+ name)
+ continue
+ }
+
+ var mainPath string
+ if name == LicenseFile || name == ContributorFile {
+ mainPath = details.Directories[i]
+ } else {
+ mainPath = filepath.Join(details.Directories[i], "README.md")
+ }
+
+ err := os.Remove(mainPath)
+ if err != nil && !(strings.Contains(err.Error(), "no such file or directory") ||
+ strings.Contains(err.Error(), "The system cannot find the file specified.")) {
+ return err
+ }
+
+ file, err := os.Create(mainPath)
+ if err != nil {
+ return err
+ }
+
+ attr := GetDocumentationAttributes(name, details.Contributors)
+
+ err = details.Tmpl.ExecuteTemplate(file, name, attr)
+ if err != nil {
+ file.Close()
+ return err
+ }
+ file.Close()
+ }
+ return nil
+}
diff --git a/tools/documentation/events_templates/events_readme.tmpl b/cmd/documentation/events_templates/events_readme.tmpl
similarity index 100%
rename from tools/documentation/events_templates/events_readme.tmpl
rename to cmd/documentation/events_templates/events_readme.tmpl
diff --git a/tools/documentation/exchanges_templates/alphapoint.tmpl b/cmd/documentation/exchanges_templates/alphapoint.tmpl
similarity index 100%
rename from tools/documentation/exchanges_templates/alphapoint.tmpl
rename to cmd/documentation/exchanges_templates/alphapoint.tmpl
diff --git a/tools/documentation/exchanges_templates/anx.tmpl b/cmd/documentation/exchanges_templates/anx.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/anx.tmpl
rename to cmd/documentation/exchanges_templates/anx.tmpl
index c1e2a351..ba79c69b 100644
--- a/tools/documentation/exchanges_templates/anx.tmpl
+++ b/cmd/documentation/exchanges_templates/anx.tmpl
@@ -33,22 +33,22 @@ main.go
```go
var a exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "ANX" {
- a = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "ANX" {
+ a = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := a.GetTickerPrice()
+tick, err := a.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := a.GetOrderbookEx()
+ob, err := a.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/binance.tmpl b/cmd/documentation/exchanges_templates/binance.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/binance.tmpl
rename to cmd/documentation/exchanges_templates/binance.tmpl
index 0b764357..aadea33f 100644
--- a/tools/documentation/exchanges_templates/binance.tmpl
+++ b/cmd/documentation/exchanges_templates/binance.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Binance" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Binance" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/bitfinex.tmpl b/cmd/documentation/exchanges_templates/bitfinex.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/bitfinex.tmpl
rename to cmd/documentation/exchanges_templates/bitfinex.tmpl
index 653349be..57a2c9f5 100644
--- a/tools/documentation/exchanges_templates/bitfinex.tmpl
+++ b/cmd/documentation/exchanges_templates/bitfinex.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Bitfinex" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Bitfinex" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/bitflyer.tmpl b/cmd/documentation/exchanges_templates/bitflyer.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/bitflyer.tmpl
rename to cmd/documentation/exchanges_templates/bitflyer.tmpl
index 9039e574..1e6259c8 100644
--- a/tools/documentation/exchanges_templates/bitflyer.tmpl
+++ b/cmd/documentation/exchanges_templates/bitflyer.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Bitflyer" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Bitflyer" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/bithumb.tmpl b/cmd/documentation/exchanges_templates/bithumb.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/bithumb.tmpl
rename to cmd/documentation/exchanges_templates/bithumb.tmpl
index 1bee2047..849398cc 100644
--- a/tools/documentation/exchanges_templates/bithumb.tmpl
+++ b/cmd/documentation/exchanges_templates/bithumb.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Bithumb" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Bithumb" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/bitmex.tmpl b/cmd/documentation/exchanges_templates/bitmex.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/bitmex.tmpl
rename to cmd/documentation/exchanges_templates/bitmex.tmpl
index 7c160828..69668b4c 100644
--- a/tools/documentation/exchanges_templates/bitmex.tmpl
+++ b/cmd/documentation/exchanges_templates/bitmex.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Bitmex" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Bitmex" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/bitstamp.tmpl b/cmd/documentation/exchanges_templates/bitstamp.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/bitstamp.tmpl
rename to cmd/documentation/exchanges_templates/bitstamp.tmpl
index c10ef122..ee1cadd0 100644
--- a/tools/documentation/exchanges_templates/bitstamp.tmpl
+++ b/cmd/documentation/exchanges_templates/bitstamp.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Bitstamp" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Bitstamp" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/bittrex.tmpl b/cmd/documentation/exchanges_templates/bittrex.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/bittrex.tmpl
rename to cmd/documentation/exchanges_templates/bittrex.tmpl
index 2d3361c9..15409464 100644
--- a/tools/documentation/exchanges_templates/bittrex.tmpl
+++ b/cmd/documentation/exchanges_templates/bittrex.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Bittrex" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Bittrex" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/btcmarkets.tmpl b/cmd/documentation/exchanges_templates/btcmarkets.tmpl
similarity index 91%
rename from tools/documentation/exchanges_templates/btcmarkets.tmpl
rename to cmd/documentation/exchanges_templates/btcmarkets.tmpl
index af89bfb7..4d81557e 100644
--- a/tools/documentation/exchanges_templates/btcmarkets.tmpl
+++ b/cmd/documentation/exchanges_templates/btcmarkets.tmpl
@@ -5,6 +5,7 @@
### Current Features
+ REST Support
++ Websocket Support
### How to enable
@@ -29,22 +30,22 @@ main.go
```go
var b exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "BTCMarkets" {
- b = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "BTCMarkets" {
+ b = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := b.GetTickerPrice()
+tick, err := b.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := b.GetOrderbookEx()
+ob, err := b.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/cmd/documentation/exchanges_templates/btse.tmpl b/cmd/documentation/exchanges_templates/btse.tmpl
new file mode 100644
index 00000000..9df4638f
--- /dev/null
+++ b/cmd/documentation/exchanges_templates/btse.tmpl
@@ -0,0 +1,99 @@
+{{define "exchanges btse" -}}
+{{template "header" .}}
+## BTCMarkets Exchange
+
+### Current Features
+
++ REST Support
++ Websocket Support
+
+### How to enable
+
++ [Enable via configuration](https://github.com/thrasher-corp/gocryptotrader/tree/master/config#enable-exchange-via-config-example)
+
++ Individual package example below:
+
+```go
+ // Exchanges will be abstracted out in further updates and examples will be
+ // supplied then
+```
+
+### How to do REST public/private calls
+
++ If enabled via "configuration".json file the exchange will be added to the
+IBotExchange array in the ```go var bot Bot``` and you will only be able to use
+the wrapper interface functions for accessing exchange data. View routines.go
+for an example of integration usage with GoCryptoTrader. Rudimentary example
+below:
+
+main.go
+```go
+var b exchange.IBotExchange
+
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "BTSE" {
+ b = bot.Exchanges[i]
+ }
+}
+
+// Public calls - wrapper functions
+
+// Fetches current ticker information
+tick, err := b.FetchTicker()
+if err != nil {
+ // Handle error
+}
+
+// Fetches current orderbook information
+ob, err := b.FetchOrderbook()
+if err != nil {
+ // Handle error
+}
+
+// Private calls - wrapper functions - make sure your APIKEY and APISECRET are
+// set and AuthenticatedAPISupport is set to true
+
+// Fetches current account information
+accountInfo, err := b.GetAccountInfo()
+if err != nil {
+ // Handle error
+}
+```
+
++ If enabled via individually importing package, rudimentary example below:
+
+```go
+// Public calls
+
+// Fetches current ticker information
+ticker, err := b.GetTicker()
+if err != nil {
+ // Handle error
+}
+
+// Fetches current orderbook information
+ob, err := b.GetOrderBook()
+if err != nil {
+ // Handle error
+}
+
+// Private calls - make sure your APIKEY and APISECRET are set and
+// AuthenticatedAPISupport is set to true
+
+// GetUserInfo returns account info
+accountInfo, err := b.GetUserInfo(...)
+if err != nil {
+ // Handle error
+}
+
+// Submits an order and the exchange and returns its tradeID
+tradeID, err := b.Trade(...)
+if err != nil {
+ // Handle error
+}
+```
+
+### Please click GoDocs chevron above to view current GoDoc information for this package
+{{template "contributions"}}
+{{template "donations"}}
+{{end}}
diff --git a/tools/documentation/exchanges_templates/coinbasepro.tmpl b/cmd/documentation/exchanges_templates/coinbasepro.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/coinbasepro.tmpl
rename to cmd/documentation/exchanges_templates/coinbasepro.tmpl
index 2abbde6c..05f0b049 100644
--- a/tools/documentation/exchanges_templates/coinbasepro.tmpl
+++ b/cmd/documentation/exchanges_templates/coinbasepro.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var c exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "CoinbasePro" {
- c = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "CoinbasePro" {
+ c = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := c.GetTickerPrice()
+tick, err := c.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := c.GetOrderbookEx()
+ob, err := c.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/coinbene.tmpl b/cmd/documentation/exchanges_templates/coinbene.tmpl
similarity index 90%
rename from tools/documentation/exchanges_templates/coinbene.tmpl
rename to cmd/documentation/exchanges_templates/coinbene.tmpl
index f9de7d4c..7dc3b4d4 100644
--- a/tools/documentation/exchanges_templates/coinbene.tmpl
+++ b/cmd/documentation/exchanges_templates/coinbene.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var c exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Coinbene" {
- c = bot.exchanges[i]
+for i := range Bot.Exchanges {
+ if Bot.Exchanges[i].GetName() == "Coinbene" {
+ c = Bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := c.GetTickerPrice()
+tick, err := c.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := c.GetOrderbookEx()
+ob, err := c.FetchOrderbook()
if err != nil {
// Handle error
}
@@ -72,7 +72,7 @@ if err != nil {
}
// Fetches current orderbook information
-ob, err := c.GetOrderBook()
+ob, err := c.GetOrderbook()
if err != nil {
// Handle error
}
@@ -87,7 +87,7 @@ if err != nil {
}
// Submits an order and the exchange and returns its tradeID
-tradeID, err := c.Trade(...)
+resp, err := c.SubmitOrder(...)
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/coinut.tmpl b/cmd/documentation/exchanges_templates/coinut.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/coinut.tmpl
rename to cmd/documentation/exchanges_templates/coinut.tmpl
index 90453625..8b6f644c 100644
--- a/tools/documentation/exchanges_templates/coinut.tmpl
+++ b/cmd/documentation/exchanges_templates/coinut.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var c exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Coinut" {
- c = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Coinut" {
+ c = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := c.GetTickerPrice()
+tick, err := c.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := c.GetOrderbookEx()
+ob, err := c.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/exchanges_orderbook_readme.tmpl b/cmd/documentation/exchanges_templates/exchanges_orderbook_readme.tmpl
similarity index 95%
rename from tools/documentation/exchanges_templates/exchanges_orderbook_readme.tmpl
rename to cmd/documentation/exchanges_templates/exchanges_orderbook_readme.tmpl
index 78de8a20..047d7c92 100644
--- a/tools/documentation/exchanges_templates/exchanges_orderbook_readme.tmpl
+++ b/cmd/documentation/exchanges_templates/exchanges_orderbook_readme.tmpl
@@ -16,7 +16,7 @@ exchange interface system set by exchange wrapper orderbook functions in
Examples below:
```go
-ob, err := yobitExchange.GetOrderbookEx()
+ob, err := yobitExchange.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/exchanges_readme.tmpl b/cmd/documentation/exchanges_templates/exchanges_readme.tmpl
similarity index 100%
rename from tools/documentation/exchanges_templates/exchanges_readme.tmpl
rename to cmd/documentation/exchanges_templates/exchanges_readme.tmpl
diff --git a/tools/documentation/exchanges_templates/exchanges_stats_readme.tmpl b/cmd/documentation/exchanges_templates/exchanges_stats_readme.tmpl
similarity index 100%
rename from tools/documentation/exchanges_templates/exchanges_stats_readme.tmpl
rename to cmd/documentation/exchanges_templates/exchanges_stats_readme.tmpl
diff --git a/tools/documentation/exchanges_templates/exchanges_ticker_readme.tmpl b/cmd/documentation/exchanges_templates/exchanges_ticker_readme.tmpl
similarity index 95%
rename from tools/documentation/exchanges_templates/exchanges_ticker_readme.tmpl
rename to cmd/documentation/exchanges_templates/exchanges_ticker_readme.tmpl
index 0f47ef6d..afd210aa 100644
--- a/tools/documentation/exchanges_templates/exchanges_ticker_readme.tmpl
+++ b/cmd/documentation/exchanges_templates/exchanges_ticker_readme.tmpl
@@ -17,7 +17,7 @@ exchange interface system set by exchange wrapper orderbook functions in
Examples below:
```go
-tick, err := yobitExchange.GetTickerPrice()
+tick, err := yobitExchange.FetchTicker()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/exmo.tmpl b/cmd/documentation/exchanges_templates/exmo.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/exmo.tmpl
rename to cmd/documentation/exchanges_templates/exmo.tmpl
index da52c11e..4378a6dc 100644
--- a/tools/documentation/exchanges_templates/exmo.tmpl
+++ b/cmd/documentation/exchanges_templates/exmo.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var e exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Exmo" {
- e = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Exmo" {
+ e = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := e.GetTickerPrice()
+tick, err := e.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := e.GetOrderbookEx()
+ob, err := e.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/gateio.tmpl b/cmd/documentation/exchanges_templates/gateio.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/gateio.tmpl
rename to cmd/documentation/exchanges_templates/gateio.tmpl
index f6b0f75c..2f311ac1 100644
--- a/tools/documentation/exchanges_templates/gateio.tmpl
+++ b/cmd/documentation/exchanges_templates/gateio.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var g exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "GateIO" {
- g = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "GateIO" {
+ g = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := g.GetTickerPrice()
+tick, err := g.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := g.GetOrderbookEx()
+ob, err := g.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/gemini.tmpl b/cmd/documentation/exchanges_templates/gemini.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/gemini.tmpl
rename to cmd/documentation/exchanges_templates/gemini.tmpl
index 296b83a3..9810785b 100644
--- a/tools/documentation/exchanges_templates/gemini.tmpl
+++ b/cmd/documentation/exchanges_templates/gemini.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var g exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Gemini" {
- g = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Gemini" {
+ g = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := g.GetTickerPrice()
+tick, err := g.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := g.GetOrderbookEx()
+ob, err := g.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/hitbtc.tmpl b/cmd/documentation/exchanges_templates/hitbtc.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/hitbtc.tmpl
rename to cmd/documentation/exchanges_templates/hitbtc.tmpl
index 1860462b..624be46d 100644
--- a/tools/documentation/exchanges_templates/hitbtc.tmpl
+++ b/cmd/documentation/exchanges_templates/hitbtc.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var h exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "HitBTC" {
- h = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "HitBTC" {
+ h = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := h.GetTickerPrice()
+tick, err := h.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := h.GetOrderbookEx()
+ob, err := h.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/huobi.tmpl b/cmd/documentation/exchanges_templates/huobi.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/huobi.tmpl
rename to cmd/documentation/exchanges_templates/huobi.tmpl
index 42db521f..f85ccd95 100644
--- a/tools/documentation/exchanges_templates/huobi.tmpl
+++ b/cmd/documentation/exchanges_templates/huobi.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var h exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Huobi" {
- h = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Huobi" {
+ h = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := h.GetTickerPrice()
+tick, err := h.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := h.GetOrderbookEx()
+ob, err := h.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/itbit.tmpl b/cmd/documentation/exchanges_templates/itbit.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/itbit.tmpl
rename to cmd/documentation/exchanges_templates/itbit.tmpl
index 1a8cca57..908c0e6d 100644
--- a/tools/documentation/exchanges_templates/itbit.tmpl
+++ b/cmd/documentation/exchanges_templates/itbit.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var i exchange.IBotExchange
-for x := range bot.exchanges {
- if bot.exchanges[x].GetName() == "Itbit" {
- i = bot.exchanges[x]
+for x := range bot.Exchanges {
+ if bot.Exchanges[x].GetName() == "Itbit" {
+ i = bot.Exchanges[x]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := i.GetTickerPrice()
+tick, err := i.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := i.GetOrderbookEx()
+ob, err := i.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/kraken.tmpl b/cmd/documentation/exchanges_templates/kraken.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/kraken.tmpl
rename to cmd/documentation/exchanges_templates/kraken.tmpl
index 8b4d052c..3a6ec6a3 100644
--- a/tools/documentation/exchanges_templates/kraken.tmpl
+++ b/cmd/documentation/exchanges_templates/kraken.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var k exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Kraken" {
- k = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Kraken" {
+ k = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := k.GetTickerPrice()
+tick, err := k.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := k.GetOrderbookEx()
+ob, err := k.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/lakebtc.tmpl b/cmd/documentation/exchanges_templates/lakebtc.tmpl
similarity index 91%
rename from tools/documentation/exchanges_templates/lakebtc.tmpl
rename to cmd/documentation/exchanges_templates/lakebtc.tmpl
index b422d6c8..28a0e9c3 100644
--- a/tools/documentation/exchanges_templates/lakebtc.tmpl
+++ b/cmd/documentation/exchanges_templates/lakebtc.tmpl
@@ -5,6 +5,7 @@
### Current Features
+ REST Support
++ Websocket Support
### How to enable
@@ -29,22 +30,22 @@ main.go
```go
var l exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "LakeBTC" {
- l = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "LakeBTC" {
+ l = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := l.GetTickerPrice()
+tick, err := l.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := l.GetOrderbookEx()
+ob, err := l.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/lbank.tmpl b/cmd/documentation/exchanges_templates/lbank.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/lbank.tmpl
rename to cmd/documentation/exchanges_templates/lbank.tmpl
index 45fb9441..890fb91f 100644
--- a/tools/documentation/exchanges_templates/lbank.tmpl
+++ b/cmd/documentation/exchanges_templates/lbank.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var l exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Lbank" {
- l = bot.exchanges[i]
+for i := range Bot.Exchanges {
+ if Bot.Exchanges[i].GetName() == "Lbank" {
+ l = Bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := l.GetTickerPrice()
+tick, err := l.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := l.GetOrderbookEx()
+ob, err := l.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/localbitcoins.tmpl b/cmd/documentation/exchanges_templates/localbitcoins.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/localbitcoins.tmpl
rename to cmd/documentation/exchanges_templates/localbitcoins.tmpl
index 13725b1c..8526c267 100644
--- a/tools/documentation/exchanges_templates/localbitcoins.tmpl
+++ b/cmd/documentation/exchanges_templates/localbitcoins.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var l exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "LocalBitcoins" {
- l = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "LocalBitcoins" {
+ l = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := l.GetTickerPrice()
+tick, err := l.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := l.GetOrderbookEx()
+ob, err := l.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/nonce.tmpl b/cmd/documentation/exchanges_templates/nonce.tmpl
similarity index 100%
rename from tools/documentation/exchanges_templates/nonce.tmpl
rename to cmd/documentation/exchanges_templates/nonce.tmpl
diff --git a/tools/documentation/exchanges_templates/okcoin.tmpl b/cmd/documentation/exchanges_templates/okcoin.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/okcoin.tmpl
rename to cmd/documentation/exchanges_templates/okcoin.tmpl
index 3d4ba0e0..ec16b998 100644
--- a/tools/documentation/exchanges_templates/okcoin.tmpl
+++ b/cmd/documentation/exchanges_templates/okcoin.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var o exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "OKCoin" {
- y = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "OKCoin" {
+ y = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := o.GetTickerPrice()
+tick, err := o.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := o.GetOrderbookEx()
+ob, err := o.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/okex.tmpl b/cmd/documentation/exchanges_templates/okex.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/okex.tmpl
rename to cmd/documentation/exchanges_templates/okex.tmpl
index 368bb13f..9117ce49 100644
--- a/tools/documentation/exchanges_templates/okex.tmpl
+++ b/cmd/documentation/exchanges_templates/okex.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var o exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "OKex" {
- y = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "OKex" {
+ y = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := o.GetTickerPrice()
+tick, err := o.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := o.GetOrderbookEx()
+ob, err := o.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/orders.tmpl b/cmd/documentation/exchanges_templates/orders.tmpl
similarity index 100%
rename from tools/documentation/exchanges_templates/orders.tmpl
rename to cmd/documentation/exchanges_templates/orders.tmpl
diff --git a/tools/documentation/exchanges_templates/poloniex.tmpl b/cmd/documentation/exchanges_templates/poloniex.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/poloniex.tmpl
rename to cmd/documentation/exchanges_templates/poloniex.tmpl
index cfb76abb..eae1386c 100644
--- a/tools/documentation/exchanges_templates/poloniex.tmpl
+++ b/cmd/documentation/exchanges_templates/poloniex.tmpl
@@ -30,22 +30,22 @@ main.go
```go
var p exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Poloniex" {
- y = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Poloniex" {
+ y = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := p.GetTickerPrice()
+tick, err := p.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := p.GetOrderbookEx()
+ob, err := p.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/request.tmpl b/cmd/documentation/exchanges_templates/request.tmpl
similarity index 100%
rename from tools/documentation/exchanges_templates/request.tmpl
rename to cmd/documentation/exchanges_templates/request.tmpl
diff --git a/tools/documentation/exchanges_templates/yobit.tmpl b/cmd/documentation/exchanges_templates/yobit.tmpl
similarity index 92%
rename from tools/documentation/exchanges_templates/yobit.tmpl
rename to cmd/documentation/exchanges_templates/yobit.tmpl
index 9fee688b..5b9acc9e 100644
--- a/tools/documentation/exchanges_templates/yobit.tmpl
+++ b/cmd/documentation/exchanges_templates/yobit.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var y exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "Yobit" {
- y = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "Yobit" {
+ y = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := y.GetTickerPrice()
+tick, err := y.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := y.GetOrderbookEx()
+ob, err := y.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/exchanges_templates/zb.tmpl b/cmd/documentation/exchanges_templates/zb.tmpl
similarity index 93%
rename from tools/documentation/exchanges_templates/zb.tmpl
rename to cmd/documentation/exchanges_templates/zb.tmpl
index 8d37ae46..9dd6bb0e 100644
--- a/tools/documentation/exchanges_templates/zb.tmpl
+++ b/cmd/documentation/exchanges_templates/zb.tmpl
@@ -29,22 +29,22 @@ main.go
```go
var z exchange.IBotExchange
-for i := range bot.exchanges {
- if bot.exchanges[i].GetName() == "ZB" {
- z = bot.exchanges[i]
+for i := range bot.Exchanges {
+ if bot.Exchanges[i].GetName() == "ZB" {
+ z = bot.Exchanges[i]
}
}
// Public calls - wrapper functions
// Fetches current ticker information
-tick, err := z.GetTickerPrice()
+tick, err := z.FetchTicker()
if err != nil {
// Handle error
}
// Fetches current orderbook information
-ob, err := z.GetOrderbookEx()
+ob, err := z.FetchOrderbook()
if err != nil {
// Handle error
}
diff --git a/tools/documentation/portfolio_templates/portfolio_readme.tmpl b/cmd/documentation/portfolio_templates/portfolio_readme.tmpl
similarity index 100%
rename from tools/documentation/portfolio_templates/portfolio_readme.tmpl
rename to cmd/documentation/portfolio_templates/portfolio_readme.tmpl
diff --git a/tools/documentation/root_templates/CONTRIBUTORS b/cmd/documentation/root_templates/CONTRIBUTORS.tmpl
similarity index 69%
rename from tools/documentation/root_templates/CONTRIBUTORS
rename to cmd/documentation/root_templates/CONTRIBUTORS.tmpl
index eda72237..0a25998d 100644
--- a/tools/documentation/root_templates/CONTRIBUTORS
+++ b/cmd/documentation/root_templates/CONTRIBUTORS.tmpl
@@ -1,6 +1,6 @@
{{define "CONTRIBUTORS"}}
Thanks to the following contributors:
-{{ range $contributor := .Contributors -}}
+{{range $contributor := .Contributors -}}
{{$contributor.Login}} | {{$contributor.URL}}
-{{ end }}
{{end}}
+{{- end}}
diff --git a/tools/documentation/root_templates/LICENSE b/cmd/documentation/root_templates/LICENSE.tmpl
similarity index 100%
rename from tools/documentation/root_templates/LICENSE
rename to cmd/documentation/root_templates/LICENSE.tmpl
diff --git a/tools/documentation/root_templates/root_readme.tmpl b/cmd/documentation/root_templates/root_readme.tmpl
similarity index 90%
rename from tools/documentation/root_templates/root_readme.tmpl
rename to cmd/documentation/root_templates/root_readme.tmpl
index 92c1c039..ec6f5159 100644
--- a/tools/documentation/root_templates/root_readme.tmpl
+++ b/cmd/documentation/root_templates/root_readme.tmpl
@@ -33,6 +33,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
| COINUT | Yes | Yes | NA |
| Exmo | Yes | NA | NA |
| CoinbasePro | Yes | Yes | No|
+| Coinbene | Yes | No | No |
| GateIO | Yes | Yes | NA |
| Gemini | Yes | Yes | No |
| HitBTC | Yes | Yes | No |
@@ -54,19 +55,26 @@ We are aiming to support the top 20 highest volume exchanges based off the [Coin
## Current Features
-+ Support for all Exchange fiat and digital currencies, with the ability to individually toggle them on/off.
++ Support for all exchange fiat and digital currencies, with the ability to individually toggle them on/off.
+ AES256 encrypted config file.
+ REST API support for all exchanges.
+ Websocket support for applicable exchanges.
+ Ability to turn off/on certain exchanges.
-+ Ability to adjust manual polling timer for exchanges.
+ Communication packages (Slack, SMS via SMSGlobal, Telegram and SMTP)
+ HTTP rate limiter package.
++ Unified API for exchange usage.
++ Customisation of HTTP client features including setting a proxy, user agent and adjusting transport settings.
++ NTP client package.
++ Database support (Postgres and SQLite3). See [database](/database/README.md).
++ OTP generation tool. See [gen otp](/cmd/gen_otp).
++ Connection monitor package.
++ gRPC service and JSON RPC proxy. See [gRPC service](/gctrpc/README.md).
++ gRPC client. See [gctcli](/cmd/gctcli/README.md).
+ Forex currency converter packages (CurrencyConverterAPI, CurrencyLayer, Fixer.io, OpenExchangeRates)
+ Packages for handling currency pairs, tickers and orderbooks.
+ Portfolio management tool; fetches balances from supported exchanges and allows for custom address tracking.
+ Basic event trigger system.
-+ WebGUI.
++ WebGUI (discontinued).
## Planned Features
@@ -125,4 +133,4 @@ If this framework helped you in any way, or you would like to support the develo
Binaries will be published once the codebase reaches a stable condition.
{{template "contributors" .}}
-{{end}}
+{{- end}}
diff --git a/tools/documentation/sub_templates/contributions.tmpl b/cmd/documentation/sub_templates/contributions.tmpl
similarity index 100%
rename from tools/documentation/sub_templates/contributions.tmpl
rename to cmd/documentation/sub_templates/contributions.tmpl
diff --git a/cmd/documentation/sub_templates/contributors.tmpl b/cmd/documentation/sub_templates/contributors.tmpl
new file mode 100644
index 00000000..35c8c455
--- /dev/null
+++ b/cmd/documentation/sub_templates/contributors.tmpl
@@ -0,0 +1,11 @@
+{{define "contributors"}}
+## Contributor List
+
+### A very special thank you to all who have contributed to this program:
+
+|User|Contribution Amount|
+|--|--|
+{{range $contributor := .Contributors -}}
+| [{{$contributor.Login}}]({{$contributor.URL}}) | {{$contributor.Contributions}} |
+{{end}}
+{{- end}}
diff --git a/tools/documentation/sub_templates/donations.tmpl b/cmd/documentation/sub_templates/donations.tmpl
similarity index 97%
rename from tools/documentation/sub_templates/donations.tmpl
rename to cmd/documentation/sub_templates/donations.tmpl
index a864ed70..3fd5682f 100644
--- a/tools/documentation/sub_templates/donations.tmpl
+++ b/cmd/documentation/sub_templates/donations.tmpl
@@ -6,4 +6,4 @@
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
-{{end}}
+{{- end}}
diff --git a/tools/documentation/sub_templates/header.tmpl b/cmd/documentation/sub_templates/header.tmpl
similarity index 100%
rename from tools/documentation/sub_templates/header.tmpl
rename to cmd/documentation/sub_templates/header.tmpl
diff --git a/tools/documentation/sub_templates/status.tmpl b/cmd/documentation/sub_templates/status.tmpl
similarity index 100%
rename from tools/documentation/sub_templates/status.tmpl
rename to cmd/documentation/sub_templates/status.tmpl
diff --git a/tools/documentation/testdata_templates/testdata_readme.tmpl b/cmd/documentation/testdata_templates/testdata_readme.tmpl
similarity index 92%
rename from tools/documentation/testdata_templates/testdata_readme.tmpl
rename to cmd/documentation/testdata_templates/testdata_readme.tmpl
index 15a6e5d9..68a08abf 100644
--- a/tools/documentation/testdata_templates/testdata_readme.tmpl
+++ b/cmd/documentation/testdata_templates/testdata_readme.tmpl
@@ -6,5 +6,5 @@ This folder contains a configuration test file for non-deployement test params.
It also has the code coverage test files that allow us to monitor our entire
codebase, click this link for more information [https://codecov.io/](https://codecov.io/).
{{template "contributions"}}
-{{template "donations"}}
+{{template "donations" -}}
{{end}}
diff --git a/tools/documentation/tools_templates/config_tool.tmpl b/cmd/documentation/tools_templates/config_tool.tmpl
similarity index 100%
rename from tools/documentation/tools_templates/config_tool.tmpl
rename to cmd/documentation/tools_templates/config_tool.tmpl
diff --git a/tools/documentation/tools_templates/documentation_tool.tmpl b/cmd/documentation/tools_templates/documentation_tool.tmpl
similarity index 100%
rename from tools/documentation/tools_templates/documentation_tool.tmpl
rename to cmd/documentation/tools_templates/documentation_tool.tmpl
diff --git a/tools/documentation/tools_templates/exchange_tool.tmpl b/cmd/documentation/tools_templates/exchange_tool.tmpl
similarity index 100%
rename from tools/documentation/tools_templates/exchange_tool.tmpl
rename to cmd/documentation/tools_templates/exchange_tool.tmpl
diff --git a/tools/documentation/tools_templates/huobi_auth_tool.tmpl b/cmd/documentation/tools_templates/huobi_auth_tool.tmpl
similarity index 100%
rename from tools/documentation/tools_templates/huobi_auth_tool.tmpl
rename to cmd/documentation/tools_templates/huobi_auth_tool.tmpl
diff --git a/tools/documentation/tools_templates/portfolio_tool.tmpl b/cmd/documentation/tools_templates/portfolio_tool.tmpl
similarity index 100%
rename from tools/documentation/tools_templates/portfolio_tool.tmpl
rename to cmd/documentation/tools_templates/portfolio_tool.tmpl
diff --git a/tools/documentation/tools_templates/tools.tmpl b/cmd/documentation/tools_templates/tools.tmpl
similarity index 100%
rename from tools/documentation/tools_templates/tools.tmpl
rename to cmd/documentation/tools_templates/tools.tmpl
diff --git a/tools/documentation/tools_templates/websocket_client_tool.tmpl b/cmd/documentation/tools_templates/websocket_client_tool.tmpl
similarity index 100%
rename from tools/documentation/tools_templates/websocket_client_tool.tmpl
rename to cmd/documentation/tools_templates/websocket_client_tool.tmpl
diff --git a/tools/documentation/web_templates/web_readme.tmpl b/cmd/documentation/web_templates/web_readme.tmpl
similarity index 100%
rename from tools/documentation/web_templates/web_readme.tmpl
rename to cmd/documentation/web_templates/web_readme.tmpl
diff --git a/tools/exchange_template/exchange_template.go b/cmd/exchange_template/exchange_template.go
similarity index 75%
rename from tools/exchange_template/exchange_template.go
rename to cmd/exchange_template/exchange_template.go
index 2276365c..ef976e09 100644
--- a/tools/exchange_template/exchange_template.go
+++ b/cmd/exchange_template/exchange_template.go
@@ -7,10 +7,13 @@ import (
"log"
"os"
"os/exec"
+ "path/filepath"
+ "strings"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/config"
- "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
+ "github.com/thrasher-corp/gocryptotrader/currency"
+ "github.com/thrasher-corp/gocryptotrader/exchanges/asset"
)
const (
@@ -20,9 +23,8 @@ const (
packageMain = "%s.go"
packageReadme = "README.md"
- exchangePackageLocation = "..%s..%sexchanges%s"
- exchangeLocation = "..%s..%sexchange.go"
- exchangeConfigPath = "..%s..%stestdata%sconfigtest.json"
+ exchangePackageLocation = "../../exchanges"
+ exchangeConfigPath = "../../testdata/configtest.json"
)
var (
@@ -32,7 +34,6 @@ var (
exchangeWrapper string
exchangeMain string
exchangeReadme string
- exchangeJSON string
)
type exchange struct {
@@ -82,9 +83,9 @@ func main() {
log.Fatal("GoCryptoTrader: Exchange templating tool stopped...")
}
- newExchangeName = common.StringToLower(newExchangeName)
+ newExchangeName = strings.ToLower(newExchangeName)
v := newExchangeName[:1]
- capName := common.StringToUpper(v) + newExchangeName[1:]
+ capName := strings.ToUpper(v) + newExchangeName[1:]
exch := exchange{
Name: newExchangeName,
@@ -95,18 +96,14 @@ func main() {
FIX: fixSupport,
}
- osPathSlash := common.GetOSPathSlash()
- exchangeJSON := fmt.Sprintf(exchangeConfigPath, osPathSlash, osPathSlash, osPathSlash)
-
configTestFile := config.GetConfig()
- err = configTestFile.LoadConfig(exchangeJSON)
+ err = configTestFile.LoadConfig(exchangeConfigPath, true)
if err != nil {
log.Fatal("GoCryptoTrader: Exchange templating configuration retrieval error ", err)
}
// NOTE need to nullify encrypt configuration
var configTestExchanges []string
-
for x := range configTestFile.Exchanges {
configTestExchanges = append(configTestExchanges, configTestFile.Exchanges[x].Name)
}
@@ -118,31 +115,34 @@ func main() {
newExchConfig := config.ExchangeConfig{}
newExchConfig.Name = capName
newExchConfig.Enabled = true
- newExchConfig.RESTPollingDelay = 10
- newExchConfig.APIKey = "Key"
- newExchConfig.APISecret = "Secret"
- newExchConfig.AssetTypes = orderbook.Spot
+ newExchConfig.API.Credentials.Key = "Key"
+ newExchConfig.API.Credentials.Secret = "Secret"
+ newExchConfig.CurrencyPairs = ¤cy.PairsManager{
+ AssetTypes: asset.Items{
+ asset.Spot,
+ },
+ UseGlobalFormat: true,
+ RequestFormat: ¤cy.PairFormat{
+ Uppercase: true,
+ },
+ ConfigFormat: ¤cy.PairFormat{
+ Uppercase: true,
+ },
+ }
configTestFile.Exchanges = append(configTestFile.Exchanges, newExchConfig)
- // TODO sorting function so exchanges are in alphabetical order - low priority
- err = configTestFile.SaveConfig(exchangeJSON)
+ err = configTestFile.SaveConfig(exchangeConfigPath, false)
if err != nil {
log.Fatal("GoCryptoTrader: Exchange templating configuration error - cannot save")
}
- exchangeDirectory = fmt.Sprintf(
- exchangePackageLocation+newExchangeName+"%s",
- osPathSlash,
- osPathSlash,
- osPathSlash,
- osPathSlash)
-
- exchangeTest = fmt.Sprintf(exchangeDirectory+packageTests, newExchangeName)
- exchangeTypes = fmt.Sprintf(exchangeDirectory+packageTypes, newExchangeName)
- exchangeWrapper = fmt.Sprintf(exchangeDirectory+packageWrapper, newExchangeName)
- exchangeMain = fmt.Sprintf(exchangeDirectory+packageMain, newExchangeName)
- exchangeReadme = exchangeDirectory + packageReadme
+ exchangeDirectory = filepath.Join(exchangePackageLocation, newExchangeName)
+ exchangeTest = filepath.Join(exchangeDirectory, fmt.Sprintf(packageTests, newExchangeName))
+ exchangeTypes = filepath.Join(exchangeDirectory, fmt.Sprintf(packageTypes, newExchangeName))
+ exchangeWrapper = filepath.Join(exchangeDirectory, fmt.Sprintf(packageWrapper, newExchangeName))
+ exchangeMain = filepath.Join(exchangeDirectory, fmt.Sprintf(packageMain, newExchangeName))
+ exchangeReadme = filepath.Join(exchangeDirectory, packageReadme)
err = os.Mkdir(exchangeDirectory, 0700)
if err != nil {
@@ -220,12 +220,13 @@ func main() {
}
fmt.Println("GoCryptoTrader: Exchange templating tool service complete")
- fmt.Println("When wrapper is finished add exchange to exchange.go")
- fmt.Println("Test exchange.go")
- fmt.Println("Update the config_test.go file")
- fmt.Println("Test config.go")
+ fmt.Println("When the exchange code implementation has been completed (REST/Websocket/wrappers and tests), please add the exchange to engine/exchange.go")
+ fmt.Println("Add the exchange config settings to config_example.json (it will automatically be added to testdata/configtest.json)")
+ fmt.Println("Increment the available exchanges counter in config/config_test.go")
+ fmt.Println("Add the exchange name to exchanges/support.go")
+ fmt.Println("Ensure go test ./... -race passes")
fmt.Println("Open a pull request")
- fmt.Println("If help is needed please post a message on Slack.")
+ fmt.Println("If help is needed, please post a message in Slack.")
}
func newFile(path string) {
diff --git a/cmd/exchange_template/main_file.tmpl b/cmd/exchange_template/main_file.tmpl
new file mode 100644
index 00000000..ef86003a
--- /dev/null
+++ b/cmd/exchange_template/main_file.tmpl
@@ -0,0 +1,24 @@
+{{define "main"}}
+package {{.Name}}
+
+import (
+ exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
+)
+
+// {{.CapitalName}} is the overarching type across this package
+type {{.CapitalName}} struct {
+ exchange.Base
+}
+
+const (
+ {{.Name}}APIURL = ""
+ {{.Name}}APIVersion = ""
+
+ // Public endpoints
+
+ // Authenticated endpoints
+)
+
+// Start implementing public and private exchange API funcs below
+
+{{end}}
diff --git a/tools/exchange_template/readme_file.tmpl b/cmd/exchange_template/readme_file.tmpl
similarity index 100%
rename from tools/exchange_template/readme_file.tmpl
rename to cmd/exchange_template/readme_file.tmpl
diff --git a/cmd/exchange_template/test_file.tmpl b/cmd/exchange_template/test_file.tmpl
new file mode 100644
index 00000000..989238e8
--- /dev/null
+++ b/cmd/exchange_template/test_file.tmpl
@@ -0,0 +1,52 @@
+{{define "test"}}
+package {{.Name}}
+
+import (
+ "log"
+ "os"
+ "testing"
+
+ "github.com/thrasher-corp/gocryptotrader/config"
+)
+
+// Please supply your own keys here to do authenticated endpoint testing
+const (
+ apiKey = ""
+ apiSecret = ""
+ canManipulateRealOrders = false
+)
+
+var {{.Variable}} {{.CapitalName}}
+
+func TestMain(m *testing.M) {
+ {{.Variable}}.SetDefaults()
+ cfg := config.GetConfig()
+ err := cfg.LoadConfig("../../testdata/configtest.json", true)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ exchCfg, err := cfg.GetExchangeConfig("{{.CapitalName}}")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ exchCfg.API.AuthenticatedSupport = true
+ {{ if .WS }} exchCfg.API.AuthenticatedWebsocketSupport = true {{ end }}
+ exchCfg.API.Credentials.Key = apiKey
+ exchCfg.API.Credentials.Secret = apiSecret
+
+ err = {{.Variable}}.Setup(exchCfg)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ os.Exit(m.Run())
+}
+
+func areTestAPIKeysSet() bool {
+ return {{.Variable}}.ValidateAPICredentials()
+}
+
+// Implement tests for API endpoints below
+{{end}}
diff --git a/tools/exchange_template/type_file.tmpl b/cmd/exchange_template/type_file.tmpl
similarity index 100%
rename from tools/exchange_template/type_file.tmpl
rename to cmd/exchange_template/type_file.tmpl
diff --git a/cmd/exchange_template/wrapper_file.tmpl b/cmd/exchange_template/wrapper_file.tmpl
new file mode 100644
index 00000000..0ed4873f
--- /dev/null
+++ b/cmd/exchange_template/wrapper_file.tmpl
@@ -0,0 +1,397 @@
+{{define "wrapper"}}
+package {{.Name}}
+
+import (
+ "sync"
+ "time"
+
+ "github.com/thrasher-corp/gocryptotrader/common"
+ "github.com/thrasher-corp/gocryptotrader/config"
+ "github.com/thrasher-corp/gocryptotrader/currency"
+ exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
+ "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/protocol"
+ "github.com/thrasher-corp/gocryptotrader/exchanges/request"
+ "github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
+ "github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
+ log "github.com/thrasher-corp/gocryptotrader/logger"
+)
+
+// GetDefaultConfig returns a default exchange config
+func ({{.Variable}} *{{.CapitalName}}) GetDefaultConfig() (*config.ExchangeConfig, error) {
+ {{.Variable}}.SetDefaults()
+ exchCfg := new(config.ExchangeConfig)
+ exchCfg.Name = {{.Variable}}.Name
+ exchCfg.HTTPTimeout = exchange.DefaultHTTPTimeout
+ exchCfg.BaseCurrencies = {{.Variable}}.BaseCurrencies
+
+ err := {{.Variable}}.SetupDefaults(exchCfg)
+ if err != nil {
+ return nil, err
+ }
+
+ if {{.Variable}}.Features.Supports.RESTCapabilities.AutoPairUpdates {
+ err = {{.Variable}}.UpdateTradablePairs(true)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return exchCfg, nil
+}
+
+// SetDefaults sets the basic defaults for {{.CapitalName}}
+func ({{.Variable}} *{{.CapitalName}}) SetDefaults() {
+ {{.Variable}}.Name = "{{.CapitalName}}"
+ {{.Variable}}.Enabled = true
+ {{.Variable}}.Verbose = true
+ {{.Variable}}.API.CredentialsValidator.RequiresKey = true
+ {{.Variable}}.API.CredentialsValidator.RequiresSecret = true
+ {{.Variable}}.CurrencyPairs = currency.PairsManager{
+ AssetTypes: asset.Items{
+ asset.Spot,
+ },
+ UseGlobalFormat: true,
+ RequestFormat: ¤cy.PairFormat{
+ Uppercase: true,
+ Delimiter: "-",
+ },
+ ConfigFormat: ¤cy.PairFormat{
+ Uppercase: true,
+ Delimiter: "-",
+ },
+ }
+ // Fill out the capabilities/features that the exchange supports
+ {{.Variable}}.Features = exchange.Features{
+ Supports: exchange.FeaturesSupported{
+ {{ if .REST }} REST: true, {{ end }}
+ {{ if .WS }} Websocket: true, {{ end }}
+ RESTCapabilities: protocol.Features{
+ TickerFetching: true,
+ OrderbookFetching: true,
+ },
+ WebsocketCapabilities: protocol.Features{
+ TickerFetching: true,
+ OrderbookFetching: true,
+ },
+ WithdrawPermissions: exchange.AutoWithdrawCrypto |
+ exchange.AutoWithdrawFiat,
+ },
+ Enabled: exchange.FeaturesEnabled{
+ AutoPairUpdates: true,
+ },
+ }
+ {{.Variable}}.Requester = request.New({{.Variable}}.Name,
+ request.NewRateLimit(time.Second, 0),
+ request.NewRateLimit(time.Second, 0),
+ common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
+ {{.Variable}}.API.Endpoints.URLDefault = {{.Name}}APIURL
+ {{.Variable}}.API.Endpoints.URL = {{.Variable}}.API.Endpoints.URLDefault
+ {{.Variable}}.Websocket = wshandler.New()
+ {{.Variable}}.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
+ {{.Variable}}.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
+ {{.Variable}}.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
+}
+
+// Setup takes in the supplied exchange configuration details and sets params
+func ({{.Variable}} *{{.CapitalName}}) Setup(exch *config.ExchangeConfig) error {
+ if !exch.Enabled {
+ {{.Variable}}.SetEnabled(false)
+ return nil
+ }
+
+ err := {{.Variable}}.SetupDefaults(exch)
+ if err != nil {
+ return err
+ }
+
+ // If websocket is supported, please fill out the following
+ /*
+ err = {{.Variable}}.Websocket.Setup(
+ &wshandler.WebsocketSetup{
+ Enabled: exch.Features.Enabled.Websocket,
+ Verbose: exch.Verbose,
+ AuthenticatedWebsocketAPISupport: exch.API.AuthenticatedWebsocketSupport,
+ WebsocketTimeout: exch.WebsocketTrafficTimeout,
+ DefaultURL: {{.Name}}WSURL,
+ ExchangeName: exch.Name,
+ RunningURL: exch.API.Endpoints.WebsocketURL,
+ Connector: {{.Variable}}.WsConnect,
+ Subscriber: {{.Variable}}.Subscribe,
+ UnSubscriber: {{.Variable}}.Unsubscribe,
+ Features: &{{.Variable}}.Features.Supports.WebsocketCapabilities,
+ })
+ if err != nil {
+ return err
+ }
+
+ {{.Variable}}.WebsocketConn = &wshandler.WebsocketConnection{
+ ExchangeName: {{.Variable}}.Name,
+ URL: {{.Variable}}.Websocket.GetWebsocketURL(),
+ ProxyURL: {{.Variable}}.Websocket.GetProxyAddress(),
+ Verbose: {{.Variable}}.Verbose,
+ ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
+ ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
+ }
+
+ // NOTE: PLEASE ENSURE YOU SET THE ORDERBOOK BUFFER SETTINGS CORRECTLY
+ {{.Variable}}.Websocket.Orderbook.Setup(
+ exch.WebsocketOrderbookBufferLimit,
+ true,
+ true,
+ false,
+ false,
+ exch.Name)
+ */
+ return nil
+}
+
+// Start starts the {{.CapitalName}} go routine
+func ({{.Variable}} *{{.CapitalName}}) Start(wg *sync.WaitGroup) {
+ wg.Add(1)
+ go func() {
+ {{.Variable}}.Run()
+ wg.Done()
+ }()
+}
+
+// Run implements the {{.CapitalName}} wrapper
+func ({{.Variable}} *{{.CapitalName}}) Run() {
+ if {{.Variable}}.Verbose {
+ {{ if .WS }} log.Debugf(log.ExchangeSys,
+ "%s Websocket: %s.",
+ {{.Variable}}.Name,
+ common.IsEnabled({{.Variable}}.Websocket.IsEnabled())) {{ end }}
+ {{.Variable}}.PrintEnabledPairs()
+ }
+
+ if !{{.Variable}}.GetEnabledFeatures().AutoPairUpdates {
+ return
+ }
+
+ err := {{.Variable}}.UpdateTradablePairs(false)
+ if err != nil {
+ log.Errorf(log.ExchangeSys,
+ "%s failed to update tradable pairs. Err: %s",
+ {{.Variable}}.Name,
+ err)
+ }
+}
+
+// FetchTradablePairs returns a list of the exchanges tradable pairs
+func ({{.Variable}} *{{.CapitalName}}) FetchTradablePairs(asset asset.Item) ([]string, error) {
+ // Implement fetching the exchange available pairs if supported
+ return nil, nil
+}
+
+// UpdateTradablePairs updates the exchanges available pairs and stores
+// them in the exchanges config
+func ({{.Variable}} *{{.CapitalName}}) UpdateTradablePairs(forceUpdate bool) error {
+ pairs, err := {{.Variable}}.FetchTradablePairs(asset.Spot)
+ if err != nil {
+ return err
+ }
+ return {{.Variable}}.UpdatePairs(currency.NewPairsFromStrings(pairs),
+ asset.Spot, false, forceUpdate)
+}
+
+
+// UpdateTicker updates and returns the ticker for a currency pair
+func ({{.Variable}} *{{.CapitalName}}) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
+ // NOTE: EXAMPLE FOR GETTING TICKER PRICE
+ /*
+ var tickerPrice ticker.Price
+ tick, err := {{.Variable}}.GetTicker(p.String())
+ if err != nil {
+ return tickerPrice, err
+ }
+ tickerPrice = ticker.Price{
+ High: tick.High,
+ Low: tick.Low,
+ Bid: tick.Bid,
+ Ask: tick.Ask,
+ Open: tick.Open,
+ Close: tick.Close,
+ Pair: p,
+ }
+ err = ticker.ProcessTicker({{.Variable}}.Name, &tickerPrice, assetType)
+ if err != nil {
+ return tickerPrice, err
+ }
+ */
+ return ticker.GetTicker({{.Variable}}.Name, p, assetType)
+}
+
+// FetchTicker returns the ticker for a currency pair
+func ({{.Variable}} *{{.CapitalName}}) FetchTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
+ tickerNew, err := ticker.GetTicker({{.Variable}}.Name, p, assetType)
+ if err != nil {
+ return {{.Variable}}.UpdateTicker(p, assetType)
+ }
+ return tickerNew, nil
+}
+
+// FetchOrderbook returns orderbook base on the currency pair
+func ({{.Variable}} *{{.CapitalName}}) FetchOrderbook(currency currency.Pair, assetType asset.Item) (orderbook.Base, error) {
+ ob, err := orderbook.Get({{.Variable}}.Name, currency, assetType)
+ if err != nil {
+ return {{.Variable}}.UpdateOrderbook(currency, assetType)
+ }
+ return ob, nil
+}
+
+// UpdateOrderbook updates and returns the orderbook for a currency pair
+func ({{.Variable}} *{{.CapitalName}}) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbook.Base, error) {
+ var orderBook orderbook.Base
+ // NOTE: UPDATE ORDERBOOK EXAMPLE
+ /*
+ orderbookNew, err := {{.Variable}}.GetOrderBook(exchange.FormatExchangeCurrency({{.Variable}}.Name, p).String(), 1000)
+ if err != nil {
+ return orderBook, err
+ }
+
+ for x := range orderbookNew.Bids {
+ orderBook.Bids = append(orderBook.Bids, orderbook.Item{
+ Amount: orderbookNew.Bids[x].Quantity,
+ Price: orderbookNew.Bids[x].Price,
+ })
+ }
+
+ for x := range orderbookNew.Asks {
+ orderBook.Asks = append(orderBook.Asks, orderbook.Item{
+ Amount: orderBook.Asks[x].Quantity,
+ Price: orderBook.Asks[x].Price,
+ })
+ }
+ */
+
+
+ orderBook.Pair = p
+ orderBook.ExchangeName = {{.Variable}}.Name
+ orderBook.AssetType = assetType
+
+ err := orderBook.Process()
+ if err != nil {
+ return orderBook, err
+ }
+
+ return orderbook.Get({{.Variable}}.Name, p, assetType)
+}
+
+// GetAccountInfo retrieves balances for all enabled currencies for the
+// {{.CapitalName}} exchange
+func ({{.Variable}} *{{.CapitalName}}) GetAccountInfo() (exchange.AccountInfo, error) {
+ return exchange.AccountInfo{}, common.ErrNotYetImplemented
+}
+
+// GetFundingHistory returns funding history, deposits and
+// withdrawals
+func ({{.Variable}} *{{.CapitalName}}) GetFundingHistory() ([]exchange.FundHistory, error) {
+ return nil, common.ErrNotYetImplemented
+}
+
+// GetExchangeHistory returns historic trade data since exchange opening.
+func ({{.Variable}} *{{.CapitalName}}) GetExchangeHistory(p currency.Pair, assetType asset.Item) ([]exchange.TradeHistory, error) {
+ return nil, common.ErrNotYetImplemented
+}
+
+// SubmitOrder submits a new order
+func ({{.Variable}} *{{.CapitalName}}) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) {
+ var submitOrderResponse order.SubmitResponse
+ if err := s.Validate(); err != nil {
+ return submitOrderResponse, err
+ }
+ return submitOrderResponse, common.ErrNotYetImplemented
+}
+
+// ModifyOrder will allow of changing orderbook placement and limit to
+// market conversion
+func ({{.Variable}} *{{.CapitalName}}) ModifyOrder(action *order.Modify) (string, error) {
+ return "", common.ErrNotYetImplemented
+}
+
+// CancelOrder cancels an order by its corresponding ID number
+func ({{.Variable}} *{{.CapitalName}}) CancelOrder(order *order.Cancel) error {
+ return common.ErrNotYetImplemented
+}
+
+// CancelAllOrders cancels all orders associated with a currency pair
+func ({{.Variable}} *{{.CapitalName}}) CancelAllOrders(orderCancellation *order.Cancel) (order.CancelAllResponse, error) {
+ return order.CancelAllResponse{}, common.ErrNotYetImplemented
+}
+
+// GetOrderInfo returns information on a current open order
+func ({{.Variable}} *{{.CapitalName}}) GetOrderInfo(orderID string) (order.Detail, error) {
+ return order.Detail{}, common.ErrNotYetImplemented
+}
+
+// GetDepositAddress returns a deposit address for a specified currency
+func ({{.Variable}} *{{.CapitalName}}) GetDepositAddress(cryptocurrency currency.Code, accountID string) (string, error) {
+ return "", common.ErrNotYetImplemented
+}
+
+// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
+// submitted
+func ({{.Variable}} *{{.CapitalName}}) WithdrawCryptocurrencyFunds(withdrawRequest *exchange.CryptoWithdrawRequest) (string, error) {
+ return "", common.ErrNotYetImplemented
+}
+
+// WithdrawFiatFunds returns a withdrawal ID when a withdrawal is
+// submitted
+func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFunds(withdrawRequest *exchange.FiatWithdrawRequest) (string, error) {
+ return "", common.ErrNotYetImplemented
+}
+
+// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is
+// submitted
+func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFundsToInternationalBank(withdrawRequest *exchange.FiatWithdrawRequest) (string, error) {
+ return "", common.ErrNotYetImplemented
+}
+
+// GetWebsocket returns a pointer to the exchange websocket
+func ({{.Variable}} *{{.CapitalName}}) GetWebsocket() (*wshandler.Websocket, error) {
+ return nil, common.ErrNotYetImplemented
+}
+
+// GetActiveOrders retrieves any orders that are active/open
+func ({{.Variable}} *{{.CapitalName}}) GetActiveOrders(getOrdersRequest *order.GetOrdersRequest) ([]order.Detail, error) {
+ return nil, common.ErrNotYetImplemented
+}
+
+// GetOrderHistory retrieves account order information
+// Can Limit response to specific order status
+func ({{.Variable}} *{{.CapitalName}}) GetOrderHistory(getOrdersRequest *order.GetOrdersRequest) ([]order.Detail, error) {
+ return nil, common.ErrNotYetImplemented
+}
+
+// GetFeeByType returns an estimate of fee based on the type of transaction
+func ({{.Variable}} *{{.CapitalName}}) GetFeeByType(feeBuilder *exchange.FeeBuilder) (float64, error) {
+ return 0, common.ErrNotYetImplemented
+}
+
+// SubscribeToWebsocketChannels appends to ChannelsToSubscribe
+// which lets websocket.manageSubscriptions handle subscribing
+func ({{.Variable}} *{{.CapitalName}}) SubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
+ {{.Variable}}.Websocket.SubscribeToChannels(channels)
+ return nil
+}
+
+// UnsubscribeToWebsocketChannels removes from ChannelsToSubscribe
+// which lets websocket.manageSubscriptions handle unsubscribing
+func ({{.Variable}} *{{.CapitalName}}) UnsubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
+ {{.Variable}}.Websocket.RemoveSubscribedChannels(channels)
+ return nil
+}
+
+// GetSubscriptions returns a copied list of subscriptions
+func ({{.Variable}} *{{.CapitalName}}) GetSubscriptions() ([]wshandler.WebsocketChannelSubscription, error) {
+ return nil, common.ErrNotYetImplemented
+}
+
+// AuthenticateWebsocket sends an authentication message to the websocket
+func ({{.Variable}} *{{.CapitalName}}) AuthenticateWebsocket() error {
+ return common.ErrNotYetImplemented
+}
+
+{{end}}
diff --git a/cmd/exchange_wrapper_coverage/main.go b/cmd/exchange_wrapper_coverage/main.go
new file mode 100644
index 00000000..40dba073
--- /dev/null
+++ b/cmd/exchange_wrapper_coverage/main.go
@@ -0,0 +1,191 @@
+package main
+
+import (
+ "log"
+ "math/rand"
+ "sync"
+ "time"
+
+ "github.com/thrasher-corp/gocryptotrader/common"
+ "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/order"
+)
+
+const (
+ totalWrappers = 20
+)
+
+func main() {
+ var err error
+ engine.Bot, err = engine.New()
+ if err != nil {
+ log.Fatalf("Failed to initialise engine. Err: %s", err)
+ }
+
+ engine.Bot.Settings = engine.Settings{
+ DisableExchangeAutoPairUpdates: true,
+ }
+
+ log.Printf("Loading exchanges..")
+ var wg sync.WaitGroup
+ for x := range exchange.Exchanges {
+ name := exchange.Exchanges[x]
+ 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.")
+
+ log.Printf("Testing exchange wrappers..")
+ results := make(map[string][]string)
+ wg = sync.WaitGroup{}
+ for x := range engine.Bot.Exchanges {
+ wg.Add(1)
+ go func(num int) {
+ name := engine.Bot.Exchanges[num].GetName()
+ results[name] = testWrappers(engine.Bot.Exchanges[num])
+ wg.Done()
+ }(x)
+ }
+ wg.Wait()
+ log.Println("Done.")
+
+ log.Println()
+ for name, funcs := range results {
+ pct := float64(totalWrappers-len(funcs)) / float64(totalWrappers) * 100
+ log.Printf("Exchange %s wrapper coverage [%d/%d - %.2f%%] | Total missing: %d", name, totalWrappers-len(funcs), totalWrappers, pct, len(funcs))
+ log.Printf("\t Wrappers not implemented:")
+
+ for x := range funcs {
+ log.Printf("\t - %s", funcs[x])
+ }
+ log.Println()
+ }
+}
+
+func testWrappers(e exchange.IBotExchange) []string {
+ p := currency.NewPair(currency.BTC, currency.USD)
+ assetType := asset.Spot
+ if !e.SupportsAsset(assetType) {
+ assets := e.GetAssetTypes()
+ rand.Seed(time.Now().Unix())
+ assetType = assets[rand.Intn(len(assets))]
+ }
+
+ var funcs []string
+
+ _, err := e.FetchTicker(p, assetType)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "FetchTicker")
+ }
+
+ _, err = e.UpdateTicker(p, assetType)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "UpdateTicker")
+ }
+
+ _, err = e.FetchOrderbook(p, assetType)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "FetchOrderbook")
+ }
+
+ _, err = e.UpdateOrderbook(p, assetType)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "UpdateOrderbook")
+ }
+
+ _, err = e.FetchTradablePairs(asset.Spot)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "FetchTradablePairs")
+ }
+
+ err = e.UpdateTradablePairs(false)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "UpdateTradablePairs")
+ }
+
+ _, err = e.GetAccountInfo()
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "GetAccountInfo")
+ }
+
+ _, err = e.GetExchangeHistory(p, assetType)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "GetExchangeHistory")
+ }
+
+ _, err = e.GetFundingHistory()
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "GetFundingHistory")
+ }
+
+ s := &order.Submit{
+ Pair: p,
+ OrderSide: order.Buy,
+ OrderType: order.Limit,
+ Amount: 1000000,
+ Price: 10000000000,
+ ClientID: "meow",
+ }
+ _, err = e.SubmitOrder(s)
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "SubmitOrder")
+ }
+
+ _, err = e.ModifyOrder(&order.Modify{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "ModifyOrder")
+ }
+
+ err = e.CancelOrder(&order.Cancel{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "CancelOrder")
+ }
+
+ _, err = e.CancelAllOrders(&order.Cancel{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "CancelAllOrders")
+ }
+
+ _, err = e.GetOrderInfo("1")
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "GetOrderInfo")
+ }
+
+ _, err = e.GetOrderHistory(&order.GetOrdersRequest{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "GetOrderHistory")
+ }
+
+ _, err = e.GetActiveOrders(&order.GetOrdersRequest{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "GetActiveOrders")
+ }
+
+ _, err = e.GetDepositAddress(currency.BTC, "")
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "GetDepositAddress")
+ }
+
+ _, err = e.WithdrawCryptocurrencyFunds(&exchange.CryptoWithdrawRequest{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "WithdrawCryptocurrencyFunds")
+ }
+
+ _, err = e.WithdrawFiatFunds(&exchange.FiatWithdrawRequest{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "WithdrawFiatFunds")
+ }
+ _, err = e.WithdrawFiatFundsToInternationalBank(&exchange.FiatWithdrawRequest{})
+ if err == common.ErrNotYetImplemented {
+ funcs = append(funcs, "WithdrawFiatFundsToInternationalBank")
+ }
+
+ return funcs
+}
diff --git a/cmd/exchange_wrapper_issues/.gitignore b/cmd/exchange_wrapper_issues/.gitignore
new file mode 100644
index 00000000..ff5a41ed
--- /dev/null
+++ b/cmd/exchange_wrapper_issues/.gitignore
@@ -0,0 +1,3 @@
+/data.json
+/output.json
+/report.html
\ No newline at end of file
diff --git a/cmd/exchange_wrapper_issues/main.go b/cmd/exchange_wrapper_issues/main.go
new file mode 100644
index 00000000..e4d2b6e4
--- /dev/null
+++ b/cmd/exchange_wrapper_issues/main.go
@@ -0,0 +1,839 @@
+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/asset"
+ "github.com/thrasher-corp/gocryptotrader/exchanges/order"
+ "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) 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 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 := &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 := 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 = 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()
+ }
+}
diff --git a/cmd/exchange_wrapper_issues/report.tmpl b/cmd/exchange_wrapper_issues/report.tmpl
new file mode 100644
index 00000000..2fcede34
--- /dev/null
+++ b/cmd/exchange_wrapper_issues/report.tmpl
@@ -0,0 +1,155 @@
+{{ $output := . }}
+
+
+
+
+
| + Asset Type + | ++ Currency Pair + | ++ Function + | ++ Wrapper Params Sent + | ++ Error + | ++ Wrapper Response + | + + + + {{ range $k, $endpointResponse := $assetPairResponses.EndpointResponses }} +
|---|---|---|---|---|---|
| + {{ $assetPairResponses.AssetType }} + | ++ {{ $assetPairResponses.CurrencyPair }} + | ++ {{ $endpointResponse.Function }} + | +
+
+
+
+
+ {{ $endpointResponse.SentParams | printf "%s" }}
+
+ |
+ + {{ $endpointResponse.Error }} + | +
+
+
+
+
+ {{ $endpointResponse.Response | printf "%s" }}
+
+ |
+
+