Merge branch 'develop' into feat/short
This commit is contained in:
commit
bd488cc086
@ -53,7 +53,7 @@ Please find the complete documentation on our [website](https://www.freqtrade.io
|
|||||||
- [x] **Dry-run**: Run the bot without paying money.
|
- [x] **Dry-run**: Run the bot without paying money.
|
||||||
- [x] **Backtesting**: Run a simulation of your buy/sell strategy.
|
- [x] **Backtesting**: Run a simulation of your buy/sell strategy.
|
||||||
- [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data.
|
- [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data.
|
||||||
- [x] **Edge position sizing** Calculate your win rate, risk reward ratio, the best stoploss and adjust your position size before taking a position for each specific market. [Learn more](https://www.freqtrade.io/en/latest/edge/).
|
- [x] **Edge position sizing** Calculate your win rate, risk reward ratio, the best stoploss and adjust your position size before taking a position for each specific market. [Learn more](https://www.freqtrade.io/en/stable/edge/).
|
||||||
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade or use dynamic whitelists.
|
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade or use dynamic whitelists.
|
||||||
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
|
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
|
||||||
- [x] **Manageable via Telegram**: Manage the bot with Telegram.
|
- [x] **Manageable via Telegram**: Manage the bot with Telegram.
|
||||||
@ -66,12 +66,12 @@ Please find the complete documentation on our [website](https://www.freqtrade.io
|
|||||||
Freqtrade provides a Linux/macOS script to install all dependencies and help you to configure the bot.
|
Freqtrade provides a Linux/macOS script to install all dependencies and help you to configure the bot.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone -b develop https://github.com/freqtrade/freqtrade.git
|
git clone -b develop https://github.com/freqtrade/freqtrade.git
|
||||||
cd freqtrade
|
cd freqtrade
|
||||||
./setup.sh --install
|
./setup.sh --install
|
||||||
```
|
```
|
||||||
|
|
||||||
For any other type of installation please refer to [Installation doc](https://www.freqtrade.io/en/latest/installation/).
|
For any other type of installation please refer to [Installation doc](https://www.freqtrade.io/en/stable/installation/).
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
|
@ -28,10 +28,8 @@
|
|||||||
"name": "binance",
|
"name": "binance",
|
||||||
"key": "your_exchange_key",
|
"key": "your_exchange_key",
|
||||||
"secret": "your_exchange_secret",
|
"secret": "your_exchange_secret",
|
||||||
"ccxt_config": {"enableRateLimit": true},
|
"ccxt_config": {},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {
|
||||||
"enableRateLimit": true,
|
|
||||||
"rateLimit": 200
|
|
||||||
},
|
},
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
"ALGO/BTC",
|
"ALGO/BTC",
|
||||||
|
@ -28,11 +28,8 @@
|
|||||||
"name": "ftx",
|
"name": "ftx",
|
||||||
"key": "your_exchange_key",
|
"key": "your_exchange_key",
|
||||||
"secret": "your_exchange_secret",
|
"secret": "your_exchange_secret",
|
||||||
"ccxt_config": {"enableRateLimit": true},
|
"ccxt_config": {},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {},
|
||||||
"enableRateLimit": true,
|
|
||||||
"rateLimit": 50
|
|
||||||
},
|
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
"BTC/USD",
|
"BTC/USD",
|
||||||
"ETH/USD",
|
"ETH/USD",
|
||||||
|
@ -84,12 +84,8 @@
|
|||||||
"key": "your_exchange_key",
|
"key": "your_exchange_key",
|
||||||
"secret": "your_exchange_secret",
|
"secret": "your_exchange_secret",
|
||||||
"password": "",
|
"password": "",
|
||||||
"ccxt_config": {"enableRateLimit": true},
|
"ccxt_config": {},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {},
|
||||||
"enableRateLimit": true,
|
|
||||||
"rateLimit": 500,
|
|
||||||
"aiohttp_trust_env": false
|
|
||||||
},
|
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
"ALGO/BTC",
|
"ALGO/BTC",
|
||||||
"ATOM/BTC",
|
"ATOM/BTC",
|
||||||
|
@ -28,10 +28,8 @@
|
|||||||
"name": "kraken",
|
"name": "kraken",
|
||||||
"key": "your_exchange_key",
|
"key": "your_exchange_key",
|
||||||
"secret": "your_exchange_key",
|
"secret": "your_exchange_key",
|
||||||
"ccxt_config": {"enableRateLimit": true},
|
"ccxt_config": {},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {
|
||||||
"enableRateLimit": true,
|
|
||||||
"rateLimit": 1000
|
|
||||||
},
|
},
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
"ADA/EUR",
|
"ADA/EUR",
|
||||||
|
@ -15,10 +15,10 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- "./user_data:/freqtrade/user_data"
|
- "./user_data:/freqtrade/user_data"
|
||||||
# Expose api on port 8080 (localhost only)
|
# Expose api on port 8080 (localhost only)
|
||||||
# Please read the https://www.freqtrade.io/en/latest/rest-api/ documentation
|
# Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation
|
||||||
# before enabling this.
|
# before enabling this.
|
||||||
# ports:
|
ports:
|
||||||
# - "127.0.0.1:8080:8080"
|
- "127.0.0.1:8080:8080"
|
||||||
# Default command used when running `docker compose up`
|
# Default command used when running `docker compose up`
|
||||||
command: >
|
command: >
|
||||||
trade
|
trade
|
||||||
|
@ -447,45 +447,6 @@ The possible values are: `gtc` (default), `fok` or `ioc`.
|
|||||||
This is ongoing work. For now, it is supported only for binance and kucoin.
|
This is ongoing work. For now, it is supported only for binance and kucoin.
|
||||||
Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
|
Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
|
||||||
|
|
||||||
### Exchange configuration
|
|
||||||
|
|
||||||
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports over 100 cryptocurrency
|
|
||||||
exchange markets and trading APIs. The complete up-to-date list can be found in the
|
|
||||||
[CCXT repo homepage](https://github.com/ccxt/ccxt/tree/master/python).
|
|
||||||
However, the bot was tested by the development team with only Bittrex, Binance and Kraken,
|
|
||||||
so these are the only officially supported exchanges:
|
|
||||||
|
|
||||||
- [Bittrex](https://bittrex.com/): "bittrex"
|
|
||||||
- [Binance](https://www.binance.com/): "binance"
|
|
||||||
- [Kraken](https://kraken.com/): "kraken"
|
|
||||||
|
|
||||||
Feel free to test other exchanges and submit your PR to improve the bot.
|
|
||||||
|
|
||||||
Some exchanges require special configuration, which can be found on the [Exchange-specific Notes](exchanges.md) documentation page.
|
|
||||||
|
|
||||||
#### Sample exchange configuration
|
|
||||||
|
|
||||||
A exchange configuration for "binance" would look as follows:
|
|
||||||
|
|
||||||
```json
|
|
||||||
"exchange": {
|
|
||||||
"name": "binance",
|
|
||||||
"key": "your_exchange_key",
|
|
||||||
"secret": "your_exchange_secret",
|
|
||||||
"ccxt_config": {"enableRateLimit": true},
|
|
||||||
"ccxt_async_config": {
|
|
||||||
"enableRateLimit": true,
|
|
||||||
"rateLimit": 200
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
This configuration enables binance, as well as rate-limiting to avoid bans from the exchange.
|
|
||||||
`"rateLimit": 200` defines a wait-event of 0.2s between each call. This can also be completely disabled by setting `"enableRateLimit"` to false.
|
|
||||||
|
|
||||||
!!! Note
|
|
||||||
Optimal settings for rate-limiting depend on the exchange and the size of the whitelist, so an ideal parameter will vary on many other settings.
|
|
||||||
We try to provide sensible defaults per exchange where possible, if you encounter bans please make sure that `"enableRateLimit"` is enabled and increase the `"rateLimit"` parameter step by step.
|
|
||||||
|
|
||||||
### What values can be used for fiat_display_currency?
|
### What values can be used for fiat_display_currency?
|
||||||
|
|
||||||
The `fiat_display_currency` configuration parameter sets the base currency to use for the
|
The `fiat_display_currency` configuration parameter sets the base currency to use for the
|
||||||
|
@ -70,6 +70,18 @@ docker-compose up -d
|
|||||||
!!! Warning "Default configuration"
|
!!! Warning "Default configuration"
|
||||||
While the configuration generated will be mostly functional, you will still need to verify that all options correspond to what you want (like Pricing, pairlist, ...) before starting the bot.
|
While the configuration generated will be mostly functional, you will still need to verify that all options correspond to what you want (like Pricing, pairlist, ...) before starting the bot.
|
||||||
|
|
||||||
|
#### Accessing the UI
|
||||||
|
|
||||||
|
If you've selected to enable FreqUI in the `new-config` step, you will have freqUI available at port `localhost:8080`.
|
||||||
|
|
||||||
|
You can now access the UI by typing localhost:8080 in your browser.
|
||||||
|
|
||||||
|
??? Note "UI Access on a remote servers"
|
||||||
|
If you're running on a VPS, you should consider using either a ssh tunnel, or setup a VPN (openVPN, wireguard) to connect to your bot.
|
||||||
|
This will ensure that freqUI is not directly exposed to the internet, which is not recommended for security reasons (freqUI does not support https out of the box).
|
||||||
|
Setup of these tools is not part of this tutorial, however many good tutorials can be found on the internet.
|
||||||
|
Please also read the [API configuration with docker](rest-api.md#configuration-with-docker) section to learn more about this configuration.
|
||||||
|
|
||||||
#### Monitoring the bot
|
#### Monitoring the bot
|
||||||
|
|
||||||
You can check for running instances with `docker-compose ps`.
|
You can check for running instances with `docker-compose ps`.
|
||||||
@ -148,27 +160,9 @@ You'll then also need to modify the `docker-compose.yml` file and uncomment the
|
|||||||
dockerfile: "./Dockerfile.<yourextension>"
|
dockerfile: "./Dockerfile.<yourextension>"
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then run `docker-compose build` to build the docker image, and run it using the commands described above.
|
You can then run `docker-compose build --pull` to build the docker image, and run it using the commands described above.
|
||||||
|
|
||||||
### Troubleshooting
|
### Plotting with docker-compose
|
||||||
|
|
||||||
#### Docker on Windows
|
|
||||||
|
|
||||||
* Error: `"Timestamp for this request is outside of the recvWindow."`
|
|
||||||
* The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past.
|
|
||||||
To fix this issue temporarily you need to run `wsl --shutdown` and restart docker again (a popup on windows 10 will ask you to do so).
|
|
||||||
A permanent solution is either to host the docker container on a linux host or restart the wsl from time to time with the scheduler.
|
|
||||||
```
|
|
||||||
taskkill /IM "Docker Desktop.exe" /F
|
|
||||||
wsl --shutdown
|
|
||||||
start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe"
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! Warning
|
|
||||||
Due to the above, we do not recommend the usage of docker on windows for production setups, but only for experimentation, datadownload and backtesting.
|
|
||||||
Best use a linux-VPS for running freqtrade reliably.
|
|
||||||
|
|
||||||
## Plotting with docker-compose
|
|
||||||
|
|
||||||
Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your docker-compose.yml file.
|
Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your docker-compose.yml file.
|
||||||
You can then use these commands as follows:
|
You can then use these commands as follows:
|
||||||
@ -179,7 +173,7 @@ docker-compose run --rm freqtrade plot-dataframe --strategy AwesomeStrategy -p B
|
|||||||
|
|
||||||
The output will be stored in the `user_data/plot` directory, and can be opened with any modern browser.
|
The output will be stored in the `user_data/plot` directory, and can be opened with any modern browser.
|
||||||
|
|
||||||
## Data analysis using docker compose
|
### Data analysis using docker compose
|
||||||
|
|
||||||
Freqtrade provides a docker-compose file which starts up a jupyter lab server.
|
Freqtrade provides a docker-compose file which starts up a jupyter lab server.
|
||||||
You can run this server using the following command:
|
You can run this server using the following command:
|
||||||
@ -196,3 +190,22 @@ Since part of this image is built on your machine, it is recommended to rebuild
|
|||||||
``` bash
|
``` bash
|
||||||
docker-compose -f docker/docker-compose-jupyter.yml build --no-cache
|
docker-compose -f docker/docker-compose-jupyter.yml build --no-cache
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Docker on Windows
|
||||||
|
|
||||||
|
* Error: `"Timestamp for this request is outside of the recvWindow."`
|
||||||
|
* The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past.
|
||||||
|
To fix this issue temporarily you need to run `wsl --shutdown` and restart docker again (a popup on windows 10 will ask you to do so).
|
||||||
|
A permanent solution is either to host the docker container on a linux host or restart the wsl from time to time with the scheduler.
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
taskkill /IM "Docker Desktop.exe" /F
|
||||||
|
wsl --shutdown
|
||||||
|
start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe"
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
Due to the above, we do not recommend the usage of docker on windows for production setups, but only for experimentation, datadownload and backtesting.
|
||||||
|
Best use a linux-VPS for running freqtrade reliably.
|
||||||
|
@ -2,6 +2,56 @@
|
|||||||
|
|
||||||
This page combines common gotchas and informations which are exchange-specific and most likely don't apply to other exchanges.
|
This page combines common gotchas and informations which are exchange-specific and most likely don't apply to other exchanges.
|
||||||
|
|
||||||
|
## Exchange configuration
|
||||||
|
|
||||||
|
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports over 100 cryptocurrency
|
||||||
|
exchange markets and trading APIs. The complete up-to-date list can be found in the
|
||||||
|
[CCXT repo homepage](https://github.com/ccxt/ccxt/tree/master/python).
|
||||||
|
However, the bot was tested by the development team with only a few exchanges.
|
||||||
|
A current list of these can be found in the "Home" section of this documentation.
|
||||||
|
|
||||||
|
Feel free to test other exchanges and submit your feedback or PR to improve the bot or confirm exchanges that work flawlessly..
|
||||||
|
|
||||||
|
Some exchanges require special configuration, which can be found below.
|
||||||
|
|
||||||
|
### Sample exchange configuration
|
||||||
|
|
||||||
|
A exchange configuration for "binance" would look as follows:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"exchange": {
|
||||||
|
"name": "binance",
|
||||||
|
"key": "your_exchange_key",
|
||||||
|
"secret": "your_exchange_secret",
|
||||||
|
"ccxt_config": {},
|
||||||
|
"ccxt_async_config": {},
|
||||||
|
// ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting rate limits
|
||||||
|
|
||||||
|
Usually, rate limits set by CCXT are reliable and work well.
|
||||||
|
In case of problems related to rate-limits (usually DDOS Exceptions in your logs), it's easy to change rateLimit settings to other values.
|
||||||
|
|
||||||
|
```json
|
||||||
|
"exchange": {
|
||||||
|
"name": "kraken",
|
||||||
|
"key": "your_exchange_key",
|
||||||
|
"secret": "your_exchange_secret",
|
||||||
|
"ccxt_config": {"enableRateLimit": true},
|
||||||
|
"ccxt_async_config": {
|
||||||
|
"enableRateLimit": true,
|
||||||
|
"rateLimit": 3100
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
This configuration enables kraken, as well as rate-limiting to avoid bans from the exchange.
|
||||||
|
`"rateLimit": 3100` defines a wait-event of 0.2s between each call. This can also be completely disabled by setting `"enableRateLimit"` to false.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
Optimal settings for rate-limiting depend on the exchange and the size of the whitelist, so an ideal parameter will vary on many other settings.
|
||||||
|
We try to provide sensible defaults per exchange where possible, if you encounter bans please make sure that `"enableRateLimit"` is enabled and increase the `"rateLimit"` parameter step by step.
|
||||||
|
|
||||||
## Binance
|
## Binance
|
||||||
|
|
||||||
Binance supports [time_in_force](configuration.md#understand-order_time_in_force).
|
Binance supports [time_in_force](configuration.md#understand-order_time_in_force).
|
||||||
|
16
docs/faq.md
16
docs/faq.md
@ -54,9 +54,11 @@ you can't say much from few trades.
|
|||||||
|
|
||||||
Yes. You can edit your config and use the `/reload_config` command to reload the configuration. The bot will stop, reload the configuration and strategy and will restart with the new configuration and strategy.
|
Yes. You can edit your config and use the `/reload_config` command to reload the configuration. The bot will stop, reload the configuration and strategy and will restart with the new configuration and strategy.
|
||||||
|
|
||||||
### I want to improve the bot with a new strategy
|
### I want to use incomplete candles
|
||||||
|
|
||||||
That's great. We have a nice backtesting and hyperoptimization setup. See the tutorial [here|Testing-new-strategies-with-Hyperopt](bot-usage.md#hyperopt-commands).
|
Freqtrade will not provide incomplete candles to strategies. Using incomplete candles will lead to repainting and consequently to strategies with "ghost" buys, which are impossible to both backtest, and verify after they happened.
|
||||||
|
|
||||||
|
You can use "current" market data by using the [dataprovider](strategy-customization.md#orderbookpair-maximum)'s orderbook or ticker methods - which however cannot be used during backtesting.
|
||||||
|
|
||||||
### Is there a setting to only SELL the coins being held and not perform anymore BUYS?
|
### Is there a setting to only SELL the coins being held and not perform anymore BUYS?
|
||||||
|
|
||||||
@ -82,11 +84,11 @@ Currently known to happen for US Bittrex users.
|
|||||||
|
|
||||||
Read [the Bittrex section about restricted markets](exchanges.md#restricted-markets) for more information.
|
Read [the Bittrex section about restricted markets](exchanges.md#restricted-markets) for more information.
|
||||||
|
|
||||||
### I'm getting the "Exchange Bittrex does not support market orders." message and cannot run my strategy
|
### I'm getting the "Exchange XXX does not support market orders." message and cannot run my strategy
|
||||||
|
|
||||||
As the message says, Bittrex does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Bittrex).
|
As the message says, your exchange does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Bittrex and Gate.io).
|
||||||
|
|
||||||
To fix it for Bittrex, redefine order types in the strategy to use "limit" instead of "market":
|
To fix this, redefine order types in the strategy to use "limit" instead of "market":
|
||||||
|
|
||||||
```
|
```
|
||||||
order_types = {
|
order_types = {
|
||||||
@ -136,6 +138,8 @@ On Windows, the `--logfile` option is also supported by Freqtrade and you can us
|
|||||||
> type \path\to\mylogfile.log | findstr "something"
|
> type \path\to\mylogfile.log | findstr "something"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Hyperopt module
|
||||||
|
|
||||||
### Why does freqtrade not have GPU support?
|
### Why does freqtrade not have GPU support?
|
||||||
|
|
||||||
First of all, most indicator libraries don't have GPU support - as such, there would be little benefit for indicator calculations.
|
First of all, most indicator libraries don't have GPU support - as such, there would be little benefit for indicator calculations.
|
||||||
@ -152,8 +156,6 @@ The benefit of using GPU would therefore be pretty slim - and will not justify t
|
|||||||
|
|
||||||
There is however nothing preventing you from using GPU-enabled indicators within your strategy if you think you must have this - you will however probably be disappointed by the slim gain that will give you (compared to the complexity).
|
There is however nothing preventing you from using GPU-enabled indicators within your strategy if you think you must have this - you will however probably be disappointed by the slim gain that will give you (compared to the complexity).
|
||||||
|
|
||||||
## Hyperopt module
|
|
||||||
|
|
||||||
### How many epochs do I need to get a good Hyperopt result?
|
### How many epochs do I need to get a good Hyperopt result?
|
||||||
|
|
||||||
Per default Hyperopt called without the `-e`/`--epochs` command line option will only
|
Per default Hyperopt called without the `-e`/`--epochs` command line option will only
|
||||||
|
@ -60,7 +60,7 @@ optional arguments:
|
|||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
--data-format-ohlcv {json,jsongz,hdf5}
|
--data-format-ohlcv {json,jsongz,hdf5}
|
||||||
Storage format for downloaded candle (OHLCV) data.
|
Storage format for downloaded candle (OHLCV) data.
|
||||||
(default: `None`).
|
(default: `json`).
|
||||||
--max-open-trades INT
|
--max-open-trades INT
|
||||||
Override the value of the `max_open_trades`
|
Override the value of the `max_open_trades`
|
||||||
configuration setting.
|
configuration setting.
|
||||||
@ -114,7 +114,8 @@ optional arguments:
|
|||||||
Hyperopt-loss-functions are:
|
Hyperopt-loss-functions are:
|
||||||
ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss,
|
ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss,
|
||||||
SharpeHyperOptLoss, SharpeHyperOptLossDaily,
|
SharpeHyperOptLoss, SharpeHyperOptLossDaily,
|
||||||
SortinoHyperOptLoss, SortinoHyperOptLossDaily
|
SortinoHyperOptLoss, SortinoHyperOptLossDaily,
|
||||||
|
MaxDrawDownHyperOptLoss
|
||||||
--disable-param-export
|
--disable-param-export
|
||||||
Disable automatic hyperopt parameter export.
|
Disable automatic hyperopt parameter export.
|
||||||
|
|
||||||
@ -512,12 +513,13 @@ This class should be in its own file within the `user_data/hyperopts/` directory
|
|||||||
|
|
||||||
Currently, the following loss functions are builtin:
|
Currently, the following loss functions are builtin:
|
||||||
|
|
||||||
* `ShortTradeDurHyperOptLoss` (default legacy Freqtrade hyperoptimization loss function) - Mostly for short trade duration and avoiding losses.
|
* `ShortTradeDurHyperOptLoss` - (default legacy Freqtrade hyperoptimization loss function) - Mostly for short trade duration and avoiding losses.
|
||||||
* `OnlyProfitHyperOptLoss` (which takes only amount of profit into consideration)
|
* `OnlyProfitHyperOptLoss` - takes only amount of profit into consideration.
|
||||||
* `SharpeHyperOptLoss` (optimizes Sharpe Ratio calculated on trade returns relative to standard deviation)
|
* `SharpeHyperOptLoss` - optimizes Sharpe Ratio calculated on trade returns relative to standard deviation.
|
||||||
* `SharpeHyperOptLossDaily` (optimizes Sharpe Ratio calculated on **daily** trade returns relative to standard deviation)
|
* `SharpeHyperOptLossDaily` - optimizes Sharpe Ratio calculated on **daily** trade returns relative to standard deviation.
|
||||||
* `SortinoHyperOptLoss` (optimizes Sortino Ratio calculated on trade returns relative to **downside** standard deviation)
|
* `SortinoHyperOptLoss` - optimizes Sortino Ratio calculated on trade returns relative to **downside** standard deviation.
|
||||||
* `SortinoHyperOptLossDaily` (optimizes Sortino Ratio calculated on **daily** trade returns relative to **downside** standard deviation)
|
* `SortinoHyperOptLossDaily` - optimizes Sortino Ratio calculated on **daily** trade returns relative to **downside** standard deviation.
|
||||||
|
* `MaxDrawDownHyperOptLoss` - Optimizes Maximum drawdown.
|
||||||
|
|
||||||
Creation of a custom loss function is covered in the [Advanced Hyperopt](advanced-hyperopt.md) part of the documentation.
|
Creation of a custom loss function is covered in the [Advanced Hyperopt](advanced-hyperopt.md) part of the documentation.
|
||||||
|
|
||||||
|
@ -113,6 +113,13 @@ git checkout develop
|
|||||||
|
|
||||||
You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands.
|
You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands.
|
||||||
|
|
||||||
|
??? Note "Install from pypi"
|
||||||
|
An alternative way to install Freqtrade is from [pypi](https://pypi.org/project/freqtrade/). The downside is that this method requires ta-lib to be correctly installed beforehand, and is therefore currently not the recommended way to install Freqtrade.
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
pip install freqtrade
|
||||||
|
```
|
||||||
|
|
||||||
------
|
------
|
||||||
|
|
||||||
## Script Installation
|
## Script Installation
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
mkdocs==1.2.2
|
mkdocs==1.2.2
|
||||||
mkdocs-material==7.3.0
|
mkdocs-material==7.3.2
|
||||||
mdx_truly_sane_lists==1.2
|
mdx_truly_sane_lists==1.2
|
||||||
pymdown-extensions==8.2
|
pymdown-extensions==9.0
|
||||||
|
@ -78,7 +78,7 @@ If you run your bot using docker, you'll need to have the bot listen to incoming
|
|||||||
},
|
},
|
||||||
```
|
```
|
||||||
|
|
||||||
Uncomment the following from your docker-compose file:
|
Make sure that the following 2 lines are available in your docker-compose file:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
ports:
|
ports:
|
||||||
|
@ -73,7 +73,7 @@ ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit",
|
|||||||
ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url",
|
ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url",
|
||||||
"trade_source", "timeframe", "plot_auto_open"]
|
"trade_source", "timeframe", "plot_auto_open"]
|
||||||
|
|
||||||
ARGS_INSTALL_UI = ["erase_ui_only"]
|
ARGS_INSTALL_UI = ["erase_ui_only", 'ui_version']
|
||||||
|
|
||||||
ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"]
|
ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"]
|
||||||
|
|
||||||
|
@ -163,7 +163,8 @@ def ask_user_config() -> Dict[str, Any]:
|
|||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"name": "api_server_listen_addr",
|
"name": "api_server_listen_addr",
|
||||||
"message": "Insert Api server Listen Address (best left untouched default!)",
|
"message": ("Insert Api server Listen Address (0.0.0.0 for docker, "
|
||||||
|
"otherwise best left untouched)"),
|
||||||
"default": "127.0.0.1",
|
"default": "127.0.0.1",
|
||||||
"when": lambda x: x['api_server']
|
"when": lambda x: x['api_server']
|
||||||
},
|
},
|
||||||
|
@ -414,6 +414,12 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
default=False,
|
default=False,
|
||||||
),
|
),
|
||||||
|
"ui_version": Arg(
|
||||||
|
'--ui-version',
|
||||||
|
help=('Specify a specific version of FreqUI to install. '
|
||||||
|
'Not specifying this installs the latest version.'),
|
||||||
|
type=str,
|
||||||
|
),
|
||||||
# Templating options
|
# Templating options
|
||||||
"template": Arg(
|
"template": Arg(
|
||||||
'--template',
|
'--template',
|
||||||
|
@ -128,7 +128,7 @@ def download_and_install_ui(dest_folder: Path, dl_url: str, version: str):
|
|||||||
f.write(version)
|
f.write(version)
|
||||||
|
|
||||||
|
|
||||||
def get_ui_download_url() -> Tuple[str, str]:
|
def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]:
|
||||||
base_url = 'https://api.github.com/repos/freqtrade/frequi/'
|
base_url = 'https://api.github.com/repos/freqtrade/frequi/'
|
||||||
# Get base UI Repo path
|
# Get base UI Repo path
|
||||||
|
|
||||||
@ -136,8 +136,16 @@ def get_ui_download_url() -> Tuple[str, str]:
|
|||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
r = resp.json()
|
r = resp.json()
|
||||||
|
|
||||||
latest_version = r[0]['name']
|
if version:
|
||||||
assets = r[0].get('assets', [])
|
tmp = [x for x in r if x['name'] == version]
|
||||||
|
if tmp:
|
||||||
|
latest_version = tmp[0]['name']
|
||||||
|
assets = tmp[0].get('assets', [])
|
||||||
|
else:
|
||||||
|
raise ValueError("UI-Version not found.")
|
||||||
|
else:
|
||||||
|
latest_version = r[0]['name']
|
||||||
|
assets = r[0].get('assets', [])
|
||||||
dl_url = ''
|
dl_url = ''
|
||||||
if assets and len(assets) > 0:
|
if assets and len(assets) > 0:
|
||||||
dl_url = assets[0]['browser_download_url']
|
dl_url = assets[0]['browser_download_url']
|
||||||
@ -156,7 +164,7 @@ def start_install_ui(args: Dict[str, Any]) -> None:
|
|||||||
|
|
||||||
dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui/installed/'
|
dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui/installed/'
|
||||||
# First make sure the assets are removed.
|
# First make sure the assets are removed.
|
||||||
dl_url, latest_version = get_ui_download_url()
|
dl_url, latest_version = get_ui_download_url(args.get('ui_version'))
|
||||||
|
|
||||||
curr_version = read_ui_version(dest_folder)
|
curr_version = read_ui_version(dest_folder)
|
||||||
if curr_version == latest_version and not args.get('erase_ui_only'):
|
if curr_version == latest_version and not args.get('erase_ui_only'):
|
||||||
|
@ -24,7 +24,8 @@ ORDERTYPE_POSSIBILITIES = ['limit', 'market']
|
|||||||
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
|
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
|
||||||
HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss',
|
HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss',
|
||||||
'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily',
|
'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily',
|
||||||
'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily']
|
'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily',
|
||||||
|
'MaxDrawDownHyperOptLoss']
|
||||||
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList',
|
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList',
|
||||||
'AgeFilter', 'OffsetFilter', 'PerformanceFilter',
|
'AgeFilter', 'OffsetFilter', 'PerformanceFilter',
|
||||||
'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter',
|
'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter',
|
||||||
|
@ -507,7 +507,7 @@ class Exchange:
|
|||||||
if startup_candles + 5 > candle_limit:
|
if startup_candles + 5 > candle_limit:
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"This strategy requires {startup_candles} candles to start. "
|
f"This strategy requires {startup_candles} candles to start. "
|
||||||
f"{self.name} only provides {candle_limit} for {timeframe}.")
|
f"{self.name} only provides {candle_limit - 5} for {timeframe}.")
|
||||||
|
|
||||||
def validate_trading_mode_and_collateral(
|
def validate_trading_mode_and_collateral(
|
||||||
self,
|
self,
|
||||||
@ -569,7 +569,7 @@ class Exchange:
|
|||||||
precision = self.markets[pair]['precision']['price']
|
precision = self.markets[pair]['precision']['price']
|
||||||
missing = price % precision
|
missing = price % precision
|
||||||
if missing != 0:
|
if missing != 0:
|
||||||
price = price - missing + precision
|
price = round(price - missing + precision, 10)
|
||||||
else:
|
else:
|
||||||
symbol_prec = self.markets[pair]['precision']['price']
|
symbol_prec = self.markets[pair]['precision']['price']
|
||||||
big_price = price * pow(10, symbol_prec)
|
big_price = price * pow(10, symbol_prec)
|
||||||
@ -1128,7 +1128,7 @@ class Exchange:
|
|||||||
ticker_rate = ticker[conf_strategy['price_side']]
|
ticker_rate = ticker[conf_strategy['price_side']]
|
||||||
if ticker['last'] and ticker_rate:
|
if ticker['last'] and ticker_rate:
|
||||||
if side == 'buy' and ticker_rate > ticker['last']:
|
if side == 'buy' and ticker_rate > ticker['last']:
|
||||||
balance = conf_strategy['ask_last_balance']
|
balance = conf_strategy.get('ask_last_balance', 0.0)
|
||||||
ticker_rate = ticker_rate + balance * (ticker['last'] - ticker_rate)
|
ticker_rate = ticker_rate + balance * (ticker['last'] - ticker_rate)
|
||||||
elif side == 'sell' and ticker_rate < ticker['last']:
|
elif side == 'sell' and ticker_rate < ticker['last']:
|
||||||
balance = conf_strategy.get('bid_last_balance', 0.0)
|
balance = conf_strategy.get('bid_last_balance', 0.0)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
|
from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
|
|
||||||
|
|
||||||
@ -25,3 +26,10 @@ class Gateio(Exchange):
|
|||||||
_headers = {'X-Gate-Channel-Id': 'freqtrade'}
|
_headers = {'X-Gate-Channel-Id': 'freqtrade'}
|
||||||
|
|
||||||
funding_fee_times: List[int] = [0, 8, 16] # hours of the day
|
funding_fee_times: List[int] = [0, 8, 16] # hours of the day
|
||||||
|
|
||||||
|
def validate_ordertypes(self, order_types: Dict) -> None:
|
||||||
|
super().validate_ordertypes(order_types)
|
||||||
|
|
||||||
|
if any(v == 'market' for k, v in order_types.items()):
|
||||||
|
raise OperationalException(
|
||||||
|
f'Exchange {self.name} does not support market orders.')
|
||||||
|
41
freqtrade/optimize/hyperopt_loss_max_drawdown.py
Normal file
41
freqtrade/optimize/hyperopt_loss_max_drawdown.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
MaxDrawDownHyperOptLoss
|
||||||
|
|
||||||
|
This module defines the alternative HyperOptLoss class which can be used for
|
||||||
|
Hyperoptimization.
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
from freqtrade.data.btanalysis import calculate_max_drawdown
|
||||||
|
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||||
|
|
||||||
|
|
||||||
|
class MaxDrawDownHyperOptLoss(IHyperOptLoss):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Defines the loss function for hyperopt.
|
||||||
|
|
||||||
|
This implementation optimizes for max draw down and profit
|
||||||
|
Less max drawdown more profit -> Lower return value
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hyperopt_loss_function(results: DataFrame, trade_count: int,
|
||||||
|
min_date: datetime, max_date: datetime,
|
||||||
|
*args, **kwargs) -> float:
|
||||||
|
|
||||||
|
"""
|
||||||
|
Objective function.
|
||||||
|
|
||||||
|
Uses profit ratio weighted max_drawdown when drawdown is available.
|
||||||
|
Otherwise directly optimizes profit ratio.
|
||||||
|
"""
|
||||||
|
total_profit = results['profit_abs'].sum()
|
||||||
|
try:
|
||||||
|
max_drawdown = calculate_max_drawdown(results, value_col='profit_abs')
|
||||||
|
except ValueError:
|
||||||
|
# No losing trade, therefore no drawdown.
|
||||||
|
return -total_profit
|
||||||
|
return -total_profit / max_drawdown[0]
|
@ -347,3 +347,8 @@ class BacktestResponse(BaseModel):
|
|||||||
trade_count: Optional[float]
|
trade_count: Optional[float]
|
||||||
# TODO: Properly type backtestresult...
|
# TODO: Properly type backtestresult...
|
||||||
backtest_result: Optional[Dict[str, Any]]
|
backtest_result: Optional[Dict[str, Any]]
|
||||||
|
|
||||||
|
|
||||||
|
class SysInfo(BaseModel):
|
||||||
|
cpu_pct: List[float]
|
||||||
|
ram_pct: float
|
||||||
|
@ -18,7 +18,8 @@ from freqtrade.rpc.api_server.api_schemas import (AvailablePairs, Balances, Blac
|
|||||||
OpenTradeSchema, PairHistory, PerformanceEntry,
|
OpenTradeSchema, PairHistory, PerformanceEntry,
|
||||||
Ping, PlotConfig, Profit, ResultMsg, ShowConfig,
|
Ping, PlotConfig, Profit, ResultMsg, ShowConfig,
|
||||||
Stats, StatusMsg, StrategyListResponse,
|
Stats, StatusMsg, StrategyListResponse,
|
||||||
StrategyResponse, Version, WhitelistResponse)
|
StrategyResponse, SysInfo, Version,
|
||||||
|
WhitelistResponse)
|
||||||
from freqtrade.rpc.api_server.deps import get_config, get_rpc, get_rpc_optional
|
from freqtrade.rpc.api_server.deps import get_config, get_rpc, get_rpc_optional
|
||||||
from freqtrade.rpc.rpc import RPCException
|
from freqtrade.rpc.rpc import RPCException
|
||||||
|
|
||||||
@ -259,3 +260,8 @@ def list_available_pairs(timeframe: Optional[str] = None, stake_currency: Option
|
|||||||
'pair_interval': pair_interval,
|
'pair_interval': pair_interval,
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/sysinfo', response_model=SysInfo, tags=['info'])
|
||||||
|
def sysinfo():
|
||||||
|
return RPC._rpc_sysinfo()
|
||||||
|
@ -8,6 +8,7 @@ from math import isnan
|
|||||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
|
import psutil
|
||||||
from numpy import NAN, inf, int64, mean
|
from numpy import NAN, inf, int64, mean
|
||||||
from pandas import DataFrame
|
from pandas import DataFrame
|
||||||
|
|
||||||
@ -871,3 +872,10 @@ class RPC:
|
|||||||
'subplots' not in self._freqtrade.strategy.plot_config):
|
'subplots' not in self._freqtrade.strategy.plot_config):
|
||||||
self._freqtrade.strategy.plot_config['subplots'] = {}
|
self._freqtrade.strategy.plot_config['subplots'] = {}
|
||||||
return self._freqtrade.strategy.plot_config
|
return self._freqtrade.strategy.plot_config
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _rpc_sysinfo() -> Dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"cpu_pct": psutil.cpu_percent(interval=1, percpu=True),
|
||||||
|
"ram_pct": psutil.virtual_memory().percent
|
||||||
|
}
|
||||||
|
@ -2,11 +2,8 @@
|
|||||||
"name": "{{ exchange_name | lower }}",
|
"name": "{{ exchange_name | lower }}",
|
||||||
"key": "{{ exchange_key }}",
|
"key": "{{ exchange_key }}",
|
||||||
"secret": "{{ exchange_secret }}",
|
"secret": "{{ exchange_secret }}",
|
||||||
"ccxt_config": {"enableRateLimit": true},
|
"ccxt_config": {},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {},
|
||||||
"enableRateLimit": true,
|
|
||||||
"rateLimit": 200
|
|
||||||
},
|
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
],
|
],
|
||||||
"pair_blacklist": [
|
"pair_blacklist": [
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
"name": "{{ exchange_name | lower }}",
|
"name": "{{ exchange_name | lower }}",
|
||||||
"key": "{{ exchange_key }}",
|
"key": "{{ exchange_key }}",
|
||||||
"secret": "{{ exchange_secret }}",
|
"secret": "{{ exchange_secret }}",
|
||||||
"ccxt_config": {"enableRateLimit": true},
|
"ccxt_config": {},
|
||||||
"ccxt_async_config": {
|
"ccxt_async_config": {},
|
||||||
"enableRateLimit": true
|
|
||||||
},
|
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
|
|
||||||
],
|
],
|
||||||
|
@ -3,14 +3,8 @@
|
|||||||
"key": "{{ exchange_key }}",
|
"key": "{{ exchange_key }}",
|
||||||
"secret": "{{ exchange_secret }}",
|
"secret": "{{ exchange_secret }}",
|
||||||
"password": "{{ exchange_key_password }}",
|
"password": "{{ exchange_key_password }}",
|
||||||
"ccxt_config": {
|
"ccxt_config": {},
|
||||||
"enableRateLimit": true,
|
"ccxt_async_config": {},
|
||||||
"rateLimit": 200
|
|
||||||
},
|
|
||||||
"ccxt_async_config": {
|
|
||||||
"enableRateLimit": true,
|
|
||||||
"rateLimit": 200
|
|
||||||
},
|
|
||||||
"pair_whitelist": [
|
"pair_whitelist": [
|
||||||
],
|
],
|
||||||
"pair_blacklist": [
|
"pair_blacklist": [
|
||||||
|
@ -32,8 +32,7 @@ def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: f
|
|||||||
use_custom_stoploss = True
|
use_custom_stoploss = True
|
||||||
|
|
||||||
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
|
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
|
||||||
current_rate: float, current_profit: float, dataframe: DataFrame,
|
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||||
**kwargs) -> float:
|
|
||||||
"""
|
"""
|
||||||
Custom stoploss logic, returning the new distance relative to current_rate (as ratio).
|
Custom stoploss logic, returning the new distance relative to current_rate (as ratio).
|
||||||
e.g. returning -0.05 would create a stoploss 5% below current_rate.
|
e.g. returning -0.05 would create a stoploss 5% below current_rate.
|
||||||
@ -44,14 +43,13 @@ def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
|
|||||||
When not implemented by a strategy, returns the initial stoploss value
|
When not implemented by a strategy, returns the initial stoploss value
|
||||||
Only called when use_custom_stoploss is set to True.
|
Only called when use_custom_stoploss is set to True.
|
||||||
|
|
||||||
:param pair: Pair that's about to be sold.
|
:param pair: Pair that's currently analyzed
|
||||||
:param trade: trade object.
|
:param trade: trade object.
|
||||||
:param current_time: datetime object, containing the current datetime
|
:param current_time: datetime object, containing the current datetime
|
||||||
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
|
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
|
||||||
:param current_profit: Current profit (as ratio), calculated based on current_rate.
|
:param current_profit: Current profit (as ratio), calculated based on current_rate.
|
||||||
:param dataframe: Analyzed dataframe for this pair. Can contain future data in backtesting.
|
|
||||||
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
|
||||||
:return float: New stoploss value, relative to the currentrate
|
:return float: New stoploss value, relative to the current_rate
|
||||||
"""
|
"""
|
||||||
return self.stoploss
|
return self.stoploss
|
||||||
|
|
||||||
|
@ -4,13 +4,12 @@
|
|||||||
-r requirements-hyperopt.txt
|
-r requirements-hyperopt.txt
|
||||||
|
|
||||||
coveralls==3.2.0
|
coveralls==3.2.0
|
||||||
flake8==3.9.2
|
flake8==4.0.0
|
||||||
flake8-type-annotations==0.1.0
|
flake8-tidy-imports==4.5.0
|
||||||
flake8-tidy-imports==4.4.1
|
|
||||||
mypy==0.910
|
mypy==0.910
|
||||||
pytest==6.2.5
|
pytest==6.2.5
|
||||||
pytest-asyncio==0.15.1
|
pytest-asyncio==0.15.1
|
||||||
pytest-cov==2.12.1
|
pytest-cov==3.0.0
|
||||||
pytest-mock==3.6.1
|
pytest-mock==3.6.1
|
||||||
pytest-random-order==1.0.4
|
pytest-random-order==1.0.4
|
||||||
isort==5.9.3
|
isort==5.9.3
|
||||||
@ -21,7 +20,7 @@ time-machine==2.4.0
|
|||||||
nbconvert==6.2.0
|
nbconvert==6.2.0
|
||||||
|
|
||||||
# mypy types
|
# mypy types
|
||||||
types-cachetools==4.2.0
|
types-cachetools==4.2.2
|
||||||
types-filelock==0.1.5
|
types-filelock==3.2.0
|
||||||
types-requests==2.25.9
|
types-requests==2.25.9
|
||||||
types-tabulate==0.8.2
|
types-tabulate==0.8.2
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
# Required for hyperopt
|
# Required for hyperopt
|
||||||
scipy==1.7.1
|
scipy==1.7.1
|
||||||
scikit-learn==0.24.2
|
scikit-learn==1.0
|
||||||
scikit-optimize==0.8.1
|
scikit-optimize==0.9.0
|
||||||
filelock==3.0.12
|
filelock==3.3.0
|
||||||
joblib==1.0.1
|
joblib==1.1.0
|
||||||
psutil==5.8.0
|
psutil==5.8.0
|
||||||
progressbar2==3.53.3
|
progressbar2==3.53.3
|
||||||
|
@ -2,25 +2,25 @@ numpy==1.21.2
|
|||||||
pandas==1.3.3
|
pandas==1.3.3
|
||||||
pandas-ta==0.3.14b
|
pandas-ta==0.3.14b
|
||||||
|
|
||||||
ccxt==1.57.3
|
ccxt==1.57.94
|
||||||
# Pin cryptography for now due to rust build errors with piwheels
|
# Pin cryptography for now due to rust build errors with piwheels
|
||||||
cryptography==3.4.8
|
cryptography==35.0.0
|
||||||
aiohttp==3.7.4.post0
|
aiohttp==3.7.4.post0
|
||||||
SQLAlchemy==1.4.25
|
SQLAlchemy==1.4.25
|
||||||
python-telegram-bot==13.7
|
python-telegram-bot==13.7
|
||||||
arrow==1.1.1
|
arrow==1.2.0
|
||||||
cachetools==4.2.2
|
cachetools==4.2.2
|
||||||
requests==2.26.0
|
requests==2.26.0
|
||||||
urllib3==1.26.7
|
urllib3==1.26.7
|
||||||
wrapt==1.12.1
|
wrapt==1.13.1
|
||||||
jsonschema==3.2.0
|
jsonschema==4.1.0
|
||||||
TA-Lib==0.4.21
|
TA-Lib==0.4.21
|
||||||
technical==1.3.0
|
technical==1.3.0
|
||||||
tabulate==0.8.9
|
tabulate==0.8.9
|
||||||
pycoingecko==2.2.0
|
pycoingecko==2.2.0
|
||||||
jinja2==3.0.1
|
jinja2==3.0.2
|
||||||
tables==3.6.1
|
tables==3.6.1
|
||||||
blosc==1.10.4
|
blosc==1.10.6
|
||||||
|
|
||||||
# find first, C search in arrays
|
# find first, C search in arrays
|
||||||
py_find_1st==1.1.5
|
py_find_1st==1.1.5
|
||||||
@ -34,8 +34,9 @@ sdnotify==0.3.2
|
|||||||
# API Server
|
# API Server
|
||||||
fastapi==0.68.1
|
fastapi==0.68.1
|
||||||
uvicorn==0.15.0
|
uvicorn==0.15.0
|
||||||
pyjwt==2.1.0
|
pyjwt==2.2.0
|
||||||
aiofiles==0.7.0
|
aiofiles==0.7.0
|
||||||
|
psutil==5.8.0
|
||||||
|
|
||||||
# Support for colorized terminal output
|
# Support for colorized terminal output
|
||||||
colorama==0.4.4
|
colorama==0.4.4
|
||||||
|
@ -334,6 +334,13 @@ class FtRestClient():
|
|||||||
"timerange": timerange if timerange else '',
|
"timerange": timerange if timerange else '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def sysinfo(self):
|
||||||
|
"""Provides system information (CPU, RAM usage)
|
||||||
|
|
||||||
|
:return: json object
|
||||||
|
"""
|
||||||
|
return self._get("sysinfo")
|
||||||
|
|
||||||
|
|
||||||
def add_arguments():
|
def add_arguments():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
@ -605,16 +605,33 @@ def test_get_ui_download_url(mocker):
|
|||||||
def test_get_ui_download_url_direct(mocker):
|
def test_get_ui_download_url_direct(mocker):
|
||||||
response = MagicMock()
|
response = MagicMock()
|
||||||
response.json = MagicMock(
|
response.json = MagicMock(
|
||||||
side_effect=[[{
|
return_value=[
|
||||||
'assets_url': 'http://whatever.json',
|
{
|
||||||
'name': '0.0.1',
|
'assets_url': 'http://whatever.json',
|
||||||
'assets': [{'browser_download_url': 'http://download11.zip'}]}]])
|
'name': '0.0.2',
|
||||||
|
'assets': [{'browser_download_url': 'http://download22.zip'}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'assets_url': 'http://whatever.json',
|
||||||
|
'name': '0.0.1',
|
||||||
|
'assets': [{'browser_download_url': 'http://download1.zip'}]
|
||||||
|
},
|
||||||
|
])
|
||||||
get_mock = mocker.patch("freqtrade.commands.deploy_commands.requests.get",
|
get_mock = mocker.patch("freqtrade.commands.deploy_commands.requests.get",
|
||||||
return_value=response)
|
return_value=response)
|
||||||
x, last_version = get_ui_download_url()
|
x, last_version = get_ui_download_url()
|
||||||
assert get_mock.call_count == 1
|
assert get_mock.call_count == 1
|
||||||
|
assert last_version == '0.0.2'
|
||||||
|
assert x == 'http://download22.zip'
|
||||||
|
get_mock.reset_mock()
|
||||||
|
response.json.reset_mock()
|
||||||
|
|
||||||
|
x, last_version = get_ui_download_url('0.0.1')
|
||||||
assert last_version == '0.0.1'
|
assert last_version == '0.0.1'
|
||||||
assert x == 'http://download11.zip'
|
assert x == 'http://download1.zip'
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match="UI-Version not found."):
|
||||||
|
x, last_version = get_ui_download_url('0.0.3')
|
||||||
|
|
||||||
|
|
||||||
def test_download_data_keyboardInterrupt(mocker, caplog, markets):
|
def test_download_data_keyboardInterrupt(mocker, caplog, markets):
|
||||||
|
@ -277,6 +277,7 @@ def test_amount_to_precision(default_conf, mocker, amount, precision_mode, preci
|
|||||||
(234.43, 4, 0.5, 234.5),
|
(234.43, 4, 0.5, 234.5),
|
||||||
(234.53, 4, 0.5, 235.0),
|
(234.53, 4, 0.5, 235.0),
|
||||||
(0.891534, 4, 0.0001, 0.8916),
|
(0.891534, 4, 0.0001, 0.8916),
|
||||||
|
(64968.89, 4, 0.01, 64968.89),
|
||||||
|
|
||||||
])
|
])
|
||||||
def test_price_to_precision(default_conf, mocker, price, precision_mode, precision, expected):
|
def test_price_to_precision(default_conf, mocker, price, precision_mode, precision, expected):
|
||||||
@ -295,7 +296,7 @@ def test_price_to_precision(default_conf, mocker, price, precision_mode, precisi
|
|||||||
PropertyMock(return_value=precision_mode))
|
PropertyMock(return_value=precision_mode))
|
||||||
|
|
||||||
pair = 'ETH/BTC'
|
pair = 'ETH/BTC'
|
||||||
assert pytest.approx(exchange.price_to_precision(pair, price)) == expected
|
assert exchange.price_to_precision(pair, price) == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("price,precision_mode,precision,expected", [
|
@pytest.mark.parametrize("price,precision_mode,precision,expected", [
|
||||||
@ -1895,6 +1896,7 @@ def test_fetch_l2_order_book_exception(default_conf, mocker, exchange_name):
|
|||||||
('ask', 20, 19, 10, 0.3, 17), # Between ask and last
|
('ask', 20, 19, 10, 0.3, 17), # Between ask and last
|
||||||
('ask', 5, 6, 10, 1.0, 5), # last bigger than ask
|
('ask', 5, 6, 10, 1.0, 5), # last bigger than ask
|
||||||
('ask', 5, 6, 10, 0.5, 5), # last bigger than ask
|
('ask', 5, 6, 10, 0.5, 5), # last bigger than ask
|
||||||
|
('ask', 20, 19, 10, None, 20), # ask_last_balance missing
|
||||||
('ask', 10, 20, None, 0.5, 10), # last not available - uses ask
|
('ask', 10, 20, None, 0.5, 10), # last not available - uses ask
|
||||||
('ask', 4, 5, None, 0.5, 4), # last not available - uses ask
|
('ask', 4, 5, None, 0.5, 4), # last not available - uses ask
|
||||||
('ask', 4, 5, None, 1, 4), # last not available - uses ask
|
('ask', 4, 5, None, 1, 4), # last not available - uses ask
|
||||||
@ -1905,6 +1907,7 @@ def test_fetch_l2_order_book_exception(default_conf, mocker, exchange_name):
|
|||||||
('bid', 21, 20, 10, 0.7, 13), # Between bid and last
|
('bid', 21, 20, 10, 0.7, 13), # Between bid and last
|
||||||
('bid', 21, 20, 10, 0.3, 17), # Between bid and last
|
('bid', 21, 20, 10, 0.3, 17), # Between bid and last
|
||||||
('bid', 6, 5, 10, 1.0, 5), # last bigger than bid
|
('bid', 6, 5, 10, 1.0, 5), # last bigger than bid
|
||||||
|
('bid', 21, 20, 10, None, 20), # ask_last_balance missing
|
||||||
('bid', 6, 5, 10, 0.5, 5), # last bigger than bid
|
('bid', 6, 5, 10, 0.5, 5), # last bigger than bid
|
||||||
('bid', 21, 20, None, 0.5, 20), # last not available - uses bid
|
('bid', 21, 20, None, 0.5, 20), # last not available - uses bid
|
||||||
('bid', 6, 5, None, 0.5, 5), # last not available - uses bid
|
('bid', 6, 5, None, 0.5, 5), # last not available - uses bid
|
||||||
@ -1914,7 +1917,10 @@ def test_fetch_l2_order_book_exception(default_conf, mocker, exchange_name):
|
|||||||
def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
|
def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
|
||||||
last, last_ab, expected) -> None:
|
last, last_ab, expected) -> None:
|
||||||
caplog.set_level(logging.DEBUG)
|
caplog.set_level(logging.DEBUG)
|
||||||
default_conf['bid_strategy']['ask_last_balance'] = last_ab
|
if last_ab is None:
|
||||||
|
del default_conf['bid_strategy']['ask_last_balance']
|
||||||
|
else:
|
||||||
|
default_conf['bid_strategy']['ask_last_balance'] = last_ab
|
||||||
default_conf['bid_strategy']['price_side'] = side
|
default_conf['bid_strategy']['price_side'] = side
|
||||||
exchange = get_patched_exchange(mocker, default_conf)
|
exchange = get_patched_exchange(mocker, default_conf)
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||||
@ -1939,6 +1945,7 @@ def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
|
|||||||
('bid', 12.0, 11.2, 10.5, 1.0, 11.2), # Last smaller than bid - uses bid
|
('bid', 12.0, 11.2, 10.5, 1.0, 11.2), # Last smaller than bid - uses bid
|
||||||
('bid', 12.0, 11.2, 10.5, 0.5, 11.2), # Last smaller than bid - uses bid
|
('bid', 12.0, 11.2, 10.5, 0.5, 11.2), # Last smaller than bid - uses bid
|
||||||
('bid', 0.003, 0.002, 0.005, 0.0, 0.002),
|
('bid', 0.003, 0.002, 0.005, 0.0, 0.002),
|
||||||
|
('bid', 0.003, 0.002, 0.005, None, 0.002),
|
||||||
('ask', 12.0, 11.0, 12.5, 0.0, 12.0), # full ask side
|
('ask', 12.0, 11.0, 12.5, 0.0, 12.0), # full ask side
|
||||||
('ask', 12.0, 11.0, 12.5, 1.0, 12.5), # full last side
|
('ask', 12.0, 11.0, 12.5, 1.0, 12.5), # full last side
|
||||||
('ask', 12.0, 11.0, 12.5, 0.5, 12.25), # between bid and lat
|
('ask', 12.0, 11.0, 12.5, 0.5, 12.25), # between bid and lat
|
||||||
@ -1949,13 +1956,15 @@ def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
|
|||||||
('ask', 10.11, 11.2, 11.0, 0.0, 10.11),
|
('ask', 10.11, 11.2, 11.0, 0.0, 10.11),
|
||||||
('ask', 0.001, 0.002, 11.0, 0.0, 0.001),
|
('ask', 0.001, 0.002, 11.0, 0.0, 0.001),
|
||||||
('ask', 0.006, 1.0, 11.0, 0.0, 0.006),
|
('ask', 0.006, 1.0, 11.0, 0.0, 0.006),
|
||||||
|
('ask', 0.006, 1.0, 11.0, None, 0.006),
|
||||||
])
|
])
|
||||||
def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask,
|
def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask,
|
||||||
last, last_ab, expected) -> None:
|
last, last_ab, expected) -> None:
|
||||||
caplog.set_level(logging.DEBUG)
|
caplog.set_level(logging.DEBUG)
|
||||||
|
|
||||||
default_conf['ask_strategy']['price_side'] = side
|
default_conf['ask_strategy']['price_side'] = side
|
||||||
default_conf['ask_strategy']['bid_last_balance'] = last_ab
|
if last_ab is not None:
|
||||||
|
default_conf['ask_strategy']['bid_last_balance'] = last_ab
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||||
return_value={'ask': ask, 'bid': bid, 'last': last})
|
return_value={'ask': ask, 'bid': bid, 'last': last})
|
||||||
pair = "ETH/BTC"
|
pair = "ETH/BTC"
|
||||||
|
28
tests/exchange/test_gateio.py
Normal file
28
tests/exchange/test_gateio.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from freqtrade.exceptions import OperationalException
|
||||||
|
from freqtrade.exchange import Gateio
|
||||||
|
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_order_types_gateio(default_conf, mocker):
|
||||||
|
default_conf['exchange']['name'] = 'gateio'
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._init_ccxt')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange._load_markets', return_value={})
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
|
||||||
|
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
|
||||||
|
exch = ExchangeResolver.load_exchange('gateio', default_conf, True)
|
||||||
|
assert isinstance(exch, Gateio)
|
||||||
|
|
||||||
|
default_conf['order_types'] = {
|
||||||
|
'buy': 'market',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
with pytest.raises(OperationalException,
|
||||||
|
match=r'Exchange .* does not support market orders.'):
|
||||||
|
ExchangeResolver.load_exchange('gateio', default_conf, True)
|
@ -84,13 +84,14 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) ->
|
|||||||
"SortinoHyperOptLossDaily",
|
"SortinoHyperOptLossDaily",
|
||||||
"SharpeHyperOptLoss",
|
"SharpeHyperOptLoss",
|
||||||
"SharpeHyperOptLossDaily",
|
"SharpeHyperOptLossDaily",
|
||||||
|
"MaxDrawDownHyperOptLoss",
|
||||||
])
|
])
|
||||||
def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunction) -> None:
|
def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunction) -> None:
|
||||||
results_over = hyperopt_results.copy()
|
results_over = hyperopt_results.copy()
|
||||||
results_over['profit_abs'] = hyperopt_results['profit_abs'] * 2
|
results_over['profit_abs'] = hyperopt_results['profit_abs'] * 2 + 0.2
|
||||||
results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2
|
results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2
|
||||||
results_under = hyperopt_results.copy()
|
results_under = hyperopt_results.copy()
|
||||||
results_under['profit_abs'] = hyperopt_results['profit_abs'] / 2
|
results_under['profit_abs'] = hyperopt_results['profit_abs'] / 2 - 0.2
|
||||||
results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2
|
results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2
|
||||||
|
|
||||||
default_conf.update({'hyperopt_loss': lossfunction})
|
default_conf.update({'hyperopt_loss': lossfunction})
|
||||||
|
@ -1272,6 +1272,16 @@ def test_list_available_pairs(botclient):
|
|||||||
assert len(rc.json()['pair_interval']) == 1
|
assert len(rc.json()['pair_interval']) == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_sysinfo(botclient):
|
||||||
|
ftbot, client = botclient
|
||||||
|
|
||||||
|
rc = client_get(client, f"{BASE_URI}/sysinfo")
|
||||||
|
assert_response(rc)
|
||||||
|
result = rc.json()
|
||||||
|
assert 'cpu_pct' in result
|
||||||
|
assert 'ram_pct' in result
|
||||||
|
|
||||||
|
|
||||||
def test_api_backtesting(botclient, mocker, fee, caplog):
|
def test_api_backtesting(botclient, mocker, fee, caplog):
|
||||||
ftbot, client = botclient
|
ftbot, client = botclient
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||||
|
Loading…
Reference in New Issue
Block a user