mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-17 15:09:59 +00:00
Merge pull request #382 from thrasher-corp/engine
Merge engine branch into master
This commit is contained in:
@@ -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
|
||||
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
go.mod text eol=lf
|
||||
go.sum text eol=lf
|
||||
59
.github/CONTRIBUTING.md
vendored
59
.github/CONTRIBUTING.md
vendored
@@ -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.
|
||||
|
||||
6
.github/CONTRIBUTING_TEMPLATE.md
vendored
6
.github/CONTRIBUTING_TEMPLATE.md
vendored
@@ -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}}
|
||||
{{end}}
|
||||
|
||||
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -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.
|
||||
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.
|
||||
|
||||
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -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
|
||||
- [ ] Any dependent changes have been merged and published in downstream modules
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -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
|
||||
|
||||
50
.travis.yml
50
.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:
|
||||
|
||||
@@ -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
|
||||
zeldrinn | https://github.com/zeldrinn
|
||||
|
||||
16
Dockerfile
16
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" ]
|
||||
|
||||
17
Makefile
17
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'
|
||||
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
|
||||
|
||||
91
README.md
91
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 |
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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",
|
||||
)
|
||||
}
|
||||
}
|
||||
51
cmd/config_builder/builder.go
Normal file
51
cmd/config_builder/builder.go
Normal file
@@ -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))
|
||||
}
|
||||
102
cmd/dbmigrate/main.go
Normal file
102
cmd/dbmigrate/main.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
97
cmd/documentation/README.md
Normal file
97
cmd/documentation/README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# GoCryptoTrader package Documentation
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/page-logo.png?raw=true" width="350px" height="350px" hspace="70">
|
||||
|
||||
|
||||
[](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
|
||||
|
||||
<img src="https://github.com/thrasher-corp/gocryptotrader/blob/master/web/src/assets/donate.png?raw=true" hspace="70">
|
||||
|
||||
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
|
||||
|
||||
***1F5zVDgNjorJ51oGebSvNCrSAHpwGkUdDB***
|
||||
63
cmd/documentation/cmd_templates/documentation.tmpl
Normal file
63
cmd/documentation/cmd_templates/documentation.tmpl
Normal file
@@ -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}}
|
||||
@@ -11,7 +11,7 @@ import "github.com/thrasher-corp/gocryptotrader/common"
|
||||
|
||||
testString := "aAaAa"
|
||||
|
||||
upper := common.StringToUpper(testString)
|
||||
upper := strings.ToUpper(testString)
|
||||
|
||||
// upper == "AAAAA"
|
||||
```
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
@@ -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}}
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
487
cmd/documentation/documentation.go
Normal file
487
cmd/documentation/documentation.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
99
cmd/documentation/exchanges_templates/btse.tmpl
Normal file
99
cmd/documentation/exchanges_templates/btse.tmpl
Normal file
@@ -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}}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{{define "CONTRIBUTORS"}}
|
||||
Thanks to the following contributors:
|
||||
{{ range $contributor := .Contributors -}}
|
||||
{{range $contributor := .Contributors -}}
|
||||
{{$contributor.Login}} | {{$contributor.URL}}
|
||||
{{ end }}
|
||||
{{end}}
|
||||
{{- end}}
|
||||
@@ -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}}
|
||||
11
cmd/documentation/sub_templates/contributors.tmpl
Normal file
11
cmd/documentation/sub_templates/contributors.tmpl
Normal file
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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) {
|
||||
24
cmd/exchange_template/main_file.tmpl
Normal file
24
cmd/exchange_template/main_file.tmpl
Normal file
@@ -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}}
|
||||
52
cmd/exchange_template/test_file.tmpl
Normal file
52
cmd/exchange_template/test_file.tmpl
Normal file
@@ -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}}
|
||||
397
cmd/exchange_template/wrapper_file.tmpl
Normal file
397
cmd/exchange_template/wrapper_file.tmpl
Normal file
@@ -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}}
|
||||
191
cmd/exchange_wrapper_coverage/main.go
Normal file
191
cmd/exchange_wrapper_coverage/main.go
Normal file
@@ -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
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user