Merge pull request #2264 from freqtrade/args_aftersubcommand2
Allow all arguments after subcommand
This commit is contained in:
commit
df43b1f533
@ -28,11 +28,11 @@ jobs:
|
|||||||
name: pytest
|
name: pytest
|
||||||
- script:
|
- script:
|
||||||
- cp config.json.example config.json
|
- cp config.json.example config.json
|
||||||
- freqtrade --datadir tests/testdata backtesting
|
- freqtrade backtesting --datadir tests/testdata --strategy DefaultStrategy
|
||||||
name: backtest
|
name: backtest
|
||||||
- script:
|
- script:
|
||||||
- cp config.json.example config.json
|
- cp config.json.example config.json
|
||||||
- freqtrade --datadir tests/testdata hyperopt -e 5
|
- freqtrade hyperopt --datadir tests/testdata -e 5 --strategy DefaultStrategy --hyperopt DefaultHyperOpts
|
||||||
name: hyperopt
|
name: hyperopt
|
||||||
- script: flake8
|
- script: flake8
|
||||||
name: flake8
|
name: flake8
|
||||||
|
@ -24,3 +24,5 @@ RUN pip install numpy --no-cache-dir \
|
|||||||
COPY . /freqtrade/
|
COPY . /freqtrade/
|
||||||
RUN pip install -e . --no-cache-dir
|
RUN pip install -e . --no-cache-dir
|
||||||
ENTRYPOINT ["freqtrade"]
|
ENTRYPOINT ["freqtrade"]
|
||||||
|
# Default to trade mode
|
||||||
|
CMD [ "trade" ]
|
||||||
|
@ -23,7 +23,7 @@ if [ $? -ne 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Run backtest
|
# Run backtest
|
||||||
docker run --rm -it -v $(pwd)/config.json.example:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG} --datadir /tests/testdata backtesting
|
docker run --rm -it -v $(pwd)/config.json.example:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG} backtesting --datadir /tests/testdata --strategy DefaultStrategy
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "failed running backtest"
|
echo "failed running backtest"
|
||||||
|
@ -45,7 +45,7 @@ freqtrade backtesting --datadir user_data/data/bittrex-20180101
|
|||||||
#### With a (custom) strategy file
|
#### With a (custom) strategy file
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade -s SampleStrategy backtesting
|
freqtrade backtesting -s SampleStrategy
|
||||||
```
|
```
|
||||||
|
|
||||||
Where `-s SampleStrategy` refers to the class name within the strategy file `sample_strategy.py` found in the `freqtrade/user_data/strategies` directory.
|
Where `-s SampleStrategy` refers to the class name within the strategy file `sample_strategy.py` found in the `freqtrade/user_data/strategies` directory.
|
||||||
|
@ -5,27 +5,49 @@ This page explains the different parameters of the bot and how to run it.
|
|||||||
!!! Note
|
!!! Note
|
||||||
If you've used `setup.sh`, don't forget to activate your virtual environment (`source .env/bin/activate`) before running freqtrade commands.
|
If you've used `setup.sh`, don't forget to activate your virtual environment (`source .env/bin/activate`) before running freqtrade commands.
|
||||||
|
|
||||||
|
|
||||||
## Bot commands
|
## Bot commands
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
|
usage: freqtrade [-h] [-V]
|
||||||
[--userdir PATH] [-s NAME] [--strategy-path PATH]
|
{trade,backtesting,edge,hyperopt,create-userdir,list-exchanges,download-data,plot-dataframe,plot-profit}
|
||||||
[--db-url PATH] [--sd-notify]
|
...
|
||||||
{backtesting,edge,hyperopt,create-userdir,list-exchanges} ...
|
|
||||||
|
|
||||||
Free, open source crypto trading bot
|
Free, open source crypto trading bot
|
||||||
|
|
||||||
positional arguments:
|
positional arguments:
|
||||||
{backtesting,edge,hyperopt,create-userdir,list-exchanges}
|
{trade,backtesting,edge,hyperopt,create-userdir,list-exchanges,download-data,plot-dataframe,plot-profit}
|
||||||
|
trade Trade module.
|
||||||
backtesting Backtesting module.
|
backtesting Backtesting module.
|
||||||
edge Edge module.
|
edge Edge module.
|
||||||
hyperopt Hyperopt module.
|
hyperopt Hyperopt module.
|
||||||
create-userdir Create user-data directory.
|
create-userdir Create user-data directory.
|
||||||
list-exchanges Print available exchanges.
|
list-exchanges Print available exchanges.
|
||||||
|
download-data Download backtesting data.
|
||||||
|
plot-dataframe Plot candles with indicators.
|
||||||
|
plot-profit Generate plot showing profits.
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
|
-V, --version show program's version number and exit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bot trading commands
|
||||||
|
|
||||||
|
```
|
||||||
|
usage: freqtrade trade [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
|
||||||
|
[--userdir PATH] [-s NAME] [--strategy-path PATH]
|
||||||
|
[--db-url PATH] [--sd-notify] [--dry-run]
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
--db-url PATH Override trades database URL, this is useful in custom
|
||||||
|
deployments (default: `sqlite:///tradesv3.sqlite` for
|
||||||
|
Live Run mode, `sqlite://` for Dry Run).
|
||||||
|
--sd-notify Notify systemd service manager.
|
||||||
|
--dry-run Enforce dry-run for trading (removes Exchange secrets
|
||||||
|
and simulates trades).
|
||||||
|
|
||||||
|
Common arguments:
|
||||||
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
--logfile FILE Log to the file specified.
|
--logfile FILE Log to the file specified.
|
||||||
-V, --version show program's version number and exit
|
-V, --version show program's version number and exit
|
||||||
@ -37,15 +59,12 @@ optional arguments:
|
|||||||
Path to directory with historical backtesting data.
|
Path to directory with historical backtesting data.
|
||||||
--userdir PATH, --user-data-dir PATH
|
--userdir PATH, --user-data-dir PATH
|
||||||
Path to userdata directory.
|
Path to userdata directory.
|
||||||
-s NAME, --strategy NAME
|
|
||||||
Specify strategy class name (default:
|
|
||||||
`DefaultStrategy`).
|
|
||||||
--strategy-path PATH Specify additional strategy lookup path.
|
|
||||||
--db-url PATH Override trades database URL, this is useful in custom
|
|
||||||
deployments (default: `sqlite:///tradesv3.sqlite` for
|
|
||||||
Live Run mode, `sqlite://` for Dry Run).
|
|
||||||
--sd-notify Notify systemd service manager.
|
|
||||||
|
|
||||||
|
Strategy arguments:
|
||||||
|
-s NAME, --strategy NAME
|
||||||
|
Specify strategy class name which will be used by the
|
||||||
|
bot.
|
||||||
|
--strategy-path PATH Specify additional strategy lookup path.
|
||||||
```
|
```
|
||||||
|
|
||||||
### How to specify which configuration file be used?
|
### How to specify which configuration file be used?
|
||||||
@ -54,7 +73,7 @@ The bot allows you to select which configuration file you want to use by means o
|
|||||||
the `-c/--config` command line option:
|
the `-c/--config` command line option:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade -c path/far/far/away/config.json
|
freqtrade trade -c path/far/far/away/config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
Per default, the bot loads the `config.json` configuration file from the current
|
Per default, the bot loads the `config.json` configuration file from the current
|
||||||
@ -73,13 +92,13 @@ empty key and secrete values while running in the Dry Mode (which does not actua
|
|||||||
require them):
|
require them):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade -c ./config.json
|
freqtrade trade -c ./config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
and specify both configuration files when running in the normal Live Trade Mode:
|
and specify both configuration files when running in the normal Live Trade Mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade -c ./config.json -c path/to/secrets/keys.config.json
|
freqtrade trade -c ./config.json -c path/to/secrets/keys.config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
This could help you hide your private Exchange key and Exchange secrete on you local machine
|
This could help you hide your private Exchange key and Exchange secrete on you local machine
|
||||||
@ -128,7 +147,7 @@ In `user_data/strategies` you have a file `my_awesome_strategy.py` which has
|
|||||||
a strategy class called `AwesomeStrategy` to load it:
|
a strategy class called `AwesomeStrategy` to load it:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade --strategy AwesomeStrategy
|
freqtrade trade --strategy AwesomeStrategy
|
||||||
```
|
```
|
||||||
|
|
||||||
If the bot does not find your strategy file, it will display in an error
|
If the bot does not find your strategy file, it will display in an error
|
||||||
@ -143,7 +162,7 @@ This parameter allows you to add an additional strategy lookup path, which gets
|
|||||||
checked before the default locations (The passed path must be a directory!):
|
checked before the default locations (The passed path must be a directory!):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade --strategy AwesomeStrategy --strategy-path /some/directory
|
freqtrade trade --strategy AwesomeStrategy --strategy-path /some/directory
|
||||||
```
|
```
|
||||||
|
|
||||||
#### How to install a strategy?
|
#### How to install a strategy?
|
||||||
@ -159,7 +178,7 @@ using `--db-url`. This can also be used to specify a custom database
|
|||||||
in production mode. Example command:
|
in production mode. Example command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade -c config.json --db-url sqlite:///tradesv3.dry_run.sqlite
|
freqtrade trade -c config.json --db-url sqlite:///tradesv3.dry_run.sqlite
|
||||||
```
|
```
|
||||||
|
|
||||||
## Backtesting commands
|
## Backtesting commands
|
||||||
@ -167,68 +186,13 @@ freqtrade -c config.json --db-url sqlite:///tradesv3.dry_run.sqlite
|
|||||||
Backtesting also uses the config specified via `-c/--config`.
|
Backtesting also uses the config specified via `-c/--config`.
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade backtesting [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
usage: freqtrade backtesting [-h] [-v] [--logfile FILE] [-V] [-c PATH]
|
||||||
[--max_open_trades MAX_OPEN_TRADES]
|
[-d PATH] [--userdir PATH] [-s NAME]
|
||||||
[--stake_amount STAKE_AMOUNT] [-r] [--eps] [--dmmp]
|
[--strategy-path PATH] [-i TICKER_INTERVAL]
|
||||||
[-l]
|
[--timerange TIMERANGE] [--max_open_trades INT]
|
||||||
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
[--stake_amount STAKE_AMOUNT] [--eps] [--dmmp]
|
||||||
[--export EXPORT] [--export-filename PATH]
|
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
|
||||||
|
[--export EXPORT] [--export-filename PATH]
|
||||||
optional arguments:
|
|
||||||
-h, --help show this help message and exit
|
|
||||||
-i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL
|
|
||||||
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
|
||||||
--timerange TIMERANGE
|
|
||||||
Specify what timerange of data to use.
|
|
||||||
--max_open_trades MAX_OPEN_TRADES
|
|
||||||
Specify max_open_trades to use.
|
|
||||||
--stake_amount STAKE_AMOUNT
|
|
||||||
Specify stake_amount.
|
|
||||||
--eps, --enable-position-stacking
|
|
||||||
Allow buying the same pair multiple times (position
|
|
||||||
stacking).
|
|
||||||
--dmmp, --disable-max-market-positions
|
|
||||||
Disable applying `max_open_trades` during backtest
|
|
||||||
(same as setting `max_open_trades` to a very high
|
|
||||||
number).
|
|
||||||
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
|
|
||||||
Provide a space-separated list of strategies to
|
|
||||||
backtest Please note that ticker-interval needs to be
|
|
||||||
set either in config or via command line. When using
|
|
||||||
this together with --export trades, the strategy-name
|
|
||||||
is injected into the filename (so backtest-data.json
|
|
||||||
becomes backtest-data-DefaultStrategy.json
|
|
||||||
--export EXPORT Export backtest results, argument are: trades. Example
|
|
||||||
--export=trades
|
|
||||||
--export-filename PATH
|
|
||||||
Save backtest results to this filename requires
|
|
||||||
--export to be set as well Example --export-
|
|
||||||
filename=user_data/backtest_results/backtest_today.json
|
|
||||||
(default: user_data/backtest_results/backtest-
|
|
||||||
result.json)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Getting historic data for backtesting
|
|
||||||
|
|
||||||
The first time your run Backtesting, you will need to download some historic data first.
|
|
||||||
This can be accomplished by using `freqtrade download-data`.
|
|
||||||
Check the corresponding [help page section](backtesting.md#Getting-data-for-backtesting-and-hyperopt) for more details
|
|
||||||
|
|
||||||
## Hyperopt commands
|
|
||||||
|
|
||||||
To optimize your strategy, you can use hyperopt parameter hyperoptimization
|
|
||||||
to find optimal parameter values for your stategy.
|
|
||||||
|
|
||||||
```
|
|
||||||
usage: freqtrade hyperopt [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
|
||||||
[--max_open_trades INT]
|
|
||||||
[--stake_amount STAKE_AMOUNT] [-r]
|
|
||||||
[--customhyperopt NAME] [--hyperopt-path PATH]
|
|
||||||
[--eps] [-e INT]
|
|
||||||
[-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]]
|
|
||||||
[--dmmp] [--print-all] [--no-color] [-j JOBS]
|
|
||||||
[--random-state INT] [--min-trades INT] [--continue]
|
|
||||||
[--hyperopt-loss NAME]
|
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@ -241,16 +205,96 @@ optional arguments:
|
|||||||
Specify max_open_trades to use.
|
Specify max_open_trades to use.
|
||||||
--stake_amount STAKE_AMOUNT
|
--stake_amount STAKE_AMOUNT
|
||||||
Specify stake_amount.
|
Specify stake_amount.
|
||||||
--customhyperopt NAME
|
--eps, --enable-position-stacking
|
||||||
Specify hyperopt class name (default:
|
Allow buying the same pair multiple times (position
|
||||||
`DefaultHyperOpts`).
|
stacking).
|
||||||
|
--dmmp, --disable-max-market-positions
|
||||||
|
Disable applying `max_open_trades` during backtest
|
||||||
|
(same as setting `max_open_trades` to a very high
|
||||||
|
number).
|
||||||
|
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
|
||||||
|
Provide a space-separated list of strategies to
|
||||||
|
backtest. Please note that ticker-interval needs to be
|
||||||
|
set either in config or via command line. When using
|
||||||
|
this together with `--export trades`, the strategy-
|
||||||
|
name is injected into the filename (so `backtest-
|
||||||
|
data.json` becomes `backtest-data-
|
||||||
|
DefaultStrategy.json`
|
||||||
|
--export EXPORT Export backtest results, argument are: trades.
|
||||||
|
Example: `--export=trades`
|
||||||
|
--export-filename PATH
|
||||||
|
Save backtest results to the file with this filename
|
||||||
|
(default: `user_data/backtest_results/backtest-
|
||||||
|
result.json`). Requires `--export` to be set as well.
|
||||||
|
Example: `--export-filename=user_data/backtest_results
|
||||||
|
/backtest_today.json`
|
||||||
|
|
||||||
|
Common arguments:
|
||||||
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
--logfile FILE Log to the file specified.
|
||||||
|
-V, --version show program's version number and exit
|
||||||
|
-c PATH, --config PATH
|
||||||
|
Specify configuration file (default: `config.json`).
|
||||||
|
Multiple --config options may be used. Can be set to
|
||||||
|
`-` to read config from stdin.
|
||||||
|
-d PATH, --datadir PATH
|
||||||
|
Path to directory with historical backtesting data.
|
||||||
|
--userdir PATH, --user-data-dir PATH
|
||||||
|
Path to userdata directory.
|
||||||
|
|
||||||
|
Strategy arguments:
|
||||||
|
-s NAME, --strategy NAME
|
||||||
|
Specify strategy class name (default:
|
||||||
|
`DefaultStrategy`).
|
||||||
|
--strategy-path PATH Specify additional strategy lookup path.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Getting historic data for backtesting
|
||||||
|
|
||||||
|
The first time your run Backtesting, you will need to download some historic data first.
|
||||||
|
This can be accomplished by using `freqtrade download-data`.
|
||||||
|
Check the corresponding [Data Downloading](data-download.md) section for more details
|
||||||
|
|
||||||
|
## Hyperopt commands
|
||||||
|
|
||||||
|
To optimize your strategy, you can use hyperopt parameter hyperoptimization
|
||||||
|
to find optimal parameter values for your stategy.
|
||||||
|
|
||||||
|
```
|
||||||
|
usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
|
||||||
|
[--userdir PATH] [-s NAME] [--strategy-path PATH]
|
||||||
|
[-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
||||||
|
[--max_open_trades INT]
|
||||||
|
[--stake_amount STAKE_AMOUNT]
|
||||||
|
[--hyperopt NAME] [--hyperopt-path PATH]
|
||||||
|
[--eps] [-e INT]
|
||||||
|
[--spaces {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]]
|
||||||
|
[--dmmp] [--print-all] [--no-color] [--print-json]
|
||||||
|
[-j JOBS] [--random-state INT] [--min-trades INT]
|
||||||
|
[--continue] [--hyperopt-loss NAME]
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL
|
||||||
|
Specify ticker interval (`1m`, `5m`, `30m`, `1h`,
|
||||||
|
`1d`).
|
||||||
|
--timerange TIMERANGE
|
||||||
|
Specify what timerange of data to use.
|
||||||
|
--max_open_trades INT
|
||||||
|
Specify max_open_trades to use.
|
||||||
|
--stake_amount STAKE_AMOUNT
|
||||||
|
Specify stake_amount.
|
||||||
|
--hyperopt NAME
|
||||||
|
Specify hyperopt class name which will be used by the
|
||||||
|
bot.
|
||||||
--hyperopt-path PATH Specify additional lookup path for Hyperopts and
|
--hyperopt-path PATH Specify additional lookup path for Hyperopts and
|
||||||
Hyperopt Loss functions.
|
Hyperopt Loss functions.
|
||||||
--eps, --enable-position-stacking
|
--eps, --enable-position-stacking
|
||||||
Allow buying the same pair multiple times (position
|
Allow buying the same pair multiple times (position
|
||||||
stacking).
|
stacking).
|
||||||
-e INT, --epochs INT Specify number of epochs (default: 100).
|
-e INT, --epochs INT Specify number of epochs (default: 100).
|
||||||
-s {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...], --spaces {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]
|
--spaces {all,buy,sell,roi,stoploss} [{all,buy,sell,roi,stoploss} ...]
|
||||||
Specify which parameters to hyperopt. Space-separated
|
Specify which parameters to hyperopt. Space-separated
|
||||||
list. Default: `all`.
|
list. Default: `all`.
|
||||||
--dmmp, --disable-max-market-positions
|
--dmmp, --disable-max-market-positions
|
||||||
@ -260,6 +304,7 @@ optional arguments:
|
|||||||
--print-all Print all results, not only the best ones.
|
--print-all Print all results, not only the best ones.
|
||||||
--no-color Disable colorization of hyperopt results. May be
|
--no-color Disable colorization of hyperopt results. May be
|
||||||
useful if you are redirecting output to a file.
|
useful if you are redirecting output to a file.
|
||||||
|
--print-json Print best result detailization in JSON format.
|
||||||
-j JOBS, --job-workers JOBS
|
-j JOBS, --job-workers JOBS
|
||||||
The number of concurrently running jobs for
|
The number of concurrently running jobs for
|
||||||
hyperoptimization (hyperopt worker processes). If -1
|
hyperoptimization (hyperopt worker processes). If -1
|
||||||
@ -278,8 +323,29 @@ optional arguments:
|
|||||||
generate completely different results, since the
|
generate completely different results, since the
|
||||||
target for optimization is different. Built-in
|
target for optimization is different. Built-in
|
||||||
Hyperopt-loss-functions are: DefaultHyperOptLoss,
|
Hyperopt-loss-functions are: DefaultHyperOptLoss,
|
||||||
OnlyProfitHyperOptLoss, SharpeHyperOptLoss.
|
OnlyProfitHyperOptLoss, SharpeHyperOptLoss (default:
|
||||||
(default: `DefaultHyperOptLoss`).
|
`DefaultHyperOptLoss`).
|
||||||
|
|
||||||
|
|
||||||
|
Common arguments:
|
||||||
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
--logfile FILE Log to the file specified.
|
||||||
|
-V, --version show program's version number and exit
|
||||||
|
-c PATH, --config PATH
|
||||||
|
Specify configuration file (default: `config.json`).
|
||||||
|
Multiple --config options may be used. Can be set to
|
||||||
|
`-` to read config from stdin.
|
||||||
|
-d PATH, --datadir PATH
|
||||||
|
Path to directory with historical backtesting data.
|
||||||
|
--userdir PATH, --user-data-dir PATH
|
||||||
|
Path to userdata directory.
|
||||||
|
|
||||||
|
Strategy arguments:
|
||||||
|
-s NAME, --strategy NAME
|
||||||
|
Specify strategy class name (default:
|
||||||
|
`DefaultStrategy`).
|
||||||
|
--strategy-path PATH Specify additional strategy lookup path.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Edge commands
|
## Edge commands
|
||||||
@ -287,26 +353,48 @@ optional arguments:
|
|||||||
To know your trade expectancy and winrate against historical data, you can use Edge.
|
To know your trade expectancy and winrate against historical data, you can use Edge.
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade edge [-h] [-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
usage: freqtrade edge [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
|
||||||
[--max_open_trades MAX_OPEN_TRADES]
|
[--userdir PATH] [-s NAME] [--strategy-path PATH]
|
||||||
[--stake_amount STAKE_AMOUNT] [-r]
|
[-i TICKER_INTERVAL] [--timerange TIMERANGE]
|
||||||
[--stoplosses STOPLOSS_RANGE]
|
[--max_open_trades INT] [--stake_amount STAKE_AMOUNT]
|
||||||
|
[--stoplosses STOPLOSS_RANGE]
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL
|
-i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL
|
||||||
Specify ticker interval (1m, 5m, 30m, 1h, 1d).
|
Specify ticker interval (`1m`, `5m`, `30m`, `1h`,
|
||||||
|
`1d`).
|
||||||
--timerange TIMERANGE
|
--timerange TIMERANGE
|
||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
--max_open_trades MAX_OPEN_TRADES
|
--max_open_trades INT
|
||||||
Specify max_open_trades to use.
|
Specify max_open_trades to use.
|
||||||
--stake_amount STAKE_AMOUNT
|
--stake_amount STAKE_AMOUNT
|
||||||
Specify stake_amount.
|
Specify stake_amount.
|
||||||
--stoplosses STOPLOSS_RANGE
|
--stoplosses STOPLOSS_RANGE
|
||||||
Defines a range of stoploss against which edge will
|
Defines a range of stoploss values against which edge
|
||||||
assess the strategy the format is "min,max,step"
|
will assess the strategy. The format is "min,max,step"
|
||||||
(without any space).example:
|
(without any space). Example:
|
||||||
--stoplosses=-0.01,-0.1,-0.001
|
`--stoplosses=-0.01,-0.1,-0.001`
|
||||||
|
|
||||||
|
Common arguments:
|
||||||
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
--logfile FILE Log to the file specified.
|
||||||
|
-V, --version show program's version number and exit
|
||||||
|
-c PATH, --config PATH
|
||||||
|
Specify configuration file (default: `config.json`).
|
||||||
|
Multiple --config options may be used. Can be set to
|
||||||
|
`-` to read config from stdin.
|
||||||
|
-d PATH, --datadir PATH
|
||||||
|
Path to directory with historical backtesting data.
|
||||||
|
--userdir PATH, --user-data-dir PATH
|
||||||
|
Path to userdata directory.
|
||||||
|
|
||||||
|
Strategy arguments:
|
||||||
|
-s NAME, --strategy NAME
|
||||||
|
Specify strategy class name (default:
|
||||||
|
`DefaultStrategy`).
|
||||||
|
--strategy-path PATH Specify additional strategy lookup path.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
To understand edge and how to read the results, please read the [edge documentation](edge.md).
|
To understand edge and how to read the results, please read the [edge documentation](edge.md).
|
||||||
|
@ -95,7 +95,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
|||||||
| `db_url` | `sqlite:///tradesv3.sqlite`| Declares database URL to use. NOTE: This defaults to `sqlite://` if `dry_run` is `True`.
|
| `db_url` | `sqlite:///tradesv3.sqlite`| Declares database URL to use. NOTE: This defaults to `sqlite://` if `dry_run` is `True`.
|
||||||
| `initial_state` | running | Defines the initial application state. More information below.
|
| `initial_state` | running | Defines the initial application state. More information below.
|
||||||
| `forcebuy_enable` | false | Enables the RPC Commands to force a buy. More information below.
|
| `forcebuy_enable` | false | Enables the RPC Commands to force a buy. More information below.
|
||||||
| `strategy` | DefaultStrategy | Defines Strategy class to use.
|
| `strategy` | None | **Required** Defines Strategy class to use. Recommended to set via `--strategy NAME`.
|
||||||
| `strategy_path` | null | Adds an additional strategy lookup path (must be a directory).
|
| `strategy_path` | null | Adds an additional strategy lookup path (must be a directory).
|
||||||
| `internals.process_throttle_secs` | 5 | **Required.** Set the process throttle. Value in second.
|
| `internals.process_throttle_secs` | 5 | **Required.** Set the process throttle. Value in second.
|
||||||
| `internals.sd_notify` | false | Enables use of the sd_notify protocol to tell systemd service manager about changes in the bot state and issue keep-alive pings. See [here](installation.md#7-optional-configure-freqtrade-as-a-systemd-service) for more details.
|
| `internals.sd_notify` | false | Enables use of the sd_notify protocol to tell systemd service manager about changes in the bot state and issue keep-alive pings. See [here](installation.md#7-optional-configure-freqtrade-as-a-systemd-service) for more details.
|
||||||
|
@ -160,7 +160,7 @@ docker run -d \
|
|||||||
-v ~/.freqtrade/config.json:/freqtrade/config.json \
|
-v ~/.freqtrade/config.json:/freqtrade/config.json \
|
||||||
-v ~/.freqtrade/user_data/:/freqtrade/user_data \
|
-v ~/.freqtrade/user_data/:/freqtrade/user_data \
|
||||||
-v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \
|
-v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \
|
||||||
freqtrade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy
|
freqtrade trade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
@ -199,7 +199,7 @@ docker run -d \
|
|||||||
-v ~/.freqtrade/config.json:/freqtrade/config.json \
|
-v ~/.freqtrade/config.json:/freqtrade/config.json \
|
||||||
-v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \
|
-v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \
|
||||||
-v ~/.freqtrade/user_data/:/freqtrade/user_data/ \
|
-v ~/.freqtrade/user_data/:/freqtrade/user_data/ \
|
||||||
freqtrade --strategy AwsomelyProfitableStrategy backtesting
|
freqtrade backtesting --strategy AwsomelyProfitableStrategy
|
||||||
```
|
```
|
||||||
|
|
||||||
Head over to the [Backtesting Documentation](backtesting.md) for more details.
|
Head over to the [Backtesting Documentation](backtesting.md) for more details.
|
||||||
|
@ -235,7 +235,7 @@ An example of its output:
|
|||||||
### Update cached pairs with the latest data
|
### Update cached pairs with the latest data
|
||||||
|
|
||||||
Edge requires historic data the same way as backtesting does.
|
Edge requires historic data the same way as backtesting does.
|
||||||
Please refer to the [download section](backtesting.md#Getting-data-for-backtesting-and-hyperopt) of the documentation for details.
|
Please refer to the [Data Downloading](data-download.md) section of the documentation for details.
|
||||||
|
|
||||||
### Precising stoploss range
|
### Precising stoploss range
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
### The bot does not start
|
### The bot does not start
|
||||||
|
|
||||||
Running the bot with `freqtrade --config config.json` does show the output `freqtrade: command not found`.
|
Running the bot with `freqtrade trade --config config.json` does show the output `freqtrade: command not found`.
|
||||||
|
|
||||||
This could have the following reasons:
|
This could have the following reasons:
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ Because hyperopt tries a lot of combinations to find the best parameters it will
|
|||||||
We strongly recommend to use `screen` or `tmux` to prevent any connection loss.
|
We strongly recommend to use `screen` or `tmux` to prevent any connection loss.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade -c config.json hyperopt --customhyperopt <hyperoptname> -e 5000 --spaces all
|
freqtrade hyperopt --config config.json --hyperopt <hyperoptname> -e 5000 --spaces all
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `<hyperoptname>` as the name of the custom hyperopt used.
|
Use `<hyperoptname>` as the name of the custom hyperopt used.
|
||||||
|
@ -187,7 +187,7 @@ python3 -m pip install -e .
|
|||||||
If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins.
|
If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade -c config.json
|
freqtrade trade -c config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
*Note*: If you run the bot on a server, you should consider using [Docker](docker.md) or a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout.
|
*Note*: If you run the bot on a server, you should consider using [Docker](docker.md) or a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout.
|
||||||
|
@ -23,13 +23,15 @@ The `freqtrade plot-dataframe` subcommand shows an interactive graph with three
|
|||||||
Possible arguments:
|
Possible arguments:
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade plot-dataframe [-h] [-p PAIRS [PAIRS ...]]
|
usage: freqtrade plot-dataframe [-h] [-v] [--logfile FILE] [-V] [-c PATH]
|
||||||
|
[-d PATH] [--userdir PATH] [-s NAME]
|
||||||
|
[--strategy-path PATH] [-p PAIRS [PAIRS ...]]
|
||||||
[--indicators1 INDICATORS1 [INDICATORS1 ...]]
|
[--indicators1 INDICATORS1 [INDICATORS1 ...]]
|
||||||
[--indicators2 INDICATORS2 [INDICATORS2 ...]]
|
[--indicators2 INDICATORS2 [INDICATORS2 ...]]
|
||||||
[--plot-limit INT] [--db-url PATH]
|
[--plot-limit INT] [--db-url PATH]
|
||||||
[--trade-source {DB,file}] [--export EXPORT]
|
[--trade-source {DB,file}] [--export EXPORT]
|
||||||
[--export-filename PATH]
|
[--export-filename PATH]
|
||||||
[--timerange TIMERANGE]
|
[--timerange TIMERANGE] [-i TICKER_INTERVAL]
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@ -62,6 +64,28 @@ optional arguments:
|
|||||||
/backtest_today.json`
|
/backtest_today.json`
|
||||||
--timerange TIMERANGE
|
--timerange TIMERANGE
|
||||||
Specify what timerange of data to use.
|
Specify what timerange of data to use.
|
||||||
|
-i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL
|
||||||
|
Specify ticker interval (`1m`, `5m`, `30m`, `1h`,
|
||||||
|
`1d`).
|
||||||
|
|
||||||
|
Common arguments:
|
||||||
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
--logfile FILE Log to the file specified.
|
||||||
|
-V, --version show program's version number and exit
|
||||||
|
-c PATH, --config PATH
|
||||||
|
Specify configuration file (default: `config.json`).
|
||||||
|
Multiple --config options may be used. Can be set to
|
||||||
|
`-` to read config from stdin.
|
||||||
|
-d PATH, --datadir PATH
|
||||||
|
Path to directory with historical backtesting data.
|
||||||
|
--userdir PATH, --user-data-dir PATH
|
||||||
|
Path to userdata directory.
|
||||||
|
|
||||||
|
Strategy arguments:
|
||||||
|
-s NAME, --strategy NAME
|
||||||
|
Specify strategy class name (default:
|
||||||
|
`DefaultStrategy`).
|
||||||
|
--strategy-path PATH Specify additional strategy lookup path.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -83,7 +107,7 @@ Use `--indicators1` for the main plot and `--indicators2` for the subplot below
|
|||||||
You will almost certainly want to specify a custom strategy! This can be done by adding `-s Classname` / `--strategy ClassName` to the command.
|
You will almost certainly want to specify a custom strategy! This can be done by adding `-s Classname` / `--strategy ClassName` to the command.
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
freqtrade --strategy AwesomeStrategy plot-dataframe -p BTC/ETH --indicators1 sma ema --indicators2 macd
|
freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH --indicators1 sma ema --indicators2 macd
|
||||||
```
|
```
|
||||||
|
|
||||||
### Further usage examples
|
### Further usage examples
|
||||||
@ -91,25 +115,25 @@ freqtrade --strategy AwesomeStrategy plot-dataframe -p BTC/ETH --indicators1 sma
|
|||||||
To plot multiple pairs, separate them with a space:
|
To plot multiple pairs, separate them with a space:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
freqtrade --strategy AwesomeStrategy plot-dataframe -p BTC/ETH XRP/ETH
|
freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH XRP/ETH
|
||||||
```
|
```
|
||||||
|
|
||||||
To plot a timerange (to zoom in)
|
To plot a timerange (to zoom in)
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
freqtrade --strategy AwesomeStrategy plot-dataframe -p BTC/ETH --timerange=20180801-20180805
|
freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH --timerange=20180801-20180805
|
||||||
```
|
```
|
||||||
|
|
||||||
To plot trades stored in a database use `--db-url` in combination with `--trade-source DB`:
|
To plot trades stored in a database use `--db-url` in combination with `--trade-source DB`:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
freqtrade --strategy AwesomeStrategy plot-dataframe --db-url sqlite:///tradesv3.dry_run.sqlite -p BTC/ETH --trade-source DB
|
freqtrade plot-dataframe --strategy AwesomeStrategy --db-url sqlite:///tradesv3.dry_run.sqlite -p BTC/ETH --trade-source DB
|
||||||
```
|
```
|
||||||
|
|
||||||
To plot trades from a backtesting result, use `--export-filename <filename>`
|
To plot trades from a backtesting result, use `--export-filename <filename>`
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
freqtrade --strategy AwesomeStrategy plot-dataframe --export-filename user_data/backtest_results/backtest-result.json -p BTC/ETH
|
freqtrade plot-dataframe --strategy AwesomeStrategy --export-filename user_data/backtest_results/backtest-result.json -p BTC/ETH
|
||||||
```
|
```
|
||||||
|
|
||||||
## Plot profit
|
## Plot profit
|
||||||
@ -133,10 +157,11 @@ The third graph can be useful to spot outliers, events in pairs that cause profi
|
|||||||
Possible options for the `freqtrade plot-profit` subcommand:
|
Possible options for the `freqtrade plot-profit` subcommand:
|
||||||
|
|
||||||
```
|
```
|
||||||
usage: freqtrade plot-profit [-h] [-p PAIRS [PAIRS ...]]
|
usage: freqtrade plot-profit [-h] [-v] [--logfile FILE] [-V] [-c PATH]
|
||||||
|
[-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]]
|
||||||
[--timerange TIMERANGE] [--export EXPORT]
|
[--timerange TIMERANGE] [--export EXPORT]
|
||||||
[--export-filename PATH] [--db-url PATH]
|
[--export-filename PATH] [--db-url PATH]
|
||||||
[--trade-source {DB,file}]
|
[--trade-source {DB,file}] [-i TICKER_INTERVAL]
|
||||||
|
|
||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
@ -159,6 +184,22 @@ optional arguments:
|
|||||||
--trade-source {DB,file}
|
--trade-source {DB,file}
|
||||||
Specify the source for trades (Can be DB or file
|
Specify the source for trades (Can be DB or file
|
||||||
(backtest file)) Default: file
|
(backtest file)) Default: file
|
||||||
|
-i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL
|
||||||
|
Specify ticker interval (`1m`, `5m`, `30m`, `1h`,
|
||||||
|
`1d`).
|
||||||
|
|
||||||
|
Common arguments:
|
||||||
|
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
|
||||||
|
--logfile FILE Log to the file specified.
|
||||||
|
-V, --version show program's version number and exit
|
||||||
|
-c PATH, --config PATH
|
||||||
|
Specify configuration file (default: `config.json`).
|
||||||
|
Multiple --config options may be used. Can be set to
|
||||||
|
`-` to read config from stdin.
|
||||||
|
-d PATH, --datadir PATH
|
||||||
|
Path to directory with historical backtesting data.
|
||||||
|
--userdir PATH, --user-data-dir PATH
|
||||||
|
Path to userdata directory.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ docker run -d \
|
|||||||
-v ~/.freqtrade/user_data/:/freqtrade/user_data \
|
-v ~/.freqtrade/user_data/:/freqtrade/user_data \
|
||||||
-v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \
|
-v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \
|
||||||
-p 127.0.0.1:8080:8080 \
|
-p 127.0.0.1:8080:8080 \
|
||||||
freqtrade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy
|
freqtrade trade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! Danger "Security warning"
|
!!! Danger "Security warning"
|
||||||
|
@ -13,7 +13,7 @@ Let assume you have a class called `AwesomeStrategy` in the file `awesome-strate
|
|||||||
2. Start the bot with the param `--strategy AwesomeStrategy` (the parameter is the class name)
|
2. Start the bot with the param `--strategy AwesomeStrategy` (the parameter is the class name)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade --strategy AwesomeStrategy
|
freqtrade trade --strategy AwesomeStrategy
|
||||||
```
|
```
|
||||||
|
|
||||||
## Change your strategy
|
## Change your strategy
|
||||||
@ -45,7 +45,7 @@ The current version is 2 - which is also the default when it's not set explicitl
|
|||||||
Future versions will require this to be set.
|
Future versions will require this to be set.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade --strategy AwesomeStrategy
|
freqtrade trade --strategy AwesomeStrategy
|
||||||
```
|
```
|
||||||
|
|
||||||
**For the following section we will use the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/user_data/strategies/sample_strategy.py)
|
**For the following section we will use the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/user_data/strategies/sample_strategy.py)
|
||||||
@ -402,7 +402,7 @@ The default buy strategy is located in the file
|
|||||||
If you want to use a strategy from a different directory you can pass `--strategy-path`
|
If you want to use a strategy from a different directory you can pass `--strategy-path`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freqtrade --strategy AwesomeStrategy --strategy-path /some/directory
|
freqtrade trade --strategy AwesomeStrategy --strategy-path /some/directory
|
||||||
```
|
```
|
||||||
|
|
||||||
### Further strategy ideas
|
### Further strategy ideas
|
||||||
|
@ -6,7 +6,7 @@ After=network.target
|
|||||||
# Set WorkingDirectory and ExecStart to your file paths accordingly
|
# Set WorkingDirectory and ExecStart to your file paths accordingly
|
||||||
# NOTE: %h will be resolved to /home/<username>
|
# NOTE: %h will be resolved to /home/<username>
|
||||||
WorkingDirectory=%h/freqtrade
|
WorkingDirectory=%h/freqtrade
|
||||||
ExecStart=/usr/bin/freqtrade
|
ExecStart=/usr/bin/freqtrade trade
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
@ -6,7 +6,7 @@ After=network.target
|
|||||||
# Set WorkingDirectory and ExecStart to your file paths accordingly
|
# Set WorkingDirectory and ExecStart to your file paths accordingly
|
||||||
# NOTE: %h will be resolved to /home/<username>
|
# NOTE: %h will be resolved to /home/<username>
|
||||||
WorkingDirectory=%h/freqtrade
|
WorkingDirectory=%h/freqtrade
|
||||||
ExecStart=/usr/bin/freqtrade --sd-notify
|
ExecStart=/usr/bin/freqtrade trade --sd-notify
|
||||||
|
|
||||||
Restart=always
|
Restart=always
|
||||||
#Restart=on-failure
|
#Restart=on-failure
|
||||||
|
@ -12,10 +12,9 @@ ARGS_COMMON = ["verbosity", "logfile", "version", "config", "datadir", "user_dat
|
|||||||
|
|
||||||
ARGS_STRATEGY = ["strategy", "strategy_path"]
|
ARGS_STRATEGY = ["strategy", "strategy_path"]
|
||||||
|
|
||||||
ARGS_MAIN = ARGS_COMMON + ARGS_STRATEGY + ["db_url", "sd_notify"]
|
ARGS_TRADE = ["db_url", "sd_notify", "dry_run"]
|
||||||
|
|
||||||
ARGS_COMMON_OPTIMIZE = ["ticker_interval", "timerange",
|
ARGS_COMMON_OPTIMIZE = ["ticker_interval", "timerange", "max_open_trades", "stake_amount"]
|
||||||
"max_open_trades", "stake_amount"]
|
|
||||||
|
|
||||||
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions",
|
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions",
|
||||||
"strategy_list", "export", "exportfilename"]
|
"strategy_list", "export", "exportfilename"]
|
||||||
@ -35,8 +34,9 @@ ARGS_CREATE_USERDIR = ["user_data_dir"]
|
|||||||
|
|
||||||
ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "exchange", "timeframes", "erase"]
|
ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "exchange", "timeframes", "erase"]
|
||||||
|
|
||||||
ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", "db_url",
|
ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit",
|
||||||
"trade_source", "export", "exportfilename", "timerange", "ticker_interval"]
|
"db_url", "trade_source", "export", "exportfilename",
|
||||||
|
"timerange", "ticker_interval"]
|
||||||
|
|
||||||
ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url",
|
ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url",
|
||||||
"trade_source", "ticker_interval"]
|
"trade_source", "ticker_interval"]
|
||||||
@ -51,11 +51,6 @@ class Arguments:
|
|||||||
def __init__(self, args: Optional[List[str]]) -> None:
|
def __init__(self, args: Optional[List[str]]) -> None:
|
||||||
self.args = args
|
self.args = args
|
||||||
self._parsed_arg: Optional[argparse.Namespace] = None
|
self._parsed_arg: Optional[argparse.Namespace] = None
|
||||||
self.parser = argparse.ArgumentParser(description='Free, open source crypto trading bot')
|
|
||||||
|
|
||||||
def _load_args(self) -> None:
|
|
||||||
self._build_args(optionlist=ARGS_MAIN)
|
|
||||||
self._build_subcommands()
|
|
||||||
|
|
||||||
def get_parsed_arg(self) -> Dict[str, Any]:
|
def get_parsed_arg(self) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
@ -63,7 +58,7 @@ class Arguments:
|
|||||||
:return: List[str] List of arguments
|
:return: List[str] List of arguments
|
||||||
"""
|
"""
|
||||||
if self._parsed_arg is None:
|
if self._parsed_arg is None:
|
||||||
self._load_args()
|
self._build_subcommands()
|
||||||
self._parsed_arg = self._parse_args()
|
self._parsed_arg = self._parse_args()
|
||||||
|
|
||||||
return vars(self._parsed_arg)
|
return vars(self._parsed_arg)
|
||||||
@ -79,14 +74,14 @@ class Arguments:
|
|||||||
# Workaround issue in argparse with action='append' and default value
|
# Workaround issue in argparse with action='append' and default value
|
||||||
# (see https://bugs.python.org/issue16399)
|
# (see https://bugs.python.org/issue16399)
|
||||||
# Allow no-config for certain commands (like downloading / plotting)
|
# Allow no-config for certain commands (like downloading / plotting)
|
||||||
if (parsed_arg.config is None and ((Path.cwd() / constants.DEFAULT_CONFIG).is_file() or
|
if ('config' in parsed_arg and parsed_arg.config is None and
|
||||||
not ('subparser' in parsed_arg and parsed_arg.subparser in NO_CONF_REQURIED))):
|
((Path.cwd() / constants.DEFAULT_CONFIG).is_file() or
|
||||||
|
not ('command' in parsed_arg and parsed_arg.command in NO_CONF_REQURIED))):
|
||||||
parsed_arg.config = [constants.DEFAULT_CONFIG]
|
parsed_arg.config = [constants.DEFAULT_CONFIG]
|
||||||
|
|
||||||
return parsed_arg
|
return parsed_arg
|
||||||
|
|
||||||
def _build_args(self, optionlist, parser=None):
|
def _build_args(self, optionlist, parser):
|
||||||
parser = parser or self.parser
|
|
||||||
|
|
||||||
for val in optionlist:
|
for val in optionlist:
|
||||||
opt = AVAILABLE_CLI_OPTIONS[val]
|
opt = AVAILABLE_CLI_OPTIONS[val]
|
||||||
@ -97,61 +92,90 @@ class Arguments:
|
|||||||
Builds and attaches all subcommands.
|
Builds and attaches all subcommands.
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
from freqtrade.optimize import start_backtesting, start_hyperopt, start_edge
|
# Build shared arguments (as group Common Options)
|
||||||
from freqtrade.utils import start_create_userdir, start_download_data, start_list_exchanges
|
_common_parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
group = _common_parser.add_argument_group("Common arguments")
|
||||||
|
self._build_args(optionlist=ARGS_COMMON, parser=group)
|
||||||
|
|
||||||
subparsers = self.parser.add_subparsers(dest='subparser')
|
_strategy_parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
strategy_group = _strategy_parser.add_argument_group("Strategy arguments")
|
||||||
|
self._build_args(optionlist=ARGS_STRATEGY, parser=strategy_group)
|
||||||
|
|
||||||
|
# Build main command
|
||||||
|
self.parser = argparse.ArgumentParser(description='Free, open source crypto trading bot')
|
||||||
|
self._build_args(optionlist=['version'], parser=self.parser)
|
||||||
|
|
||||||
|
from freqtrade.optimize import start_backtesting, start_hyperopt, start_edge
|
||||||
|
from freqtrade.utils import (start_create_userdir, start_download_data,
|
||||||
|
start_list_exchanges, start_trading)
|
||||||
|
from freqtrade.plot.plot_utils import start_plot_dataframe, start_plot_profit
|
||||||
|
|
||||||
|
subparsers = self.parser.add_subparsers(dest='command',
|
||||||
|
# Use custom message when no subhandler is added
|
||||||
|
# shown from `main.py`
|
||||||
|
# required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add trade subcommand
|
||||||
|
trade_cmd = subparsers.add_parser('trade', help='Trade module.',
|
||||||
|
parents=[_common_parser, _strategy_parser])
|
||||||
|
trade_cmd.set_defaults(func=start_trading)
|
||||||
|
self._build_args(optionlist=ARGS_TRADE, parser=trade_cmd)
|
||||||
|
|
||||||
# Add backtesting subcommand
|
# Add backtesting subcommand
|
||||||
backtesting_cmd = subparsers.add_parser('backtesting', help='Backtesting module.')
|
backtesting_cmd = subparsers.add_parser('backtesting', help='Backtesting module.',
|
||||||
|
parents=[_common_parser, _strategy_parser])
|
||||||
backtesting_cmd.set_defaults(func=start_backtesting)
|
backtesting_cmd.set_defaults(func=start_backtesting)
|
||||||
self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd)
|
self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd)
|
||||||
|
|
||||||
# Add edge subcommand
|
# Add edge subcommand
|
||||||
edge_cmd = subparsers.add_parser('edge', help='Edge module.')
|
edge_cmd = subparsers.add_parser('edge', help='Edge module.',
|
||||||
|
parents=[_common_parser, _strategy_parser])
|
||||||
edge_cmd.set_defaults(func=start_edge)
|
edge_cmd.set_defaults(func=start_edge)
|
||||||
self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd)
|
self._build_args(optionlist=ARGS_EDGE, parser=edge_cmd)
|
||||||
|
|
||||||
# Add hyperopt subcommand
|
# Add hyperopt subcommand
|
||||||
hyperopt_cmd = subparsers.add_parser('hyperopt', help='Hyperopt module.')
|
hyperopt_cmd = subparsers.add_parser('hyperopt', help='Hyperopt module.',
|
||||||
|
parents=[_common_parser, _strategy_parser],
|
||||||
|
)
|
||||||
hyperopt_cmd.set_defaults(func=start_hyperopt)
|
hyperopt_cmd.set_defaults(func=start_hyperopt)
|
||||||
self._build_args(optionlist=ARGS_HYPEROPT, parser=hyperopt_cmd)
|
self._build_args(optionlist=ARGS_HYPEROPT, parser=hyperopt_cmd)
|
||||||
|
|
||||||
# add create-userdir subcommand
|
# add create-userdir subcommand
|
||||||
create_userdir_cmd = subparsers.add_parser('create-userdir',
|
create_userdir_cmd = subparsers.add_parser('create-userdir',
|
||||||
help="Create user-data directory.")
|
help="Create user-data directory.",
|
||||||
|
)
|
||||||
create_userdir_cmd.set_defaults(func=start_create_userdir)
|
create_userdir_cmd.set_defaults(func=start_create_userdir)
|
||||||
self._build_args(optionlist=ARGS_CREATE_USERDIR, parser=create_userdir_cmd)
|
self._build_args(optionlist=ARGS_CREATE_USERDIR, parser=create_userdir_cmd)
|
||||||
|
|
||||||
# Add list-exchanges subcommand
|
# Add list-exchanges subcommand
|
||||||
list_exchanges_cmd = subparsers.add_parser(
|
list_exchanges_cmd = subparsers.add_parser('list-exchanges',
|
||||||
'list-exchanges',
|
help='Print available exchanges.',
|
||||||
help='Print available exchanges.'
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
list_exchanges_cmd.set_defaults(func=start_list_exchanges)
|
list_exchanges_cmd.set_defaults(func=start_list_exchanges)
|
||||||
self._build_args(optionlist=ARGS_LIST_EXCHANGES, parser=list_exchanges_cmd)
|
self._build_args(optionlist=ARGS_LIST_EXCHANGES, parser=list_exchanges_cmd)
|
||||||
|
|
||||||
# Add download-data subcommand
|
# Add download-data subcommand
|
||||||
download_data_cmd = subparsers.add_parser(
|
download_data_cmd = subparsers.add_parser('download-data',
|
||||||
'download-data',
|
help='Download backtesting data.',
|
||||||
help='Download backtesting data.'
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
download_data_cmd.set_defaults(func=start_download_data)
|
download_data_cmd.set_defaults(func=start_download_data)
|
||||||
self._build_args(optionlist=ARGS_DOWNLOAD_DATA, parser=download_data_cmd)
|
self._build_args(optionlist=ARGS_DOWNLOAD_DATA, parser=download_data_cmd)
|
||||||
|
|
||||||
# Add Plotting subcommand
|
# Add Plotting subcommand
|
||||||
from freqtrade.plot.plot_utils import start_plot_dataframe, start_plot_profit
|
plot_dataframe_cmd = subparsers.add_parser('plot-dataframe',
|
||||||
plot_dataframe_cmd = subparsers.add_parser(
|
help='Plot candles with indicators.',
|
||||||
'plot-dataframe',
|
parents=[_common_parser, _strategy_parser],
|
||||||
help='Plot candles with indicators.'
|
)
|
||||||
)
|
|
||||||
plot_dataframe_cmd.set_defaults(func=start_plot_dataframe)
|
plot_dataframe_cmd.set_defaults(func=start_plot_dataframe)
|
||||||
self._build_args(optionlist=ARGS_PLOT_DATAFRAME, parser=plot_dataframe_cmd)
|
self._build_args(optionlist=ARGS_PLOT_DATAFRAME, parser=plot_dataframe_cmd)
|
||||||
|
|
||||||
# Plot profit
|
# Plot profit
|
||||||
plot_profit_cmd = subparsers.add_parser(
|
plot_profit_cmd = subparsers.add_parser('plot-profit',
|
||||||
'plot-profit',
|
help='Generate plot showing profits.',
|
||||||
help='Generate plot showing profits.'
|
parents=[_common_parser],
|
||||||
)
|
)
|
||||||
plot_profit_cmd.set_defaults(func=start_plot_profit)
|
plot_profit_cmd.set_defaults(func=start_plot_profit)
|
||||||
self._build_args(optionlist=ARGS_PLOT_PROFIT, parser=plot_profit_cmd)
|
self._build_args(optionlist=ARGS_PLOT_PROFIT, parser=plot_profit_cmd)
|
||||||
|
@ -66,9 +66,8 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
# Main options
|
# Main options
|
||||||
"strategy": Arg(
|
"strategy": Arg(
|
||||||
'-s', '--strategy',
|
'-s', '--strategy',
|
||||||
help='Specify strategy class name (default: `%(default)s`).',
|
help='Specify strategy class name which will be used by the bot.',
|
||||||
metavar='NAME',
|
metavar='NAME',
|
||||||
default='DefaultStrategy',
|
|
||||||
),
|
),
|
||||||
"strategy_path": Arg(
|
"strategy_path": Arg(
|
||||||
'--strategy-path',
|
'--strategy-path',
|
||||||
@ -87,6 +86,11 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
help='Notify systemd service manager.',
|
help='Notify systemd service manager.',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
),
|
),
|
||||||
|
"dry_run": Arg(
|
||||||
|
'--dry-run',
|
||||||
|
help='Enforce dry-run for trading (removes Exchange secrets and simulates trades).',
|
||||||
|
action='store_true',
|
||||||
|
),
|
||||||
# Optimize common
|
# Optimize common
|
||||||
"ticker_interval": Arg(
|
"ticker_interval": Arg(
|
||||||
'-i', '--ticker-interval',
|
'-i', '--ticker-interval',
|
||||||
@ -153,10 +157,9 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
),
|
),
|
||||||
# Hyperopt
|
# Hyperopt
|
||||||
"hyperopt": Arg(
|
"hyperopt": Arg(
|
||||||
'--customhyperopt',
|
'--hyperopt',
|
||||||
help='Specify hyperopt class name (default: `%(default)s`).',
|
help='Specify hyperopt class name which will be used by the bot.',
|
||||||
metavar='NAME',
|
metavar='NAME',
|
||||||
default=constants.DEFAULT_HYPEROPT,
|
|
||||||
),
|
),
|
||||||
"hyperopt_path": Arg(
|
"hyperopt_path": Arg(
|
||||||
'--hyperopt-path',
|
'--hyperopt-path',
|
||||||
@ -171,7 +174,7 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
default=constants.HYPEROPT_EPOCH,
|
default=constants.HYPEROPT_EPOCH,
|
||||||
),
|
),
|
||||||
"spaces": Arg(
|
"spaces": Arg(
|
||||||
'-s', '--spaces',
|
'--spaces',
|
||||||
help='Specify which parameters to hyperopt. Space-separated list. '
|
help='Specify which parameters to hyperopt. Space-separated list. '
|
||||||
'Default: `%(default)s`.',
|
'Default: `%(default)s`.',
|
||||||
choices=['all', 'buy', 'sell', 'roi', 'stoploss'],
|
choices=['all', 'buy', 'sell', 'roi', 'stoploss'],
|
||||||
@ -233,7 +236,7 @@ AVAILABLE_CLI_OPTIONS = {
|
|||||||
help='Specify the class name of the hyperopt loss function class (IHyperOptLoss). '
|
help='Specify the class name of the hyperopt loss function class (IHyperOptLoss). '
|
||||||
'Different functions can generate completely different results, '
|
'Different functions can generate completely different results, '
|
||||||
'since the target for optimization is different. Built-in Hyperopt-loss-functions are: '
|
'since the target for optimization is different. Built-in Hyperopt-loss-functions are: '
|
||||||
'DefaultHyperOptLoss, OnlyProfitHyperOptLoss, SharpeHyperOptLoss.'
|
'DefaultHyperOptLoss, OnlyProfitHyperOptLoss, SharpeHyperOptLoss '
|
||||||
'(default: `%(default)s`).',
|
'(default: `%(default)s`).',
|
||||||
metavar='NAME',
|
metavar='NAME',
|
||||||
default=constants.DEFAULT_HYPEROPT_LOSS,
|
default=constants.DEFAULT_HYPEROPT_LOSS,
|
||||||
|
@ -128,7 +128,7 @@ class Configuration:
|
|||||||
self._process_logging_options(config)
|
self._process_logging_options(config)
|
||||||
|
|
||||||
# Set strategy if not specified in config and or if it's non default
|
# Set strategy if not specified in config and or if it's non default
|
||||||
if self.args.get("strategy") != constants.DEFAULT_STRATEGY or not config.get('strategy'):
|
if self.args.get("strategy") or not config.get('strategy'):
|
||||||
config.update({'strategy': self.args.get("strategy")})
|
config.update({'strategy': self.args.get("strategy")})
|
||||||
|
|
||||||
self._args_to_config(config, argname='strategy_path',
|
self._args_to_config(config, argname='strategy_path',
|
||||||
@ -162,6 +162,10 @@ class Configuration:
|
|||||||
if 'sd_notify' in self.args and self.args["sd_notify"]:
|
if 'sd_notify' in self.args and self.args["sd_notify"]:
|
||||||
config['internals'].update({'sd_notify': True})
|
config['internals'].update({'sd_notify': True})
|
||||||
|
|
||||||
|
self._args_to_config(config, argname='dry_run',
|
||||||
|
logstring='Parameter --dry-run detected, '
|
||||||
|
'overriding dry_run to: {} ...')
|
||||||
|
|
||||||
def _process_datadir_options(self, config: Dict[str, Any]) -> None:
|
def _process_datadir_options(self, config: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Extract information for sys.argv and load directory configurations
|
Extract information for sys.argv and load directory configurations
|
||||||
|
@ -9,8 +9,6 @@ PROCESS_THROTTLE_SECS = 5 # sec
|
|||||||
DEFAULT_TICKER_INTERVAL = 5 # min
|
DEFAULT_TICKER_INTERVAL = 5 # min
|
||||||
HYPEROPT_EPOCH = 100 # epochs
|
HYPEROPT_EPOCH = 100 # epochs
|
||||||
RETRY_TIMEOUT = 30 # sec
|
RETRY_TIMEOUT = 30 # sec
|
||||||
DEFAULT_STRATEGY = 'DefaultStrategy'
|
|
||||||
DEFAULT_HYPEROPT = 'DefaultHyperOpts'
|
|
||||||
DEFAULT_HYPEROPT_LOSS = 'DefaultHyperOptLoss'
|
DEFAULT_HYPEROPT_LOSS = 'DefaultHyperOptLoss'
|
||||||
DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite'
|
DEFAULT_DB_PROD_URL = 'sqlite:///tradesv3.sqlite'
|
||||||
DEFAULT_DB_DRYRUN_URL = 'sqlite://'
|
DEFAULT_DB_DRYRUN_URL = 'sqlite://'
|
||||||
|
@ -15,7 +15,6 @@ from typing import Any, List
|
|||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException
|
||||||
from freqtrade.configuration import Arguments
|
from freqtrade.configuration import Arguments
|
||||||
from freqtrade.worker import Worker
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('freqtrade')
|
logger = logging.getLogger('freqtrade')
|
||||||
@ -33,16 +32,16 @@ def main(sysargv: List[str] = None) -> None:
|
|||||||
arguments = Arguments(sysargv)
|
arguments = Arguments(sysargv)
|
||||||
args = arguments.get_parsed_arg()
|
args = arguments.get_parsed_arg()
|
||||||
|
|
||||||
# A subcommand has been issued.
|
# Call subcommand.
|
||||||
# Means if Backtesting or Hyperopt have been called we exit the bot
|
|
||||||
if 'func' in args:
|
if 'func' in args:
|
||||||
args['func'](args)
|
return_code = args['func'](args)
|
||||||
# TODO: fetch return_code as returned by the command function here
|
|
||||||
return_code = 0
|
|
||||||
else:
|
else:
|
||||||
# Load and run worker
|
# No subcommand was issued.
|
||||||
worker = Worker(args)
|
raise OperationalException(
|
||||||
worker.run()
|
"Usage of freqtrade requires a subcommand.\n"
|
||||||
|
"To use the previous behaviour, run freqtrade with `freqtrade trade [...]`.\n"
|
||||||
|
"To see a full list of options, please use `freqtrade --help`"
|
||||||
|
)
|
||||||
|
|
||||||
except SystemExit as e:
|
except SystemExit as e:
|
||||||
return_code = e
|
return_code = e
|
||||||
|
@ -8,7 +8,7 @@ from pathlib import Path
|
|||||||
from typing import Optional, Dict
|
from typing import Optional, Dict
|
||||||
|
|
||||||
from freqtrade import OperationalException
|
from freqtrade import OperationalException
|
||||||
from freqtrade.constants import DEFAULT_HYPEROPT, DEFAULT_HYPEROPT_LOSS
|
from freqtrade.constants import DEFAULT_HYPEROPT_LOSS
|
||||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss
|
from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss
|
||||||
from freqtrade.resolvers import IResolver
|
from freqtrade.resolvers import IResolver
|
||||||
@ -20,7 +20,6 @@ class HyperOptResolver(IResolver):
|
|||||||
"""
|
"""
|
||||||
This class contains all the logic to load custom hyperopt class
|
This class contains all the logic to load custom hyperopt class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['hyperopt']
|
__slots__ = ['hyperopt']
|
||||||
|
|
||||||
def __init__(self, config: Dict) -> None:
|
def __init__(self, config: Dict) -> None:
|
||||||
@ -28,9 +27,12 @@ class HyperOptResolver(IResolver):
|
|||||||
Load the custom class from config parameter
|
Load the custom class from config parameter
|
||||||
:param config: configuration dictionary
|
:param config: configuration dictionary
|
||||||
"""
|
"""
|
||||||
|
if not config.get('hyperopt'):
|
||||||
|
raise OperationalException("No Hyperopt set. Please use `--hyperopt` to specify "
|
||||||
|
"the Hyperopt class to use.")
|
||||||
|
|
||||||
|
hyperopt_name = config['hyperopt']
|
||||||
|
|
||||||
# Verify the hyperopt is in the configuration, otherwise fallback to the default hyperopt
|
|
||||||
hyperopt_name = config.get('hyperopt') or DEFAULT_HYPEROPT
|
|
||||||
self.hyperopt = self._load_hyperopt(hyperopt_name, config,
|
self.hyperopt = self._load_hyperopt(hyperopt_name, config,
|
||||||
extra_dir=config.get('hyperopt_path'))
|
extra_dir=config.get('hyperopt_path'))
|
||||||
|
|
||||||
@ -75,27 +77,28 @@ class HyperOptLossResolver(IResolver):
|
|||||||
"""
|
"""
|
||||||
This class contains all the logic to load custom hyperopt loss class
|
This class contains all the logic to load custom hyperopt loss class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = ['hyperoptloss']
|
__slots__ = ['hyperoptloss']
|
||||||
|
|
||||||
def __init__(self, config: Dict = None) -> None:
|
def __init__(self, config: Dict) -> None:
|
||||||
"""
|
"""
|
||||||
Load the custom class from config parameter
|
Load the custom class from config parameter
|
||||||
:param config: configuration dictionary or None
|
:param config: configuration dictionary
|
||||||
"""
|
"""
|
||||||
config = config or {}
|
|
||||||
|
|
||||||
# Verify the hyperopt is in the configuration, otherwise fallback to the default hyperopt
|
# Verify the hyperopt_loss is in the configuration, otherwise fallback to the
|
||||||
hyperopt_name = config.get('hyperopt_loss') or DEFAULT_HYPEROPT_LOSS
|
# default hyperopt loss
|
||||||
|
hyperoptloss_name = config.get('hyperopt_loss') or DEFAULT_HYPEROPT_LOSS
|
||||||
|
|
||||||
self.hyperoptloss = self._load_hyperoptloss(
|
self.hyperoptloss = self._load_hyperoptloss(
|
||||||
hyperopt_name, config, extra_dir=config.get('hyperopt_path'))
|
hyperoptloss_name, config, extra_dir=config.get('hyperopt_path'))
|
||||||
|
|
||||||
# Assign ticker_interval to be used in hyperopt
|
# Assign ticker_interval to be used in hyperopt
|
||||||
self.hyperoptloss.__class__.ticker_interval = str(config['ticker_interval'])
|
self.hyperoptloss.__class__.ticker_interval = str(config['ticker_interval'])
|
||||||
|
|
||||||
if not hasattr(self.hyperoptloss, 'hyperopt_loss_function'):
|
if not hasattr(self.hyperoptloss, 'hyperopt_loss_function'):
|
||||||
raise OperationalException(
|
raise OperationalException(
|
||||||
f"Found hyperopt {hyperopt_name} does not implement `hyperopt_loss_function`.")
|
f"Found HyperoptLoss class {hyperoptloss_name} does not "
|
||||||
|
"implement `hyperopt_loss_function`.")
|
||||||
|
|
||||||
def _load_hyperoptloss(
|
def _load_hyperoptloss(
|
||||||
self, hyper_loss_name: str, config: Dict,
|
self, hyper_loss_name: str, config: Dict,
|
||||||
|
@ -32,8 +32,11 @@ class StrategyResolver(IResolver):
|
|||||||
"""
|
"""
|
||||||
config = config or {}
|
config = config or {}
|
||||||
|
|
||||||
# Verify the strategy is in the configuration, otherwise fallback to the default strategy
|
if not config.get('strategy'):
|
||||||
strategy_name = config.get('strategy') or constants.DEFAULT_STRATEGY
|
raise OperationalException("No strategy set. Please use `--strategy` to specify "
|
||||||
|
"the strategy class to use.")
|
||||||
|
|
||||||
|
strategy_name = config['strategy']
|
||||||
self.strategy: IStrategy = self._load_strategy(strategy_name,
|
self.strategy: IStrategy = self._load_strategy(strategy_name,
|
||||||
config=config,
|
config=config,
|
||||||
extra_dir=config.get('strategy_path'))
|
extra_dir=config.get('strategy_path'))
|
||||||
|
@ -33,6 +33,17 @@ def setup_utils_configuration(args: Dict[str, Any], method: RunMode) -> Dict[str
|
|||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def start_trading(args: Dict[str, Any]) -> int:
|
||||||
|
"""
|
||||||
|
Main entry point for trading mode
|
||||||
|
"""
|
||||||
|
from freqtrade.worker import Worker
|
||||||
|
# Load and run worker
|
||||||
|
worker = Worker(args)
|
||||||
|
worker.run()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def start_list_exchanges(args: Dict[str, Any]) -> None:
|
def start_list_exchanges(args: Dict[str, Any]) -> None:
|
||||||
"""
|
"""
|
||||||
Print available exchanges
|
Print available exchanges
|
||||||
|
@ -242,6 +242,7 @@ def default_conf(testdatadir):
|
|||||||
"db_url": "sqlite://",
|
"db_url": "sqlite://",
|
||||||
"user_data_dir": Path("user_data"),
|
"user_data_dir": Path("user_data"),
|
||||||
"verbosity": 3,
|
"verbosity": 3,
|
||||||
|
"strategy": "DefaultStrategy"
|
||||||
}
|
}
|
||||||
return configuration
|
return configuration
|
||||||
|
|
||||||
|
@ -169,9 +169,9 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'backtesting'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args), RunMode.BACKTEST)
|
config = setup_configuration(get_args(args), RunMode.BACKTEST)
|
||||||
@ -202,10 +202,10 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) ->
|
|||||||
)
|
)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'--datadir', '/foo/bar',
|
'--datadir', '/foo/bar',
|
||||||
'backtesting',
|
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--enable-position-stacking',
|
'--enable-position-stacking',
|
||||||
'--disable-max-market-positions',
|
'--disable-max-market-positions',
|
||||||
@ -250,9 +250,9 @@ def test_setup_configuration_unlimited_stake_amount(mocker, default_conf, caplog
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'backtesting'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
with pytest.raises(DependencyException, match=r'.*stake amount.*'):
|
||||||
@ -267,9 +267,9 @@ def test_start(mocker, fee, default_conf, caplog) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'backtesting'
|
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start_backtesting(args)
|
start_backtesting(args)
|
||||||
@ -812,10 +812,10 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'--datadir', str(testdatadir),
|
'--datadir', str(testdatadir),
|
||||||
'backtesting',
|
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--timerange', '-100',
|
'--timerange', '-100',
|
||||||
'--enable-position-stacking',
|
'--enable-position-stacking',
|
||||||
@ -859,9 +859,9 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--datadir', str(testdatadir),
|
'--datadir', str(testdatadir),
|
||||||
'backtesting',
|
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--timerange', '-100',
|
'--timerange', '-100',
|
||||||
'--enable-position-stacking',
|
'--enable-position-stacking',
|
||||||
|
@ -15,9 +15,9 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'edge',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'edge'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args), RunMode.EDGE)
|
config = setup_configuration(get_args(args), RunMode.EDGE)
|
||||||
@ -45,10 +45,10 @@ def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> N
|
|||||||
)
|
)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'edge',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'--datadir', '/foo/bar',
|
'--datadir', '/foo/bar',
|
||||||
'edge',
|
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--timerange', ':100',
|
'--timerange', ':100',
|
||||||
'--stoplosses=-0.01,-0.10,-0.001'
|
'--stoplosses=-0.01,-0.10,-0.001'
|
||||||
@ -79,9 +79,9 @@ def test_start(mocker, fee, edge_conf, caplog) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, edge_conf)
|
patched_configuration_load_config_file(mocker, edge_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'edge',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'edge'
|
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
start_edge(args)
|
start_edge(args)
|
||||||
|
@ -25,7 +25,10 @@ from tests.conftest import (get_args, log_has, log_has_re, patch_exchange,
|
|||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def hyperopt(default_conf, mocker):
|
def hyperopt(default_conf, mocker):
|
||||||
default_conf.update({'spaces': ['all']})
|
default_conf.update({
|
||||||
|
'spaces': ['all'],
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
|
})
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
return Hyperopt(default_conf)
|
return Hyperopt(default_conf)
|
||||||
|
|
||||||
@ -68,8 +71,9 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
|
'hyperopt',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'hyperopt'
|
'--hyperopt', 'DefaultHyperOpts',
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
|
config = setup_configuration(get_args(args), RunMode.HYPEROPT)
|
||||||
@ -99,9 +103,10 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo
|
|||||||
)
|
)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
'--config', 'config.json',
|
|
||||||
'--datadir', '/foo/bar',
|
|
||||||
'hyperopt',
|
'hyperopt',
|
||||||
|
'--config', 'config.json',
|
||||||
|
'--hyperopt', 'DefaultHyperOpts',
|
||||||
|
'--datadir', '/foo/bar',
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--timerange', ':100',
|
'--timerange', ':100',
|
||||||
'--enable-position-stacking',
|
'--enable-position-stacking',
|
||||||
@ -155,7 +160,8 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
|||||||
'freqtrade.resolvers.hyperopt_resolver.HyperOptResolver._load_hyperopt',
|
'freqtrade.resolvers.hyperopt_resolver.HyperOptResolver._load_hyperopt',
|
||||||
MagicMock(return_value=hyperopts(default_conf))
|
MagicMock(return_value=hyperopts(default_conf))
|
||||||
)
|
)
|
||||||
x = HyperOptResolver(default_conf, ).hyperopt
|
default_conf.update({'hyperopt': 'DefaultHyperOpts'})
|
||||||
|
x = HyperOptResolver(default_conf).hyperopt
|
||||||
assert not hasattr(x, 'populate_buy_trend')
|
assert not hasattr(x, 'populate_buy_trend')
|
||||||
assert not hasattr(x, 'populate_sell_trend')
|
assert not hasattr(x, 'populate_sell_trend')
|
||||||
assert log_has("Hyperopt class does not provide populate_sell_trend() method. "
|
assert log_has("Hyperopt class does not provide populate_sell_trend() method. "
|
||||||
@ -169,7 +175,15 @@ def test_hyperoptresolver_wrongname(mocker, default_conf, caplog) -> None:
|
|||||||
default_conf.update({'hyperopt': "NonExistingHyperoptClass"})
|
default_conf.update({'hyperopt': "NonExistingHyperoptClass"})
|
||||||
|
|
||||||
with pytest.raises(OperationalException, match=r'Impossible to load Hyperopt.*'):
|
with pytest.raises(OperationalException, match=r'Impossible to load Hyperopt.*'):
|
||||||
HyperOptResolver(default_conf, ).hyperopt
|
HyperOptResolver(default_conf).hyperopt
|
||||||
|
|
||||||
|
|
||||||
|
def test_hyperoptresolver_noname(default_conf):
|
||||||
|
default_conf['hyperopt'] = ''
|
||||||
|
with pytest.raises(OperationalException,
|
||||||
|
match="No Hyperopt set. Please use `--hyperopt` to specify "
|
||||||
|
"the Hyperopt class to use."):
|
||||||
|
HyperOptResolver(default_conf)
|
||||||
|
|
||||||
|
|
||||||
def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None:
|
def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None:
|
||||||
@ -179,7 +193,7 @@ def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None:
|
|||||||
'freqtrade.resolvers.hyperopt_resolver.HyperOptLossResolver._load_hyperoptloss',
|
'freqtrade.resolvers.hyperopt_resolver.HyperOptLossResolver._load_hyperoptloss',
|
||||||
MagicMock(return_value=hl)
|
MagicMock(return_value=hl)
|
||||||
)
|
)
|
||||||
x = HyperOptLossResolver(default_conf, ).hyperoptloss
|
x = HyperOptLossResolver(default_conf).hyperoptloss
|
||||||
assert hasattr(x, "hyperopt_loss_function")
|
assert hasattr(x, "hyperopt_loss_function")
|
||||||
|
|
||||||
|
|
||||||
@ -187,7 +201,7 @@ def test_hyperoptlossresolver_wrongname(mocker, default_conf, caplog) -> None:
|
|||||||
default_conf.update({'hyperopt_loss': "NonExistingLossClass"})
|
default_conf.update({'hyperopt_loss': "NonExistingLossClass"})
|
||||||
|
|
||||||
with pytest.raises(OperationalException, match=r'Impossible to load HyperoptLoss.*'):
|
with pytest.raises(OperationalException, match=r'Impossible to load HyperoptLoss.*'):
|
||||||
HyperOptLossResolver(default_conf, ).hyperopt
|
HyperOptLossResolver(default_conf).hyperopt
|
||||||
|
|
||||||
|
|
||||||
def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None:
|
def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None:
|
||||||
@ -198,8 +212,9 @@ def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
'--config', 'config.json',
|
|
||||||
'hyperopt',
|
'hyperopt',
|
||||||
|
'--config', 'config.json',
|
||||||
|
'--hyperopt', 'DefaultHyperOpts',
|
||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
@ -215,8 +230,9 @@ def test_start(mocker, default_conf, caplog) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
'--config', 'config.json',
|
|
||||||
'hyperopt',
|
'hyperopt',
|
||||||
|
'--config', 'config.json',
|
||||||
|
'--hyperopt', 'DefaultHyperOpts',
|
||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
@ -237,8 +253,9 @@ def test_start_no_data(mocker, default_conf, caplog) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
'--config', 'config.json',
|
|
||||||
'hyperopt',
|
'hyperopt',
|
||||||
|
'--config', 'config.json',
|
||||||
|
'--hyperopt', 'DefaultHyperOpts',
|
||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
@ -254,8 +271,9 @@ def test_start_filelock(mocker, default_conf, caplog) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
args = [
|
args = [
|
||||||
'--config', 'config.json',
|
|
||||||
'hyperopt',
|
'hyperopt',
|
||||||
|
'--config', 'config.json',
|
||||||
|
'--hyperopt', 'DefaultHyperOpts',
|
||||||
'--epochs', '5'
|
'--epochs', '5'
|
||||||
]
|
]
|
||||||
args = get_args(args)
|
args = get_args(args)
|
||||||
@ -407,6 +425,7 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'all',
|
'spaces': 'all',
|
||||||
@ -510,10 +529,12 @@ def test_buy_strategy_generator(hyperopt, testdatadir) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_generate_optimizer(mocker, default_conf) -> None:
|
def test_generate_optimizer(mocker, default_conf) -> None:
|
||||||
default_conf.update({'config': 'config.json.example'})
|
default_conf.update({'config': 'config.json.example',
|
||||||
default_conf.update({'timerange': None})
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
default_conf.update({'spaces': 'all'})
|
'timerange': None,
|
||||||
default_conf.update({'hyperopt_min_trades': 1})
|
'spaces': 'all',
|
||||||
|
'hyperopt_min_trades': 1,
|
||||||
|
})
|
||||||
|
|
||||||
trades = [
|
trades = [
|
||||||
('POWR/BTC', 0.023117, 0.000233, 100)
|
('POWR/BTC', 0.023117, 0.000233, 100)
|
||||||
@ -576,6 +597,7 @@ def test_generate_optimizer(mocker, default_conf) -> None:
|
|||||||
def test_clean_hyperopt(mocker, default_conf, caplog):
|
def test_clean_hyperopt(mocker, default_conf, caplog):
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'all',
|
'spaces': 'all',
|
||||||
@ -592,6 +614,7 @@ def test_clean_hyperopt(mocker, default_conf, caplog):
|
|||||||
def test_continue_hyperopt(mocker, default_conf, caplog):
|
def test_continue_hyperopt(mocker, default_conf, caplog):
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'all',
|
'spaces': 'all',
|
||||||
@ -621,6 +644,7 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'all',
|
'spaces': 'all',
|
||||||
@ -658,6 +682,7 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) ->
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'roi stoploss',
|
'spaces': 'roi stoploss',
|
||||||
@ -696,6 +721,7 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys)
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'roi stoploss',
|
'spaces': 'roi stoploss',
|
||||||
@ -737,6 +763,7 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) -
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'all',
|
'spaces': 'all',
|
||||||
@ -770,6 +797,7 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'buy',
|
'spaces': 'buy',
|
||||||
@ -815,6 +843,7 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': 'sell',
|
'spaces': 'sell',
|
||||||
@ -862,6 +891,7 @@ def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, metho
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
|
|
||||||
default_conf.update({'config': 'config.json.example',
|
default_conf.update({'config': 'config.json.example',
|
||||||
|
'hyperopt': 'DefaultHyperOpts',
|
||||||
'epochs': 1,
|
'epochs': 1,
|
||||||
'timerange': None,
|
'timerange': None,
|
||||||
'spaces': space,
|
'spaces': space,
|
||||||
|
@ -55,6 +55,7 @@ def test_load_strategy_base64(result, caplog, default_conf):
|
|||||||
|
|
||||||
|
|
||||||
def test_load_strategy_invalid_directory(result, caplog, default_conf):
|
def test_load_strategy_invalid_directory(result, caplog, default_conf):
|
||||||
|
default_conf['strategy'] = 'SampleStrategy'
|
||||||
resolver = StrategyResolver(default_conf)
|
resolver = StrategyResolver(default_conf)
|
||||||
extra_dir = Path.cwd() / 'some/path'
|
extra_dir = Path.cwd() / 'some/path'
|
||||||
resolver._load_strategy('SampleStrategy', config=default_conf, extra_dir=extra_dir)
|
resolver._load_strategy('SampleStrategy', config=default_conf, extra_dir=extra_dir)
|
||||||
@ -65,11 +66,19 @@ def test_load_strategy_invalid_directory(result, caplog, default_conf):
|
|||||||
|
|
||||||
|
|
||||||
def test_load_not_found_strategy(default_conf):
|
def test_load_not_found_strategy(default_conf):
|
||||||
strategy = StrategyResolver(default_conf)
|
default_conf['strategy'] = 'NotFoundStrategy'
|
||||||
with pytest.raises(OperationalException,
|
with pytest.raises(OperationalException,
|
||||||
match=r"Impossible to load Strategy 'NotFoundStrategy'. "
|
match=r"Impossible to load Strategy 'NotFoundStrategy'. "
|
||||||
r"This class does not exist or contains Python code errors."):
|
r"This class does not exist or contains Python code errors."):
|
||||||
strategy._load_strategy(strategy_name='NotFoundStrategy', config=default_conf)
|
StrategyResolver(default_conf)
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_strategy_noname(default_conf):
|
||||||
|
default_conf['strategy'] = ''
|
||||||
|
with pytest.raises(OperationalException,
|
||||||
|
match="No strategy set. Please use `--strategy` to specify "
|
||||||
|
"the strategy class to use."):
|
||||||
|
StrategyResolver(default_conf)
|
||||||
|
|
||||||
|
|
||||||
def test_strategy(result, default_conf):
|
def test_strategy(result, default_conf):
|
||||||
|
@ -9,7 +9,7 @@ from freqtrade.configuration.cli_options import check_int_positive
|
|||||||
|
|
||||||
# Parse common command-line-arguments. Used for all tools
|
# Parse common command-line-arguments. Used for all tools
|
||||||
def test_parse_args_none() -> None:
|
def test_parse_args_none() -> None:
|
||||||
arguments = Arguments([])
|
arguments = Arguments(['trade'])
|
||||||
assert isinstance(arguments, Arguments)
|
assert isinstance(arguments, Arguments)
|
||||||
x = arguments.get_parsed_arg()
|
x = arguments.get_parsed_arg()
|
||||||
assert isinstance(x, dict)
|
assert isinstance(x, dict)
|
||||||
@ -17,7 +17,7 @@ def test_parse_args_none() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_parse_args_defaults() -> None:
|
def test_parse_args_defaults() -> None:
|
||||||
args = Arguments([]).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
assert args["config"] == ['config.json']
|
assert args["config"] == ['config.json']
|
||||||
assert args["strategy_path"] is None
|
assert args["strategy_path"] is None
|
||||||
assert args["datadir"] is None
|
assert args["datadir"] is None
|
||||||
@ -25,27 +25,27 @@ def test_parse_args_defaults() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_parse_args_config() -> None:
|
def test_parse_args_config() -> None:
|
||||||
args = Arguments(['-c', '/dev/null']).get_parsed_arg()
|
args = Arguments(['trade', '-c', '/dev/null']).get_parsed_arg()
|
||||||
assert args["config"] == ['/dev/null']
|
assert args["config"] == ['/dev/null']
|
||||||
|
|
||||||
args = Arguments(['--config', '/dev/null']).get_parsed_arg()
|
args = Arguments(['trade', '--config', '/dev/null']).get_parsed_arg()
|
||||||
assert args["config"] == ['/dev/null']
|
assert args["config"] == ['/dev/null']
|
||||||
|
|
||||||
args = Arguments(['--config', '/dev/null',
|
args = Arguments(['trade', '--config', '/dev/null',
|
||||||
'--config', '/dev/zero'],).get_parsed_arg()
|
'--config', '/dev/zero'],).get_parsed_arg()
|
||||||
assert args["config"] == ['/dev/null', '/dev/zero']
|
assert args["config"] == ['/dev/null', '/dev/zero']
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_db_url() -> None:
|
def test_parse_args_db_url() -> None:
|
||||||
args = Arguments(['--db-url', 'sqlite:///test.sqlite']).get_parsed_arg()
|
args = Arguments(['trade', '--db-url', 'sqlite:///test.sqlite']).get_parsed_arg()
|
||||||
assert args["db_url"] == 'sqlite:///test.sqlite'
|
assert args["db_url"] == 'sqlite:///test.sqlite'
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_verbose() -> None:
|
def test_parse_args_verbose() -> None:
|
||||||
args = Arguments(['-v']).get_parsed_arg()
|
args = Arguments(['trade', '-v']).get_parsed_arg()
|
||||||
assert args["verbosity"] == 1
|
assert args["verbosity"] == 1
|
||||||
|
|
||||||
args = Arguments(['--verbose']).get_parsed_arg()
|
args = Arguments(['trade', '--verbose']).get_parsed_arg()
|
||||||
assert args["verbosity"] == 1
|
assert args["verbosity"] == 1
|
||||||
|
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ def test_parse_args_invalid() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_parse_args_strategy() -> None:
|
def test_parse_args_strategy() -> None:
|
||||||
args = Arguments(['--strategy', 'SomeStrategy']).get_parsed_arg()
|
args = Arguments(['trade', '--strategy', 'SomeStrategy']).get_parsed_arg()
|
||||||
assert args["strategy"] == 'SomeStrategy'
|
assert args["strategy"] == 'SomeStrategy'
|
||||||
|
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ def test_parse_args_strategy_invalid() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def test_parse_args_strategy_path() -> None:
|
def test_parse_args_strategy_path() -> None:
|
||||||
args = Arguments(['--strategy-path', '/some/path']).get_parsed_arg()
|
args = Arguments(['trade', '--strategy-path', '/some/path']).get_parsed_arg()
|
||||||
assert args["strategy_path"] == '/some/path'
|
assert args["strategy_path"] == '/some/path'
|
||||||
|
|
||||||
|
|
||||||
@ -96,8 +96,8 @@ def test_parse_args_backtesting_invalid() -> None:
|
|||||||
|
|
||||||
def test_parse_args_backtesting_custom() -> None:
|
def test_parse_args_backtesting_custom() -> None:
|
||||||
args = [
|
args = [
|
||||||
'-c', 'test_conf.json',
|
|
||||||
'backtesting',
|
'backtesting',
|
||||||
|
'-c', 'test_conf.json',
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--strategy-list',
|
'--strategy-list',
|
||||||
'DefaultStrategy',
|
'DefaultStrategy',
|
||||||
@ -106,7 +106,7 @@ def test_parse_args_backtesting_custom() -> None:
|
|||||||
call_args = Arguments(args).get_parsed_arg()
|
call_args = Arguments(args).get_parsed_arg()
|
||||||
assert call_args["config"] == ['test_conf.json']
|
assert call_args["config"] == ['test_conf.json']
|
||||||
assert call_args["verbosity"] == 0
|
assert call_args["verbosity"] == 0
|
||||||
assert call_args["subparser"] == 'backtesting'
|
assert call_args["command"] == 'backtesting'
|
||||||
assert call_args["func"] is not None
|
assert call_args["func"] is not None
|
||||||
assert call_args["ticker_interval"] == '1m'
|
assert call_args["ticker_interval"] == '1m'
|
||||||
assert type(call_args["strategy_list"]) is list
|
assert type(call_args["strategy_list"]) is list
|
||||||
@ -115,8 +115,8 @@ def test_parse_args_backtesting_custom() -> None:
|
|||||||
|
|
||||||
def test_parse_args_hyperopt_custom() -> None:
|
def test_parse_args_hyperopt_custom() -> None:
|
||||||
args = [
|
args = [
|
||||||
'-c', 'test_conf.json',
|
|
||||||
'hyperopt',
|
'hyperopt',
|
||||||
|
'-c', 'test_conf.json',
|
||||||
'--epochs', '20',
|
'--epochs', '20',
|
||||||
'--spaces', 'buy'
|
'--spaces', 'buy'
|
||||||
]
|
]
|
||||||
@ -124,7 +124,7 @@ def test_parse_args_hyperopt_custom() -> None:
|
|||||||
assert call_args["config"] == ['test_conf.json']
|
assert call_args["config"] == ['test_conf.json']
|
||||||
assert call_args["epochs"] == 20
|
assert call_args["epochs"] == 20
|
||||||
assert call_args["verbosity"] == 0
|
assert call_args["verbosity"] == 0
|
||||||
assert call_args["subparser"] == 'hyperopt'
|
assert call_args["command"] == 'hyperopt'
|
||||||
assert call_args["spaces"] == ['buy']
|
assert call_args["spaces"] == ['buy']
|
||||||
assert call_args["func"] is not None
|
assert call_args["func"] is not None
|
||||||
assert callable(call_args["func"])
|
assert callable(call_args["func"])
|
||||||
@ -132,8 +132,8 @@ def test_parse_args_hyperopt_custom() -> None:
|
|||||||
|
|
||||||
def test_download_data_options() -> None:
|
def test_download_data_options() -> None:
|
||||||
args = [
|
args = [
|
||||||
'--datadir', 'datadir/directory',
|
|
||||||
'download-data',
|
'download-data',
|
||||||
|
'--datadir', 'datadir/directory',
|
||||||
'--pairs-file', 'file_with_pairs',
|
'--pairs-file', 'file_with_pairs',
|
||||||
'--days', '30',
|
'--days', '30',
|
||||||
'--exchange', 'binance'
|
'--exchange', 'binance'
|
||||||
@ -148,8 +148,8 @@ def test_download_data_options() -> None:
|
|||||||
|
|
||||||
def test_plot_dataframe_options() -> None:
|
def test_plot_dataframe_options() -> None:
|
||||||
args = [
|
args = [
|
||||||
'-c', 'config.json.example',
|
|
||||||
'plot-dataframe',
|
'plot-dataframe',
|
||||||
|
'-c', 'config.json.example',
|
||||||
'--indicators1', 'sma10', 'sma100',
|
'--indicators1', 'sma10', 'sma100',
|
||||||
'--indicators2', 'macd', 'fastd', 'fastk',
|
'--indicators2', 'macd', 'fastd', 'fastk',
|
||||||
'--plot-limit', '30',
|
'--plot-limit', '30',
|
||||||
|
@ -65,7 +65,7 @@ def test_load_config_file(default_conf, mocker, caplog) -> None:
|
|||||||
|
|
||||||
def test__args_to_config(caplog):
|
def test__args_to_config(caplog):
|
||||||
|
|
||||||
arg_list = ['--strategy-path', 'TestTest']
|
arg_list = ['trade', '--strategy-path', 'TestTest']
|
||||||
args = Arguments(arg_list).get_parsed_arg()
|
args = Arguments(arg_list).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
config = {}
|
config = {}
|
||||||
@ -93,7 +93,7 @@ def test_load_config_max_open_trades_zero(default_conf, mocker, caplog) -> None:
|
|||||||
default_conf['max_open_trades'] = 0
|
default_conf['max_open_trades'] = 0
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = Arguments([]).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
validated_conf = configuration.load_config()
|
validated_conf = configuration.load_config()
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ def test_load_config_combine_dicts(default_conf, mocker, caplog) -> None:
|
|||||||
configsmock
|
configsmock
|
||||||
)
|
)
|
||||||
|
|
||||||
arg_list = ['-c', 'test_conf.json', '--config', 'test2_conf.json', ]
|
arg_list = ['trade', '-c', 'test_conf.json', '--config', 'test2_conf.json', ]
|
||||||
args = Arguments(arg_list).get_parsed_arg()
|
args = Arguments(arg_list).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
validated_conf = configuration.load_config()
|
validated_conf = configuration.load_config()
|
||||||
@ -184,7 +184,7 @@ def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) ->
|
|||||||
default_conf['max_open_trades'] = -1
|
default_conf['max_open_trades'] = -1
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = Arguments([]).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
validated_conf = configuration.load_config()
|
validated_conf = configuration.load_config()
|
||||||
|
|
||||||
@ -208,11 +208,10 @@ def test_load_config_file_exception(mocker) -> None:
|
|||||||
def test_load_config(default_conf, mocker) -> None:
|
def test_load_config(default_conf, mocker) -> None:
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = Arguments([]).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
validated_conf = configuration.load_config()
|
validated_conf = configuration.load_config()
|
||||||
|
|
||||||
assert validated_conf.get('strategy') == 'DefaultStrategy'
|
|
||||||
assert validated_conf.get('strategy_path') is None
|
assert validated_conf.get('strategy_path') is None
|
||||||
assert 'edge' not in validated_conf
|
assert 'edge' not in validated_conf
|
||||||
|
|
||||||
@ -221,6 +220,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'trade',
|
||||||
'--strategy', 'TestStrategy',
|
'--strategy', 'TestStrategy',
|
||||||
'--strategy-path', '/some/path',
|
'--strategy-path', '/some/path',
|
||||||
'--db-url', 'sqlite:///someurl',
|
'--db-url', 'sqlite:///someurl',
|
||||||
@ -240,6 +240,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, conf)
|
patched_configuration_load_config_file(mocker, conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'trade',
|
||||||
'--strategy', 'TestStrategy',
|
'--strategy', 'TestStrategy',
|
||||||
'--strategy-path', '/some/path'
|
'--strategy-path', '/some/path'
|
||||||
]
|
]
|
||||||
@ -256,6 +257,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, conf)
|
patched_configuration_load_config_file(mocker, conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'trade',
|
||||||
'--strategy', 'TestStrategy',
|
'--strategy', 'TestStrategy',
|
||||||
'--strategy-path', '/some/path'
|
'--strategy-path', '/some/path'
|
||||||
]
|
]
|
||||||
@ -272,6 +274,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, conf)
|
patched_configuration_load_config_file(mocker, conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'trade',
|
||||||
'--strategy', 'TestStrategy',
|
'--strategy', 'TestStrategy',
|
||||||
'--strategy-path', '/some/path'
|
'--strategy-path', '/some/path'
|
||||||
]
|
]
|
||||||
@ -290,6 +293,7 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, conf)
|
patched_configuration_load_config_file(mocker, conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'trade',
|
||||||
'--strategy', 'TestStrategy',
|
'--strategy', 'TestStrategy',
|
||||||
'--strategy-path', '/some/path'
|
'--strategy-path', '/some/path'
|
||||||
]
|
]
|
||||||
@ -300,6 +304,23 @@ def test_load_config_with_params(default_conf, mocker) -> None:
|
|||||||
assert validated_conf.get('db_url') == DEFAULT_DB_DRYRUN_URL
|
assert validated_conf.get('db_url') == DEFAULT_DB_DRYRUN_URL
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("config_value,expected,arglist", [
|
||||||
|
(True, True, ['trade', '--dry-run']), # Leave config untouched
|
||||||
|
(False, True, ['trade', '--dry-run']), # Override config untouched
|
||||||
|
(False, False, ['trade']), # Leave config untouched
|
||||||
|
(True, True, ['trade']), # Leave config untouched
|
||||||
|
])
|
||||||
|
def test_load_dry_run(default_conf, mocker, config_value, expected, arglist) -> None:
|
||||||
|
|
||||||
|
default_conf['dry_run'] = config_value
|
||||||
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
|
configuration = Configuration(Arguments(arglist).get_parsed_arg())
|
||||||
|
validated_conf = configuration.load_config()
|
||||||
|
|
||||||
|
assert validated_conf.get('dry_run') is expected
|
||||||
|
|
||||||
|
|
||||||
def test_load_custom_strategy(default_conf, mocker) -> None:
|
def test_load_custom_strategy(default_conf, mocker) -> None:
|
||||||
default_conf.update({
|
default_conf.update({
|
||||||
'strategy': 'CustomStrategy',
|
'strategy': 'CustomStrategy',
|
||||||
@ -307,7 +328,7 @@ def test_load_custom_strategy(default_conf, mocker) -> None:
|
|||||||
})
|
})
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = Arguments([]).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
validated_conf = configuration.load_config()
|
validated_conf = configuration.load_config()
|
||||||
|
|
||||||
@ -319,6 +340,7 @@ def test_show_info(default_conf, mocker, caplog) -> None:
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'trade',
|
||||||
'--strategy', 'TestStrategy',
|
'--strategy', 'TestStrategy',
|
||||||
'--db-url', 'sqlite:///tmp/testdb',
|
'--db-url', 'sqlite:///tmp/testdb',
|
||||||
]
|
]
|
||||||
@ -335,9 +357,9 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) ->
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'backtesting'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
args = Arguments(arglist).get_parsed_arg()
|
args = Arguments(arglist).get_parsed_arg()
|
||||||
@ -373,11 +395,11 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non
|
|||||||
lambda x, *args, **kwargs: Path(x)
|
lambda x, *args, **kwargs: Path(x)
|
||||||
)
|
)
|
||||||
arglist = [
|
arglist = [
|
||||||
|
'backtesting',
|
||||||
'--config', 'config.json',
|
'--config', 'config.json',
|
||||||
'--strategy', 'DefaultStrategy',
|
'--strategy', 'DefaultStrategy',
|
||||||
'--datadir', '/foo/bar',
|
'--datadir', '/foo/bar',
|
||||||
'--userdir', "/tmp/freqtrade",
|
'--userdir', "/tmp/freqtrade",
|
||||||
'backtesting',
|
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--enable-position-stacking',
|
'--enable-position-stacking',
|
||||||
'--disable-max-market-positions',
|
'--disable-max-market-positions',
|
||||||
@ -424,8 +446,8 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
'--config', 'config.json',
|
|
||||||
'backtesting',
|
'backtesting',
|
||||||
|
'--config', 'config.json',
|
||||||
'--ticker-interval', '1m',
|
'--ticker-interval', '1m',
|
||||||
'--export', '/bar/foo',
|
'--export', '/bar/foo',
|
||||||
'--strategy-list',
|
'--strategy-list',
|
||||||
@ -552,7 +574,7 @@ def test_cli_verbose_with_params(default_conf, mocker, caplog) -> None:
|
|||||||
|
|
||||||
# Prevent setting loggers
|
# Prevent setting loggers
|
||||||
mocker.patch('freqtrade.loggers._set_loggers', MagicMock)
|
mocker.patch('freqtrade.loggers._set_loggers', MagicMock)
|
||||||
arglist = ['-vvv']
|
arglist = ['trade', '-vvv']
|
||||||
args = Arguments(arglist).get_parsed_arg()
|
args = Arguments(arglist).get_parsed_arg()
|
||||||
|
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
@ -604,7 +626,7 @@ def test_set_logfile(default_conf, mocker):
|
|||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
'--logfile', 'test_file.log',
|
'trade', '--logfile', 'test_file.log',
|
||||||
]
|
]
|
||||||
args = Arguments(arglist).get_parsed_arg()
|
args = Arguments(arglist).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
@ -620,7 +642,7 @@ def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None:
|
|||||||
default_conf['forcebuy_enable'] = True
|
default_conf['forcebuy_enable'] = True
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
|
|
||||||
args = Arguments([]).get_parsed_arg()
|
args = Arguments(['trade']).get_parsed_arg()
|
||||||
configuration = Configuration(args)
|
configuration = Configuration(args)
|
||||||
validated_conf = configuration.load_config()
|
validated_conf = configuration.load_config()
|
||||||
|
|
||||||
@ -806,8 +828,8 @@ def test_pairlist_resolving():
|
|||||||
def test_pairlist_resolving_with_config(mocker, default_conf):
|
def test_pairlist_resolving_with_config(mocker, default_conf):
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
arglist = [
|
arglist = [
|
||||||
'--config', 'config.json',
|
|
||||||
'download-data',
|
'download-data',
|
||||||
|
'--config', 'config.json',
|
||||||
]
|
]
|
||||||
|
|
||||||
args = Arguments(arglist).get_parsed_arg()
|
args = Arguments(arglist).get_parsed_arg()
|
||||||
@ -820,8 +842,8 @@ def test_pairlist_resolving_with_config(mocker, default_conf):
|
|||||||
|
|
||||||
# Override pairs
|
# Override pairs
|
||||||
arglist = [
|
arglist = [
|
||||||
'--config', 'config.json',
|
|
||||||
'download-data',
|
'download-data',
|
||||||
|
'--config', 'config.json',
|
||||||
'--pairs', 'ETH/BTC', 'XRP/BTC',
|
'--pairs', 'ETH/BTC', 'XRP/BTC',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -842,8 +864,8 @@ def test_pairlist_resolving_with_config_pl(mocker, default_conf):
|
|||||||
mocker.patch.object(Path, "open", MagicMock(return_value=MagicMock()))
|
mocker.patch.object(Path, "open", MagicMock(return_value=MagicMock()))
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
'--config', 'config.json',
|
|
||||||
'download-data',
|
'download-data',
|
||||||
|
'--config', 'config.json',
|
||||||
'--pairs-file', 'pairs.json',
|
'--pairs-file', 'pairs.json',
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -864,8 +886,8 @@ def test_pairlist_resolving_with_config_pl_not_exists(mocker, default_conf):
|
|||||||
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
|
mocker.patch.object(Path, "exists", MagicMock(return_value=False))
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
'--config', 'config.json',
|
|
||||||
'download-data',
|
'download-data',
|
||||||
|
'--config', 'config.json',
|
||||||
'--pairs-file', 'pairs.json',
|
'--pairs-file', 'pairs.json',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -11,10 +11,16 @@ from freqtrade.freqtradebot import FreqtradeBot
|
|||||||
from freqtrade.main import main
|
from freqtrade.main import main
|
||||||
from freqtrade.state import State
|
from freqtrade.state import State
|
||||||
from freqtrade.worker import Worker
|
from freqtrade.worker import Worker
|
||||||
from tests.conftest import (log_has, patch_exchange,
|
from tests.conftest import (log_has, log_has_re, patch_exchange,
|
||||||
patched_configuration_load_config_file)
|
patched_configuration_load_config_file)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_args_None(caplog) -> None:
|
||||||
|
with pytest.raises(SystemExit):
|
||||||
|
main([])
|
||||||
|
assert log_has_re(r"Usage of freqtrade requires a subcommand\.", caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_parse_args_backtesting(mocker) -> None:
|
def test_parse_args_backtesting(mocker) -> None:
|
||||||
"""
|
"""
|
||||||
Test that main() can start backtesting and also ensure we can pass some specific arguments
|
Test that main() can start backtesting and also ensure we can pass some specific arguments
|
||||||
@ -29,7 +35,7 @@ def test_parse_args_backtesting(mocker) -> None:
|
|||||||
call_args = backtesting_mock.call_args[0][0]
|
call_args = backtesting_mock.call_args[0][0]
|
||||||
assert call_args["config"] == ['config.json']
|
assert call_args["config"] == ['config.json']
|
||||||
assert call_args["verbosity"] == 0
|
assert call_args["verbosity"] == 0
|
||||||
assert call_args["subparser"] == 'backtesting'
|
assert call_args["command"] == 'backtesting'
|
||||||
assert call_args["func"] is not None
|
assert call_args["func"] is not None
|
||||||
assert callable(call_args["func"])
|
assert callable(call_args["func"])
|
||||||
assert call_args["ticker_interval"] is None
|
assert call_args["ticker_interval"] is None
|
||||||
@ -45,7 +51,7 @@ def test_main_start_hyperopt(mocker) -> None:
|
|||||||
call_args = hyperopt_mock.call_args[0][0]
|
call_args = hyperopt_mock.call_args[0][0]
|
||||||
assert call_args["config"] == ['config.json']
|
assert call_args["config"] == ['config.json']
|
||||||
assert call_args["verbosity"] == 0
|
assert call_args["verbosity"] == 0
|
||||||
assert call_args["subparser"] == 'hyperopt'
|
assert call_args["command"] == 'hyperopt'
|
||||||
assert call_args["func"] is not None
|
assert call_args["func"] is not None
|
||||||
assert callable(call_args["func"])
|
assert callable(call_args["func"])
|
||||||
|
|
||||||
@ -58,7 +64,7 @@ def test_main_fatal_exception(mocker, default_conf, caplog) -> None:
|
|||||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||||
|
|
||||||
args = ['-c', 'config.json.example']
|
args = ['trade', '-c', 'config.json.example']
|
||||||
|
|
||||||
# Test Main + the KeyboardInterrupt exception
|
# Test Main + the KeyboardInterrupt exception
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
@ -75,7 +81,7 @@ def test_main_keyboard_interrupt(mocker, default_conf, caplog) -> None:
|
|||||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||||
|
|
||||||
args = ['-c', 'config.json.example']
|
args = ['trade', '-c', 'config.json.example']
|
||||||
|
|
||||||
# Test Main + the KeyboardInterrupt exception
|
# Test Main + the KeyboardInterrupt exception
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
@ -95,7 +101,7 @@ def test_main_operational_exception(mocker, default_conf, caplog) -> None:
|
|||||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||||
|
|
||||||
args = ['-c', 'config.json.example']
|
args = ['trade', '-c', 'config.json.example']
|
||||||
|
|
||||||
# Test Main + the KeyboardInterrupt exception
|
# Test Main + the KeyboardInterrupt exception
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
@ -114,15 +120,15 @@ def test_main_reload_conf(mocker, default_conf, caplog) -> None:
|
|||||||
OperationalException("Oh snap!")])
|
OperationalException("Oh snap!")])
|
||||||
mocker.patch('freqtrade.worker.Worker._worker', worker_mock)
|
mocker.patch('freqtrade.worker.Worker._worker', worker_mock)
|
||||||
patched_configuration_load_config_file(mocker, default_conf)
|
patched_configuration_load_config_file(mocker, default_conf)
|
||||||
reconfigure_mock = mocker.patch('freqtrade.main.Worker._reconfigure', MagicMock())
|
reconfigure_mock = mocker.patch('freqtrade.worker.Worker._reconfigure', MagicMock())
|
||||||
|
|
||||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||||
|
|
||||||
args = Arguments(['-c', 'config.json.example']).get_parsed_arg()
|
args = Arguments(['trade', '-c', 'config.json.example']).get_parsed_arg()
|
||||||
worker = Worker(args=args, config=default_conf)
|
worker = Worker(args=args, config=default_conf)
|
||||||
with pytest.raises(SystemExit):
|
with pytest.raises(SystemExit):
|
||||||
main(['-c', 'config.json.example'])
|
main(['trade', '-c', 'config.json.example'])
|
||||||
|
|
||||||
assert log_has('Using config: config.json.example ...', caplog)
|
assert log_has('Using config: config.json.example ...', caplog)
|
||||||
assert worker_mock.call_count == 4
|
assert worker_mock.call_count == 4
|
||||||
@ -141,7 +147,7 @@ def test_reconfigure(mocker, default_conf) -> None:
|
|||||||
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
|
||||||
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
mocker.patch('freqtrade.freqtradebot.persistence.init', MagicMock())
|
||||||
|
|
||||||
args = Arguments(['-c', 'config.json.example']).get_parsed_arg()
|
args = Arguments(['trade', '-c', 'config.json.example']).get_parsed_arg()
|
||||||
worker = Worker(args=args, config=default_conf)
|
worker = Worker(args=args, config=default_conf)
|
||||||
freqtrade = worker.freqtrade
|
freqtrade = worker.freqtrade
|
||||||
|
|
||||||
|
@ -281,8 +281,8 @@ def test_generate_profit_graph(testdatadir):
|
|||||||
def test_start_plot_dataframe(mocker):
|
def test_start_plot_dataframe(mocker):
|
||||||
aup = mocker.patch("freqtrade.plot.plotting.load_and_plot_trades", MagicMock())
|
aup = mocker.patch("freqtrade.plot.plotting.load_and_plot_trades", MagicMock())
|
||||||
args = [
|
args = [
|
||||||
"--config", "config.json.example",
|
|
||||||
"plot-dataframe",
|
"plot-dataframe",
|
||||||
|
"--config", "config.json.example",
|
||||||
"--pairs", "ETH/BTC"
|
"--pairs", "ETH/BTC"
|
||||||
]
|
]
|
||||||
start_plot_dataframe(get_args(args))
|
start_plot_dataframe(get_args(args))
|
||||||
@ -323,8 +323,8 @@ def test_load_and_plot_trades(default_conf, mocker, caplog, testdatadir):
|
|||||||
def test_start_plot_profit(mocker):
|
def test_start_plot_profit(mocker):
|
||||||
aup = mocker.patch("freqtrade.plot.plotting.plot_profit", MagicMock())
|
aup = mocker.patch("freqtrade.plot.plotting.plot_profit", MagicMock())
|
||||||
args = [
|
args = [
|
||||||
"--config", "config.json.example",
|
|
||||||
"plot-profit",
|
"plot-profit",
|
||||||
|
"--config", "config.json.example",
|
||||||
"--pairs", "ETH/BTC"
|
"--pairs", "ETH/BTC"
|
||||||
]
|
]
|
||||||
start_plot_profit(get_args(args))
|
start_plot_profit(get_args(args))
|
||||||
|
@ -13,7 +13,7 @@ from tests.conftest import get_args, log_has, patch_exchange
|
|||||||
|
|
||||||
def test_setup_utils_configuration():
|
def test_setup_utils_configuration():
|
||||||
args = [
|
args = [
|
||||||
'--config', 'config.json.example',
|
'list-exchanges', '--config', 'config.json.example',
|
||||||
]
|
]
|
||||||
|
|
||||||
config = setup_utils_configuration(get_args(args), RunMode.OTHER)
|
config = setup_utils_configuration(get_args(args), RunMode.OTHER)
|
||||||
|
Loading…
Reference in New Issue
Block a user