diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index bbe4bf58..b011f227 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -158,27 +158,3 @@ jobs:
run: |
docker run --env SKIP_WRAPPER_CI_TESTS=true --env CI=true --env GCT_DOCKER_CI=true --rm gct-backend-amd64
- frontend:
- name: GoCryptoTrader frontend
- runs-on: ubuntu-latest
- steps:
- - name: Cancel previous workflow runs
- uses: styfle/cancel-workflow-action@0.12.1
- with:
- access_token: ${{ github.token }}
-
- - uses: actions/checkout@v5
-
- - name: Use Node.js
- uses: actions/setup-node@v5
- with:
- node-version: '10.8.x'
- cache: 'npm'
- cache-dependency-path: web/package-lock.json
-
- - name: Build
- run: |
- cd web/
- npm install
- npm run lint
- npm run build
diff --git a/.gitignore b/.gitignore
index ba933dc0..88faccb4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,8 @@
wrapperconfig.json
config.json
config.dat
-node_modules
lib
+.DS_STORE
# VS Code
.vscode
@@ -37,10 +37,6 @@ backtester/btcli/btcli
sqlboiler.toml
sqlboiler.json
-# GCT API Check
-backup.json
-.DS_STORE
-
# Designated generated files dir
target/
diff --git a/README.md b/README.md
index bc395aa4..19773b3c 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,6 @@ However, we welcome pull requests for any exchange which does not match this cri
+ Scripting support. See [gctscript](/gctscript/README.md).
+ Recent and historic trade processing. See [trades](/exchanges/trade/README.md).
+ Backtesting application. An event-driven backtesting tool to test and iterate trading strategies using historical or custom data. See [backtester](/backtester/README.md).
-+ WebGUI (discontinued).
+ Exchange HTTP mock testing. See [mock](/exchanges/mock/README.md).
+ Exchange multichain deposits and withdrawals for specific exchanges. See [multichain transfer support](/docs/MULTICHAIN_TRANSFER_SUPPORT.md).
@@ -134,7 +133,7 @@ go build -tags=sonic_on
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/README.md b/backtester/README.md
index d7563b88..2cd850c3 100644
--- a/backtester/README.md
+++ b/backtester/README.md
@@ -109,7 +109,7 @@ Creating strategies requires programming skills. [Here](/backtester/eventhandler
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/btcli/README.md b/backtester/btcli/README.md
index 4fc6a370..da115e76 100644
--- a/backtester/btcli/README.md
+++ b/backtester/btcli/README.md
@@ -31,7 +31,7 @@ go run .
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/btrpc/README.md b/backtester/btrpc/README.md
index 0b684f18..5cda9789 100644
--- a/backtester/btrpc/README.md
+++ b/backtester/btrpc/README.md
@@ -75,7 +75,7 @@ If any changes were made, ensure that the `rpc.proto` file is formatted correctl
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/common/README.md b/backtester/common/README.md
index c97d6e39..6af0edc4 100644
--- a/backtester/common/README.md
+++ b/backtester/common/README.md
@@ -24,7 +24,7 @@ Common contains some basic data types which are used throughout.
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/config/README.md b/backtester/config/README.md
index b009e321..7eb052e3 100644
--- a/backtester/config/README.md
+++ b/backtester/config/README.md
@@ -288,7 +288,7 @@ See below for a set of tables and fields, expected values and what they can do
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/config/strategyconfigbuilder/README.md b/backtester/config/strategyconfigbuilder/README.md
index 93954a8b..c4421bbf 100644
--- a/backtester/config/strategyconfigbuilder/README.md
+++ b/backtester/config/strategyconfigbuilder/README.md
@@ -32,7 +32,7 @@ The config builder will ask you all the necessary questions required to create a
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/config/strategyexamples/README.md b/backtester/config/strategyexamples/README.md
index 60098c45..ac07bb70 100644
--- a/backtester/config/strategyexamples/README.md
+++ b/backtester/config/strategyexamples/README.md
@@ -42,7 +42,7 @@ Use the provided config builder under `/backtester/config/configbuilder` or modi
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/data/README.md b/backtester/data/README.md
index d60edb5e..75fb0d9b 100644
--- a/backtester/data/README.md
+++ b/backtester/data/README.md
@@ -27,7 +27,7 @@ This can also be used to implement other means to load data for the backtester t
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/data/kline/README.md b/backtester/data/kline/README.md
index 9e381838..b5664759 100644
--- a/backtester/data/kline/README.md
+++ b/backtester/data/kline/README.md
@@ -28,7 +28,7 @@ Trade data represents the raw trading data on an exchange. Every buy or sell act
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/data/kline/api/README.md b/backtester/data/kline/api/README.md
index 93cf1dad..0d770f65 100644
--- a/backtester/data/kline/api/README.md
+++ b/backtester/data/kline/api/README.md
@@ -27,7 +27,7 @@ See individual exchange implementations [here](/exchanges) and the interface use
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/data/kline/csv/README.md b/backtester/data/kline/csv/README.md
index cb1f2fc1..f735131a 100644
--- a/backtester/data/kline/csv/README.md
+++ b/backtester/data/kline/csv/README.md
@@ -48,7 +48,7 @@ Additionally, you can view an example under `./testdata/binance_BTCUSDT_24h-trad
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/data/kline/database/README.md b/backtester/data/kline/database/README.md
index efb12475..3f0ddac8 100644
--- a/backtester/data/kline/database/README.md
+++ b/backtester/data/kline/database/README.md
@@ -33,7 +33,7 @@ Database configuration details can be overridden in the `.strat` config file to
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/data/kline/live/README.md b/backtester/data/kline/live/README.md
index 4365a54b..13ed43ce 100644
--- a/backtester/data/kline/live/README.md
+++ b/backtester/data/kline/live/README.md
@@ -27,7 +27,7 @@ Its incredibly risky to enable `real-orders`. *Past performance is no guarantee
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/engine/README.md b/backtester/engine/README.md
index c8b25883..4d6519ce 100644
--- a/backtester/engine/README.md
+++ b/backtester/engine/README.md
@@ -34,7 +34,7 @@ A flow of the application is as follows:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/engine/backtest.md b/backtester/engine/backtest.md
index 33060b25..c271ba47 100644
--- a/backtester/engine/backtest.md
+++ b/backtester/engine/backtest.md
@@ -28,7 +28,7 @@ A flow of the application is as follows:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/engine/grpcserver.md b/backtester/engine/grpcserver.md
index 00cdd82e..68e16bc5 100644
--- a/backtester/engine/grpcserver.md
+++ b/backtester/engine/grpcserver.md
@@ -24,7 +24,7 @@ The GRPC server is responsible for handling requests from the client. All GRPC f
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/engine/live.md b/backtester/engine/live.md
index 90c78d1f..df32c592 100644
--- a/backtester/engine/live.md
+++ b/backtester/engine/live.md
@@ -30,7 +30,7 @@ A flow of the application is as follows:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/README.md b/backtester/eventhandlers/README.md
index 5de942e1..a5f7fbd5 100644
--- a/backtester/eventhandlers/README.md
+++ b/backtester/eventhandlers/README.md
@@ -26,7 +26,7 @@ Below is an overview of how event handlers are used
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/eventholder/README.md b/backtester/eventhandlers/eventholder/README.md
index 0c94e7d1..cf881477 100644
--- a/backtester/eventhandlers/eventholder/README.md
+++ b/backtester/eventhandlers/eventholder/README.md
@@ -26,7 +26,7 @@ It is used by `backtest.Backtester` and it accepts appending any struct which im
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/exchange/README.md b/backtester/eventhandlers/exchange/README.md
index 269212cc..814f05d0 100644
--- a/backtester/eventhandlers/exchange/README.md
+++ b/backtester/eventhandlers/exchange/README.md
@@ -37,7 +37,7 @@ The following steps are taken for the `ExecuteOrder` function:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/exchange/slippage/README.md b/backtester/eventhandlers/exchange/slippage/README.md
index e8d8543a..5179950f 100644
--- a/backtester/eventhandlers/exchange/slippage/README.md
+++ b/backtester/eventhandlers/exchange/slippage/README.md
@@ -34,7 +34,7 @@ Slippage is calculated in two ways in the GoCryptoTrader Backtester
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/portfolio/README.md b/backtester/eventhandlers/portfolio/README.md
index 48c5a3f9..21b4aee7 100644
--- a/backtester/eventhandlers/portfolio/README.md
+++ b/backtester/eventhandlers/portfolio/README.md
@@ -46,7 +46,7 @@ The following steps are taken for the `Update` function:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/portfolio/compliance/README.md b/backtester/eventhandlers/portfolio/compliance/README.md
index a6eca527..1bafcb50 100644
--- a/backtester/eventhandlers/portfolio/compliance/README.md
+++ b/backtester/eventhandlers/portfolio/compliance/README.md
@@ -24,7 +24,7 @@ The compliance manager is used to store all events at each time interval. When d
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/portfolio/holdings/README.md b/backtester/eventhandlers/portfolio/holdings/README.md
index a4a1e801..f4813b81 100644
--- a/backtester/eventhandlers/portfolio/holdings/README.md
+++ b/backtester/eventhandlers/portfolio/holdings/README.md
@@ -25,7 +25,7 @@ Every data event will update and calculate holdings value based on the new price
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/portfolio/risk/README.md b/backtester/eventhandlers/portfolio/risk/README.md
index 775031e7..3a3c5180 100644
--- a/backtester/eventhandlers/portfolio/risk/README.md
+++ b/backtester/eventhandlers/portfolio/risk/README.md
@@ -27,7 +27,7 @@ See config package [readme](/backtester/config/README.md) to view the risk relat
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/portfolio/size/README.md b/backtester/eventhandlers/portfolio/size/README.md
index fc45b93c..172422eb 100644
--- a/backtester/eventhandlers/portfolio/size/README.md
+++ b/backtester/eventhandlers/portfolio/size/README.md
@@ -27,7 +27,7 @@ The sizing package ensures that all potential orders raised are within both the
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/statistics/README.md b/backtester/eventhandlers/statistics/README.md
index cad1888f..b147a470 100644
--- a/backtester/eventhandlers/statistics/README.md
+++ b/backtester/eventhandlers/statistics/README.md
@@ -56,7 +56,7 @@ If the strategy config setting `DisableUSDTracking` is `false`, then the GoCrypt
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/strategies/README.md b/backtester/eventhandlers/strategies/README.md
index 86a42530..3dd87dea 100644
--- a/backtester/eventhandlers/strategies/README.md
+++ b/backtester/eventhandlers/strategies/README.md
@@ -41,7 +41,7 @@ Each strategy has a unique name and is to be added to the function `getStrategie
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/strategies/base/README.md b/backtester/eventhandlers/strategies/base/README.md
index b985c169..fae4d90f 100644
--- a/backtester/eventhandlers/strategies/base/README.md
+++ b/backtester/eventhandlers/strategies/base/README.md
@@ -24,7 +24,7 @@ The strategy base file has basic implementations of the `strategies.Handler` int
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/strategies/binancecashandcarry/README.md b/backtester/eventhandlers/strategies/binancecashandcarry/README.md
index 6c54ae7b..a2a8b1df 100644
--- a/backtester/eventhandlers/strategies/binancecashandcarry/README.md
+++ b/backtester/eventhandlers/strategies/binancecashandcarry/README.md
@@ -51,7 +51,7 @@ This strategy does support strategy customisation in the following ways:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/strategies/dollarcostaverage/README.md b/backtester/eventhandlers/strategies/dollarcostaverage/README.md
index 1ece37e2..590f7b4f 100644
--- a/backtester/eventhandlers/strategies/dollarcostaverage/README.md
+++ b/backtester/eventhandlers/strategies/dollarcostaverage/README.md
@@ -26,7 +26,7 @@ This strategy does not support customisation
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/strategies/rsi/README.md b/backtester/eventhandlers/strategies/rsi/README.md
index 994e0c80..e4a8a908 100644
--- a/backtester/eventhandlers/strategies/rsi/README.md
+++ b/backtester/eventhandlers/strategies/rsi/README.md
@@ -32,7 +32,7 @@ This strategy does support strategy customisation in the following ways:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventhandlers/strategies/top2bottom2/README.md b/backtester/eventhandlers/strategies/top2bottom2/README.md
index c4af0e86..a57393a3 100644
--- a/backtester/eventhandlers/strategies/top2bottom2/README.md
+++ b/backtester/eventhandlers/strategies/top2bottom2/README.md
@@ -35,7 +35,7 @@ This strategy does support strategy customisation in the following ways:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventtypes/README.md b/backtester/eventtypes/README.md
index 23541e7b..d8baf3ef 100644
--- a/backtester/eventtypes/README.md
+++ b/backtester/eventtypes/README.md
@@ -26,7 +26,7 @@ Below is an overview of how events are used
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventtypes/event/README.md b/backtester/eventtypes/event/README.md
index 1673c6b0..1081b439 100644
--- a/backtester/eventtypes/event/README.md
+++ b/backtester/eventtypes/event/README.md
@@ -24,7 +24,7 @@ The event type is an important base for all other events. It allows for consiste
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventtypes/fill/README.md b/backtester/eventtypes/fill/README.md
index 19ff0e75..0a38a926 100644
--- a/backtester/eventtypes/fill/README.md
+++ b/backtester/eventtypes/fill/README.md
@@ -37,7 +37,7 @@ SetAmount(float64)
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventtypes/kline/README.md b/backtester/eventtypes/kline/README.md
index 06fd8481..7ef2da01 100644
--- a/backtester/eventtypes/kline/README.md
+++ b/backtester/eventtypes/kline/README.md
@@ -24,7 +24,7 @@ The Kline event type is used to store the candle data of an individual data even
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventtypes/order/README.md b/backtester/eventtypes/order/README.md
index 2b72c61e..cda5218e 100644
--- a/backtester/eventtypes/order/README.md
+++ b/backtester/eventtypes/order/README.md
@@ -37,7 +37,7 @@ The Order Event Type is based on `common.EventHandler` and `common.Directioner`
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/eventtypes/signal/README.md b/backtester/eventtypes/signal/README.md
index fe364519..6d5f527b 100644
--- a/backtester/eventtypes/signal/README.md
+++ b/backtester/eventtypes/signal/README.md
@@ -25,7 +25,7 @@ The signal event will contain data such as price, the direction as well as the r
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/funding/README.md b/backtester/funding/README.md
index 87208a2b..d67a56e8 100644
--- a/backtester/funding/README.md
+++ b/backtester/funding/README.md
@@ -91,7 +91,7 @@ No. The already existing `CurrencySettings` will populate the funding manager wi
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/funding/trackingcurrencies/README.md b/backtester/funding/trackingcurrencies/README.md
index 3d6c4466..593f8887 100644
--- a/backtester/funding/trackingcurrencies/README.md
+++ b/backtester/funding/trackingcurrencies/README.md
@@ -45,7 +45,7 @@ This is currently not supported. If this is a feature you would like to have, pl
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/plugins/README.md b/backtester/plugins/README.md
index 41ce5f0f..c6a96554 100644
--- a/backtester/plugins/README.md
+++ b/backtester/plugins/README.md
@@ -47,7 +47,7 @@ See the following for instructions on installing Golang in WSL: [here](https://a
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/plugins/strategies/README.md b/backtester/plugins/strategies/README.md
index c35cb725..dea8ce83 100644
--- a/backtester/plugins/strategies/README.md
+++ b/backtester/plugins/strategies/README.md
@@ -43,7 +43,7 @@ Upon startup, the GoCryptoTrader Backtester will load the strategy and run it fo
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/plugins/strategies/example/README.md b/backtester/plugins/strategies/example/README.md
index b737543a..e9d4302f 100644
--- a/backtester/plugins/strategies/example/README.md
+++ b/backtester/plugins/strategies/example/README.md
@@ -50,7 +50,7 @@ Upon startup, the GoCryptoTrader Backtester will load the strategy and run it fo
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/report/README.md b/backtester/report/README.md
index 18bc2c1c..9def1e25 100644
--- a/backtester/report/README.md
+++ b/backtester/report/README.md
@@ -34,7 +34,7 @@ Output example:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/backtester/report/tpl.gohtml b/backtester/report/tpl.gohtml
index 558d9ace..92d1e614 100644
--- a/backtester/report/tpl.gohtml
+++ b/backtester/report/tpl.gohtml
@@ -3,7 +3,7 @@
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
@@ -103,7 +103,7 @@ btc markets,
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/cmd/documentation/README.md b/cmd/documentation/README.md
index d3233667..32906c6d 100644
--- a/cmd/documentation/README.md
+++ b/cmd/documentation/README.md
@@ -76,7 +76,7 @@ upper := strings.ToUpper(testString)
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/cmd/documentation/engine_templates/apiserver.tmpl b/cmd/documentation/engine_templates/apiserver.tmpl
deleted file mode 100644
index 118e0baa..00000000
--- a/cmd/documentation/engine_templates/apiserver.tmpl
+++ /dev/null
@@ -1,26 +0,0 @@
-{{define "engine apiserver" -}}
-{{template "header" .}}
-## Current Features for {{.CapitalName}}
-+ The API server subsystem is a deprecated service used to host a REST or websocket server to interact with some functions of GoCryptoTrader
-+ This subsystem is no longer maintained and it is highly encouraged to interact with GRPC endpoints directly where possible
-+ In order to modify the behaviour of the API server subsystem, you can edit the following inside your config file:
-
-### deprecatedRPC
-
-| Config | Description | Example |
-| ------ | ----------- | ------- |
-| enabled | If enabled will create a REST server which will listen to commands on the listen address | `true` |
-| listenAddress | If enabled will listen for REST requests on this address and return a JSON response | `localhost:9050` |
-
-### websocketRPC
-
-| Config | Description | Example |
-| ------ | ----------- | ------- |
-| enabled | If enabled will create a REST server which will listen to commands on the listen address | `true` |
-| listenAddress | If enabled will listen for requests on this address and return a JSON response | `localhost:9051` |
-| connectionLimit | Defines how many connections the websocket RPC server can handle simultanesoly | `1` |
-| maxAuthFailures | For authenticated endpoints, the amount of failed attempts allowed before disconnection | `3` |
-| allowInsecureOrigin | Allows use of insecure connections | `true` |
-
-{{template "donations" .}}
-{{end}}
diff --git a/cmd/documentation/root_templates/root_readme.tmpl b/cmd/documentation/root_templates/root_readme.tmpl
index 443edfbc..c59fac51 100644
--- a/cmd/documentation/root_templates/root_readme.tmpl
+++ b/cmd/documentation/root_templates/root_readme.tmpl
@@ -74,7 +74,6 @@ However, we welcome pull requests for any exchange which does not match this cri
+ Scripting support. See [gctscript](/gctscript/README.md).
+ Recent and historic trade processing. See [trades](/exchanges/trade/README.md).
+ Backtesting application. An event-driven backtesting tool to test and iterate trading strategies using historical or custom data. See [backtester](/backtester/README.md).
-+ WebGUI (discontinued).
+ Exchange HTTP mock testing. See [mock](/exchanges/mock/README.md).
+ Exchange multichain deposits and withdrawals for specific exchanges. See [multichain transfer support](/docs/MULTICHAIN_TRANSFER_SUPPORT.md).
diff --git a/cmd/documentation/sub_templates/donations.tmpl b/cmd/documentation/sub_templates/donations.tmpl
index ae3dfb1b..b0e98190 100644
--- a/cmd/documentation/sub_templates/donations.tmpl
+++ b/cmd/documentation/sub_templates/donations.tmpl
@@ -1,7 +1,7 @@
{{define "donations" -}}
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/cmd/gctcli/README.md b/cmd/gctcli/README.md
index 7ce50126..918775a9 100644
--- a/cmd/gctcli/README.md
+++ b/cmd/gctcli/README.md
@@ -1,6 +1,6 @@
# GoCryptoTrader gRPC client
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
diff --git a/cmd/websocket_client/main.go b/cmd/websocket_client/main.go
deleted file mode 100644
index a1a619bc..00000000
--- a/cmd/websocket_client/main.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package main
-
-import (
- "crypto/sha256"
- "encoding/hex"
- "errors"
- "fmt"
- "log"
- "net"
- "net/http"
- "strconv"
-
- gws "github.com/gorilla/websocket"
- "github.com/thrasher-corp/gocryptotrader/common"
- "github.com/thrasher-corp/gocryptotrader/config"
- "github.com/thrasher-corp/gocryptotrader/encoding/json"
- "github.com/thrasher-corp/gocryptotrader/exchanges/asset"
-)
-
-// Vars for the websocket client
-var (
- WSConn *gws.Conn
-)
-
-// WebsocketEvent is the struct used for websocket events
-type WebsocketEvent struct {
- Exchange string `json:"exchange,omitempty"`
- AssetType string `json:"assetType,omitempty"`
- Event string
- Data any
-}
-
-// WebsocketAuth is the struct used for a websocket auth request
-type WebsocketAuth struct {
- Username string `json:"username"`
- Password string `json:"password"`
-}
-
-// WebsocketEventResponse is the struct used for websocket event responses
-type WebsocketEventResponse struct {
- Event string `json:"event"`
- Data any `json:"data"`
- Error string `json:"error"`
-}
-
-// WebsocketOrderbookTickerRequest is a struct used for ticker and orderbook
-// requests
-type WebsocketOrderbookTickerRequest struct {
- Exchange string `json:"exchangeName"`
- Currency string `json:"currency"`
- AssetType asset.Item `json:"assetType"`
-}
-
-// SendWebsocketEvent sends a websocket event message
-func SendWebsocketEvent(event string, reqData any, result *WebsocketEventResponse) error {
- req := WebsocketEvent{
- Event: event,
- }
-
- if reqData != nil {
- req.Data = reqData
- }
-
- err := WSConn.WriteJSON(req)
- if err != nil {
- return err
- }
-
- err = WSConn.ReadJSON(&result)
- if err != nil {
- return err
- }
-
- if result.Error != "" {
- return errors.New(result.Error)
- }
-
- return nil
-}
-
-func main() {
- cfg := config.GetConfig()
- err := cfg.LoadConfig(config.File, true)
- if err != nil {
- log.Fatalf("Failed to load config file: %s", err)
- }
-
- listenAddr := cfg.RemoteControl.WebsocketRPC.ListenAddress
- wsHost := fmt.Sprintf("ws://%s/ws", net.JoinHostPort(common.ExtractHostOrDefault(listenAddr),
- strconv.Itoa(common.ExtractPortOrDefault(listenAddr))))
- log.Printf("Connecting to websocket host: %s", wsHost)
-
- var dialer gws.Dialer
- var resp *http.Response
- WSConn, resp, err = dialer.Dial(wsHost, http.Header{})
- if err != nil {
- log.Println("Unable to connect to websocket server")
- return
- }
- resp.Body.Close()
- log.Println("Connected to websocket!")
-
- log.Println("Authenticating..")
- shasum := sha256.Sum256([]byte(cfg.RemoteControl.Password))
- reqData := WebsocketAuth{
- Username: cfg.RemoteControl.Username,
- Password: hex.EncodeToString(shasum[:]),
- }
- var wsResp WebsocketEventResponse
- err = SendWebsocketEvent("auth", reqData, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Authenticated successfully")
-
- log.Println("Getting config..")
- err = SendWebsocketEvent("GetConfig", nil, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Printf("Fetched config.")
-
- dataJSON, err := json.Marshal(&wsResp.Data)
- if err != nil {
- log.Fatal(err)
- }
-
- var resultCfg config.Config
- err = json.Unmarshal(dataJSON, &resultCfg)
- if err != nil {
- log.Fatal(err)
- }
-
- log.Println("Saving config..")
- origBotName := resultCfg.Name
- resultCfg.Name = "TEST"
- err = SendWebsocketEvent("SaveConfig", resultCfg, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Saved config!")
- resultCfg.Name = origBotName
- err = SendWebsocketEvent("SaveConfig", resultCfg, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Saved config (restored original bot name)!")
-
- log.Println("Getting account info..")
- err = SendWebsocketEvent("GetAccountInfo", nil, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Got account info!")
-
- log.Println("Getting tickers..")
- err = SendWebsocketEvent("GetTickers", nil, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Got tickers!")
-
- log.Println("Getting specific ticker..")
- dataReq := WebsocketOrderbookTickerRequest{
- Exchange: "Bitfinex",
- Currency: "BTCUSD",
- AssetType: asset.Spot,
- }
-
- err = SendWebsocketEvent("GetTicker", dataReq, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Got ticker!")
-
- log.Println("Getting orderbooks..")
- err = SendWebsocketEvent("GetOrderbooks", nil, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Got orderbooks!")
-
- log.Println("Getting specific orderbook..")
- err = SendWebsocketEvent("GetOrderbook", dataReq, &wsResp)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Got orderbook!")
-
- for {
- var wsEvent WebsocketEvent
- err = WSConn.ReadJSON(&wsEvent)
- if err != nil {
- break
- }
-
- log.Printf("Recv'd: %s", wsEvent.Event)
- }
- WSConn.Close()
-}
diff --git a/common/README.md b/common/README.md
index 6d8211cf..cb0205f9 100644
--- a/common/README.md
+++ b/common/README.md
@@ -36,7 +36,7 @@ upper := strings.ToUpper(testString)
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/common/cache/README.md b/common/cache/README.md
index a13be617..17fc4463 100644
--- a/common/cache/README.md
+++ b/common/cache/README.md
@@ -1,6 +1,6 @@
# GoCryptoTrader package cache
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
@@ -48,7 +48,7 @@ func main() {
```
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/common/common.go b/common/common.go
index 1f4641a4..bc60ba0c 100644
--- a/common/common.go
+++ b/common/common.go
@@ -683,3 +683,13 @@ func (c *Counter) IncrementAndGet() int64 {
}
return newID
}
+
+// SetIfZero sets the value of p to def if p is the zero value for its type and returns true if it was set
+func SetIfZero[T comparable](p *T, def T) bool {
+ var zero T
+ if *p != zero {
+ return false
+ }
+ *p = def
+ return true
+}
diff --git a/common/common_test.go b/common/common_test.go
index ab95180d..e85eff09 100644
--- a/common/common_test.go
+++ b/common/common_test.go
@@ -680,3 +680,15 @@ func TestNilGuard(t *testing.T) {
err = NilGuard()
require.NoError(t, err, "NilGuard with no arguments must not error")
}
+
+func TestSetIfZero(t *testing.T) {
+ t.Parallel()
+ s := "hello"
+ changed := SetIfZero(&s, "world")
+ assert.False(t, changed, "SetIfZero should not change a non-zero value")
+ assert.Equal(t, "hello", s, "SetIfZero should not change a non-zero value")
+ s = ""
+ changed = SetIfZero(&s, "world")
+ assert.True(t, changed, "SetIfZero should change a zero value")
+ assert.Equal(t, "world", s, "SetIfZero should change a zero value")
+}
diff --git a/communications/README.md b/communications/README.md
index 262beb38..d76590c0 100644
--- a/communications/README.md
+++ b/communications/README.md
@@ -1,6 +1,6 @@
# GoCryptoTrader package Comms
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
@@ -39,7 +39,7 @@ to be exported out to a defined communication medium
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/communications/base/README.md b/communications/base/README.md
index af9e3051..a61b5e0c 100644
--- a/communications/base/README.md
+++ b/communications/base/README.md
@@ -26,7 +26,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/communications/slack/README.md b/communications/slack/README.md
index 676713db..0234e6fd 100644
--- a/communications/slack/README.md
+++ b/communications/slack/README.md
@@ -69,7 +69,7 @@ via Slack:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/communications/smsglobal/README.md b/communications/smsglobal/README.md
index 6f89aa54..1dbb388c 100644
--- a/communications/smsglobal/README.md
+++ b/communications/smsglobal/README.md
@@ -59,7 +59,7 @@ err := s.Connect
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/communications/smtpservice/README.md b/communications/smtpservice/README.md
index ddf3dc13..4cb88a1c 100644
--- a/communications/smtpservice/README.md
+++ b/communications/smtpservice/README.md
@@ -61,7 +61,7 @@ err := s.Connect
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/communications/telegram/README.md b/communications/telegram/README.md
index fc759835..8a942847 100644
--- a/communications/telegram/README.md
+++ b/communications/telegram/README.md
@@ -74,7 +74,7 @@ via Telegram:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/config/README.md b/config/README.md
index 2ef84644..48c8577f 100644
--- a/config/README.md
+++ b/config/README.md
@@ -263,7 +263,7 @@ servers are configured by the pool array and attempted first to last allowedDiff
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/config/config.go b/config/config.go
index cfdab519..a6fcbc9d 100644
--- a/config/config.go
+++ b/config/config.go
@@ -11,7 +11,6 @@ import (
"path/filepath"
"runtime"
"slices"
- "strconv"
"strings"
"time"
@@ -1580,46 +1579,25 @@ func (c *Config) Save(writerProvider func() (io.Writer, error)) error {
return err
}
-// CheckRemoteControlConfig checks to see if the old c.Webserver field is used
-// and migrates the existing settings to the new RemoteControl struct
+func setDefaultIfZeroWarn[T comparable](scope, name string, p *T, def T) {
+ if common.SetIfZero(p, def) {
+ log.Warnf(log.ConfigMgr, "%s field %q not set, defaulting to `%v`", scope, name, def)
+ }
+}
+
+// CheckRemoteControlConfig checks and sets default values for the remote control config
func (c *Config) CheckRemoteControlConfig() {
m.Lock()
defer m.Unlock()
- if c.Webserver != nil {
- port := common.ExtractPortOrDefault(c.Webserver.ListenAddress)
- host := common.ExtractHostOrDefault(c.Webserver.ListenAddress)
+ setDefaultIfZeroWarn("Remote control", "username", &c.RemoteControl.Username, DefaultGRPCUsername)
+ setDefaultIfZeroWarn("Remote control", "password", &c.RemoteControl.Password, DefaultGRPCPassword)
+ setDefaultIfZeroWarn("Remote control gRPC", "listen address", &c.RemoteControl.GRPC.ListenAddress, "localhost:9052")
+ setDefaultIfZeroWarn("Remote control gRPC", "gRPC proxy listen address", &c.RemoteControl.GRPC.GRPCProxyListenAddress, "localhost:9053")
- c.RemoteControl = RemoteControlConfig{
- Username: c.Webserver.AdminUsername,
- Password: c.Webserver.AdminPassword,
-
- DeprecatedRPC: DepcrecatedRPCConfig{
- Enabled: c.Webserver.Enabled,
- ListenAddress: host + ":" + strconv.Itoa(port),
- },
- }
-
- port++
- c.RemoteControl.WebsocketRPC = WebsocketRPCConfig{
- Enabled: c.Webserver.Enabled,
- ListenAddress: host + ":" + strconv.Itoa(port),
- ConnectionLimit: c.Webserver.WebsocketConnectionLimit,
- MaxAuthFailures: c.Webserver.WebsocketMaxAuthFailures,
- AllowInsecureOrigin: c.Webserver.WebsocketAllowInsecureOrigin,
- }
-
- port++
- gRPCProxyPort := port + 1
- c.RemoteControl.GRPC = GRPCConfig{
- Enabled: c.Webserver.Enabled,
- ListenAddress: host + ":" + strconv.Itoa(port),
- GRPCProxyEnabled: c.Webserver.Enabled,
- GRPCProxyListenAddress: host + ":" + strconv.Itoa(gRPCProxyPort),
- }
-
- // Then flush the old webserver settings
- c.Webserver = nil
+ if c.RemoteControl.GRPC.GRPCProxyEnabled && !c.RemoteControl.GRPC.Enabled {
+ log.Warnln(log.ConfigMgr, "gRPC proxy cannot be enabled when gRPC is disabled, disabling gRPC proxy")
+ c.RemoteControl.GRPC.GRPCProxyEnabled = false
}
}
@@ -1688,7 +1666,6 @@ func (c *Config) UpdateConfig(configPath string, newCfg *Config, dryrun bool) er
c.GlobalHTTPTimeout = newCfg.GlobalHTTPTimeout
c.Portfolio = newCfg.Portfolio
c.Communications = newCfg.Communications
- c.Webserver = newCfg.Webserver
c.Exchanges = newCfg.Exchanges
if !dryrun {
diff --git a/config/config_test.go b/config/config_test.go
index 6baf7bce..ed209c4e 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -1564,40 +1564,23 @@ func TestGetFilePath(t *testing.T) {
func TestCheckRemoteControlConfig(t *testing.T) {
t.Parallel()
-
var c Config
- c.Webserver = &WebserverConfig{
- Enabled: true,
- AdminUsername: "satoshi",
- AdminPassword: "ultrasecurepassword",
- ListenAddress: ":9050",
- WebsocketConnectionLimit: 5,
- WebsocketMaxAuthFailures: 10,
- WebsocketAllowInsecureOrigin: true,
- }
-
+ c.RemoteControl = RemoteControlConfig{}
c.CheckRemoteControlConfig()
-
- if c.RemoteControl.Username != "satoshi" ||
- c.RemoteControl.Password != "ultrasecurepassword" ||
- !c.RemoteControl.GRPC.Enabled ||
- c.RemoteControl.GRPC.ListenAddress != "localhost:9052" ||
- !c.RemoteControl.GRPC.GRPCProxyEnabled ||
- c.RemoteControl.GRPC.GRPCProxyListenAddress != "localhost:9053" ||
- !c.RemoteControl.DeprecatedRPC.Enabled ||
- c.RemoteControl.DeprecatedRPC.ListenAddress != "localhost:9050" ||
- !c.RemoteControl.WebsocketRPC.Enabled ||
- c.RemoteControl.WebsocketRPC.ListenAddress != "localhost:9051" ||
- !c.RemoteControl.WebsocketRPC.AllowInsecureOrigin ||
- c.RemoteControl.WebsocketRPC.ConnectionLimit != 5 ||
- c.RemoteControl.WebsocketRPC.MaxAuthFailures != 10 {
- t.Error("unexpected results")
- }
-
- // Now test to ensure the previous settings are flushed
- if c.Webserver != nil {
- t.Error("old webserver settings should be nil")
- }
+ assert.Equal(t, "admin", c.RemoteControl.Username, "Username default should be set correctly")
+ assert.Equal(t, "Password", c.RemoteControl.Password, "Password default should be set correctly")
+ assert.Equal(t, "localhost:9052", c.RemoteControl.GRPC.ListenAddress, "ListenAddress default should be set correctly")
+ assert.Equal(t, "localhost:9053", c.RemoteControl.GRPC.GRPCProxyListenAddress, "GRPCProxyListenAddress default should be set correctly")
+ assert.False(t, c.RemoteControl.GRPC.Enabled, "gRPC default should be set correctly")
+ assert.False(t, c.RemoteControl.GRPC.GRPCProxyEnabled, "gRPCProxyEnabled default should be set correctly")
+ c.RemoteControl.GRPC.GRPCProxyEnabled = true
+ c.CheckRemoteControlConfig()
+ assert.False(t, c.RemoteControl.GRPC.GRPCProxyEnabled, "gRPCProxyEnabled should be set to false when gRPC is not enabled")
+ c.RemoteControl.GRPC.Enabled = true
+ c.RemoteControl.GRPC.GRPCProxyEnabled = true
+ c.CheckRemoteControlConfig()
+ assert.True(t, c.RemoteControl.GRPC.Enabled, "gRPC should be true")
+ assert.True(t, c.RemoteControl.GRPC.GRPCProxyEnabled, "gRPCProxyEnabled should be true when gRPC is enabled")
}
func TestCheckConfig(t *testing.T) {
diff --git a/config/config_types.go b/config/config_types.go
index 2c8ee22c..8b4f0e8a 100644
--- a/config/config_types.go
+++ b/config/config_types.go
@@ -69,6 +69,8 @@ const (
DefaultUnsetAPIKey = "Key"
DefaultUnsetAPISecret = "Secret"
DefaultUnsetAccountPlan = "accountPlan"
+ DefaultGRPCUsername = "admin"
+ DefaultGRPCPassword = "Password"
)
// Public errors exported by this package
@@ -111,7 +113,6 @@ type Config struct {
BankAccounts []banking.Account `json:"bankAccounts"`
// Deprecated config settings, will be removed at a future date
- Webserver *WebserverConfig `json:"webserver,omitempty"`
CurrencyPairFormat *currency.PairFormat `json:"currencyPairFormat,omitempty"`
FiatDisplayCurrency *currency.Code `json:"fiatDispayCurrency,omitempty"`
Cryptocurrencies *currency.Currencies `json:"cryptocurrencies,omitempty"`
@@ -216,8 +217,10 @@ type Exchange struct {
// Profiler defines the profiler configuration to enable pprof
type Profiler struct {
- Enabled bool `json:"enabled"`
- MutexProfileFraction int `json:"mutex_profile_fraction"`
+ Enabled bool `json:"enabled"`
+ MutexProfileFraction int `json:"mutex_profile_fraction"`
+ ListenAddress string `json:"listen_address"`
+ BlockProfileRate int `json:"block_profile_rate"`
}
// NTPClientConfig defines a network time protocol configuration to allow for
@@ -239,40 +242,11 @@ type GRPCConfig struct {
TimeInNanoSeconds bool `json:"timeInNanoSeconds"`
}
-// DepcrecatedRPCConfig stores the deprecatedRPCConfig settings
-type DepcrecatedRPCConfig struct {
- Enabled bool `json:"enabled"`
- ListenAddress string `json:"listenAddress"`
-}
-
-// WebsocketRPCConfig stores the websocket config info
-type WebsocketRPCConfig struct {
- Enabled bool `json:"enabled"`
- ListenAddress string `json:"listenAddress"`
- ConnectionLimit int `json:"connectionLimit"`
- MaxAuthFailures int `json:"maxAuthFailures"`
- AllowInsecureOrigin bool `json:"allowInsecureOrigin"`
-}
-
// RemoteControlConfig stores the RPC services config
type RemoteControlConfig struct {
- Username string `json:"username"`
- Password string `json:"password"`
-
- GRPC GRPCConfig `json:"gRPC"`
- DeprecatedRPC DepcrecatedRPCConfig `json:"deprecatedRPC"`
- WebsocketRPC WebsocketRPCConfig `json:"websocketRPC"`
-}
-
-// WebserverConfig stores the old webserver config
-type WebserverConfig struct {
- Enabled bool `json:"enabled"`
- AdminUsername string `json:"adminUsername"`
- AdminPassword string `json:"adminPassword"`
- ListenAddress string `json:"listenAddress"`
- WebsocketConnectionLimit int `json:"websocketConnectionLimit"`
- WebsocketMaxAuthFailures int `json:"websocketMaxAuthFailures"`
- WebsocketAllowInsecureOrigin bool `json:"websocketAllowInsecureOrigin"`
+ Username string `json:"username"`
+ Password string `json:"password"`
+ GRPC GRPCConfig `json:"gRPC"`
}
// Post holds the bot configuration data
diff --git a/config/versions/register.go b/config/versions/register.go
index 8af8927d..8cd896ef 100644
--- a/config/versions/register.go
+++ b/config/versions/register.go
@@ -3,6 +3,7 @@ package versions
import (
v0 "github.com/thrasher-corp/gocryptotrader/config/versions/v0"
v1 "github.com/thrasher-corp/gocryptotrader/config/versions/v1"
+ v10 "github.com/thrasher-corp/gocryptotrader/config/versions/v10"
v2 "github.com/thrasher-corp/gocryptotrader/config/versions/v2"
v3 "github.com/thrasher-corp/gocryptotrader/config/versions/v3"
v4 "github.com/thrasher-corp/gocryptotrader/config/versions/v4"
@@ -24,4 +25,5 @@ func init() {
Manager.registerVersion(7, &v7.Version{})
Manager.registerVersion(8, &v8.Version{})
Manager.registerVersion(9, &v9.Version{})
+ Manager.registerVersion(10, &v10.Version{})
}
diff --git a/config/versions/v10/v10.go b/config/versions/v10/v10.go
new file mode 100644
index 00000000..02aedc4d
--- /dev/null
+++ b/config/versions/v10/v10.go
@@ -0,0 +1,22 @@
+package v10
+
+import (
+ "context"
+
+ "github.com/buger/jsonparser"
+)
+
+// Version implements ConfigVersion
+type Version struct{}
+
+// UpgradeConfig checks and removes the deprecatedRPC and websocketRPC fields from the remoteControl config
+func (*Version) UpgradeConfig(_ context.Context, e []byte) ([]byte, error) {
+ e = jsonparser.Delete(e, "remoteControl", "deprecatedRPC")
+ e = jsonparser.Delete(e, "remoteControl", "websocketRPC")
+ return e, nil
+}
+
+// DowngradeConfig is a no-op. It does not restore deprecatedRPC or websocketRPC on downgrade as their removal is permanent
+func (*Version) DowngradeConfig(_ context.Context, e []byte) ([]byte, error) {
+ return e, nil
+}
diff --git a/config/versions/v10/v10_test.go b/config/versions/v10/v10_test.go
new file mode 100644
index 00000000..3542b15b
--- /dev/null
+++ b/config/versions/v10/v10_test.go
@@ -0,0 +1,27 @@
+package v10_test
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ v10 "github.com/thrasher-corp/gocryptotrader/config/versions/v10"
+)
+
+func TestUpgradeConfig(t *testing.T) {
+ t.Parallel()
+ in := []byte(`{"remoteControl":{"enabled":true,"deprecatedRPC":{"enabled":true,"listenAddress":"localhost:9050"},"websocketRPC":{"enabled":true,"listenAddress":"localhost:9051","connectionLimit":1,"maxAuthFailures":3,"allowInsecureOrigin":true}}}`)
+ out, err := new(v10.Version).UpgradeConfig(t.Context(), in)
+ require.NoError(t, err)
+ const expected = `{"remoteControl":{"enabled":true}}`
+ assert.JSONEq(t, expected, string(out))
+}
+
+func TestDowngradeConfig(t *testing.T) {
+ t.Parallel()
+ in := []byte("meow, moocow, woof, quack")
+ out, err := new(v10.Version).DowngradeConfig(t.Context(), bytes.Clone(in))
+ require.NoError(t, err)
+ assert.Equal(t, out, in)
+}
diff --git a/config_example.json b/config_example.json
index 4809156e..6fea8223 100644
--- a/config_example.json
+++ b/config_example.json
@@ -72,7 +72,9 @@
},
"profiler": {
"enabled": false,
- "mutex_profile_fraction": 0
+ "mutex_profile_fraction": 0,
+ "listen_address": "localhost:8085",
+ "block_profile_rate": 0
},
"ntpclient": {
"enabled": 0,
@@ -207,17 +209,6 @@
"grpcProxyEnabled": false,
"grpcProxyListenAddress": "localhost:9053",
"timeInNanoSeconds": false
- },
- "deprecatedRPC": {
- "enabled": true,
- "listenAddress": "localhost:9050"
- },
- "websocketRPC": {
- "enabled": true,
- "listenAddress": "localhost:9051",
- "connectionLimit": 1,
- "maxAuthFailures": 3,
- "allowInsecureOrigin": true
}
},
"portfolioAddresses": {
diff --git a/currency/README.md b/currency/README.md
index 1c41c59e..41f1b6f3 100644
--- a/currency/README.md
+++ b/currency/README.md
@@ -28,7 +28,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/currency/forexprovider/README.md b/currency/forexprovider/README.md
index 43aa3e31..0da0a63e 100644
--- a/currency/forexprovider/README.md
+++ b/currency/forexprovider/README.md
@@ -28,7 +28,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/currency/forexprovider/base/README.md b/currency/forexprovider/base/README.md
index 51ae928f..3e0dde3a 100644
--- a/currency/forexprovider/base/README.md
+++ b/currency/forexprovider/base/README.md
@@ -25,7 +25,7 @@ providers.
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/currency/forexprovider/currencyconverterapi/README.md b/currency/forexprovider/currencyconverterapi/README.md
index 54ad3418..d3d6fe7d 100644
--- a/currency/forexprovider/currencyconverterapi/README.md
+++ b/currency/forexprovider/currencyconverterapi/README.md
@@ -54,7 +54,7 @@ mapstringfloat, err := c.GetRates("USD", "EUR,CHY")
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/currency/forexprovider/currencylayer/README.md b/currency/forexprovider/currencylayer/README.md
index bed182a2..6b625708 100644
--- a/currency/forexprovider/currencylayer/README.md
+++ b/currency/forexprovider/currencylayer/README.md
@@ -54,7 +54,7 @@ mapstringfloat, err := c.GetRates("USD", "EUR,CHY")
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/currency/forexprovider/exchangeratesapi.io/README.md b/currency/forexprovider/exchangeratesapi.io/README.md
index 23ad201b..7694b98e 100644
--- a/currency/forexprovider/exchangeratesapi.io/README.md
+++ b/currency/forexprovider/exchangeratesapi.io/README.md
@@ -54,7 +54,7 @@ mapstringfloat, err := c.GetRates("USD", "EUR,CHY")
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/currency/forexprovider/fixer.io/README.md b/currency/forexprovider/fixer.io/README.md
index e0c1edd6..9cae53d3 100644
--- a/currency/forexprovider/fixer.io/README.md
+++ b/currency/forexprovider/fixer.io/README.md
@@ -54,7 +54,7 @@ mapstringfloat, err := c.GetRates("USD", "EUR,CHY")
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/currency/forexprovider/openexchangerates/README.md b/currency/forexprovider/openexchangerates/README.md
index 61e4fc10..1258e4c3 100644
--- a/currency/forexprovider/openexchangerates/README.md
+++ b/currency/forexprovider/openexchangerates/README.md
@@ -54,7 +54,7 @@ mapstringfloat, err := c.GetRates("USD", "EUR,CHY")
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/database/README.md b/database/README.md
index 676bf690..c8c1415a 100644
--- a/database/README.md
+++ b/database/README.md
@@ -1,6 +1,6 @@
# GoCryptoTrader package Database
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
@@ -152,7 +152,7 @@ A helper tool [cmd/dbseed](../cmd/dbseed/README.md) has been created for assisti
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/docker-compose.yml b/docker-compose.yml
index 87c18d76..c0fe2492 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,18 +1,8 @@
version: '3'
services:
-
- web:
- build: ./web
- depends_on:
- - daemon
- ports:
- - "9054:80"
-
daemon:
build: .
ports:
- - "9050:9050"
- - "9051:9051"
- "9052:9052"
- "9053:9053"
diff --git a/docs/ADD_NEW_EXCHANGE.md b/docs/ADD_NEW_EXCHANGE.md
index 059259f0..b772228d 100644
--- a/docs/ADD_NEW_EXCHANGE.md
+++ b/docs/ADD_NEW_EXCHANGE.md
@@ -1,6 +1,6 @@
# GoCryptoTrader ADD NEW EXCHANGE
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
diff --git a/docs/EXCHANGE_API.md b/docs/EXCHANGE_API.md
index 57637bc8..9553d0f5 100644
--- a/docs/EXCHANGE_API.md
+++ b/docs/EXCHANGE_API.md
@@ -1,6 +1,6 @@
# GoCryptoTrader Unified API
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
diff --git a/docs/FILES.md b/docs/FILES.md
index 7615eaa6..d5cdbae4 100644
--- a/docs/FILES.md
+++ b/docs/FILES.md
@@ -1,6 +1,6 @@
# GoCryptoTrader File Hierarchy
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
diff --git a/docs/OHLCV.md b/docs/OHLCV.md
index d691e303..d34c8b50 100644
--- a/docs/OHLCV.md
+++ b/docs/OHLCV.md
@@ -1,6 +1,6 @@
# GoCryptoTrader OHLCV support
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
diff --git a/docs/README.md b/docs/README.md
index 2762522c..d2531352 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,6 +1,6 @@
# GoCryptoTrader Documentation
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
diff --git a/web/src/assets/donate.png b/docs/assets/donate.png
similarity index 100%
rename from web/src/assets/donate.png
rename to docs/assets/donate.png
diff --git a/web/src/assets/images/gctlogo-notext.svg b/docs/assets/gctlogo-notext.svg
similarity index 100%
rename from web/src/assets/images/gctlogo-notext.svg
rename to docs/assets/gctlogo-notext.svg
diff --git a/web/src/assets/images/page-logo.png b/docs/assets/page-logo.png
similarity index 100%
rename from web/src/assets/images/page-logo.png
rename to docs/assets/page-logo.png
diff --git a/engine/apiserver.go b/engine/apiserver.go
deleted file mode 100644
index 00769f76..00000000
--- a/engine/apiserver.go
+++ /dev/null
@@ -1,918 +0,0 @@
-package engine
-
-import (
- "context"
- "crypto/sha256"
- "encoding/hex"
- "errors"
- "fmt"
- "net/http"
- "net/http/pprof"
- "runtime"
- "strconv"
- "strings"
- "sync/atomic"
- "time"
-
- "github.com/gorilla/mux"
- gws "github.com/gorilla/websocket"
- "github.com/thrasher-corp/gocryptotrader/common"
- "github.com/thrasher-corp/gocryptotrader/config"
- "github.com/thrasher-corp/gocryptotrader/currency"
- "github.com/thrasher-corp/gocryptotrader/encoding/json"
- "github.com/thrasher-corp/gocryptotrader/exchanges/asset"
- "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
- "github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
- "github.com/thrasher-corp/gocryptotrader/log"
-)
-
-// setupAPIServerManager checks and creates an api server manager
-func setupAPIServerManager(remoteConfig *config.RemoteControlConfig, pprofConfig *config.Profiler, exchangeManager iExchangeManager, bot iBot, portfolioManager iPortfolioManager, configPath string) (*apiServerManager, error) {
- if remoteConfig == nil {
- return nil, errNilRemoteConfig
- }
- if pprofConfig == nil {
- return nil, errNilPProfConfig
- }
- if exchangeManager == nil {
- return nil, errNilExchangeManager
- }
- if bot == nil {
- return nil, errNilBot
- }
- if configPath == "" {
- return nil, errEmptyConfigPath
- }
- return &apiServerManager{
- remoteConfig: remoteConfig,
- pprofConfig: pprofConfig,
- restListenAddress: remoteConfig.DeprecatedRPC.ListenAddress,
- websocketListenAddress: remoteConfig.WebsocketRPC.ListenAddress,
- exchangeManager: exchangeManager,
- bot: bot,
- gctConfigPath: configPath,
- portfolioManager: portfolioManager,
- }, nil
-}
-
-// IsRESTServerRunning safely checks whether the subsystem is running
-func (m *apiServerManager) IsRESTServerRunning() bool {
- if m == nil {
- return false
- }
- return atomic.LoadInt32(&m.restStarted) == 1
-}
-
-// IsWebsocketServerRunning safely checks whether the subsystem is running
-func (m *apiServerManager) IsWebsocketServerRunning() bool {
- if m == nil {
- return false
- }
- return atomic.LoadInt32(&m.websocketStarted) == 1
-}
-
-// StopRESTServer attempts to shutdown the subsystem
-func (m *apiServerManager) StopRESTServer() error {
- if m == nil {
- return fmt.Errorf("api server %w", ErrNilSubsystem)
- }
- if !atomic.CompareAndSwapInt32(&m.restStarted, 1, 0) {
- return fmt.Errorf("apiserver deprecated server %w", ErrSubSystemNotStarted)
- }
- err := m.restHTTPServer.Shutdown(context.Background())
- if err != nil && !errors.Is(err, http.ErrServerClosed) {
- return err
- }
- m.wgRest.Wait()
- m.restRouter = nil
- return nil
-}
-
-func (m *apiServerManager) StopWebsocketServer() error {
- if m == nil {
- return fmt.Errorf("api server %w", ErrNilSubsystem)
- }
- if !atomic.CompareAndSwapInt32(&m.websocketStarted, 1, 0) {
- return fmt.Errorf("apiserver websocket server %w", ErrSubSystemNotStarted)
- }
-
- err := m.websocketHTTPServer.Shutdown(context.Background())
- if err != nil && !errors.Is(err, http.ErrServerClosed) {
- return err
- }
- m.websocketRouter = nil
- m.websocketHub = nil
- m.wgWebsocket.Wait()
- m.websocketHTTPServer = nil
- return nil
-}
-
-// newRouter takes in the exchange interfaces and returns a new multiplexer
-// router
-func (m *apiServerManager) newRouter(isREST bool) *mux.Router {
- router := mux.NewRouter().StrictSlash(true)
- var routes []Route
- if common.ExtractPortOrDefault(m.websocketListenAddress) == 80 {
- m.websocketListenAddress = common.ExtractHostOrDefault(m.websocketListenAddress)
- } else {
- m.websocketListenAddress = common.ExtractHostOrDefault(m.websocketListenAddress) + ":" +
- strconv.Itoa(common.ExtractPortOrDefault(m.websocketListenAddress))
- }
-
- if isREST {
- routes = []Route{
- {"", http.MethodGet, "/", m.getIndex},
- {"GetAllSettings", http.MethodGet, "/config/all", m.restGetAllSettings},
- {"SaveAllSettings", http.MethodPost, "/config/all/save", m.restSaveAllSettings},
- {"AllEnabledAccountInfo", http.MethodGet, "/exchanges/enabled/accounts/all", m.restGetAllEnabledAccountInfo},
- {"AllActiveExchangesAndCurrencies", http.MethodGet, "/exchanges/enabled/latest/all", m.restGetAllActiveTickers},
- {"GetPortfolio", http.MethodGet, "/portfolio/all", m.restGetPortfolio},
- {"AllActiveExchangesAndOrderbooks", http.MethodGet, "/exchanges/orderbook/latest/all", m.restGetAllActiveOrderbooks},
- }
-
- if m.pprofConfig.Enabled {
- if m.pprofConfig.MutexProfileFraction > 0 {
- runtime.SetMutexProfileFraction(m.pprofConfig.MutexProfileFraction)
- }
- log.Debugf(log.RESTSys,
- "HTTP Go performance profiler (pprof) endpoint enabled: http://%s:%d/debug/pprof/\n",
- common.ExtractHostOrDefault(m.websocketListenAddress),
- common.ExtractPortOrDefault(m.websocketListenAddress),
- )
- router.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index)
- }
- } else {
- routes = []Route{
- {"ws", http.MethodGet, "/ws", m.WebsocketClientHandler},
- }
- }
-
- for _, route := range routes {
- router.
- Methods(route.Method).
- Path(route.Pattern).
- Name(route.Name).
- Handler(restLogger(route.HandlerFunc, route.Name)).
- Host(m.websocketListenAddress)
- }
- return router
-}
-
-// StartRESTServer starts a REST handler
-func (m *apiServerManager) StartRESTServer() error {
- if !atomic.CompareAndSwapInt32(&m.restStarted, 0, 1) {
- return fmt.Errorf("rest server %w", errAlreadyRunning)
- }
- if !m.remoteConfig.DeprecatedRPC.Enabled {
- atomic.StoreInt32(&m.restStarted, 0)
- return fmt.Errorf("rest %w", errServerDisabled)
- }
- log.Debugf(log.RESTSys,
- "Deprecated RPC handler support enabled. Listen URL: http://%s:%d\n",
- common.ExtractHostOrDefault(m.restListenAddress),
- common.ExtractPortOrDefault(m.restListenAddress),
- )
- m.restRouter = m.newRouter(true)
- if m.restHTTPServer == nil {
- m.restHTTPServer = &http.Server{
- Addr: m.restListenAddress,
- Handler: m.restRouter,
- ReadHeaderTimeout: time.Minute,
- }
- }
- m.wgRest.Go(func() {
- err := m.restHTTPServer.ListenAndServe()
- if err != nil {
- atomic.StoreInt32(&m.restStarted, 0)
- if !errors.Is(err, http.ErrServerClosed) {
- log.Errorln(log.APIServerMgr, err)
- }
- }
- })
- return nil
-}
-
-// restLogger logs the requests internally
-func restLogger(inner http.Handler, name string) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- start := time.Now()
- inner.ServeHTTP(w, r)
-
- log.Debugf(log.RESTSys,
- "%s\t%s\t%s\t%s",
- r.Method,
- r.RequestURI,
- name,
- time.Since(start),
- )
- })
-}
-
-// writeResponse outputs a JSON response of the response interface
-func writeResponse(w http.ResponseWriter, response any) error {
- w.Header().Set("Content-Type", "application/json; charset=UTF-8")
- w.WriteHeader(http.StatusOK)
- return json.NewEncoder(w).Encode(response)
-}
-
-// handleError prints the REST method and error
-func handleError(method string, err error) {
- log.Errorf(log.APIServerMgr, "RESTful %s: handler failed to send JSON response. Error %s\n",
- method, err)
-}
-
-// restGetAllSettings replies to a request with an encoded JSON response about the
-// trading Bots configuration.
-func (m *apiServerManager) restGetAllSettings(w http.ResponseWriter, r *http.Request) {
- err := writeResponse(w, config.GetConfig())
- if err != nil {
- handleError(r.Method, err)
- }
-}
-
-// restSaveAllSettings saves all current settings from request body as a JSON
-// document then reloads state and returns the settings
-func (m *apiServerManager) restSaveAllSettings(w http.ResponseWriter, r *http.Request) {
- // Get the data from the request
- decoder := json.NewDecoder(r.Body)
- var responseData config.Post
- err := decoder.Decode(&responseData)
- if err != nil {
- handleError(r.Method, err)
- }
- // Save change the settings
- cfg := config.GetConfig()
- err = cfg.UpdateConfig(m.gctConfigPath, &responseData.Data, false)
- if err != nil {
- handleError(r.Method, err)
- }
-
- err = writeResponse(w, cfg)
- if err != nil {
- handleError(r.Method, err)
- }
- err = m.bot.SetupExchanges()
- if err != nil {
- handleError(r.Method, err)
- }
-}
-
-// restGetAllActiveOrderbooks returns all enabled exchange orderbooks
-func (m *apiServerManager) restGetAllActiveOrderbooks(w http.ResponseWriter, r *http.Request) {
- var response AllEnabledExchangeOrderbooks
- response.Data = getAllActiveOrderbooks(m.exchangeManager)
- err := writeResponse(w, response)
- if err != nil {
- handleError(r.Method, err)
- }
-}
-
-// restGetPortfolio returns the Bot portfolio manager
-func (m *apiServerManager) restGetPortfolio(w http.ResponseWriter, r *http.Request) {
- result := m.portfolioManager.GetPortfolioSummary()
- err := writeResponse(w, result)
- if err != nil {
- handleError(r.Method, err)
- }
-}
-
-// restGetAllActiveTickers returns all active tickers
-func (m *apiServerManager) restGetAllActiveTickers(w http.ResponseWriter, r *http.Request) {
- var response AllEnabledExchangeCurrencies
- response.Data = getAllActiveTickers(m.exchangeManager)
- err := writeResponse(w, response)
- if err != nil {
- handleError(r.Method, err)
- }
-}
-
-// restGetAllEnabledAccountInfo via get request returns JSON response of account
-// info
-func (m *apiServerManager) restGetAllEnabledAccountInfo(w http.ResponseWriter, r *http.Request) {
- response := getAllActiveAccounts(m.exchangeManager)
- err := writeResponse(w, response)
- if err != nil {
- handleError(r.Method, err)
- }
-}
-
-// getIndex returns an HTML snippet for when a user requests the index URL
-func (m *apiServerManager) getIndex(w http.ResponseWriter, _ *http.Request) {
- _, err := fmt.Fprint(w, restIndexResponse)
- if err != nil {
- log.Errorln(log.APIServerMgr, err)
- }
- w.WriteHeader(http.StatusOK)
-}
-
-// getAllActiveOrderbooks returns all enabled exchanges orderbooks
-func getAllActiveOrderbooks(m iExchangeManager) []EnabledExchangeOrderbooks {
- exchanges, err := m.GetExchanges()
- if err != nil {
- log.Errorf(log.APIServerMgr, "Cannot get exchanges: %v", err)
- return nil
- }
-
- orderbookData := make([]EnabledExchangeOrderbooks, 0, len(exchanges))
- for _, e := range exchanges {
- var orderbooks []orderbook.Book
- for _, a := range e.GetAssetTypes(true) {
- pairs, err := e.GetEnabledPairs(a)
- if err != nil {
- log.Errorf(log.APIServerMgr, "Exchange %s could not retrieve enabled currencies. Err: %s\n", e.GetName(), err)
- continue
- }
- for _, pair := range pairs {
- ob, err := e.GetCachedOrderbook(pair, a)
- if err != nil {
- log.Errorf(log.APIServerMgr, "Exchange %s failed to retrieve %s orderbook. Err: %s\n", e.GetName(), pair, err)
- continue
- }
- orderbooks = append(orderbooks, *ob)
- }
- }
- orderbookData = append(orderbookData, EnabledExchangeOrderbooks{ExchangeName: e.GetName(), ExchangeValues: orderbooks})
- }
- return orderbookData
-}
-
-// getAllActiveTickers returns all enabled exchanges tickers
-func getAllActiveTickers(m iExchangeManager) []EnabledExchangeCurrencies {
- exchanges, err := m.GetExchanges()
- if err != nil {
- log.Errorf(log.APIServerMgr, "Cannot get exchanges: %v", err)
- return nil
- }
-
- exchangeTickers := make([]EnabledExchangeCurrencies, 0, len(exchanges))
- for _, e := range exchanges {
- var tickers []*ticker.Price
- for _, a := range e.GetAssetTypes(true) {
- pairs, err := e.GetEnabledPairs(a)
- if err != nil {
- log.Errorf(log.APIServerMgr, "Exchange %s could not retrieve enabled currencies. Err: %s\n", e.GetName(), err)
- continue
- }
- for _, pair := range pairs {
- t, err := e.GetCachedTicker(pair, a)
- if err != nil {
- log.Errorf(log.APIServerMgr, "Exchange %s failed to retrieve %s ticker. Err: %s\n", e.GetName(), pair.String(), err)
- continue
- }
- tickers = append(tickers, t)
- }
- }
- exchangeTickers = append(exchangeTickers, EnabledExchangeCurrencies{ExchangeName: e.GetName(), ExchangeValues: tickers})
- }
- return exchangeTickers
-}
-
-// getAllActiveAccounts returns all enabled exchanges accounts
-func getAllActiveAccounts(m iExchangeManager) []AllEnabledExchangeAccounts {
- exchanges, err := m.GetExchanges()
- if err != nil {
- log.Errorf(log.APIServerMgr, "Cannot get exchanges: %v", err)
- return nil
- }
-
- accounts := make([]AllEnabledExchangeAccounts, 0, len(exchanges))
- for x := range exchanges {
- assets := exchanges[x].GetAssetTypes(true)
- exchName := exchanges[x].GetName()
- var exchangeAccounts AllEnabledExchangeAccounts
- for y := range assets {
- a, err := exchanges[x].GetCachedAccountInfo(context.TODO(), assets[y])
- if err != nil {
- log.Errorf(log.APIServerMgr,
- "Exchange %s failed to retrieve %s ticker. Err: %s\n",
- exchName,
- assets[y],
- err)
- continue
- }
- exchangeAccounts.Data = append(exchangeAccounts.Data, a)
- }
- accounts = append(accounts, exchangeAccounts)
- }
- return accounts
-}
-
-// StartWebsocketServer starts a Websocket handler
-func (m *apiServerManager) StartWebsocketServer() error {
- if !atomic.CompareAndSwapInt32(&m.websocketStarted, 0, 1) {
- return fmt.Errorf("websocket server %w", errAlreadyRunning)
- }
- if !m.remoteConfig.WebsocketRPC.Enabled {
- atomic.StoreInt32(&m.websocketStarted, 0)
- return fmt.Errorf("websocket %w", errServerDisabled)
- }
- log.Debugf(log.APIServerMgr,
- "Websocket RPC support enabled. Listen URL: ws://%s:%d/ws\n",
- common.ExtractHostOrDefault(m.websocketListenAddress),
- common.ExtractPortOrDefault(m.websocketListenAddress),
- )
- m.websocketRouter = m.newRouter(false)
- if m.websocketHTTPServer == nil {
- m.websocketHTTPServer = &http.Server{
- Addr: m.websocketListenAddress,
- Handler: m.websocketRouter,
- ReadHeaderTimeout: time.Minute,
- }
- }
-
- m.wgWebsocket.Go(func() {
- err := m.websocketHTTPServer.ListenAndServe()
- if err != nil {
- atomic.StoreInt32(&m.websocketStarted, 0)
- if !errors.Is(err, http.ErrServerClosed) {
- log.Errorln(log.APIServerMgr, err)
- }
- }
- })
- return nil
-}
-
-// newWebsocketHub Creates a new websocket hub
-func newWebsocketHub() *websocketHub {
- return &websocketHub{
- Broadcast: make(chan []byte),
- Register: make(chan *websocketClient),
- Unregister: make(chan *websocketClient),
- Clients: make(map[*websocketClient]bool),
- }
-}
-
-func (h *websocketHub) run() {
- for {
- select {
- case client := <-h.Register:
- h.Clients[client] = true
- case client := <-h.Unregister:
- if _, ok := h.Clients[client]; ok {
- log.Debugln(log.APIServerMgr, "websocket: disconnected client")
- delete(h.Clients, client)
- close(client.Send)
- }
- case message := <-h.Broadcast:
- for client := range h.Clients {
- select {
- case client.Send <- message:
- default:
- log.Debugln(log.APIServerMgr, "websocket: disconnected client")
- close(client.Send)
- delete(h.Clients, client)
- }
- }
- }
- }
-}
-
-// SendWebsocketMessage sends a websocket event to the client
-func (c *websocketClient) SendWebsocketMessage(evt any) error {
- data, err := json.Marshal(evt)
- if err != nil {
- log.Errorf(log.APIServerMgr, "websocket: failed to send message: %s\n", err)
- return err
- }
-
- c.Send <- data
- return nil
-}
-
-func (c *websocketClient) read() {
- defer func() {
- c.Hub.Unregister <- c
- conErr := c.Conn.Close()
- if conErr != nil {
- log.Errorln(log.APIServerMgr, conErr)
- }
- }()
-
- for {
- msgType, message, err := c.Conn.ReadMessage()
- if err != nil {
- if gws.IsUnexpectedCloseError(err, gws.CloseGoingAway, gws.CloseAbnormalClosure) {
- log.Errorf(log.APIServerMgr, "websocket: client disconnected, err: %s\n", err)
- }
- break
- }
-
- if msgType == gws.TextMessage {
- var evt WebsocketEvent
- err := json.Unmarshal(message, &evt)
- if err != nil {
- log.Errorf(log.APIServerMgr, "websocket: failed to decode JSON sent from client %s\n", err)
- continue
- }
-
- if evt.Event == "" {
- log.Warnln(log.APIServerMgr, "websocket: client sent a blank event, disconnecting")
- continue
- }
-
- dataJSON, err := json.Marshal(evt.Data)
- if err != nil {
- log.Errorln(log.APIServerMgr, "websocket: client sent data we couldn't JSON decode")
- break
- }
-
- req := strings.ToLower(evt.Event)
- log.Debugf(log.APIServerMgr, "websocket: request received: %s\n", req)
-
- result, ok := wsHandlers[req]
- if !ok {
- log.Debugln(log.APIServerMgr, "websocket: unsupported event")
- continue
- }
-
- if result.authRequired && !c.Authenticated {
- log.Warnf(log.APIServerMgr, "Websocket: request %s failed due to unauthenticated request on an authenticated API\n", evt.Event)
- err = c.SendWebsocketMessage(WebsocketEventResponse{Event: evt.Event, Error: "unauthorised request on authenticated API"})
- if err != nil {
- log.Errorln(log.APIServerMgr, err)
- }
- continue
- }
-
- err = result.handler(c, dataJSON)
- if err != nil {
- log.Errorf(log.APIServerMgr, "websocket: request %s failed. Error %s\n", evt.Event, err)
- continue
- }
- }
- }
-}
-
-func (c *websocketClient) write() {
- defer func() {
- err := c.Conn.Close()
- if err != nil {
- log.Errorln(log.APIServerMgr, err)
- }
- }()
- for {
- message, ok := <-c.Send
- if !ok {
- err := c.Conn.WriteMessage(gws.CloseMessage, []byte{})
- if err != nil {
- log.Errorln(log.APIServerMgr, err)
- }
- log.Debugln(log.APIServerMgr, "websocket: hub closed the channel")
- return
- }
-
- w, err := c.Conn.NextWriter(gws.TextMessage)
- if err != nil {
- log.Errorf(log.APIServerMgr, "websocket: failed to create new io.writeCloser: %s\n", err)
- return
- }
- _, err = w.Write(message)
- if err != nil {
- log.Errorln(log.APIServerMgr, err)
- }
-
- // Add queued chat messages to the current websocket message
- n := len(c.Send)
- for range n {
- _, err = w.Write(<-c.Send)
- if err != nil {
- log.Errorln(log.APIServerMgr, err)
- }
- }
-
- if err := w.Close(); err != nil {
- log.Errorf(log.APIServerMgr, "websocket: failed to close io.WriteCloser: %s\n", err)
- return
- }
- }
-}
-
-// StartWebsocketHandler starts the websocket hub and routine which
-// handles clients
-func StartWebsocketHandler() {
- if !wsHubStarted {
- wsHubStarted = true
- wsHub = newWebsocketHub()
- go wsHub.run()
- }
-}
-
-// BroadcastWebsocketMessage meow
-func BroadcastWebsocketMessage(evt WebsocketEvent) error {
- if !wsHubStarted {
- return ErrWebsocketServiceNotRunning
- }
-
- data, err := json.Marshal(evt)
- if err != nil {
- return err
- }
-
- wsHub.Broadcast <- data
- return nil
-}
-
-// WebsocketClientHandler upgrades the HTTP connection to a websocket
-// compatible one
-func (m *apiServerManager) WebsocketClientHandler(w http.ResponseWriter, r *http.Request) {
- if !wsHubStarted {
- StartWebsocketHandler()
- }
-
- connectionLimit := m.remoteConfig.WebsocketRPC.ConnectionLimit
- numClients := len(wsHub.Clients)
-
- if numClients >= connectionLimit {
- log.Warnf(log.APIServerMgr,
- "websocket: client rejected due to websocket client limit reached. Number of clients %d. Limit %d.\n",
- numClients, connectionLimit)
- w.WriteHeader(http.StatusForbidden)
- return
- }
-
- upgrader := gws.Upgrader{
- WriteBufferSize: 1024,
- ReadBufferSize: 1024,
- }
-
- // Allow insecure origin if the Origin request header is present and not
- // equal to the Host request header. Default to false
- if m.remoteConfig.WebsocketRPC.AllowInsecureOrigin {
- upgrader.CheckOrigin = func(*http.Request) bool { return true }
- }
-
- conn, err := upgrader.Upgrade(w, r, nil)
- if err != nil {
- log.Errorln(log.APIServerMgr, err)
- return
- }
-
- client := &websocketClient{
- Hub: wsHub,
- Conn: conn,
- Send: make(chan []byte, 1024),
- maxAuthFailures: m.remoteConfig.WebsocketRPC.MaxAuthFailures,
- username: m.remoteConfig.Username,
- password: m.remoteConfig.Password,
- configPath: m.gctConfigPath,
- exchangeManager: m.exchangeManager,
- bot: m.bot,
- portfolioManager: m.portfolioManager,
- }
-
- client.Hub.Register <- client
- log.Debugf(log.APIServerMgr,
- "websocket: client connected. Connected clients: %d. Limit %d.\n",
- numClients+1, connectionLimit)
-
- go client.read()
- go client.write()
-}
-
-func wsAuth(client *websocketClient, data any) error {
- d, ok := data.([]byte)
- if !ok {
- return common.GetTypeAssertError("[]byte", data)
- }
-
- wsResp := WebsocketEventResponse{
- Event: "auth",
- }
-
- var auth WebsocketAuth
- err := json.Unmarshal(d, &auth)
- if err != nil {
- wsResp.Error = err.Error()
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
-
- shasum := sha256.Sum256([]byte(client.password))
- if auth.Username == client.username && auth.Password == hex.EncodeToString(shasum[:]) {
- client.Authenticated = true
- wsResp.Data = WebsocketResponseSuccess
- log.Debugln(log.APIServerMgr,
- "websocket: client authenticated successfully")
- return client.SendWebsocketMessage(wsResp)
- }
-
- wsResp.Error = "invalid username/password"
- client.authFailures++
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- if client.authFailures >= client.maxAuthFailures {
- log.Debugf(log.APIServerMgr,
- "websocket: disconnecting client, maximum auth failures threshold reached (failures: %d limit: %d)\n",
- client.authFailures, client.maxAuthFailures)
- wsHub.Unregister <- client
- return nil
- }
-
- log.Debugf(log.APIServerMgr,
- "websocket: client sent wrong username/password (failures: %d limit: %d)\n",
- client.authFailures, client.maxAuthFailures)
- return nil
-}
-
-func wsGetConfig(client *websocketClient, _ any) error {
- wsResp := WebsocketEventResponse{
- Event: "GetConfig",
- Data: config.GetConfig(),
- }
- return client.SendWebsocketMessage(wsResp)
-}
-
-func wsSaveConfig(client *websocketClient, data any) error {
- d, ok := data.([]byte)
- if !ok {
- return common.GetTypeAssertError("[]byte", data)
- }
-
- wsResp := WebsocketEventResponse{
- Event: "SaveConfig",
- }
- var respCfg config.Config
- err := json.Unmarshal(d, &respCfg)
- if err != nil {
- wsResp.Error = err.Error()
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
-
- cfg := config.GetConfig()
- err = cfg.UpdateConfig(client.configPath, &respCfg, false)
- if err != nil {
- wsResp.Error = err.Error()
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
-
- err = client.bot.SetupExchanges()
- if err != nil {
- wsResp.Error = err.Error()
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
- wsResp.Data = WebsocketResponseSuccess
- return client.SendWebsocketMessage(wsResp)
-}
-
-func wsGetAccountInfo(client *websocketClient, _ any) error {
- accountInfo := getAllActiveAccounts(client.exchangeManager)
- wsResp := WebsocketEventResponse{
- Event: "GetAccountInfo",
- Data: accountInfo,
- }
- return client.SendWebsocketMessage(wsResp)
-}
-
-func wsGetTickers(client *websocketClient, _ any) error {
- wsResp := WebsocketEventResponse{
- Event: "GetTickers",
- }
- wsResp.Data = getAllActiveTickers(client.exchangeManager)
- return client.SendWebsocketMessage(wsResp)
-}
-
-func wsGetTicker(client *websocketClient, data any) error {
- d, ok := data.([]byte)
- if !ok {
- return common.GetTypeAssertError("[]byte", data)
- }
-
- wsResp := WebsocketEventResponse{
- Event: "GetTicker",
- }
- var tickerReq WebsocketOrderbookTickerRequest
- err := json.Unmarshal(d, &tickerReq)
- if err != nil {
- wsResp.Error = err.Error()
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
-
- p, err := currency.NewPairFromString(tickerReq.Currency)
- if err != nil {
- return err
- }
-
- a, err := asset.New(tickerReq.AssetType)
- if err != nil {
- return err
- }
-
- exch, err := client.exchangeManager.GetExchangeByName(tickerReq.Exchange)
- if err != nil {
- wsResp.Error = err.Error()
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
- tick, err := exch.GetCachedTicker(p, a)
- if err != nil {
- wsResp.Error = err.Error()
- sendErr := client.SendWebsocketMessage(wsResp)
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
- wsResp.Data = tick
- return client.SendWebsocketMessage(wsResp)
-}
-
-func wsGetOrderbooks(client *websocketClient, _ any) error {
- wsResp := WebsocketEventResponse{
- Event: "GetOrderbooks",
- }
- wsResp.Data = getAllActiveOrderbooks(client.exchangeManager)
- return client.SendWebsocketMessage(wsResp)
-}
-
-func wsGetOrderbook(client *websocketClient, data any) error {
- d, ok := data.([]byte)
- if !ok {
- return common.GetTypeAssertError("[]byte", data)
- }
-
- var orderbookReq WebsocketOrderbookTickerRequest
- err := json.Unmarshal(d, &orderbookReq)
- if err != nil {
- sendErr := client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Error: err.Error()})
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
-
- p, err := currency.NewPairFromString(orderbookReq.Currency)
- if err != nil {
- return err
- }
-
- a, err := asset.New(orderbookReq.AssetType)
- if err != nil {
- return err
- }
-
- exch, err := client.exchangeManager.GetExchangeByName(orderbookReq.Exchange)
- if err != nil {
- sendErr := client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Error: err.Error()})
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
- ob, err := exch.GetCachedOrderbook(p, a)
- if err != nil {
- sendErr := client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Error: err.Error()})
- if sendErr != nil {
- log.Errorln(log.APIServerMgr, sendErr)
- }
- return err
- }
-
- return client.SendWebsocketMessage(WebsocketEventResponse{Event: "GetOrderbook", Data: ob})
-}
-
-func wsGetExchangeRates(client *websocketClient, _ any) error {
- wsResp := WebsocketEventResponse{
- Event: "GetExchangeRates",
- }
-
- var err error
- wsResp.Data, err = currency.GetExchangeRates()
- if err != nil {
- return err
- }
-
- return client.SendWebsocketMessage(wsResp)
-}
-
-func wsGetPortfolio(client *websocketClient, _ any) error {
- wsResp := WebsocketEventResponse{
- Event: "GetPortfolio",
- }
-
- wsResp.Data = client.portfolioManager.GetPortfolioSummary()
- return client.SendWebsocketMessage(wsResp)
-}
diff --git a/engine/apiserver.md b/engine/apiserver.md
deleted file mode 100644
index e9b99c93..00000000
--- a/engine/apiserver.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# GoCryptoTrader package Apiserver
-
-
-
-
-[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
-[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
-[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/engine/apiserver)
-[](https://codecov.io/gh/thrasher-corp/gocryptotrader)
-[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
-
-
-This apiserver package is part of the GoCryptoTrader codebase.
-
-## This is still in active development
-
-You can track ideas, planned features and what's in progress on our [GoCryptoTrader Kanban board](https://github.com/orgs/thrasher-corp/projects/3).
-
-Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/zt-38z8abs3l-gH8AAOk8XND6DP5NfCiG_g)
-
-## Current Features for Apiserver
-+ The API server subsystem is a deprecated service used to host a REST or websocket server to interact with some functions of GoCryptoTrader
-+ This subsystem is no longer maintained and it is highly encouraged to interact with GRPC endpoints directly where possible
-+ In order to modify the behaviour of the API server subsystem, you can edit the following inside your config file:
-
-### deprecatedRPC
-
-| Config | Description | Example |
-| ------ | ----------- | ------- |
-| enabled | If enabled will create a REST server which will listen to commands on the listen address | `true` |
-| listenAddress | If enabled will listen for REST requests on this address and return a JSON response | `localhost:9050` |
-
-### websocketRPC
-
-| Config | Description | Example |
-| ------ | ----------- | ------- |
-| enabled | If enabled will create a REST server which will listen to commands on the listen address | `true` |
-| listenAddress | If enabled will listen for requests on this address and return a JSON response | `localhost:9051` |
-| connectionLimit | Defines how many connections the websocket RPC server can handle simultanesoly | `1` |
-| maxAuthFailures | For authenticated endpoints, the amount of failed attempts allowed before disconnection | `3` |
-| allowInsecureOrigin | Allows use of insecure connections | `true` |
-
-## Donations
-
-
-
-If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
-
-***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc***
diff --git a/engine/apiserver_test.go b/engine/apiserver_test.go
deleted file mode 100644
index f6043fd8..00000000
--- a/engine/apiserver_test.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package engine
-
-import (
- "io"
- "net/http"
- "net/http/httptest"
- "os"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "github.com/thrasher-corp/gocryptotrader/config"
- "github.com/thrasher-corp/gocryptotrader/encoding/json"
-)
-
-func TestSetupAPIServerManager(t *testing.T) {
- t.Parallel()
- _, err := setupAPIServerManager(nil, nil, nil, nil, nil, "")
- assert.ErrorIs(t, err, errNilRemoteConfig)
-
- _, err = setupAPIServerManager(&config.RemoteControlConfig{}, nil, nil, nil, nil, "")
- assert.ErrorIs(t, err, errNilPProfConfig)
-
- _, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, nil, nil, nil, "")
- assert.ErrorIs(t, err, errNilExchangeManager)
-
- _, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, nil, nil, "")
- assert.ErrorIs(t, err, errNilBot)
-
- _, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, "")
- assert.ErrorIs(t, err, errEmptyConfigPath)
-
- wd, _ := os.Getwd()
- _, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
- assert.NoError(t, err)
-}
-
-func TestStartRESTServer(t *testing.T) {
- t.Parallel()
- wd, _ := os.Getwd()
- m, err := setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
- assert.NoError(t, err)
-
- err = m.StartRESTServer()
- assert.ErrorIs(t, err, errServerDisabled)
-
- m.remoteConfig.DeprecatedRPC.Enabled = true
- err = m.StartRESTServer()
- assert.NoError(t, err)
-}
-
-func TestStartWebsocketServer(t *testing.T) {
- t.Parallel()
- wd, _ := os.Getwd()
- m, err := setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
- assert.NoError(t, err)
-
- err = m.StartWebsocketServer()
- assert.ErrorIs(t, err, errServerDisabled)
-
- m.remoteConfig.WebsocketRPC.Enabled = true
- err = m.StartWebsocketServer()
- assert.NoError(t, err)
-}
-
-func TestStopRESTServer(t *testing.T) {
- t.Parallel()
- wd, _ := os.Getwd()
- m, err := setupAPIServerManager(&config.RemoteControlConfig{
- DeprecatedRPC: config.DepcrecatedRPCConfig{
- Enabled: true,
- ListenAddress: "localhost:9051",
- },
- }, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
- assert.NoError(t, err)
-
- err = m.StopRESTServer()
- assert.ErrorIs(t, err, ErrSubSystemNotStarted)
-
- err = m.StartRESTServer()
- assert.NoError(t, err)
-
- err = m.StopRESTServer()
- assert.NoError(t, err)
-
- // do it again to ensure things have reset appropriately and no errors occur starting
- err = m.StartRESTServer()
- assert.NoError(t, err)
-
- err = m.StopRESTServer()
- assert.NoError(t, err)
-}
-
-func TestWebsocketStop(t *testing.T) {
- t.Parallel()
- wd, _ := os.Getwd()
- m, err := setupAPIServerManager(&config.RemoteControlConfig{
- WebsocketRPC: config.WebsocketRPCConfig{
- Enabled: true,
- ListenAddress: "localhost:9052",
- },
- }, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
- assert.NoError(t, err)
-
- err = m.StopWebsocketServer()
- assert.ErrorIs(t, err, ErrSubSystemNotStarted)
-
- err = m.StartWebsocketServer()
- assert.NoError(t, err)
-
- err = m.StopWebsocketServer()
- assert.NoError(t, err)
-
- // do it again to ensure things have reset appropriately and no errors occur starting
- err = m.StartWebsocketServer()
- assert.NoError(t, err)
-
- err = m.StopWebsocketServer()
- assert.NoError(t, err)
-}
-
-func TestIsRESTServerRunning(t *testing.T) {
- t.Parallel()
- m := &apiServerManager{}
- assert.False(t, m.IsRESTServerRunning(), "should return correctly with empty type")
- m.restStarted = 1
- assert.True(t, m.IsRESTServerRunning(), "should return correctly with restStarted set")
- assert.False(t, (*apiServerManager)(nil).IsRESTServerRunning(), "should return correctly on nil type")
-}
-
-func TestIsWebsocketServerRunning(t *testing.T) {
- t.Parallel()
- m := &apiServerManager{}
- assert.False(t, m.IsWebsocketServerRunning(), "should return correctly with empty type")
- m.websocketStarted = 1
- assert.True(t, m.IsWebsocketServerRunning(), "should return correctly with websocketStarted set")
- assert.False(t, (*apiServerManager)(nil).IsWebsocketServerRunning(), "should return correctly on nil type")
-}
-
-func TestGetAllActiveOrderbooks(t *testing.T) {
- man := NewExchangeManager()
- bs, err := man.NewExchangeByName("Bitstamp")
- require.NoError(t, err, "NewExchangeByName must not error")
- bs.SetDefaults()
- err = man.Add(bs)
- require.NoError(t, err)
-
- resp := getAllActiveOrderbooks(man)
- assert.NotNil(t, resp)
-}
-
-func TestGetAllActiveTickers(t *testing.T) {
- t.Parallel()
- man := NewExchangeManager()
- bs, err := man.NewExchangeByName("Bitstamp")
- require.NoError(t, err, "NewExchangeByName must not error")
- bs.SetDefaults()
- err = man.Add(bs)
- require.NoError(t, err)
-
- resp := getAllActiveTickers(man)
- assert.NotNil(t, resp)
-}
-
-func TestGetAllActiveAccounts(t *testing.T) {
- t.Parallel()
- man := NewExchangeManager()
- bs, err := man.NewExchangeByName("Bitstamp")
- require.NoError(t, err, "NewExchangeByName must not error")
- bs.SetDefaults()
- err = man.Add(bs)
- require.NoError(t, err)
-
- resp := getAllActiveAccounts(man)
- assert.NotNil(t, resp)
-}
-
-func makeHTTPGetRequest(t *testing.T, response any) *http.Response {
- t.Helper()
- w := httptest.NewRecorder()
-
- err := writeResponse(w, response)
- require.NoError(t, err)
-
- return w.Result()
-}
-
-// TestConfigAllJsonResponse test if config/all restful json response is valid
-func TestConfigAllJsonResponse(t *testing.T) {
- t.Parallel()
- var c config.Config
- err := c.LoadConfig(config.TestFile, true)
- assert.NoError(t, err, "LoadConfig should not error")
-
- resp := makeHTTPGetRequest(t, c)
- body, err := io.ReadAll(resp.Body)
- assert.NoError(t, err, "ReadAll should not error")
- err = resp.Body.Close()
- assert.NoError(t, err, "Close body should not error")
-
- var responseConfig config.Config
- err = json.Unmarshal(body, &responseConfig)
- assert.NoError(t, err, "Unmarshal should not error")
- for i, e := range responseConfig.Exchanges {
- err = e.CurrencyPairs.SetDelimitersFromConfig()
- assert.NoError(t, err, "SetDelimitersFromConfig should not error")
- // Using require here makes it much easier to isolate differences per-exchange than below
- // We look into pointers separately
- for a, p := range e.CurrencyPairs.Pairs {
- require.Equalf(t, c.Exchanges[i].CurrencyPairs.Pairs[a], p, "%s exchange Config CurrencyManager Pairs for asset %s must match api response", e.Name, a)
- }
- require.Equalf(t, c.Exchanges[i].CurrencyPairs, e.CurrencyPairs, "%s exchange Config CurrencyManager must match api response", e.Name)
- require.Equalf(t, c.Exchanges[i], e, "%s exchange Config must match api response", e.Name) // require here makes it much easier to isolate differences than below
- }
- assert.Equal(t, c, responseConfig, "Config should match api response")
-}
-
-// fakeBot is a basic implementation of the iBot interface used for testing
-type fakeBot struct{}
-
-// SetupExchanges is a basic implementation of the iBot interface used for testing
-func (f *fakeBot) SetupExchanges() error {
- return nil
-}
diff --git a/engine/apiserver_types.go b/engine/apiserver_types.go
deleted file mode 100644
index fb1d0b17..00000000
--- a/engine/apiserver_types.go
+++ /dev/null
@@ -1,168 +0,0 @@
-package engine
-
-import (
- "errors"
- "net/http"
- "sync"
-
- "github.com/gorilla/mux"
- gws "github.com/gorilla/websocket"
- "github.com/thrasher-corp/gocryptotrader/config"
- "github.com/thrasher-corp/gocryptotrader/exchanges/account"
- "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
- "github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
-)
-
-// Const vars for websocket
-const (
- WebsocketResponseSuccess = "OK"
- restIndexResponse = "GoCryptoTrader RESTful interface. For the web GUI, please visit the web GUI readme."
- DeprecatedName = "deprecated_rpc"
- WebsocketName = "websocket_rpc"
-)
-
-var (
- wsHub *websocketHub
- wsHubStarted bool
- errNilRemoteConfig = errors.New("received nil remote config")
- errNilPProfConfig = errors.New("received nil pprof config")
- errNilBot = errors.New("received nil engine bot")
- errEmptyConfigPath = errors.New("received empty config path")
- errServerDisabled = errors.New("server disabled")
- errAlreadyRunning = errors.New("already running")
- // ErrWebsocketServiceNotRunning occurs when a message is sent to be broadcast via websocket
- // and its not running
- ErrWebsocketServiceNotRunning = errors.New("websocket service not started")
-)
-
-// apiServerManager holds all relevant fields to manage both REST and websocket
-// api servers
-type apiServerManager struct {
- restStarted int32
- websocketStarted int32
- restListenAddress string
- websocketListenAddress string
- gctConfigPath string
- restHTTPServer *http.Server
- websocketHTTPServer *http.Server
- wgRest sync.WaitGroup
- wgWebsocket sync.WaitGroup
-
- restRouter *mux.Router
- websocketRouter *mux.Router
- websocketHub *websocketHub
-
- remoteConfig *config.RemoteControlConfig
- pprofConfig *config.Profiler
- exchangeManager iExchangeManager
- bot iBot
- portfolioManager iPortfolioManager
-}
-
-// websocketClient stores information related to the websocket client
-type websocketClient struct {
- Hub *websocketHub
- Conn *gws.Conn
- Authenticated bool
- authFailures int
- Send chan []byte
- username string
- password string
- maxAuthFailures int
- exchangeManager iExchangeManager
- bot iBot
- portfolioManager iPortfolioManager
- configPath string
-}
-
-// websocketHub stores the data for managing websocket clients
-type websocketHub struct {
- Clients map[*websocketClient]bool
- Broadcast chan []byte
- Register chan *websocketClient
- Unregister chan *websocketClient
-}
-
-// WebsocketEvent is the struct used for websocket events
-type WebsocketEvent struct {
- Exchange string `json:"exchange,omitempty"`
- AssetType string `json:"assetType,omitempty"`
- Event string
- Data any
-}
-
-// WebsocketEventResponse is the struct used for websocket event responses
-type WebsocketEventResponse struct {
- Event string `json:"event"`
- Data any `json:"data"`
- Error string `json:"error"`
-}
-
-// WebsocketOrderbookTickerRequest is a struct used for ticker and orderbook
-// requests
-type WebsocketOrderbookTickerRequest struct {
- Exchange string `json:"exchangeName"`
- Currency string `json:"currency"`
- AssetType string `json:"assetType"`
-}
-
-// WebsocketAuth is a struct used for
-type WebsocketAuth struct {
- Username string `json:"username"`
- Password string `json:"password"`
-}
-
-// Route is a sub type that holds the request routes
-type Route struct {
- Name string
- Method string
- Pattern string
- HandlerFunc http.HandlerFunc
-}
-
-// AllEnabledExchangeOrderbooks holds the enabled exchange orderbooks
-type AllEnabledExchangeOrderbooks struct {
- Data []EnabledExchangeOrderbooks `json:"data"`
-}
-
-// EnabledExchangeOrderbooks is a sub type for singular exchanges and respective
-// orderbooks
-type EnabledExchangeOrderbooks struct {
- ExchangeName string `json:"exchangeName"`
- ExchangeValues []orderbook.Book `json:"exchangeValues"`
-}
-
-// AllEnabledExchangeCurrencies holds the enabled exchange currencies
-type AllEnabledExchangeCurrencies struct {
- Data []EnabledExchangeCurrencies `json:"data"`
-}
-
-// EnabledExchangeCurrencies is a sub type for singular exchanges and respective
-// currencies
-type EnabledExchangeCurrencies struct {
- ExchangeName string `json:"exchangeName"`
- ExchangeValues []*ticker.Price `json:"exchangeValues"`
-}
-
-// AllEnabledExchangeAccounts holds all enabled accounts info
-type AllEnabledExchangeAccounts struct {
- Data []account.Holdings `json:"data"`
-}
-
-var wsHandlers = map[string]wsCommandHandler{
- "auth": {authRequired: false, handler: wsAuth},
- "getconfig": {authRequired: true, handler: wsGetConfig},
- "saveconfig": {authRequired: true, handler: wsSaveConfig},
- "getaccountinfo": {authRequired: true, handler: wsGetAccountInfo},
- "gettickers": {authRequired: false, handler: wsGetTickers},
- "getticker": {authRequired: false, handler: wsGetTicker},
- "getorderbooks": {authRequired: false, handler: wsGetOrderbooks},
- "getorderbook": {authRequired: false, handler: wsGetOrderbook},
- "getexchangerates": {authRequired: false, handler: wsGetExchangeRates},
- "getportfolio": {authRequired: true, handler: wsGetPortfolio},
-}
-
-type wsCommandHandler struct {
- authRequired bool
- handler func(client *websocketClient, data any) error
-}
diff --git a/engine/communication_manager.md b/engine/communication_manager.md
index ba431cdd..6ef72126 100644
--- a/engine/communication_manager.md
+++ b/engine/communication_manager.md
@@ -68,7 +68,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/connection_manager.md b/engine/connection_manager.md
index 704d6429..02b53910 100644
--- a/engine/connection_manager.md
+++ b/engine/connection_manager.md
@@ -32,7 +32,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/currency_state_manager.md b/engine/currency_state_manager.md
index 6e0c6a1c..7dbbe462 100644
--- a/engine/currency_state_manager.md
+++ b/engine/currency_state_manager.md
@@ -17,20 +17,20 @@ This currency_state_manager package is part of the GoCryptoTrader codebase.
You can track ideas, planned features and what's in progress on our [GoCryptoTrader Kanban board](https://github.com/orgs/thrasher-corp/projects/3).
Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/zt-38z8abs3l-gH8AAOk8XND6DP5NfCiG_g)
-
-## Current Features for Currency State Manager
-+ The state manager keeps currency states up to date, which include:
-* Withdrawal - Determines if the currency is allowed to be withdrawn from the exchange.
-* Deposit - Determines if the currency is allowed to be deposited to an exchange.
-* Trading - Determines if the currency is allowed to be traded on the exchange.
-
-+ This allows for an internal state check to compliment internal and external
-strategies.
-
+
+## Current Features for Currency State Manager
++ The state manager keeps currency states up to date, which include:
+* Withdrawal - Determines if the currency is allowed to be withdrawn from the exchange.
+* Deposit - Determines if the currency is allowed to be deposited to an exchange.
+* Trading - Determines if the currency is allowed to be traded on the exchange.
+
++ This allows for an internal state check to compliment internal and external
+strategies.
+
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
-***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc***
+***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc***
diff --git a/engine/database_connection.md b/engine/database_connection.md
index 50c62693..f2abe3f4 100644
--- a/engine/database_connection.md
+++ b/engine/database_connection.md
@@ -44,7 +44,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/datahistory_manager.go b/engine/datahistory_manager.go
index 3d68505b..fb2cbdf8 100644
--- a/engine/datahistory_manager.go
+++ b/engine/datahistory_manager.go
@@ -255,7 +255,7 @@ func (m *DataHistoryManager) runJobs() error {
}
if !atomic.CompareAndSwapInt32(&m.processing, 0, 1) {
- return fmt.Errorf("cannot process jobs, %w", errAlreadyRunning)
+ return fmt.Errorf("cannot process jobs, %w", ErrSubSystemAlreadyStarted)
}
defer atomic.StoreInt32(&m.processing, 0)
diff --git a/engine/datahistory_manager.md b/engine/datahistory_manager.md
index 3f86e56f..fbac9a8e 100644
--- a/engine/datahistory_manager.md
+++ b/engine/datahistory_manager.md
@@ -207,7 +207,7 @@ The candle table also has relationships to data history jobs. Only the relevant
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/depositaddress.md b/engine/depositaddress.md
index ffc9817b..3c3bb5d3 100644
--- a/engine/depositaddress.md
+++ b/engine/depositaddress.md
@@ -24,7 +24,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/engine.go b/engine/engine.go
index 92d9c91d..a1d37a7c 100644
--- a/engine/engine.go
+++ b/engine/engine.go
@@ -33,7 +33,6 @@ import (
// overarching type across this code base.
type Engine struct {
Config *config.Config
- apiServer *apiServerManager
CommunicationsManager *CommunicationManager
connectionManager *connectionManager
currencyPairSyncer *SyncManager
@@ -198,9 +197,6 @@ func validateSettings(b *Engine, s *Settings, flagSet FlagSet) {
go b.waitForGPRCShutdown()
}
- flagSet.WithBool("websocketrpc", &b.Settings.EnableWebsocketRPC, b.Config.RemoteControl.WebsocketRPC.Enabled)
- flagSet.WithBool("deprecatedrpc", &b.Settings.EnableDeprecatedRPC, b.Config.RemoteControl.DeprecatedRPC.Enabled)
-
if flagSet["maxvirtualmachines"] {
maxMachines := b.Settings.MaxVirtualMachines
b.gctScriptManager.MaxVirtualMachines = &maxMachines
@@ -300,6 +296,12 @@ func (bot *Engine) Start() error {
newEngineMutex.Lock()
defer newEngineMutex.Unlock()
+ if bot.Config.Profiler.Enabled {
+ if err := StartPPROF(context.TODO(), &bot.Config.Profiler); err != nil {
+ gctlog.Errorf(gctlog.Global, "Failed to start pprof: %v", err)
+ }
+ }
+
if bot.Settings.EnableDatabaseManager {
if d, err := SetupDatabaseConnectionManager(&bot.Config.Database); err != nil {
gctlog.Errorf(gctlog.Global, "Database manager unable to setup: %v", err)
@@ -439,28 +441,6 @@ func (bot *Engine) Start() error {
bot.WithdrawManager = w
}
- if bot.Settings.EnableDeprecatedRPC || bot.Settings.EnableWebsocketRPC {
- if filePath, err := config.GetAndMigrateDefaultPath(bot.Settings.ConfigFile); err != nil {
- return err
- } else { //nolint:revive // TODO: revive false positive, see https://github.com/mgechev/revive/pull/832 for more information
- if a, err := setupAPIServerManager(&bot.Config.RemoteControl, &bot.Config.Profiler, bot.ExchangeManager, bot, bot.portfolioManager, filePath); err != nil {
- gctlog.Errorf(gctlog.Global, "API Server unable to start: %s", err)
- } else {
- bot.apiServer = a
- if bot.Settings.EnableDeprecatedRPC {
- if err := bot.apiServer.StartRESTServer(); err != nil {
- gctlog.Errorf(gctlog.Global, "could not start REST API server: %s", err)
- }
- }
- if bot.Settings.EnableWebsocketRPC {
- if err := bot.apiServer.StartWebsocketServer(); err != nil {
- gctlog.Errorf(gctlog.Global, "could not start websocket API server: %s", err)
- }
- }
- }
- }
- }
-
if bot.Settings.EnableDepositAddressManager {
bot.DepositAddressManager = SetupDepositAddressManager()
go func() {
@@ -624,16 +604,6 @@ func (bot *Engine) Stop() {
gctlog.Errorf(gctlog.Global, "Connection manager unable to stop. Error: %v", err)
}
}
- if bot.apiServer.IsRESTServerRunning() {
- if err := bot.apiServer.StopRESTServer(); err != nil {
- gctlog.Errorf(gctlog.Global, "API Server unable to stop REST server. Error: %s", err)
- }
- }
- if bot.apiServer.IsWebsocketServerRunning() {
- if err := bot.apiServer.StopWebsocketServer(); err != nil {
- gctlog.Errorf(gctlog.Global, "API Server unable to stop websocket server. Error: %s", err)
- }
- }
if bot.dataHistoryManager.IsRunning() {
if err := bot.dataHistoryManager.Stop(); err != nil {
gctlog.Errorf(gctlog.DataHistory, "data history manager unable to stop. Error: %v", err)
diff --git a/engine/engine_types.go b/engine/engine_types.go
index 7d482b6a..188791d1 100644
--- a/engine/engine_types.go
+++ b/engine/engine_types.go
@@ -41,8 +41,6 @@ type CoreSettings struct {
EnableGRPC bool
EnableGRPCProxy bool
EnableGRPCShutdown bool
- EnableWebsocketRPC bool
- EnableDeprecatedRPC bool
EnableCommsRelayer bool
EnableExchangeSyncManager bool
EnableDepositAddressManager bool
diff --git a/engine/event_manager.md b/engine/event_manager.md
index 9a229d7b..5307c877 100644
--- a/engine/event_manager.md
+++ b/engine/event_manager.md
@@ -31,7 +31,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/exchange_manager.md b/engine/exchange_manager.md
index d66c48bd..cc804bf9 100644
--- a/engine/exchange_manager.md
+++ b/engine/exchange_manager.md
@@ -25,7 +25,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/helpers.go b/engine/helpers.go
index f076d09a..319a617e 100644
--- a/engine/helpers.go
+++ b/engine/helpers.go
@@ -12,8 +12,11 @@ import (
"fmt"
"math/big"
"net"
+ "net/http"
+ "net/http/pprof"
"os"
"path/filepath"
+ "runtime"
"strings"
"sync"
"time"
@@ -52,6 +55,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/okx"
"github.com/thrasher-corp/gocryptotrader/exchanges/poloniex"
"github.com/thrasher-corp/gocryptotrader/exchanges/stats"
+ "github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/exchanges/yobit"
"github.com/thrasher-corp/gocryptotrader/gctscript/vm"
"github.com/thrasher-corp/gocryptotrader/log"
@@ -63,6 +67,11 @@ var (
errCertTypeInvalid = errors.New("gRPC TLS certificate type is invalid")
errSubsystemNotFound = errors.New("subsystem not found")
errGRPCManagementFault = errors.New("cannot manage GRPC subsystem via GRPC. Please manually change your config")
+ errNilBot = errors.New("received nil engine bot")
+)
+
+const (
+ defaultPPROFListenAddress = "localhost:8085"
)
// GetSubsystemsStatus returns the status of various subsystems
@@ -78,8 +87,6 @@ func (bot *Engine) GetSubsystemsStatus() map[string]bool {
grpcName: bot.Settings.EnableGRPC,
grpcProxyName: bot.Settings.EnableGRPCProxy,
vm.Name: bot.gctScriptManager.IsRunning(),
- DeprecatedName: bot.Settings.EnableDeprecatedRPC,
- WebsocketName: bot.Settings.EnableWebsocketRPC,
dispatch.Name: dispatch.IsRunning(),
dataHistoryManagerName: bot.dataHistoryManager.IsRunning(),
CurrencyStateManagementName: bot.currencyStateManager.IsRunning(),
@@ -106,14 +113,6 @@ func (bot *Engine) GetRPCEndpoints() (map[string]RPCEndpoint, error) {
Started: bot.Settings.EnableGRPCProxy,
ListenAddr: "https://" + bot.Config.RemoteControl.GRPC.GRPCProxyListenAddress,
},
- DeprecatedName: {
- Started: bot.Settings.EnableDeprecatedRPC,
- ListenAddr: "http://" + bot.Config.RemoteControl.DeprecatedRPC.ListenAddress,
- },
- WebsocketName: {
- Started: bot.Settings.EnableWebsocketRPC,
- ListenAddr: "ws://" + bot.Config.RemoteControl.WebsocketRPC.ListenAddress,
- },
}, nil
}
@@ -237,38 +236,6 @@ func (bot *Engine) SetSubsystem(subSystemName string, enable bool) error {
return dispatch.Start(bot.Settings.DispatchMaxWorkerAmount, bot.Settings.DispatchJobsLimit)
}
return dispatch.Stop()
- case DeprecatedName:
- if enable {
- if bot.apiServer == nil {
- var filePath string
- filePath, err = config.GetAndMigrateDefaultPath(bot.Settings.ConfigFile)
- if err != nil {
- return err
- }
- bot.apiServer, err = setupAPIServerManager(&bot.Config.RemoteControl, &bot.Config.Profiler, bot.ExchangeManager, bot, bot.portfolioManager, filePath)
- if err != nil {
- return err
- }
- }
- return bot.apiServer.StartRESTServer()
- }
- return bot.apiServer.StopRESTServer()
- case WebsocketName:
- if enable {
- if bot.apiServer == nil {
- var filePath string
- filePath, err = config.GetAndMigrateDefaultPath(bot.Settings.ConfigFile)
- if err != nil {
- return err
- }
- bot.apiServer, err = setupAPIServerManager(&bot.Config.RemoteControl, &bot.Config.Profiler, bot.ExchangeManager, bot, bot.portfolioManager, filePath)
- if err != nil {
- return err
- }
- }
- return bot.apiServer.StartWebsocketServer()
- }
- return bot.apiServer.StopWebsocketServer()
case grpcName, grpcProxyName:
return errGRPCManagementFault
case dataHistoryManagerName:
@@ -807,6 +774,18 @@ func (bot *Engine) GetExchangeNames(enabledOnly bool) []string {
return response
}
+// AllEnabledExchangeCurrencies holds the enabled exchange currencies
+type AllEnabledExchangeCurrencies struct {
+ Data []EnabledExchangeCurrencies `json:"data"`
+}
+
+// EnabledExchangeCurrencies is a sub type for singular exchanges and respective
+// currencies
+type EnabledExchangeCurrencies struct {
+ ExchangeName string `json:"exchangeName"`
+ ExchangeValues []*ticker.Price `json:"exchangeValues"`
+}
+
// GetAllActiveTickers returns all enabled exchange tickers
func (bot *Engine) GetAllActiveTickers() []EnabledExchangeCurrencies {
var tickerData []EnabledExchangeCurrencies
@@ -1037,3 +1016,48 @@ func NewExchangeByNameWithDefaults(ctx context.Context, name string) (exchange.I
}
return exch, nil
}
+
+// StartPPROF starts a pprof profiler if enabled
+func StartPPROF(ctx context.Context, cfg *config.Profiler) error {
+ if !cfg.Enabled {
+ return nil
+ }
+
+ runtime.SetMutexProfileFraction(cfg.MutexProfileFraction)
+ runtime.SetBlockProfileRate(cfg.BlockProfileRate)
+
+ listenAddr := cfg.ListenAddress
+ if listenAddr == "" {
+ listenAddr = defaultPPROFListenAddress
+ }
+
+ lc := net.ListenConfig{}
+ ln, err := lc.Listen(ctx, "tcp", listenAddr)
+ if err != nil {
+ return fmt.Errorf("pprof listen error: %w", err)
+ }
+
+ mux := http.NewServeMux()
+ mux.HandleFunc("/debug/pprof/", pprof.Index)
+ mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
+ mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
+ mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
+ mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
+
+ srv := &http.Server{
+ Addr: listenAddr,
+ ReadTimeout: 10 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ Handler: mux,
+ }
+
+ log.Infof(log.Global, "PPROF profiler listening on http://%s/debug/pprof/", listenAddr)
+
+ go func() {
+ if err := srv.Serve(ln); err != nil {
+ log.Errorf(log.Global, "PPROF serve error: %s", err)
+ }
+ }()
+
+ return nil
+}
diff --git a/engine/helpers_test.go b/engine/helpers_test.go
index 2e9ffe86..c6ac82e1 100644
--- a/engine/helpers_test.go
+++ b/engine/helpers_test.go
@@ -11,6 +11,7 @@ import (
"errors"
"math/big"
"net"
+ "net/http"
"os"
"path/filepath"
"slices"
@@ -99,10 +100,7 @@ func CreateTestBot(tb testing.TB) *Engine {
}
func TestGetSubsystemsStatus(t *testing.T) {
- m := (&Engine{}).GetSubsystemsStatus()
- if len(m) != 15 {
- t.Fatalf("subsystem count is wrong expecting: %d but received: %d", 15, len(m))
- }
+ assert.Len(t, (&Engine{}).GetSubsystemsStatus(), 13, "GetSubsystemStatus should return the correct number of subsystems")
}
func TestGetRPCEndpoints(t *testing.T) {
@@ -111,10 +109,7 @@ func TestGetRPCEndpoints(t *testing.T) {
m, err := (&Engine{Config: &config.Config{}}).GetRPCEndpoints()
require.NoError(t, err)
-
- if len(m) != 4 {
- t.Fatalf("expected length: %d but received: %d", 4, len(m))
- }
+ assert.Len(t, m, 2, "GetRPCEndpoints should return the correct number of RPC endpoints")
}
func TestSetSubsystem(t *testing.T) { //nolint // TO-DO: Fix race t.Parallel() usage
@@ -175,19 +170,6 @@ func TestSetSubsystem(t *testing.T) { //nolint // TO-DO: Fix race t.Parallel() u
EnableError: nil,
DisableError: nil,
},
-
- {
- Subsystem: DeprecatedName,
- Engine: &Engine{Config: &config.Config{}, Settings: Settings{ConfigFile: config.DefaultFilePath()}},
- EnableError: errServerDisabled,
- DisableError: ErrSubSystemNotStarted,
- },
- {
- Subsystem: WebsocketName,
- Engine: &Engine{Config: &config.Config{}, Settings: Settings{ConfigFile: config.DefaultFilePath()}},
- EnableError: errServerDisabled,
- DisableError: ErrSubSystemNotStarted,
- },
{
Subsystem: grpcName,
Engine: &Engine{Config: &config.Config{}},
@@ -1258,3 +1240,22 @@ func TestNewExchangeByNameWithDefaults(t *testing.T) {
})
}
}
+
+func TestStartPPROF(t *testing.T) {
+ t.Parallel()
+ assert.NoError(t, StartPPROF(t.Context(), &config.Profiler{Enabled: false}), "StartPPROF with a disabled config should not error")
+ pprofConfig := &config.Profiler{
+ Enabled: true,
+ ListenAddress: "",
+ MutexProfileFraction: 1,
+ BlockProfileRate: 1,
+ }
+ require.NoError(t, StartPPROF(t.Context(), pprofConfig), "StartPPROF with a valid config must not error")
+ req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "http://localhost:8085/debug/pprof/mutex", http.NoBody)
+ require.NoError(t, err, "NewRequestWithContext must not error")
+ resp, err := http.DefaultClient.Do(req)
+ require.NoError(t, err, "Do must not error")
+ require.Equal(t, http.StatusOK, resp.StatusCode, "Get response status must be OK")
+ resp.Body.Close()
+ assert.Error(t, StartPPROF(t.Context(), pprofConfig), "StartPPROF with a valid config on already used port should error")
+}
diff --git a/engine/ntp_manager.md b/engine/ntp_manager.md
index def79094..1fa6f83a 100644
--- a/engine/ntp_manager.md
+++ b/engine/ntp_manager.md
@@ -35,7 +35,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/order_manager.md b/engine/order_manager.md
index 7494b50e..83345d4d 100644
--- a/engine/order_manager.md
+++ b/engine/order_manager.md
@@ -26,7 +26,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/portfolio_manager.md b/engine/portfolio_manager.md
index a54d557b..1ad2adcc 100644
--- a/engine/portfolio_manager.md
+++ b/engine/portfolio_manager.md
@@ -45,7 +45,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/subsystem_types.go b/engine/subsystem_types.go
index 0eaf0c0e..056192b2 100644
--- a/engine/subsystem_types.go
+++ b/engine/subsystem_types.go
@@ -68,11 +68,6 @@ type iPortfolioManager interface {
IsExchangeSupported(string, string) bool
}
-// iBot limits exposure of accessible functions to engine bot
-type iBot interface {
- SetupExchanges() error
-}
-
// iCurrencyPairSyncer defines a limited scoped currency pair syncer
type iCurrencyPairSyncer interface {
IsRunning() bool
diff --git a/engine/subsystem_types.md b/engine/subsystem_types.md
index 852643db..061549a0 100644
--- a/engine/subsystem_types.md
+++ b/engine/subsystem_types.md
@@ -27,7 +27,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/sync_manager.go b/engine/sync_manager.go
index 4d0ff29f..6513ee9d 100644
--- a/engine/sync_manager.go
+++ b/engine/sync_manager.go
@@ -593,11 +593,6 @@ func (m *SyncManager) syncTicker(c *currencyPairSyncAgent, e exchange.IBotExchan
c.Key.Asset)
}
m.PrintTickerSummary(result, "REST", err)
- if err == nil {
- if m.remoteConfig.WebsocketRPC.Enabled {
- relayWebsocketEvent(result, "ticker_update", c.Key.Asset.String(), exchangeName)
- }
- }
updateErr := m.update(c, SyncItemTicker, err)
if updateErr != nil {
log.Errorln(log.SyncMgr, updateErr)
@@ -642,11 +637,6 @@ func (m *SyncManager) syncOrderbook(c *currencyPairSyncAgent, e exchange.IBotExc
c.Pair,
c.Key.Asset)
m.PrintOrderbookSummary(result, "REST", err)
- if err == nil {
- if m.remoteConfig.WebsocketRPC.Enabled {
- relayWebsocketEvent(result, "orderbook_update", c.Key.Asset.String(), e.GetName())
- }
- }
updateErr := m.update(c, SyncItemOrderbook, err)
if updateErr != nil {
log.Errorln(log.SyncMgr, updateErr)
@@ -887,20 +877,6 @@ func (m *SyncManager) WaitForInitialSync() error {
return nil
}
-func relayWebsocketEvent(result any, event, assetType, exchangeName string) {
- evt := WebsocketEvent{
- Data: result,
- Event: event,
- AssetType: assetType,
- Exchange: exchangeName,
- }
- err := BroadcastWebsocketMessage(evt)
- if err != nil && !errors.Is(err, ErrWebsocketServiceNotRunning) {
- log.Errorf(log.APIServerMgr, "Failed to broadcast websocket event %v. Error: %v",
- event, err)
- }
-}
-
func greatestCommonDivisor(a, b time.Duration) time.Duration {
for b != 0 {
t := b
diff --git a/engine/sync_manager.md b/engine/sync_manager.md
index d5fa6608..57f3abad 100644
--- a/engine/sync_manager.md
+++ b/engine/sync_manager.md
@@ -35,7 +35,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/sync_manager_test.go b/engine/sync_manager_test.go
index 06edb5cb..ce19e232 100644
--- a/engine/sync_manager_test.go
+++ b/engine/sync_manager_test.go
@@ -201,12 +201,6 @@ func TestPrintOrderbookSummary(t *testing.T) {
m.PrintOrderbookSummary(nil, "REST", errors.New("test"))
}
-func TestRelayWebsocketEvent(t *testing.T) {
- t.Parallel()
-
- relayWebsocketEvent(nil, "", "", "")
-}
-
func TestWaitForInitialSync(t *testing.T) {
var m *SyncManager
err := m.WaitForInitialSync()
diff --git a/engine/websocketroutine_manager.md b/engine/websocketroutine_manager.md
index 59d2f966..8d269271 100644
--- a/engine/websocketroutine_manager.md
+++ b/engine/websocketroutine_manager.md
@@ -27,7 +27,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/engine/withdraw_manager.md b/engine/withdraw_manager.md
index ea675782..4b5ae832 100644
--- a/engine/withdraw_manager.md
+++ b/engine/withdraw_manager.md
@@ -28,7 +28,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchange/websocket/README.md b/exchange/websocket/README.md
index 3bf33bfc..67855de7 100644
--- a/exchange/websocket/README.md
+++ b/exchange/websocket/README.md
@@ -152,7 +152,7 @@ func (e *Exchange) Setup(exch *config.Exchange) error {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/README.md b/exchanges/README.md
index 9628fb8c..bc17f8cd 100644
--- a/exchanges/README.md
+++ b/exchanges/README.md
@@ -36,7 +36,7 @@ follow [these rules](../docs/WS_ORDER_EVENTS.md).
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/alert/README.md b/exchanges/alert/README.md
index eeb7c249..93ee2091 100644
--- a/exchanges/alert/README.md
+++ b/exchanges/alert/README.md
@@ -106,7 +106,7 @@ func ABadExampleRoutineThatWaits(potentialChange *SomeChangingType) {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/binance/README.md b/exchanges/binance/README.md
index 78d3cdd5..bd5047d6 100644
--- a/exchanges/binance/README.md
+++ b/exchanges/binance/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/binanceus/README.md b/exchanges/binanceus/README.md
index ba52d6f4..ce4a7730 100644
--- a/exchanges/binanceus/README.md
+++ b/exchanges/binanceus/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/bitfinex/README.md b/exchanges/bitfinex/README.md
index cf0ffeed..067be4ad 100644
--- a/exchanges/bitfinex/README.md
+++ b/exchanges/bitfinex/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/bitflyer/README.md b/exchanges/bitflyer/README.md
index 6f5a40e5..34ee9bf2 100644
--- a/exchanges/bitflyer/README.md
+++ b/exchanges/bitflyer/README.md
@@ -119,7 +119,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/bithumb/README.md b/exchanges/bithumb/README.md
index 3d113e53..469722ee 100644
--- a/exchanges/bithumb/README.md
+++ b/exchanges/bithumb/README.md
@@ -112,7 +112,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/bitmex/README.md b/exchanges/bitmex/README.md
index 345fff37..b8706f5d 100644
--- a/exchanges/bitmex/README.md
+++ b/exchanges/bitmex/README.md
@@ -112,7 +112,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/bitstamp/README.md b/exchanges/bitstamp/README.md
index e77732e6..e2447bbf 100644
--- a/exchanges/bitstamp/README.md
+++ b/exchanges/bitstamp/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/btcmarkets/README.md b/exchanges/btcmarkets/README.md
index 6b975e3d..b2094843 100644
--- a/exchanges/btcmarkets/README.md
+++ b/exchanges/btcmarkets/README.md
@@ -113,7 +113,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/btse/README.md b/exchanges/btse/README.md
index a3f064e2..36c592cd 100644
--- a/exchanges/btse/README.md
+++ b/exchanges/btse/README.md
@@ -113,7 +113,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/bybit/README.md b/exchanges/bybit/README.md
index c5840098..65323b50 100644
--- a/exchanges/bybit/README.md
+++ b/exchanges/bybit/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/bybit/bybit.go b/exchanges/bybit/bybit.go
index df8e571b..8463c24d 100644
--- a/exchanges/bybit/bybit.go
+++ b/exchanges/bybit/bybit.go
@@ -1640,7 +1640,7 @@ func (e *Exchange) GetAllowedDepositCoinInfo(ctx context.Context, coin, chain, c
return resp, e.SendAuthHTTPRequestV5(ctx, exchange.RestSpot, http.MethodGet, "/v5/asset/deposit/query-allowed-list", params, nil, &resp, defaultEPL)
}
-// SetDepositAccount sets auto transfer account after deposit. The same function as the setting for Deposit on web GUI
+// SetDepositAccount sets the auto transfer account after deposit (mirrors the behaviour available via the Bybit account settings interface)
// account types: CONTRACT Derivatives Account
// 'SPOT' Spot Account 'INVESTMENT' ByFi Account (The service has been offline) 'OPTION' USDC Account 'UNIFIED' UMA or UTA 'FUND' Funding Account
func (e *Exchange) SetDepositAccount(ctx context.Context, accountType string) (*StatusResponse, error) {
diff --git a/exchanges/coinbase/README.md b/exchanges/coinbase/README.md
index 839a87b7..6709c170 100644
--- a/exchanges/coinbase/README.md
+++ b/exchanges/coinbase/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/coinut/README.md b/exchanges/coinut/README.md
index 56d16f31..71f5f475 100644
--- a/exchanges/coinut/README.md
+++ b/exchanges/coinut/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/deribit/README.md b/exchanges/deribit/README.md
index b7a4de10..3f2187e4 100644
--- a/exchanges/deribit/README.md
+++ b/exchanges/deribit/README.md
@@ -131,7 +131,7 @@ Subscriptions are subject to enabled assets and pairs.
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/exmo/README.md b/exchanges/exmo/README.md
index 79002f47..afa92e11 100644
--- a/exchanges/exmo/README.md
+++ b/exchanges/exmo/README.md
@@ -112,7 +112,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/gateio/README.md b/exchanges/gateio/README.md
index f17a40d7..81400390 100644
--- a/exchanges/gateio/README.md
+++ b/exchanges/gateio/README.md
@@ -119,7 +119,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/gemini/README.md b/exchanges/gemini/README.md
index f706bc7c..ff9ffa30 100644
--- a/exchanges/gemini/README.md
+++ b/exchanges/gemini/README.md
@@ -112,7 +112,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/hitbtc/README.md b/exchanges/hitbtc/README.md
index b45e82d8..3ab052e1 100644
--- a/exchanges/hitbtc/README.md
+++ b/exchanges/hitbtc/README.md
@@ -132,7 +132,7 @@ Configure Levels for number of history entries to return for applicable APIs.
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/huobi/README.md b/exchanges/huobi/README.md
index 358d0444..c714354a 100644
--- a/exchanges/huobi/README.md
+++ b/exchanges/huobi/README.md
@@ -131,7 +131,7 @@ Default Authenticated Subscriptions:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/kraken/README.md b/exchanges/kraken/README.md
index 6e6edce0..c7403992 100644
--- a/exchanges/kraken/README.md
+++ b/exchanges/kraken/README.md
@@ -112,7 +112,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/kucoin/README.md b/exchanges/kucoin/README.md
index 3cfad228..ee230a8c 100644
--- a/exchanges/kucoin/README.md
+++ b/exchanges/kucoin/README.md
@@ -56,7 +56,7 @@ Unimplemented subscriptions:
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/lbank/README.md b/exchanges/lbank/README.md
index 99579ad5..5a60b491 100644
--- a/exchanges/lbank/README.md
+++ b/exchanges/lbank/README.md
@@ -112,7 +112,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/mock/README.md b/exchanges/mock/README.md
index fe87ed04..7dcce046 100644
--- a/exchanges/mock/README.md
+++ b/exchanges/mock/README.md
@@ -191,7 +191,7 @@ func TestDummyTest(t *testing.T) {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/nonce/README.md b/exchanges/nonce/README.md
index 0ceeddeb..fb7a4ccf 100644
--- a/exchanges/nonce/README.md
+++ b/exchanges/nonce/README.md
@@ -24,7 +24,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/okx/README.md b/exchanges/okx/README.md
index 2e7915cd..ca182211 100644
--- a/exchanges/okx/README.md
+++ b/exchanges/okx/README.md
@@ -134,7 +134,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/order/README.md b/exchanges/order/README.md
index 579627a1..f060ec70 100644
--- a/exchanges/order/README.md
+++ b/exchanges/order/README.md
@@ -29,7 +29,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/orderbook/README.md b/exchanges/orderbook/README.md
index 675ad6ca..8e5bec32 100644
--- a/exchanges/orderbook/README.md
+++ b/exchanges/orderbook/README.md
@@ -55,7 +55,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/poloniex/README.md b/exchanges/poloniex/README.md
index 8b2f3cba..8d47d8ce 100644
--- a/exchanges/poloniex/README.md
+++ b/exchanges/poloniex/README.md
@@ -120,7 +120,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/request/README.md b/exchanges/request/README.md
index 6e95cdcc..905edca5 100644
--- a/exchanges/request/README.md
+++ b/exchanges/request/README.md
@@ -25,7 +25,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/stats/README.md b/exchanges/stats/README.md
index d1dc2dc4..eae0330f 100644
--- a/exchanges/stats/README.md
+++ b/exchanges/stats/README.md
@@ -28,7 +28,7 @@ enabled exchanges i.e.
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/subscription/README.md b/exchanges/subscription/README.md
index 8f217980..2167b23a 100644
--- a/exchanges/subscription/README.md
+++ b/exchanges/subscription/README.md
@@ -73,7 +73,7 @@ Template functions should panic to handle errors. They are caught by text/templa
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/ticker/README.md b/exchanges/ticker/README.md
index 6f9629ee..3444f5b2 100644
--- a/exchanges/ticker/README.md
+++ b/exchanges/ticker/README.md
@@ -56,7 +56,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/trade/README.md b/exchanges/trade/README.md
index 482ae6e5..36559c09 100644
--- a/exchanges/trade/README.md
+++ b/exchanges/trade/README.md
@@ -86,7 +86,7 @@ _b in this context is an `IBotExchange` implemented struct_
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/validate/README.md b/exchanges/validate/README.md
index 9088fe55..83e85743 100644
--- a/exchanges/validate/README.md
+++ b/exchanges/validate/README.md
@@ -92,7 +92,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/exchanges/yobit/README.md b/exchanges/yobit/README.md
index 0e76e77a..0b2d2dbe 100644
--- a/exchanges/yobit/README.md
+++ b/exchanges/yobit/README.md
@@ -112,7 +112,7 @@ if err != nil {
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/gctrpc/README.md b/gctrpc/README.md
index 1a47bdf6..540f27fb 100644
--- a/gctrpc/README.md
+++ b/gctrpc/README.md
@@ -1,6 +1,6 @@
# GoCryptoTrader gRPC Service
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
diff --git a/gctscript/README.md b/gctscript/README.md
index 5fcba204..71832c5d 100644
--- a/gctscript/README.md
+++ b/gctscript/README.md
@@ -1,6 +1,6 @@
# GoCryptoTrader package gctscript
-
+
[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
@@ -247,7 +247,7 @@ withdrawcrypto
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/go.mod b/go.mod
index ff7cfc65..fe615dc3 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,6 @@ require (
github.com/bytedance/sonic v1.14.1
github.com/d5/tengo/v2 v2.17.0
github.com/gofrs/uuid v4.4.0+incompatible
- github.com/gorilla/mux v1.8.1
github.com/gorilla/websocket v1.5.3
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2
@@ -35,6 +34,7 @@ require (
)
require (
+ cloud.google.com/go/compute/metadata v0.8.4 // indirect
dario.cat/mergo v1.0.1 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
diff --git a/go.sum b/go.sum
index 2812466d..83e15a26 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,6 @@
-cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
+cloud.google.com/go/compute/metadata v0.8.4 h1:oXMa1VMQBVCyewMIOm3WQsnVd9FbKBtm8reqWRaXnHQ=
+cloud.google.com/go/compute/metadata v0.8.4/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -105,8 +105,6 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
-github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
diff --git a/main.go b/main.go
index d92d7172..77a99418 100644
--- a/main.go
+++ b/main.go
@@ -42,8 +42,6 @@ func main() {
flag.BoolVar(&settings.EnableGRPC, "grpc", true, "enables the grpc server")
flag.BoolVar(&settings.EnableGRPCProxy, "grpcproxy", false, "enables the grpc proxy server")
flag.BoolVar(&settings.EnableGRPCShutdown, "grpcshutdown", false, "enables gRPC bot instance shutdown functionality")
- flag.BoolVar(&settings.EnableWebsocketRPC, "websocketrpc", true, "enables the websocket RPC server")
- flag.BoolVar(&settings.EnableDeprecatedRPC, "deprecatedrpc", true, "enables the deprecated RPC server")
flag.BoolVar(&settings.EnableCommsRelayer, "enablecommsrelayer", true, "enables available communications relayer")
flag.BoolVar(&settings.Verbose, "verbose", false, "increases logging verbosity for GoCryptoTrader")
flag.BoolVar(&settings.EnableFuturesTracking, "enablefuturestracking", true, "tracks futures orders PNL is supported by the exchange")
diff --git a/portfolio/README.md b/portfolio/README.md
index ba61635a..3eecb52f 100644
--- a/portfolio/README.md
+++ b/portfolio/README.md
@@ -24,7 +24,7 @@ Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/testdata/README.md b/testdata/README.md
index 06934caa..501f60f3 100644
--- a/testdata/README.md
+++ b/testdata/README.md
@@ -25,7 +25,7 @@ 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/).
## Donations
-
+
If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
diff --git a/testdata/configtest.json b/testdata/configtest.json
index 07feebdd..7cc663ee 100644
--- a/testdata/configtest.json
+++ b/testdata/configtest.json
@@ -187,17 +187,6 @@
"listenAddress": "localhost:9052",
"grpcProxyEnabled": true,
"grpcProxyListenAddress": "localhost:9053"
- },
- "deprecatedRPC": {
- "enabled": true,
- "listenAddress": "localhost:9050"
- },
- "websocketRPC": {
- "enabled": true,
- "listenAddress": "localhost:9051",
- "connectionLimit": 1,
- "maxAuthFailures": 3,
- "allowInsecureOrigin": true
}
},
"portfolioAddresses": {
diff --git a/web/.dockerignore b/web/.dockerignore
deleted file mode 100644
index 651665bb..00000000
--- a/web/.dockerignore
+++ /dev/null
@@ -1,2 +0,0 @@
-node_modules
-.git
diff --git a/web/.editorconfig b/web/.editorconfig
deleted file mode 100644
index 6e87a003..00000000
--- a/web/.editorconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-# Editor configuration, see http://editorconfig.org
-root = true
-
-[*]
-charset = utf-8
-indent_style = space
-indent_size = 2
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[*.md]
-max_line_length = off
-trim_trailing_whitespace = false
diff --git a/web/.gitignore b/web/.gitignore
deleted file mode 100644
index f3b334d1..00000000
--- a/web/.gitignore
+++ /dev/null
@@ -1,44 +0,0 @@
-# See http://help.github.com/ignore-files/ for more about ignoring files.
-
-# compiled output
-/dist
-/tmp
-/out-tsc
-/app-builds
-main.js
-
-# dependencies
-/node_modules
-
-# IDEs and editors
-/.idea
-.project
-.classpath
-.c9/
-*.launch
-.settings/
-*.sublime-workspace
-
-# IDE - VSCode
-.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
-!.vscode/extensions.json
-
-# misc
-/.sass-cache
-/connect.lock
-/coverage
-/libpeerconnection.log
-npm-debug.log
-testem.log
-/typings
-
-# e2e
-/e2e/*.js
-/e2e/*.map
-
-# System Files
-.DS_Store
-Thumbs.db
diff --git a/web/Dockerfile b/web/Dockerfile
deleted file mode 100644
index ee912b68..00000000
--- a/web/Dockerfile
+++ /dev/null
@@ -1,17 +0,0 @@
-FROM node:14-alpine as build
-COPY package.json package-lock.json ./
-RUN npm set progress=false \
- && npm config set depth 0 \
- && npm cache clean --force
-RUN npm i \
- && mkdir /app \
- && cp -R ./node_modules /app
-WORKDIR /app
-COPY . .
-RUN $(npm bin)/ng build --prod --build-optimizer
-
-FROM nginx:1.19.2-alpine
-RUN rm -rf /var/www/html/*
-COPY nginx/default.conf /etc/nginx/conf.d/
-COPY --from=build /app/dist /var/www/html
-CMD ["nginx", "-g", "daemon off;"]
diff --git a/web/LICENSE.md b/web/LICENSE.md
deleted file mode 100644
index 82974222..00000000
--- a/web/LICENSE.md
+++ /dev/null
@@ -1,7 +0,0 @@
-Copyright 2018 - GloriousCode
-Copyright 2017 - Maxime GRIS
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/web/README.md b/web/README.md
deleted file mode 100644
index 15d31346..00000000
--- a/web/README.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# GoCryptoTrader package Web
-
-
-
-
-[](https://github.com/thrasher-corp/gocryptotrader/actions/workflows/tests.yml)
-[](https://github.com/thrasher-corp/gocryptotrader/blob/master/LICENSE)
-[](https://godoc.org/github.com/thrasher-corp/gocryptotrader/web)
-[](https://codecov.io/gh/thrasher-corp/gocryptotrader)
-[](https://goreportcard.com/report/github.com/thrasher-corp/gocryptotrader)
-
-
-This web package is part of the GoCryptoTrader codebase.
-
-## This is still in active development
-
-You can track ideas, planned features and what's in progress on our [GoCryptoTrader Kanban board](https://github.com/orgs/thrasher-corp/projects/3).
-
-Join our slack to discuss all things related to GoCryptoTrader! [GoCryptoTrader Slack](https://join.slack.com/t/gocryptotrader/shared_invite/zt-38z8abs3l-gH8AAOk8XND6DP5NfCiG_g)
-
-
-# The Angular version of the front-end is being replaced by a React implementation on this branch: https://github.com/thrasher-corp/gocryptotrader/tree/react-web/web
-### There will be no further development on the Angular front end and all development should be directed to the new branch until it is merged.
-
-## Install dependencies with npm
-
-``` bash
-npm install
-```
-
-If you want to generate Angular components with Angular-cli , you **MUST** install `@angular/cli` in npm global context.
-Please follow [Angular-cli documentation](https://github.com/angular/angular-cli) if you had installed a previous version of `angular-cli`.
-
-``` bash
-npm install -g @angular/cli
-```
-
-## To build for development
-
-``` bash
-npm run start:web
-```
-
-Currently runs with:
-
-- Angular v7
-
-## To build for production
-
-- **in a terminal window** -> npm start
-
-Voila! You can use your Angular + Electron app in a local development environment with hot reload !
-
-## Manage your environment variables
-
-- Using local variables : `npm start` or `cross-env ENV=local npm start`
-- Using development variables : `cross-env ENV=dev npm start`
-- Using production variables : `cross-env ENV=prod npm start`
-
-## Included Commands
-
-|Command|Description|
-|--|--|
-|`npm run ng:serve`| Execute the app in the browser |
-|`npm run start:web`| Execute the app in the browser |
-|`npm run build`| Build the app. Your built files are in the /dist folder. |
-|`npm run build:prod`| Build the app with Angular aot. Your built files are in the /dist folder. |
-|`npm run electron:local`| Builds your application and start electron
-|`npm run electron:linux`| Builds your application and creates an app consumable on linux system |
-|`npm run electron:windows`| On a Windows OS, builds your application and creates an app consumable in windows 32/64 bit systems |
-|`npm run electron:mac`| On a MAC OS, builds your application and generates a `.app` file of your application that can be run on Mac |
-
-**Your application is optimised. Only /dist folder and node dependencies are included in the executable.**
-
-## Donations
-
-
-
-If this framework helped you in any way, or you would like to support the developers working on it, please donate Bitcoin to:
-
-***bc1qk0jareu4jytc0cfrhr5wgshsq8282awpavfahc***
diff --git a/web/_config.yml b/web/_config.yml
deleted file mode 100644
index 3397c9a4..00000000
--- a/web/_config.yml
+++ /dev/null
@@ -1 +0,0 @@
-theme: jekyll-theme-architect
\ No newline at end of file
diff --git a/web/angular.json b/web/angular.json
deleted file mode 100644
index 9a8f2cf5..00000000
--- a/web/angular.json
+++ /dev/null
@@ -1,136 +0,0 @@
-{
- "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
- "version": 1,
- "newProjectRoot": "projects",
- "projects": {
- "gocryptotrader-web": {
- "root": "",
- "sourceRoot": "src",
- "projectType": "application",
- "architect": {
- "build": {
- "builder": "@angular-devkit/build-angular:browser",
- "options": {
- "outputPath": "dist",
- "index": "src/index.html",
- "main": "src/main.ts",
- "tsConfig": "src/tsconfig.app.json",
- "polyfills": "src/polyfills.ts",
- "assets": [
- "src/assets",
- "src/favicon.ico",
- "src/favicon.png",
- "src/favicon.256x256.png"
- ],
- "styles": [
- "src/styles.scss"
- ],
- "scripts": []
- },
- "configurations": {
- "production": {
- "optimization": true,
- "outputHashing": "all",
- "sourceMap": false,
- "extractCss": true,
- "namedChunks": false,
- "aot": true,
- "extractLicenses": true,
- "vendorChunk": false,
- "buildOptimizer": true,
- "fileReplacements": [
- {
- "replace": "src/environments/environment.ts",
- "with": "src/environments/environment.prod.ts"
- }
- ]
- }
- }
- },
- "serve": {
- "builder": "@angular-devkit/build-angular:dev-server",
- "options": {
- "browserTarget": "gocryptotrader-web:build"
- },
- "configurations": {
- "production": {
- "browserTarget": "gocryptotrader-web:build:production"
- }
- }
- },
- "extract-i18n": {
- "builder": "@angular-devkit/build-angular:extract-i18n",
- "options": {
- "browserTarget": "gocryptotrader-web:build"
- }
- },
- "test": {
- "builder": "@angular-devkit/build-angular:karma",
- "options": {
- "main": "src/test.ts",
- "karmaConfig": "./karma.conf.js",
- "polyfills": "src/polyfills.ts",
- "tsConfig": "src/tsconfig.spec.json",
- "scripts": [],
- "styles": [
- "src/styles.scss"
- ],
- "assets": [
- "src/assets",
- "src/favicon.ico",
- "src/favicon.png",
- "src/favicon.256x256.png"
- ]
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "src/tsconfig.app.json",
- "src/tsconfig.spec.json"
- ],
- "exclude": [
- "**/node_modules/**"
- ]
- }
- }
- }
- },
- "gocryptotrader-web-e2e": {
- "root": "",
- "sourceRoot": "e2e",
- "projectType": "application",
- "architect": {
- "e2e": {
- "builder": "@angular-devkit/build-angular:protractor",
- "options": {
- "protractorConfig": "./protractor.conf.js",
- "devServerTarget": "gocryptotrader-web:serve"
- }
- },
- "lint": {
- "builder": "@angular-devkit/build-angular:tslint",
- "options": {
- "tsConfig": [
- "e2e/tsconfig.e2e.json"
- ],
- "exclude": [
- "**/node_modules/**"
- ]
- }
- }
- }
- }
- },
- "defaultProject": "gocryptotrader-web",
- "schematics": {
- "@schematics/angular:component": {
- "prefix": "app",
- "styleext": "scss"
- },
- "@schematics/angular:directive": {
- "prefix": "app"
- }
- }
-}
\ No newline at end of file
diff --git a/web/e2e/app.e2e-spec.ts b/web/e2e/app.e2e-spec.ts
deleted file mode 100644
index 5cd698f8..00000000
--- a/web/e2e/app.e2e-spec.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { AngularElectronPage } from './app.po';
-import { browser, element, by } from 'protractor';
-
-describe('angular-electron App', () => {
- let page: AngularElectronPage;
-
- beforeEach(() => {
- page = new AngularElectronPage();
- });
-
- it('should display message saying App works !', () => {
- page.navigateTo('/');
- expect(element(by.css('app-home h1')).getText()).toMatch('App works !');
- });
-});
diff --git a/web/e2e/app.po.ts b/web/e2e/app.po.ts
deleted file mode 100644
index 2dedeae9..00000000
--- a/web/e2e/app.po.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { browser, element, by } from 'protractor';
-
-/* tslint:disable */
-export class AngularElectronPage {
- navigateTo(route: string) {
- return browser.get(route);
- }
-}
diff --git a/web/e2e/tsconfig.e2e.json b/web/e2e/tsconfig.e2e.json
deleted file mode 100644
index ac7a3732..00000000
--- a/web/e2e/tsconfig.e2e.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "compilerOptions": {
- "outDir": "../out-tsc/e2e",
- "module": "commonjs",
- "target": "es5",
- "types":[
- "jasmine",
- "node"
- ]
- }
-}
diff --git a/web/electron-builder.json b/web/electron-builder.json
deleted file mode 100644
index c68f0be0..00000000
--- a/web/electron-builder.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "productName": "gocyrptotrader-web",
- "directories": {
- "output": "app-builds"
- },
- "win": {
- "icon": "dist",
- "target": [
- "portable"
- ]
- },
- "mac": {
- "icon": "dist",
- "target": [
- "dmg"
- ]
- },
- "linux": {
- "icon": "dist",
- "target": [
- "AppImage"
- ]
- }
-}
diff --git a/web/hooks/environments/README.md b/web/hooks/environments/README.md
deleted file mode 100644
index 62e58b48..00000000
--- a/web/hooks/environments/README.md
+++ /dev/null
@@ -1,196 +0,0 @@
-
-# Cordova Hooks
-
-Cordova Hooks represent special scripts which could be added by application and plugin developers or even by your own build system to customize cordova commands. Hook scripts could be defined by adding them to the special predefined folder (`/hooks`) or via configuration files (`config.xml` and `plugin.xml`) and run serially in the following order:
-* Application hooks from `/hooks`;
-* Application hooks from `config.xml`;
-* Plugin hooks from `plugins/.../plugin.xml`.
-
-__Remember__: Make your scripts executable.
-
-__Note__: `.cordova/hooks` directory is also supported for backward compatibility, but we don't recommend using it as it is deprecated.
-
-## Supported hook types
-The following hook types are supported:
-
- after_build/
- after_compile/
- after_docs/
- after_emulate/
- after_platform_add/
- after_platform_rm/
- after_platform_ls/
- after_plugin_add/
- after_plugin_ls/
- after_plugin_rm/
- after_plugin_search/
- after_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed
- after_prepare/
- after_run/
- after_serve/
- before_build/
- before_compile/
- before_docs/
- before_emulate/
- before_platform_add/
- before_platform_rm/
- before_platform_ls/
- before_plugin_add/
- before_plugin_ls/
- before_plugin_rm/
- before_plugin_search/
- before_plugin_install/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being installed
- before_plugin_uninstall/ <-- Plugin hooks defined in plugin.xml are executed exclusively for a plugin being uninstalled
- before_prepare/
- before_run/
- before_serve/
- pre_package/ <-- Windows 8 and Windows Phone only.
-
-## Ways to define hooks
-### Via '/hooks' directory
-To execute custom action when corresponding hook type is fired, use hook type as a name for a subfolder inside 'hooks' directory and place you script file here, for example:
-
- # script file will be automatically executed after each build
- hooks/after_build/after_build_custom_action.js
-
-
-### Config.xml
-
-Hooks can be defined in project's `config.xml` using `- about works! -
diff --git a/web/src/app/pages/about/about.component.scss b/web/src/app/pages/about/about.component.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/web/src/app/pages/about/about.component.spec.ts b/web/src/app/pages/about/about.component.spec.ts deleted file mode 100644 index 3ed18005..00000000 --- a/web/src/app/pages/about/about.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AboutComponent } from './about.component'; - -describe('AboutComponent', () => { - let component: AboutComponent; - let fixture: ComponentFixture
- If this framework helped you in any way, or you would like to support the developers working on it, please donate
-- history works! -
diff --git a/web/src/app/pages/history/history.component.scss b/web/src/app/pages/history/history.component.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/web/src/app/pages/history/history.component.spec.ts b/web/src/app/pages/history/history.component.spec.ts deleted file mode 100644 index f68be4f2..00000000 --- a/web/src/app/pages/history/history.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HistoryComponent } from './history.component'; - -describe('HistoryComponent', () => { - let component: HistoryComponent; - let fixture: ComponentFixture
- With support for over 25 of the top cryptocurrency exchanges
-
- Constant checking of all enabled exchanges* to get you the most up to date information
-
-
- The latest tech with Material design lets you focus on what's important
-W?!0:!1);if(!J)switch(this.showBalloonAt){case "close":v.y=F;break;case "open":v.y=
-N;break;case "high":v.y=ta;break;case "low":v.y=ra}var ja=G.x[ma.id],Xa=this.periodSpan-1;"step"!=h||isNaN(G.cellWidth)||(Y=G.cellWidth);var wa=Math.floor(Y/2)+Math.floor(Xa*Y/2),Ga=wa,qb=0;"left"==this.stepDirection&&(qb=(2*Y+Xa*Y)/2,ja-=qb);"center"==this.stepDirection&&(qb=Y/2,ja-=qb);"start"==this.pointPosition&&(ja-=Y/2+Math.floor(Xa*Y/2),wa=0,Ga=Math.floor(Y)+Math.floor(Xa*Y));"end"==this.pointPosition&&(ja+=Y/2+Math.floor(Xa*Y/2),wa=Math.floor(Y)+Math.floor(Xa*Y),Ga=0);if(Ob){var Cb=this.columnWidth;
-isNaN(Cb)||(wa*=Cb,Ga*=Cb)}J||(v.x=ja);-1E5>ja&&(ja=-1E5);ja>n+1E5&&(ja=n+1E5);t?(E=F,O=N,N=F=ja,isNaN(ua)&&!this.fillToGraph&&(O=na),qa=ra,sa=ta):(O=E=ja,isNaN(ua)&&!this.fillToGraph&&(N=na));if(!Bb&&W b?this.colors[b]:a.lineColorR?a.lineColorR:d.randomColor();a.lineColorR=c}a.fillColorsR=a.fillColors?a.fillColors:a.lineColorR;a.bulletBorderColorR=a.bulletBorderColor?a.bulletBorderColor:a.useLineColorForBulletBorder?a.lineColorR:a.bulletColor;a.bulletColorR=a.bulletColor?a.bulletColor:a.lineColorR;if(c=this.patterns)a.pattern=
-c[b]},handleLegendEvent:function(a){var b=a.type;if(a=a.dataItem){var c=a.hidden,d=a.showBalloon;switch(b){case "clickMarker":this.textClickEnabled&&(d?this.hideGraphsBalloon(a):this.showGraphsBalloon(a));break;case "clickLabel":d?this.hideGraphsBalloon(a):this.showGraphsBalloon(a);break;case "rollOverItem":c||this.highlightGraph(a);break;case "rollOutItem":c||this.unhighlightGraph();break;case "hideItem":this.hideGraph(a);break;case "showItem":this.showGraph(a)}}},highlightGraph:function(a){var b=
-this.graphs;if(b){var c,d=.2;this.legend&&(d=this.legend.rollOverGraphAlpha);if(1!=d)for(c=0;c c&&(d="00"+c);10<=c&&100>c&&(d="0"+c);a=a.replace(/fff/g,d)}return a};d.extractPeriod=function(a){var b=d.stripNumbers(a),c=1;b!=a&&(c=Number(a.slice(0,a.indexOf(b))));return{period:b,count:c}};d.getDate=function(a,b,c){return a instanceof Date?d.newDate(a,c):b&&isNaN(a)?d.stringToDate(a,b):new Date(a)};d.daysInMonth=function(a){return(new Date(a.getYear(),a.getMonth()+
-1,0)).getDate()};d.newDate=function(a,b){return b&&-1==b.indexOf("fff")?new Date(a):new Date(a.getFullYear(),a.getMonth(),a.getDate(),a.getHours(),a.getMinutes(),a.getSeconds(),a.getMilliseconds())};d.resetDateToMin=function(a,b,c,e){void 0===e&&(e=1);var g,f,h,k,l,m,n;d.useUTC?(g=a.getUTCFullYear(),f=a.getUTCMonth(),h=a.getUTCDate(),k=a.getUTCHours(),l=a.getUTCMinutes(),m=a.getUTCSeconds(),n=a.getUTCMilliseconds(),a=a.getUTCDay()):(g=a.getFullYear(),f=a.getMonth(),h=a.getDate(),k=a.getHours(),l=
-a.getMinutes(),m=a.getSeconds(),n=a.getMilliseconds(),a=a.getDay());switch(b){case "YYYY":g=Math.floor(g/c)*c;f=0;h=1;n=m=l=k=0;break;case "MM":f=Math.floor(f/c)*c;h=1;n=m=l=k=0;break;case "WW":h=a>=e?h-a+e:h-(7+a)+e;n=m=l=k=0;break;case "DD":n=m=l=k=0;break;case "hh":k=Math.floor(k/c)*c;n=m=l=0;break;case "mm":l=Math.floor(l/c)*c;n=m=0;break;case "ss":m=Math.floor(m/c)*c;n=0;break;case "fff":n=Math.floor(n/c)*c}d.useUTC?(a=new Date,a.setUTCFullYear(g,f,h),a.setUTCHours(k,l,m,n)):a=new Date(g,f,h,
-k,l,m,n);return a};d.getPeriodDuration=function(a,b){void 0===b&&(b=1);var c;switch(a){case "YYYY":c=316224E5;break;case "MM":c=26784E5;break;case "WW":c=6048E5;break;case "DD":c=864E5;break;case "hh":c=36E5;break;case "mm":c=6E4;break;case "ss":c=1E3;break;case "fff":c=1}return c*b};d.intervals={s:{nextInterval:"ss",contains:1E3},ss:{nextInterval:"mm",contains:60,count:0},mm:{nextInterval:"hh",contains:60,count:1},hh:{nextInterval:"DD",contains:24,count:2},DD:{nextInterval:"",contains:Infinity,count:3}};
-d.getMaxInterval=function(a,b){var c=d.intervals;return a>=c[b].contains?(a=Math.round(a/c[b].contains),b=c[b].nextInterval,d.getMaxInterval(a,b)):"ss"==b?c[b].nextInterval:b};d.dayNames="Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" ");d.shortDayNames="Sun Mon Tue Wed Thu Fri Sat".split(" ");d.monthNames="January February March April May June July August September October November December".split(" ");d.shortMonthNames="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");
-d.getWeekNumber=function(a){a=new Date(a);a.setHours(0,0,0);a.setDate(a.getDate()+4-(a.getDay()||7));var b=new Date(a.getFullYear(),0,1);return Math.ceil(((a-b)/864E5+1)/7)};d.stringToDate=function(a,b){var c={},e=[{pattern:"YYYY",period:"year"},{pattern:"YY",period:"year"},{pattern:"MM",period:"month"},{pattern:"M",period:"month"},{pattern:"DD",period:"date"},{pattern:"D",period:"date"},{pattern:"JJ",period:"hours"},{pattern:"J",period:"hours"},{pattern:"HH",period:"hours"},{pattern:"H",period:"hours"},
-{pattern:"KK",period:"hours"},{pattern:"K",period:"hours"},{pattern:"LL",period:"hours"},{pattern:"L",period:"hours"},{pattern:"NN",period:"minutes"},{pattern:"N",period:"minutes"},{pattern:"SS",period:"seconds"},{pattern:"S",period:"seconds"},{pattern:"QQQ",period:"milliseconds"},{pattern:"QQ",period:"milliseconds"},{pattern:"Q",period:"milliseconds"}],g=!0,f=b.indexOf("AA");-1!=f&&(a.substr(f,2),"pm"==a.toLowerCase&&(g=!1));var f=b,h,k,l;for(l=0;ln+Aa*H&&(K=n-S+Aa*H);S
ua?(Eb=[E,sa],Fb=[O,qa]):(Eb=[O,sa],Fb=[E,qa]);!isNaN(sa)&&!isNaN(qa)&&F
n&&(K=n-S);0>S&&(K+=S,S=0);ba=F-N;if(S
g.getTime()&&(a=g);b.getTime()
