diff --git a/README.md b/README.md index cfb384702..7e0acde46 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,8 @@ positional arguments: new-hyperopt Create new hyperopt new-strategy Create new strategy download-data Download backtesting data. - convert-data Convert candle (OHLCV) data from one format to another. + convert-data Convert candle (OHLCV) data from one format to + another. convert-trade-data Convert trade data from one format to another. backtesting Backtesting module. edge Edge module. @@ -94,7 +95,7 @@ positional arguments: list-markets Print markets on exchange. list-pairs Print pairs on exchange. list-strategies Print available strategies. - list-timeframes Print available ticker intervals (timeframes) for the exchange. + list-timeframes Print available timeframes for the exchange. show-trades Show trades. test-pairlist Test your pairlist configuration. plot-dataframe Plot candles with indicators. diff --git a/config.json.example b/config.json.example index ae87164d6..9e3daa2b5 100644 --- a/config.json.example +++ b/config.json.example @@ -4,7 +4,7 @@ "stake_amount": 0.05, "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", - "ticker_interval": "5m", + "timeframe": "5m", "dry_run": false, "cancel_open_orders_on_exit": false, "trailing_stop": false, diff --git a/config_binance.json.example b/config_binance.json.example index 74207d565..b45e69bba 100644 --- a/config_binance.json.example +++ b/config_binance.json.example @@ -4,7 +4,7 @@ "stake_amount": 0.05, "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", - "ticker_interval": "5m", + "timeframe": "5m", "dry_run": true, "cancel_open_orders_on_exit": false, "trailing_stop": false, diff --git a/config_full.json.example b/config_full.json.example index 57ebb22e6..1fd1b44a5 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -9,7 +9,7 @@ "last_stake_amount_min_ratio": 0.5, "dry_run": false, "cancel_open_orders_on_exit": false, - "ticker_interval": "5m", + "timeframe": "5m", "trailing_stop": false, "trailing_stop_positive": 0.005, "trailing_stop_positive_offset": 0.0051, diff --git a/config_kraken.json.example b/config_kraken.json.example index f1e522da5..7e4001ff3 100644 --- a/config_kraken.json.example +++ b/config_kraken.json.example @@ -4,7 +4,7 @@ "stake_amount": 10, "tradable_balance_ratio": 0.99, "fiat_display_currency": "EUR", - "ticker_interval": "5m", + "timeframe": "5m", "dry_run": true, "cancel_open_orders_on_exit": false, "trailing_stop": false, diff --git a/docs/backtesting.md b/docs/backtesting.md index 9b2997510..51b2e953b 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -12,7 +12,7 @@ real data. This is what we call [backtesting](https://en.wikipedia.org/wiki/Backtesting). Backtesting will use the crypto-currencies (pairs) from your config file and load historical candle (OHCLV) data from `user_data/data/` by default. -If no data is available for the exchange / pair / timeframe (ticker interval) combination, backtesting will ask you to download them first using `freqtrade download-data`. +If no data is available for the exchange / pair / timeframe combination, backtesting will ask you to download them first using `freqtrade download-data`. For details on downloading, please refer to the [Data Downloading](data-download.md) section in the documentation. The result of backtesting will confirm if your bot has better odds of making a profit than a loss. @@ -35,7 +35,7 @@ freqtrade backtesting #### With 1 min candle (OHLCV) data ```bash -freqtrade backtesting --ticker-interval 1m +freqtrade backtesting --timeframe 1m ``` #### Using a different on-disk historical candle (OHLCV) data source @@ -58,7 +58,7 @@ Where `-s SampleStrategy` refers to the class name within the strategy file `sam #### Comparing multiple Strategies ```bash -freqtrade backtesting --strategy-list SampleStrategy1 AwesomeStrategy --ticker-interval 5m +freqtrade backtesting --strategy-list SampleStrategy1 AwesomeStrategy --timeframe 5m ``` Where `SampleStrategy1` and `AwesomeStrategy` refer to class names of strategies. @@ -228,13 +228,13 @@ You can then load the trades to perform further analysis as shown in our [data a To compare multiple strategies, a list of Strategies can be provided to backtesting. -This is limited to 1 timeframe (ticker interval) value per run. However, data is only loaded once from disk so if you have multiple +This is limited to 1 timeframe value per run. However, data is only loaded once from disk so if you have multiple strategies you'd like to compare, this will give a nice runtime boost. All listed Strategies need to be in the same directory. ``` bash -freqtrade backtesting --timerange 20180401-20180410 --ticker-interval 5m --strategy-list Strategy001 Strategy002 --export trades +freqtrade backtesting --timerange 20180401-20180410 --timeframe 5m --strategy-list Strategy001 Strategy002 --export trades ``` This will save the results to `user_data/backtest_results/backtest-result-.json`, injecting the strategy-name into the target filename. diff --git a/docs/bot-usage.md b/docs/bot-usage.md index b1649374a..40ff3d82b 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -9,22 +9,35 @@ This page explains the different parameters of the bot and how to run it. ``` usage: freqtrade [-h] [-V] - {trade,backtesting,edge,hyperopt,create-userdir,list-exchanges,list-timeframes,download-data,plot-dataframe,plot-profit} + {trade,create-userdir,new-config,new-hyperopt,new-strategy,download-data,convert-data,convert-trade-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,plot-dataframe,plot-profit} ... Free, open source crypto trading bot positional arguments: - {trade,backtesting,edge,hyperopt,create-userdir,list-exchanges,list-timeframes,download-data,plot-dataframe,plot-profit} + {trade,create-userdir,new-config,new-hyperopt,new-strategy,download-data,convert-data,convert-trade-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,plot-dataframe,plot-profit} trade Trade module. + create-userdir Create user-data directory. + new-config Create new config + new-hyperopt Create new hyperopt + new-strategy Create new strategy + download-data Download backtesting data. + convert-data Convert candle (OHLCV) data from one format to + another. + convert-trade-data Convert trade data from one format to another. backtesting Backtesting module. edge Edge module. hyperopt Hyperopt module. - create-userdir Create user-data directory. + hyperopt-list List Hyperopt results + hyperopt-show Show details of Hyperopt results list-exchanges Print available exchanges. - list-timeframes Print available ticker intervals (timeframes) for the - exchange. - download-data Download backtesting data. + list-hyperopts Print available hyperopt classes. + list-markets Print markets on exchange. + list-pairs Print pairs on exchange. + list-strategies Print available strategies. + list-timeframes Print available timeframes for the exchange. + show-trades Show trades. + test-pairlist Test your pairlist configuration. plot-dataframe Plot candles with indicators. plot-profit Generate plot showing profits. @@ -72,7 +85,6 @@ Strategy arguments: Specify strategy class name which will be used by the bot. --strategy-path PATH Specify additional strategy lookup path. -. ``` @@ -197,7 +209,7 @@ Backtesting also uses the config specified via `-c/--config`. ``` usage: freqtrade backtesting [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-s NAME] - [--strategy-path PATH] [-i TICKER_INTERVAL] + [--strategy-path PATH] [-i TIMEFRAME] [--timerange TIMERANGE] [--max-open-trades INT] [--stake-amount STAKE_AMOUNT] [--fee FLOAT] [--eps] [--dmmp] @@ -206,7 +218,7 @@ usage: freqtrade backtesting [-h] [-v] [--logfile FILE] [-V] [-c PATH] optional arguments: -h, --help show this help message and exit - -i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL + -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME Specify ticker interval (`1m`, `5m`, `30m`, `1h`, `1d`). --timerange TIMERANGE @@ -280,7 +292,7 @@ to find optimal parameter values for your strategy. ``` usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-s NAME] [--strategy-path PATH] - [-i TICKER_INTERVAL] [--timerange TIMERANGE] + [-i TIMEFRAME] [--timerange TIMERANGE] [--max-open-trades INT] [--stake-amount STAKE_AMOUNT] [--fee FLOAT] [--hyperopt NAME] [--hyperopt-path PATH] [--eps] @@ -292,7 +304,7 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] optional arguments: -h, --help show this help message and exit - -i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL + -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME Specify ticker interval (`1m`, `5m`, `30m`, `1h`, `1d`). --timerange TIMERANGE @@ -323,7 +335,7 @@ optional arguments: --print-all Print all results, not only the best ones. --no-color Disable colorization of hyperopt results. May be useful if you are redirecting output to a file. - --print-json Print best results in JSON format. + --print-json Print output in JSON format. -j JOBS, --job-workers JOBS The number of concurrently running jobs for hyperoptimization (hyperopt worker processes). If -1 @@ -341,11 +353,11 @@ optional arguments: class (IHyperOptLoss). Different functions can generate completely different results, since the target for optimization is different. Built-in - Hyperopt-loss-functions are: - DefaultHyperOptLoss, OnlyProfitHyperOptLoss, - SharpeHyperOptLoss, SharpeHyperOptLossDaily, - SortinoHyperOptLoss, SortinoHyperOptLossDaily. - (default: `DefaultHyperOptLoss`). + Hyperopt-loss-functions are: DefaultHyperOptLoss, + OnlyProfitHyperOptLoss, SharpeHyperOptLoss, + SharpeHyperOptLossDaily, SortinoHyperOptLoss, + SortinoHyperOptLossDaily.(default: + `DefaultHyperOptLoss`). Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). @@ -378,13 +390,13 @@ To know your trade expectancy and winrate against historical data, you can use E ``` usage: freqtrade edge [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-s NAME] [--strategy-path PATH] - [-i TICKER_INTERVAL] [--timerange TIMERANGE] + [-i TIMEFRAME] [--timerange TIMERANGE] [--max-open-trades INT] [--stake-amount STAKE_AMOUNT] [--fee FLOAT] [--stoplosses STOPLOSS_RANGE] optional arguments: -h, --help show this help message and exit - -i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL + -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME Specify ticker interval (`1m`, `5m`, `30m`, `1h`, `1d`). --timerange TIMERANGE diff --git a/docs/configuration.md b/docs/configuration.md index 5c485af4a..8438d55da 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -47,7 +47,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `amend_last_stake_amount` | Use reduced last stake amount if necessary. [More information below](#configuring-amount-per-trade).
*Defaults to `false`.*
**Datatype:** Boolean | `last_stake_amount_min_ratio` | Defines minimum stake amount that has to be left and executed. Applies only to the last stake amount when it's amended to a reduced value (i.e. if `amend_last_stake_amount` is set to `true`). [More information below](#configuring-amount-per-trade).
*Defaults to `0.5`.*
**Datatype:** Float (as ratio) | `amount_reserve_percent` | Reserve some amount in min pair stake amount. The bot will reserve `amount_reserve_percent` + stoploss value when calculating min pair stake amount in order to avoid possible trade refusals.
*Defaults to `0.05` (5%).*
**Datatype:** Positive Float as ratio. -| `ticker_interval` | The timeframe (ticker interval) to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** String +| `timeframe` | The timeframe (former ticker interval) to use (e.g `1m`, `5m`, `15m`, `30m`, `1h` ...). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** String | `fiat_display_currency` | Fiat currency used to show your profits. [More information below](#what-values-can-be-used-for-fiat_display_currency).
**Datatype:** String | `dry_run` | **Required.** Define if the bot must be in Dry Run or production mode.
*Defaults to `true`.*
**Datatype:** Boolean | `dry_run_wallet` | Define the starting amount in stake currency for the simulated wallet used by the bot running in the Dry Run mode.
*Defaults to `1000`.*
**Datatype:** Float @@ -126,7 +126,7 @@ The following parameters can be set in either configuration file or strategy. Values set in the configuration file always overwrite values set in the strategy. * `minimal_roi` -* `ticker_interval` +* `timeframe` * `stoploss` * `trailing_stop` * `trailing_stop_positive` diff --git a/docs/edge.md b/docs/edge.md index bdcf6cde9..c91e72a3a 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -155,7 +155,7 @@ Edge module has following configuration options: | `minimum_winrate` | It filters out pairs which don't have at least minimum_winrate.
This comes handy if you want to be conservative and don't comprise win rate in favour of risk reward ratio.
*Defaults to `0.60`.*
**Datatype:** Float | `minimum_expectancy` | It filters out pairs which have the expectancy lower than this number.
Having an expectancy of 0.20 means if you put 10$ on a trade you expect a 12$ return.
*Defaults to `0.20`.*
**Datatype:** Float | `min_trade_number` | When calculating *W*, *R* and *E* (expectancy) against historical data, you always want to have a minimum number of trades. The more this number is the more Edge is reliable.
Having a win rate of 100% on a single trade doesn't mean anything at all. But having a win rate of 70% over past 100 trades means clearly something.
*Defaults to `10` (it is highly recommended not to decrease this number).*
**Datatype:** Integer -| `max_trade_duration_minute` | Edge will filter out trades with long duration. If a trade is profitable after 1 month, it is hard to evaluate the strategy based on it. But if most of trades are profitable and they have maximum duration of 30 minutes, then it is clearly a good sign.
**NOTICE:** While configuring this value, you should take into consideration your timeframe (ticker interval). As an example filtering out trades having duration less than one day for a strategy which has 4h interval does not make sense. Default value is set assuming your strategy interval is relatively small (1m or 5m, etc.).
*Defaults to `1440` (one day).*
**Datatype:** Integer +| `max_trade_duration_minute` | Edge will filter out trades with long duration. If a trade is profitable after 1 month, it is hard to evaluate the strategy based on it. But if most of trades are profitable and they have maximum duration of 30 minutes, then it is clearly a good sign.
**NOTICE:** While configuring this value, you should take into consideration your timeframe. As an example filtering out trades having duration less than one day for a strategy which has 4h interval does not make sense. Default value is set assuming your strategy interval is relatively small (1m or 5m, etc.).
*Defaults to `1440` (one day).*
**Datatype:** Integer | `remove_pumps` | Edge will remove sudden pumps in a given market while going through historical data. However, given that pumps happen very often in crypto markets, we recommend you keep this off.
*Defaults to `false`.*
**Datatype:** Boolean ## Running Edge independently diff --git a/docs/hyperopt.md b/docs/hyperopt.md index f66534726..9acb606c3 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -124,9 +124,9 @@ To avoid naming collisions in the search-space, please prefix all sell-spaces wi #### Using timeframe as a part of the Strategy -The Strategy class exposes the timeframe (ticker interval) value as the `self.ticker_interval` attribute. -The same value is available as class-attribute `HyperoptName.ticker_interval`. -In the case of the linked sample-value this would be `SampleHyperOpt.ticker_interval`. +The Strategy class exposes the timeframe value as the `self.timeframe` attribute. +The same value is available as class-attribute `HyperoptName.timeframe`. +In the case of the linked sample-value this would be `SampleHyperOpt.timeframe`. ## Solving a Mystery @@ -403,7 +403,7 @@ As stated in the comment, you can also use it as the value of the `minimal_roi` #### Default ROI Search Space -If you are optimizing ROI, Freqtrade creates the 'roi' optimization hyperspace for you -- it's the hyperspace of components for the ROI tables. By default, each ROI table generated by the Freqtrade consists of 4 rows (steps). Hyperopt implements adaptive ranges for ROI tables with ranges for values in the ROI steps that depend on the ticker_interval used. By default the values vary in the following ranges (for some of the most used timeframes, values are rounded to 5 digits after the decimal point): +If you are optimizing ROI, Freqtrade creates the 'roi' optimization hyperspace for you -- it's the hyperspace of components for the ROI tables. By default, each ROI table generated by the Freqtrade consists of 4 rows (steps). Hyperopt implements adaptive ranges for ROI tables with ranges for values in the ROI steps that depend on the timeframe used. By default the values vary in the following ranges (for some of the most used timeframes, values are rounded to 5 digits after the decimal point): | # step | 1m | | 5m | | 1h | | 1d | | | ------ | ------ | ----------------- | -------- | ----------- | ---------- | ----------------- | ------------ | ----------------- | @@ -412,7 +412,7 @@ If you are optimizing ROI, Freqtrade creates the 'roi' optimization hyperspace f | 3 | 4...20 | 0.00387...0.01547 | 20...100 | 0.01...0.04 | 240...1200 | 0.02294...0.09177 | 5760...28800 | 0.04059...0.16237 | | 4 | 6...44 | 0.0 | 30...220 | 0.0 | 360...2640 | 0.0 | 8640...63360 | 0.0 | -These ranges should be sufficient in most cases. The minutes in the steps (ROI dict keys) are scaled linearly depending on the timeframe (ticker interval) used. The ROI values in the steps (ROI dict values) are scaled logarithmically depending on the timeframe used. +These ranges should be sufficient in most cases. The minutes in the steps (ROI dict keys) are scaled linearly depending on the timeframe used. The ROI values in the steps (ROI dict values) are scaled logarithmically depending on the timeframe used. If you have the `generate_roi_table()` and `roi_space()` methods in your custom hyperopt file, remove them in order to utilize these adaptive ROI tables and the ROI hyperoptimization space generated by Freqtrade by default. diff --git a/docs/plotting.md b/docs/plotting.md index be83065a6..d3a2df1c1 100644 --- a/docs/plotting.md +++ b/docs/plotting.md @@ -31,7 +31,7 @@ usage: freqtrade plot-dataframe [-h] [-v] [--logfile FILE] [-V] [-c PATH] [--plot-limit INT] [--db-url PATH] [--trade-source {DB,file}] [--export EXPORT] [--export-filename PATH] - [--timerange TIMERANGE] [-i TICKER_INTERVAL] + [--timerange TIMERANGE] [-i TIMEFRAME] [--no-trades] optional arguments: @@ -65,7 +65,7 @@ optional arguments: _today.json` --timerange TIMERANGE Specify what timerange of data to use. - -i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL + -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME Specify ticker interval (`1m`, `5m`, `30m`, `1h`, `1d`). --no-trades Skip using trades from backtesting file and DB. @@ -227,7 +227,7 @@ usage: freqtrade plot-profit [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] [--timerange TIMERANGE] [--export EXPORT] [--export-filename PATH] [--db-url PATH] - [--trade-source {DB,file}] [-i TICKER_INTERVAL] + [--trade-source {DB,file}] [-i TIMEFRAME] optional arguments: -h, --help show this help message and exit @@ -250,7 +250,7 @@ optional arguments: --trade-source {DB,file} Specify the source for trades (Can be DB or file (backtest file)) Default: file - -i TICKER_INTERVAL, --ticker-interval TICKER_INTERVAL + -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME Specify ticker interval (`1m`, `5m`, `30m`, `1h`, `1d`). @@ -261,9 +261,10 @@ Common arguments: details. -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. + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). 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 diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index 88eb0d3d4..1d396b8ce 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -70,7 +70,7 @@ CREATE TABLE trades min_rate FLOAT, sell_reason VARCHAR, strategy VARCHAR, - ticker_interval INTEGER, + timeframe INTEGER, PRIMARY KEY (id), CHECK (is_open IN (0, 1)) ); diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index be41b196e..08e79d307 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -142,7 +142,7 @@ By letting the bot know how much history is needed, backtest trades can start at Let's try to backtest 1 month (January 2019) of 5m candles using an example strategy with EMA100, as above. ``` bash -freqtrade backtesting --timerange 20190101-20190201 --ticker-interval 5m +freqtrade backtesting --timerange 20190101-20190201 --timeframe 5m ``` Assuming `startup_candle_count` is set to 100, backtesting knows it needs 100 candles to generate valid buy signals. It will load data from `20190101 - (100 * 5m)` - which is ~2019-12-31 15:30:00. @@ -248,7 +248,7 @@ minimal_roi = { While technically not completely disabled, this would sell once the trade reaches 10000% Profit. -To use times based on candle duration (ticker_interval or timeframe), the following snippet can be handy. +To use times based on candle duration (timeframe), the following snippet can be handy. This will allow you to change the ticket_interval for the strategy, and ROI times will still be set as candles (e.g. after 3 candles ...) ``` python @@ -256,12 +256,12 @@ from freqtrade.exchange import timeframe_to_minutes class AwesomeStrategy(IStrategy): - ticker_interval = "1d" - ticker_interval_mins = timeframe_to_minutes(ticker_interval) + timeframe = "1d" + timeframe_mins = timeframe_to_minutes(timeframe) minimal_roi = { "0": 0.05, # 5% for the first 3 candles - str(ticker_interval_mins * 3)): 0.02, # 2% after 3 candles - str(ticker_interval_mins * 6)): 0.01, # 1% After 6 candles + str(timeframe_mins * 3)): 0.02, # 2% after 3 candles + str(timeframe_mins * 6)): 0.01, # 1% After 6 candles } ``` @@ -290,7 +290,7 @@ Common values are `"1m"`, `"5m"`, `"15m"`, `"1h"`, however all values supported Please note that the same buy/sell signals may work well with one timeframe, but not with the others. -This setting is accessible within the strategy methods as the `self.ticker_interval` attribute. +This setting is accessible within the strategy methods as the `self.timeframe` attribute. ### Metadata dict @@ -400,7 +400,7 @@ This is where calling `self.dp.current_whitelist()` comes in handy. class SampleStrategy(IStrategy): # strategy init stuff... - ticker_interval = '5m' + timeframe = '5m' # more strategy init stuff.. diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index d26d684ce..6b4ad567f 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -18,7 +18,7 @@ config = Configuration.from_files([]) # config = Configuration.from_files(["config.json"]) # Define some constants -config["ticker_interval"] = "5m" +config["timeframe"] = "5m" # Name of the strategy class config["strategy"] = "SampleStrategy" # Location of the data @@ -33,7 +33,7 @@ pair = "BTC_USDT" from freqtrade.data.history import load_pair_history candles = load_pair_history(datadir=data_location, - timeframe=config["ticker_interval"], + timeframe=config["timeframe"], pair=pair) # Confirm success diff --git a/docs/utils.md b/docs/utils.md index 7ed31376f..793c84a93 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -62,7 +62,7 @@ $ freqtrade new-config --config config_binance.json ? Please insert your stake currency: BTC ? Please insert your stake amount: 0.05 ? Please insert max_open_trades (Integer or 'unlimited'): 3 -? Please insert your timeframe (ticker interval): 5m +? Please insert your desired timeframe (e.g. 5m): 5m ? Please insert your display Currency (for reporting): USD ? Select exchange binance ? Do you want to enable Telegram? No diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 1b7bbfeb5..72f2a02f0 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -15,7 +15,7 @@ ARGS_STRATEGY = ["strategy", "strategy_path"] ARGS_TRADE = ["db_url", "sd_notify", "dry_run"] -ARGS_COMMON_OPTIMIZE = ["ticker_interval", "timerange", +ARGS_COMMON_OPTIMIZE = ["timeframe", "timerange", "max_open_trades", "stake_amount", "fee"] ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions", @@ -59,10 +59,10 @@ ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "download_trades", "exchang ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", "db_url", "trade_source", "export", "exportfilename", - "timerange", "ticker_interval", "no_trades"] + "timerange", "timeframe", "no_trades"] ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url", - "trade_source", "ticker_interval"] + "trade_source", "timeframe"] ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"] @@ -318,7 +318,7 @@ class Arguments: # Add list-timeframes subcommand list_timeframes_cmd = subparsers.add_parser( 'list-timeframes', - help='Print available ticker intervals (timeframes) for the exchange.', + help='Print available timeframes for the exchange.', parents=[_common_parser], ) list_timeframes_cmd.set_defaults(func=start_list_timeframes) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 87098f53c..0c98b2e55 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -75,8 +75,8 @@ def ask_user_config() -> Dict[str, Any]: }, { "type": "text", - "name": "ticker_interval", - "message": "Please insert your timeframe (ticker interval):", + "name": "timeframe", + "message": "Please insert your desired timeframe (e.g. 5m):", "default": "5m", }, { diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index ee9208c33..3ed2f81d1 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -110,8 +110,8 @@ AVAILABLE_CLI_OPTIONS = { action='store_true', ), # Optimize common - "ticker_interval": Arg( - '-i', '--ticker-interval', + "timeframe": Arg( + '-i', '--timeframe', '--ticker-interval', help='Specify ticker interval (`1m`, `5m`, `30m`, `1h`, `1d`).', ), "timerange": Arg( diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index e5131f9b2..b29aabe25 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -102,8 +102,8 @@ def start_list_timeframes(args: Dict[str, Any]) -> None: Print ticker intervals (timeframes) available on Exchange """ config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE) - # Do not use ticker_interval set in the config - config['ticker_interval'] = None + # Do not use timeframe set in the config + config['timeframe'] = None # Init exchange exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) diff --git a/freqtrade/commands/pairlist_commands.py b/freqtrade/commands/pairlist_commands.py index bf0b217a5..77bcb04b4 100644 --- a/freqtrade/commands/pairlist_commands.py +++ b/freqtrade/commands/pairlist_commands.py @@ -25,7 +25,6 @@ def start_test_pairlist(args: Dict[str, Any]) -> None: results = {} for curr in quote_currencies: config['stake_currency'] = curr - # Do not use ticker_interval set in the config pairlists = PairListManager(exchange, config) pairlists.refresh_pairlist() results[curr] = pairlists.whitelist diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 7edd9bca1..139e42084 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -204,9 +204,9 @@ class Configuration: def _process_optimize_options(self, config: Dict[str, Any]) -> None: # This will override the strategy configuration - self._args_to_config(config, argname='ticker_interval', - logstring='Parameter -i/--ticker-interval detected ... ' - 'Using ticker_interval: {} ...') + self._args_to_config(config, argname='timeframe', + logstring='Parameter -i/--timeframe detected ... ' + 'Using timeframe: {} ...') self._args_to_config(config, argname='position_stacking', logstring='Parameter --enable-position-stacking detected ...') @@ -242,8 +242,8 @@ class Configuration: self._args_to_config(config, argname='strategy_list', logstring='Using strategy list of {} strategies', logfun=len) - self._args_to_config(config, argname='ticker_interval', - logstring='Overriding ticker interval with Command line argument') + self._args_to_config(config, argname='timeframe', + logstring='Overriding timeframe with Command line argument') self._args_to_config(config, argname='export', logstring='Parameter --export detected: {} ...') diff --git a/freqtrade/configuration/deprecated_settings.py b/freqtrade/configuration/deprecated_settings.py index ff4401c27..cefc6ac14 100644 --- a/freqtrade/configuration/deprecated_settings.py +++ b/freqtrade/configuration/deprecated_settings.py @@ -67,3 +67,9 @@ def process_temporary_deprecated_settings(config: Dict[str, Any]) -> None: "'tradable_balance_ratio' and remove 'capital_available_percentage' " "from the edge configuration." ) + if 'ticker_interval' in config: + logger.warning( + "DEPRECATED: " + "Please use 'timeframe' instead of 'ticker_interval." + ) + config['timeframe'] = config['ticker_interval'] diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 09ee54208..6741e0605 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -71,7 +71,7 @@ CONF_SCHEMA = { 'type': 'object', 'properties': { 'max_open_trades': {'type': ['integer', 'number'], 'minimum': -1}, - 'ticker_interval': {'type': 'string'}, + 'timeframe': {'type': 'string'}, 'stake_currency': {'type': 'string'}, 'stake_amount': { 'type': ['number', 'string'], @@ -303,6 +303,7 @@ CONF_SCHEMA = { SCHEMA_TRADE_REQUIRED = [ 'exchange', + 'timeframe', 'max_open_trades', 'stake_currency', 'stake_amount', diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 6c498a470..b169850ba 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -103,7 +103,7 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: "open_rate", "close_rate", "amount", "duration", "sell_reason", "fee_open", "fee_close", "open_rate_requested", "close_rate_requested", "stake_amount", "max_rate", "min_rate", "id", "exchange", - "stop_loss", "initial_stop_loss", "strategy", "ticker_interval"] + "stop_loss", "initial_stop_loss", "strategy", "timeframe"] trades = pd.DataFrame([(t.pair, t.open_date.replace(tzinfo=timezone.utc), @@ -121,7 +121,7 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: t.min_rate, t.id, t.exchange, t.stop_loss, t.initial_stop_loss, - t.strategy, t.ticker_interval + t.strategy, t.timeframe ) for t in Trade.get_trades().all()], columns=columns) diff --git a/freqtrade/data/converter.py b/freqtrade/data/converter.py index f73775432..46b653eb0 100644 --- a/freqtrade/data/converter.py +++ b/freqtrade/data/converter.py @@ -236,12 +236,12 @@ def convert_ohlcv_format(config: Dict[str, Any], convert_from: str, convert_to: from freqtrade.data.history.idatahandler import get_datahandler src = get_datahandler(config['datadir'], convert_from) trg = get_datahandler(config['datadir'], convert_to) - timeframes = config.get('timeframes', [config.get('ticker_interval')]) + timeframes = config.get('timeframes', [config.get('timeframe')]) logger.info(f"Converting candle (OHLCV) for timeframe {timeframes}") if 'pairs' not in config: config['pairs'] = [] - # Check timeframes or fall back to ticker_interval. + # Check timeframes or fall back to timeframe. for timeframe in timeframes: config['pairs'].extend(src.ohlcv_get_pairs(config['datadir'], timeframe)) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index a01344364..058ca42da 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -55,7 +55,7 @@ class DataProvider: Use False only for read-only operations (where the dataframe is not modified) """ if self.runmode in (RunMode.DRY_RUN, RunMode.LIVE): - return self._exchange.klines((pair, timeframe or self._config['ticker_interval']), + return self._exchange.klines((pair, timeframe or self._config['timeframe']), copy=copy) else: return DataFrame() @@ -67,7 +67,7 @@ class DataProvider: :param timeframe: timeframe to get data for """ return load_pair_history(pair=pair, - timeframe=timeframe or self._config['ticker_interval'], + timeframe=timeframe or self._config['timeframe'], datadir=self._config['datadir'] ) diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index 2550cf604..41252ee51 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -98,14 +98,14 @@ class Edge: datadir=self.config['datadir'], pairs=pairs, exchange=self.exchange, - timeframe=self.strategy.ticker_interval, + timeframe=self.strategy.timeframe, timerange=self._timerange, ) data = load_data( datadir=self.config['datadir'], pairs=pairs, - timeframe=self.strategy.ticker_interval, + timeframe=self.strategy.timeframe, timerange=self._timerange, startup_candles=self.strategy.startup_candle_count, data_format=self.config.get('dataformat_ohlcv', 'json'), diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index ee89b658f..35c62db27 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -115,7 +115,7 @@ class Exchange: if validate: # Check if timeframe is available - self.validate_timeframes(config.get('ticker_interval')) + self.validate_timeframes(config.get('timeframe')) # Initial markets load self._load_markets() diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f86ac0e28..289850709 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -421,8 +421,8 @@ class FreqtradeBot: # running get_signal on historical data fetched (buy, sell) = self.strategy.get_signal( - pair, self.strategy.ticker_interval, - self.dataprovider.ohlcv(pair, self.strategy.ticker_interval)) + pair, self.strategy.timeframe, + self.dataprovider.ohlcv(pair, self.strategy.timeframe)) if buy and not sell: stake_amount = self.get_trade_stake_amount(pair) @@ -547,7 +547,7 @@ class FreqtradeBot: exchange=self.exchange.id, open_order_id=order_id, strategy=self.strategy.get_strategy_name(), - ticker_interval=timeframe_to_minutes(self.config['ticker_interval']) + timeframe=timeframe_to_minutes(self.config['timeframe']) ) # Update fees if order is closed @@ -698,8 +698,8 @@ class FreqtradeBot: if (config_ask_strategy.get('use_sell_signal', True) or config_ask_strategy.get('ignore_roi_if_buy_signal', False)): (buy, sell) = self.strategy.get_signal( - trade.pair, self.strategy.ticker_interval, - self.dataprovider.ohlcv(trade.pair, self.strategy.ticker_interval)) + trade.pair, self.strategy.timeframe, + self.dataprovider.ohlcv(trade.pair, self.strategy.timeframe)) if config_ask_strategy.get('use_order_book', False): order_book_min = config_ask_strategy.get('order_book_min', 1) @@ -784,7 +784,7 @@ class FreqtradeBot: self.update_trade_state(trade, stoploss_order, sl_order=True) # Lock pair for one candle to prevent immediate rebuys self.strategy.lock_pair(trade.pair, - timeframe_to_next_date(self.config['ticker_interval'])) + timeframe_to_next_date(self.config['timeframe'])) self._notify_sell(trade, "stoploss") return True @@ -1094,7 +1094,7 @@ class FreqtradeBot: Trade.session.flush() # Lock pair for one candle to prevent immediate rebuys - self.strategy.lock_pair(trade.pair, timeframe_to_next_date(self.config['ticker_interval'])) + self.strategy.lock_pair(trade.pair, timeframe_to_next_date(self.config['timeframe'])) self._notify_sell(trade, order_type) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index b47b38ea4..206279f35 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -95,10 +95,10 @@ class Backtesting: self.strategylist.append(StrategyResolver.load_strategy(self.config)) validate_config_consistency(self.config) - if "ticker_interval" not in self.config: + if "timeframe" not in self.config: raise OperationalException("Timeframe (ticker interval) needs to be set in either " - "configuration or as cli argument `--ticker-interval 5m`") - self.timeframe = str(self.config.get('ticker_interval')) + "configuration or as cli argument `--timeframe 5m`") + self.timeframe = str(self.config.get('timeframe')) self.timeframe_min = timeframe_to_minutes(self.timeframe) # Get maximum required startup period diff --git a/freqtrade/optimize/hyperopt_interface.py b/freqtrade/optimize/hyperopt_interface.py index b3cedef2c..65069b984 100644 --- a/freqtrade/optimize/hyperopt_interface.py +++ b/freqtrade/optimize/hyperopt_interface.py @@ -31,13 +31,15 @@ class IHyperOpt(ABC): Class attributes you can use: ticker_interval -> int: value of the ticker interval to use for the strategy """ - ticker_interval: str + ticker_interval: str # DEPRECATED + timeframe: str def __init__(self, config: dict) -> None: self.config = config # Assign ticker_interval to be used in hyperopt - IHyperOpt.ticker_interval = str(config['ticker_interval']) + IHyperOpt.ticker_interval = str(config['timeframe']) # DEPRECATED + IHyperOpt.timeframe = str(config['timeframe']) @staticmethod def buy_strategy_generator(params: Dict[str, Any]) -> Callable: @@ -218,9 +220,10 @@ class IHyperOpt(ABC): # Why do I still need such shamanic mantras in modern python? def __getstate__(self): state = self.__dict__.copy() - state['ticker_interval'] = self.ticker_interval + state['timeframe'] = self.timeframe return state def __setstate__(self, state): self.__dict__.update(state) - IHyperOpt.ticker_interval = state['ticker_interval'] + IHyperOpt.ticker_interval = state['timeframe'] + IHyperOpt.timeframe = state['timeframe'] diff --git a/freqtrade/optimize/hyperopt_loss_interface.py b/freqtrade/optimize/hyperopt_loss_interface.py index 879a9f0e9..48407a8a8 100644 --- a/freqtrade/optimize/hyperopt_loss_interface.py +++ b/freqtrade/optimize/hyperopt_loss_interface.py @@ -14,7 +14,7 @@ class IHyperOptLoss(ABC): Interface for freqtrade hyperopt Loss functions. Defines the custom loss function (`hyperopt_loss_function()` which is evaluated every epoch.) """ - ticker_interval: str + timeframe: str @staticmethod @abstractmethod diff --git a/freqtrade/pairlist/pairlistmanager.py b/freqtrade/pairlist/pairlistmanager.py index f532f2cd0..81e52768e 100644 --- a/freqtrade/pairlist/pairlistmanager.py +++ b/freqtrade/pairlist/pairlistmanager.py @@ -131,6 +131,6 @@ class PairListManager(): def create_pair_list(self, pairs: List[str], timeframe: str = None) -> ListPairsWithTimeframes: """ - Create list of pair tuples with (pair, ticker_interval) + Create list of pair tuples with (pair, timeframe) """ - return [(pair, timeframe or self._config['ticker_interval']) for pair in pairs] + return [(pair, timeframe or self._config['timeframe']) for pair in pairs] diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 2e02c3999..097a2f984 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -86,7 +86,7 @@ def check_migrate(engine) -> None: logger.debug(f'trying {table_back_name}') # Check for latest column - if not has_column(cols, 'sell_order_status'): + if not has_column(cols, 'timeframe'): logger.info(f'Running database migration - backup available as {table_back_name}') fee_open = get_column_def(cols, 'fee_open', 'fee') @@ -107,7 +107,12 @@ def check_migrate(engine) -> None: min_rate = get_column_def(cols, 'min_rate', 'null') sell_reason = get_column_def(cols, 'sell_reason', 'null') strategy = get_column_def(cols, 'strategy', 'null') - ticker_interval = get_column_def(cols, 'ticker_interval', 'null') + # If ticker-interval existed use that, else null. + if has_column(cols, 'ticker_interval'): + timeframe = get_column_def(cols, 'timeframe', 'ticker_interval') + else: + timeframe = get_column_def(cols, 'timeframe', 'null') + open_trade_price = get_column_def(cols, 'open_trade_price', f'amount * open_rate * (1 + {fee_open})') close_profit_abs = get_column_def( @@ -133,7 +138,7 @@ def check_migrate(engine) -> None: stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct, stoploss_order_id, stoploss_last_update, max_rate, min_rate, sell_reason, sell_order_status, strategy, - ticker_interval, open_trade_price, close_profit_abs + timeframe, open_trade_price, close_profit_abs ) select id, lower(exchange), case @@ -155,7 +160,7 @@ def check_migrate(engine) -> None: {stoploss_order_id} stoploss_order_id, {stoploss_last_update} stoploss_last_update, {max_rate} max_rate, {min_rate} min_rate, {sell_reason} sell_reason, {sell_order_status} sell_order_status, - {strategy} strategy, {ticker_interval} ticker_interval, + {strategy} strategy, {timeframe} timeframe, {open_trade_price} open_trade_price, {close_profit_abs} close_profit_abs from {table_back_name} """) @@ -232,7 +237,7 @@ class Trade(_DECL_BASE): sell_reason = Column(String, nullable=True) sell_order_status = Column(String, nullable=True) strategy = Column(String, nullable=True) - ticker_interval = Column(Integer, nullable=True) + timeframe = Column(Integer, nullable=True) def __init__(self, **kwargs): super().__init__(**kwargs) @@ -253,7 +258,8 @@ class Trade(_DECL_BASE): 'amount': round(self.amount, 8), 'stake_amount': round(self.stake_amount, 8), 'strategy': self.strategy, - 'ticker_interval': self.ticker_interval, + 'ticker_interval': self.timeframe, # DEPRECATED + 'timeframe': self.timeframe, 'fee_open': self.fee_open, 'fee_open_cost': self.fee_open_cost, diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index d519c5f4e..e8b0b4938 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -45,7 +45,7 @@ def init_plotscript(config): data = load_data( datadir=config.get("datadir"), pairs=pairs, - timeframe=config.get('ticker_interval', '5m'), + timeframe=config.get('timeframe', '5m'), timerange=timerange, data_format=config.get('dataformat_ohlcv', 'json'), ) @@ -487,7 +487,7 @@ def load_and_plot_trades(config: Dict[str, Any]): plot_config=strategy.plot_config if hasattr(strategy, 'plot_config') else {} ) - store_plot_file(fig, filename=generate_plot_filename(pair, config['ticker_interval']), + store_plot_file(fig, filename=generate_plot_filename(pair, config['timeframe']), directory=config['user_data_dir'] / "plot") logger.info('End of plotting process. %s plots generated', pair_counter) @@ -515,6 +515,6 @@ def plot_profit(config: Dict[str, Any]) -> None: # Create an average close price of all the pairs that were involved. # this could be useful to gauge the overall market trend fig = generate_profit_graph(plot_elements["pairs"], plot_elements["ohlcv"], - trades, config.get('ticker_interval', '5m')) + trades, config.get('timeframe', '5m')) store_plot_file(fig, filename='freqtrade-profit-plot.html', directory=config['user_data_dir'] / "plot", auto_open=True) diff --git a/freqtrade/resolvers/hyperopt_resolver.py b/freqtrade/resolvers/hyperopt_resolver.py index ddf461252..633363134 100644 --- a/freqtrade/resolvers/hyperopt_resolver.py +++ b/freqtrade/resolvers/hyperopt_resolver.py @@ -77,8 +77,9 @@ class HyperOptLossResolver(IResolver): config, kwargs={}, extra_dir=config.get('hyperopt_path')) - # Assign ticker_interval to be used in hyperopt - hyperoptloss.__class__.ticker_interval = str(config['ticker_interval']) + # Assign timeframe to be used in hyperopt + hyperoptloss.__class__.ticker_interval = str(config['timeframe']) + hyperoptloss.__class__.timeframe = str(config['timeframe']) if not hasattr(hyperoptloss, 'hyperopt_loss_function'): raise OperationalException( diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index abd6a4195..121a04877 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -50,11 +50,19 @@ class StrategyResolver(IResolver): if 'ask_strategy' not in config: config['ask_strategy'] = {} + if hasattr(strategy, 'ticker_interval') and not hasattr(strategy, 'timeframe'): + # Assign ticker_interval to timeframe to keep compatibility + if 'timeframe' not in config: + logger.warning( + "DEPRECATED: Please migrate to using 'timeframe' instead of 'ticker_interval'." + ) + strategy.timeframe = strategy.ticker_interval + # Set attributes # Check if we need to override configuration # (Attribute name, default, subkey) attributes = [("minimal_roi", {"0": 10.0}, None), - ("ticker_interval", None, None), + ("timeframe", None, None), ("stoploss", None, None), ("trailing_stop", None, None), ("trailing_stop_positive", None, None), @@ -80,6 +88,9 @@ class StrategyResolver(IResolver): StrategyResolver._override_attribute_helper(strategy, config, attribute, default) + # Assign deprecated variable - to not break users code relying on this. + strategy.ticker_interval = strategy.timeframe + # Loop this list again to have output combined for attribute, _, subkey in attributes: if subkey and attribute in config[subkey]: diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index e4c96cf3b..aeaf82662 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -101,7 +101,8 @@ class RPC: 'trailing_stop_positive': config.get('trailing_stop_positive'), 'trailing_stop_positive_offset': config.get('trailing_stop_positive_offset'), 'trailing_only_offset_is_reached': config.get('trailing_only_offset_is_reached'), - 'ticker_interval': config['ticker_interval'], + 'ticker_interval': config['timeframe'], # DEPRECATED + 'timeframe': config['timeframe'], 'exchange': config['exchange']['name'], 'strategy': config['strategy'], 'forcebuy_enabled': config.get('forcebuy_enable', False), diff --git a/freqtrade/rpc/rpc_manager.py b/freqtrade/rpc/rpc_manager.py index 670275991..2cb44fec8 100644 --- a/freqtrade/rpc/rpc_manager.py +++ b/freqtrade/rpc/rpc_manager.py @@ -72,7 +72,7 @@ class RPCManager: minimal_roi = config['minimal_roi'] stoploss = config['stoploss'] trailing_stop = config['trailing_stop'] - ticker_interval = config['ticker_interval'] + timeframe = config['timeframe'] exchange_name = config['exchange']['name'] strategy_name = config.get('strategy', '') self.send_msg({ @@ -81,7 +81,7 @@ class RPCManager: f'*Stake per trade:* `{stake_amount} {stake_currency}`\n' f'*Minimum ROI:* `{minimal_roi}`\n' f'*{"Trailing " if trailing_stop else ""}Stoploss:* `{stoploss}`\n' - f'*Ticker Interval:* `{ticker_interval}`\n' + f'*Timeframe:* `{timeframe}`\n' f'*Strategy:* `{strategy_name}`' }) self.send_msg({ diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 006baee60..9b40ee2f6 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -669,7 +669,7 @@ class Telegram(RPC): f"*Ask strategy:* ```\n{json.dumps(val['ask_strategy'])}```\n" f"*Bid strategy:* ```\n{json.dumps(val['bid_strategy'])}```\n" f"{sl_info}" - f"*Ticker Interval:* `{val['ticker_interval']}`\n" + f"*Timeframe:* `{val['timeframe']}`\n" f"*Strategy:* `{val['strategy']}`\n" f"*Current state:* `{val['state']}`" ) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index ed2344a53..f9f3a3678 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -62,7 +62,7 @@ class IStrategy(ABC): Attributes you can use: minimal_roi -> Dict: Minimal ROI designed for the strategy stoploss -> float: optimal stoploss designed for the strategy - ticker_interval -> str: value of the timeframe (ticker interval) to use with the strategy + timeframe -> str: value of the timeframe (ticker interval) to use with the strategy """ # Strategy interface version # Default to version 2 @@ -85,8 +85,9 @@ class IStrategy(ABC): trailing_stop_positive_offset: float = 0.0 trailing_only_offset_is_reached = False - # associated ticker interval - ticker_interval: str + # associated timeframe + ticker_interval: str # DEPRECATED + timeframe: str # Optional order types order_types: Dict = { diff --git a/freqtrade/templates/base_config.json.j2 b/freqtrade/templates/base_config.json.j2 index 5339595e8..118ae348b 100644 --- a/freqtrade/templates/base_config.json.j2 +++ b/freqtrade/templates/base_config.json.j2 @@ -4,7 +4,7 @@ "stake_amount": {{ stake_amount }}, "tradable_balance_ratio": 0.99, "fiat_display_currency": "{{ fiat_display_currency }}", - "ticker_interval": "{{ ticker_interval }}", + "timeframe": "{{ timeframe }}", "dry_run": {{ dry_run | lower }}, "cancel_open_orders_on_exit": false, "unfilledtimeout": { diff --git a/freqtrade/templates/base_strategy.py.j2 b/freqtrade/templates/base_strategy.py.j2 index c37164568..ce2c6d5c0 100644 --- a/freqtrade/templates/base_strategy.py.j2 +++ b/freqtrade/templates/base_strategy.py.j2 @@ -51,8 +51,8 @@ class {{ strategy }}(IStrategy): # trailing_stop_positive = 0.01 # trailing_stop_positive_offset = 0.0 # Disabled / not configured - # Optimal ticker interval for the strategy. - ticker_interval = '5m' + # Optimal timeframe for the strategy. + timeframe = '5m' # Run "populate_indicators()" only for new candle. process_only_new_candles = False diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index f78489173..e269848d2 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -53,7 +53,7 @@ class SampleStrategy(IStrategy): # trailing_stop_positive_offset = 0.0 # Disabled / not configured # Optimal ticker interval for the strategy. - ticker_interval = '5m' + timeframe = '5m' # Run "populate_indicators()" only for new candle. process_only_new_candles = False diff --git a/tests/commands/test_build_config.py b/tests/commands/test_build_config.py index d4ebe1de2..69b277e3b 100644 --- a/tests/commands/test_build_config.py +++ b/tests/commands/test_build_config.py @@ -44,7 +44,7 @@ def test_start_new_config(mocker, caplog, exchange): 'stake_currency': 'USDT', 'stake_amount': 100, 'fiat_display_currency': 'EUR', - 'ticker_interval': '15m', + 'timeframe': '15m', 'dry_run': True, 'exchange_name': exchange, 'exchange_key': 'sampleKey', @@ -68,7 +68,7 @@ def test_start_new_config(mocker, caplog, exchange): result = rapidjson.loads(wt_mock.call_args_list[0][0][0], parse_mode=rapidjson.PM_COMMENTS | rapidjson.PM_TRAILING_COMMAS) assert result['exchange']['name'] == exchange - assert result['ticker_interval'] == '15m' + assert result['timeframe'] == '15m' def test_start_new_config_exists(mocker, caplog): diff --git a/tests/config_test_comments.json b/tests/config_test_comments.json index d9d4a86bc..4f201f86c 100644 --- a/tests/config_test_comments.json +++ b/tests/config_test_comments.json @@ -9,7 +9,7 @@ "fiat_display_currency": "USD", // C++-style comment "amount_reserve_percent" : 0.05, // And more, tabs before this comment "dry_run": false, - "ticker_interval": "5m", + "timeframe": "5m", "trailing_stop": false, "trailing_stop_positive": 0.005, "trailing_stop_positive_offset": 0.0051, diff --git a/tests/conftest.py b/tests/conftest.py index 1cd3bcc0f..3ca431f40 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -247,7 +247,7 @@ def default_conf(testdatadir): "stake_currency": "BTC", "stake_amount": 0.001, "fiat_display_currency": "USD", - "ticker_interval": '5m', + "timeframe": '5m', "dry_run": True, "cancel_open_orders_on_exit": False, "minimal_roi": { diff --git a/tests/data/test_dataprovider.py b/tests/data/test_dataprovider.py index c2d6e82f1..def3ad535 100644 --- a/tests/data/test_dataprovider.py +++ b/tests/data/test_dataprovider.py @@ -12,7 +12,7 @@ from tests.conftest import get_patched_exchange def test_ohlcv(mocker, default_conf, ohlcv_history): default_conf["runmode"] = RunMode.DRY_RUN - timeframe = default_conf["ticker_interval"] + timeframe = default_conf["timeframe"] exchange = get_patched_exchange(mocker, default_conf) exchange._klines[("XRP/BTC", timeframe)] = ohlcv_history exchange._klines[("UNITTEST/BTC", timeframe)] = ohlcv_history @@ -53,47 +53,47 @@ def test_historic_ohlcv(mocker, default_conf, ohlcv_history): def test_get_pair_dataframe(mocker, default_conf, ohlcv_history): default_conf["runmode"] = RunMode.DRY_RUN - ticker_interval = default_conf["ticker_interval"] + timeframe = default_conf["timeframe"] exchange = get_patched_exchange(mocker, default_conf) - exchange._klines[("XRP/BTC", ticker_interval)] = ohlcv_history - exchange._klines[("UNITTEST/BTC", ticker_interval)] = ohlcv_history + exchange._klines[("XRP/BTC", timeframe)] = ohlcv_history + exchange._klines[("UNITTEST/BTC", timeframe)] = ohlcv_history dp = DataProvider(default_conf, exchange) assert dp.runmode == RunMode.DRY_RUN - assert ohlcv_history.equals(dp.get_pair_dataframe("UNITTEST/BTC", ticker_interval)) - assert isinstance(dp.get_pair_dataframe("UNITTEST/BTC", ticker_interval), DataFrame) - assert dp.get_pair_dataframe("UNITTEST/BTC", ticker_interval) is not ohlcv_history - assert not dp.get_pair_dataframe("UNITTEST/BTC", ticker_interval).empty - assert dp.get_pair_dataframe("NONESENSE/AAA", ticker_interval).empty + assert ohlcv_history.equals(dp.get_pair_dataframe("UNITTEST/BTC", timeframe)) + assert isinstance(dp.get_pair_dataframe("UNITTEST/BTC", timeframe), DataFrame) + assert dp.get_pair_dataframe("UNITTEST/BTC", timeframe) is not ohlcv_history + assert not dp.get_pair_dataframe("UNITTEST/BTC", timeframe).empty + assert dp.get_pair_dataframe("NONESENSE/AAA", timeframe).empty # Test with and without parameter - assert dp.get_pair_dataframe("UNITTEST/BTC", ticker_interval)\ + assert dp.get_pair_dataframe("UNITTEST/BTC", timeframe)\ .equals(dp.get_pair_dataframe("UNITTEST/BTC")) default_conf["runmode"] = RunMode.LIVE dp = DataProvider(default_conf, exchange) assert dp.runmode == RunMode.LIVE - assert isinstance(dp.get_pair_dataframe("UNITTEST/BTC", ticker_interval), DataFrame) - assert dp.get_pair_dataframe("NONESENSE/AAA", ticker_interval).empty + assert isinstance(dp.get_pair_dataframe("UNITTEST/BTC", timeframe), DataFrame) + assert dp.get_pair_dataframe("NONESENSE/AAA", timeframe).empty historymock = MagicMock(return_value=ohlcv_history) mocker.patch("freqtrade.data.dataprovider.load_pair_history", historymock) default_conf["runmode"] = RunMode.BACKTEST dp = DataProvider(default_conf, exchange) assert dp.runmode == RunMode.BACKTEST - assert isinstance(dp.get_pair_dataframe("UNITTEST/BTC", ticker_interval), DataFrame) - # assert dp.get_pair_dataframe("NONESENSE/AAA", ticker_interval).empty + assert isinstance(dp.get_pair_dataframe("UNITTEST/BTC", timeframe), DataFrame) + # assert dp.get_pair_dataframe("NONESENSE/AAA", timeframe).empty def test_available_pairs(mocker, default_conf, ohlcv_history): exchange = get_patched_exchange(mocker, default_conf) - ticker_interval = default_conf["ticker_interval"] - exchange._klines[("XRP/BTC", ticker_interval)] = ohlcv_history - exchange._klines[("UNITTEST/BTC", ticker_interval)] = ohlcv_history + timeframe = default_conf["timeframe"] + exchange._klines[("XRP/BTC", timeframe)] = ohlcv_history + exchange._klines[("UNITTEST/BTC", timeframe)] = ohlcv_history dp = DataProvider(default_conf, exchange) assert len(dp.available_pairs) == 2 - assert dp.available_pairs == [("XRP/BTC", ticker_interval), ("UNITTEST/BTC", ticker_interval), ] + assert dp.available_pairs == [("XRP/BTC", timeframe), ("UNITTEST/BTC", timeframe), ] def test_refresh(mocker, default_conf, ohlcv_history): @@ -101,10 +101,10 @@ def test_refresh(mocker, default_conf, ohlcv_history): mocker.patch("freqtrade.exchange.Exchange.refresh_latest_ohlcv", refresh_mock) exchange = get_patched_exchange(mocker, default_conf, id="binance") - ticker_interval = default_conf["ticker_interval"] - pairs = [("XRP/BTC", ticker_interval), ("UNITTEST/BTC", ticker_interval)] + timeframe = default_conf["timeframe"] + pairs = [("XRP/BTC", timeframe), ("UNITTEST/BTC", timeframe)] - pairs_non_trad = [("ETH/USDT", ticker_interval), ("BTC/TUSD", "1h")] + pairs_non_trad = [("ETH/USDT", timeframe), ("BTC/TUSD", "1h")] dp = DataProvider(default_conf, exchange) dp.refresh(pairs) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 6fd4d9569..c52163bbc 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -354,7 +354,7 @@ def test_init(default_conf, mocker) -> None: assert {} == load_data( datadir=Path(''), pairs=[], - timeframe=default_conf['ticker_interval'] + timeframe=default_conf['timeframe'] ) @@ -363,13 +363,13 @@ def test_init_with_refresh(default_conf, mocker) -> None: refresh_data( datadir=Path(''), pairs=[], - timeframe=default_conf['ticker_interval'], + timeframe=default_conf['timeframe'], exchange=exchange ) assert {} == load_data( datadir=Path(''), pairs=[], - timeframe=default_conf['ticker_interval'] + timeframe=default_conf['timeframe'] ) diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index 163ceff4b..cf9cb6fe1 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -27,7 +27,7 @@ from tests.optimize import (BTContainer, BTrade, _build_backtest_dataframe, #################################################################### tests_start_time = arrow.get(2018, 10, 3) -ticker_interval_in_minute = 60 +timeframe_in_minute = 60 _ohlc = {'date': 0, 'buy': 1, 'open': 2, 'high': 3, 'low': 4, 'close': 5, 'sell': 6, 'volume': 7} # Helpers for this test file @@ -49,7 +49,7 @@ def _build_dataframe(buy_ohlc_sell_matrice): 'date': tests_start_time.shift( minutes=( ohlc[0] * - ticker_interval_in_minute)).timestamp * + timeframe_in_minute)).timestamp * 1000, 'buy': ohlc[1], 'open': ohlc[2], @@ -70,7 +70,7 @@ def _build_dataframe(buy_ohlc_sell_matrice): def _time_on_candle(number): return np.datetime64(tests_start_time.shift( - minutes=(number * ticker_interval_in_minute)).timestamp * 1000, 'ms') + minutes=(number * timeframe_in_minute)).timestamp * 1000, 'ms') # End helper functions @@ -262,7 +262,7 @@ def mocked_load_data(datadir, pairs=[], timeframe='0m', NEOBTC = [ [ - tests_start_time.shift(minutes=(x * ticker_interval_in_minute)).timestamp * 1000, + tests_start_time.shift(minutes=(x * timeframe_in_minute)).timestamp * 1000, math.sin(x * hz) / 1000 + base, math.sin(x * hz) / 1000 + base + 0.0001, math.sin(x * hz) / 1000 + base - 0.0001, @@ -274,7 +274,7 @@ def mocked_load_data(datadir, pairs=[], timeframe='0m', base = 0.002 LTCBTC = [ [ - tests_start_time.shift(minutes=(x * ticker_interval_in_minute)).timestamp * 1000, + tests_start_time.shift(minutes=(x * timeframe_in_minute)).timestamp * 1000, math.sin(x * hz) / 1000 + base, math.sin(x * hz) / 1000 + base + 0.0001, math.sin(x * hz) / 1000 + base - 0.0001, diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 918b81d2b..762ee295e 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -578,7 +578,7 @@ def test_validate_pairs_stakecompatibility_fail(default_conf, mocker, caplog): ('5m'), ("1m"), ("15m"), ("1h") ]) def test_validate_timeframes(default_conf, mocker, timeframe): - default_conf["ticker_interval"] = timeframe + default_conf["timeframe"] = timeframe api_mock = MagicMock() id_mock = PropertyMock(return_value='test_exchange') type(api_mock).id = id_mock @@ -596,7 +596,7 @@ def test_validate_timeframes(default_conf, mocker, timeframe): def test_validate_timeframes_failed(default_conf, mocker): - default_conf["ticker_interval"] = "3m" + default_conf["timeframe"] = "3m" api_mock = MagicMock() id_mock = PropertyMock(return_value='test_exchange') type(api_mock).id = id_mock @@ -613,7 +613,7 @@ def test_validate_timeframes_failed(default_conf, mocker): with pytest.raises(OperationalException, match=r"Invalid timeframe '3m'. This exchange supports.*"): Exchange(default_conf) - default_conf["ticker_interval"] = "15s" + default_conf["timeframe"] = "15s" with pytest.raises(OperationalException, match=r"Timeframes < 1m are currently not supported by Freqtrade."): @@ -621,7 +621,7 @@ def test_validate_timeframes_failed(default_conf, mocker): def test_validate_timeframes_emulated_ohlcv_1(default_conf, mocker): - default_conf["ticker_interval"] = "3m" + default_conf["timeframe"] = "3m" api_mock = MagicMock() id_mock = PropertyMock(return_value='test_exchange') type(api_mock).id = id_mock @@ -641,7 +641,7 @@ def test_validate_timeframes_emulated_ohlcv_1(default_conf, mocker): def test_validate_timeframes_emulated_ohlcvi_2(default_conf, mocker): - default_conf["ticker_interval"] = "3m" + default_conf["timeframe"] = "3m" api_mock = MagicMock() id_mock = PropertyMock(return_value='test_exchange') type(api_mock).id = id_mock @@ -662,7 +662,7 @@ def test_validate_timeframes_emulated_ohlcvi_2(default_conf, mocker): def test_validate_timeframes_not_in_config(default_conf, mocker): - del default_conf["ticker_interval"] + del default_conf["timeframe"] api_mock = MagicMock() id_mock = PropertyMock(return_value='test_exchange') type(api_mock).id = id_mock @@ -1351,7 +1351,7 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_ # exchange = Exchange(default_conf) await async_ccxt_exception(mocker, default_conf, MagicMock(), "_async_get_candle_history", "fetch_ohlcv", - pair='ABCD/BTC', timeframe=default_conf['ticker_interval']) + pair='ABCD/BTC', timeframe=default_conf['timeframe']) api_mock = MagicMock() with pytest.raises(OperationalException, @@ -1481,7 +1481,7 @@ async def test___async_get_candle_history_sort(default_conf, mocker, exchange_na exchange._api_async.fetch_ohlcv = get_mock_coro(ohlcv) sort_mock = mocker.patch('freqtrade.exchange.exchange.sorted', MagicMock(side_effect=sort_data)) # Test the OHLCV data sort - res = await exchange._async_get_candle_history('ETH/BTC', default_conf['ticker_interval']) + res = await exchange._async_get_candle_history('ETH/BTC', default_conf['timeframe']) assert res[0] == 'ETH/BTC' res_ohlcv = res[2] @@ -1518,9 +1518,9 @@ async def test___async_get_candle_history_sort(default_conf, mocker, exchange_na # Reset sort mock sort_mock = mocker.patch('freqtrade.exchange.sorted', MagicMock(side_effect=sort_data)) # Test the OHLCV data sort - res = await exchange._async_get_candle_history('ETH/BTC', default_conf['ticker_interval']) + res = await exchange._async_get_candle_history('ETH/BTC', default_conf['timeframe']) assert res[0] == 'ETH/BTC' - assert res[1] == default_conf['ticker_interval'] + assert res[1] == default_conf['timeframe'] res_ohlcv = res[2] # Sorted not called again - data is already in order assert sort_mock.call_count == 0 diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index e7bc76c1d..9b3043086 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -360,7 +360,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None: """ default_conf["stoploss"] = data.stop_loss default_conf["minimal_roi"] = data.roi - default_conf["ticker_interval"] = tests_timeframe + default_conf["timeframe"] = tests_timeframe default_conf["trailing_stop"] = data.trailing_stop default_conf["trailing_only_offset_is_reached"] = data.trailing_only_offset_is_reached # Only add this to configuration If it's necessary diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 1c9810ec9..6c153fe8e 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -81,7 +81,7 @@ def load_data_test(what, testdatadir): def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None: patch_exchange(mocker) - config['ticker_interval'] = '1m' + config['timeframe'] = '1m' backtesting = Backtesting(config) data = load_data_test(contour, testdatadir) @@ -165,7 +165,7 @@ def test_setup_optimize_configuration_without_arguments(mocker, default_conf, ca assert 'pair_whitelist' in config['exchange'] assert 'datadir' in config assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config + assert 'timeframe' in config assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog) assert 'position_stacking' not in config @@ -189,7 +189,7 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) -> '--config', 'config.json', '--strategy', 'DefaultStrategy', '--datadir', '/foo/bar', - '--ticker-interval', '1m', + '--timeframe', '1m', '--enable-position-stacking', '--disable-max-market-positions', '--timerange', ':100', @@ -208,8 +208,8 @@ def test_setup_bt_configuration_with_arguments(mocker, default_conf, caplog) -> assert config['runmode'] == RunMode.BACKTEST assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config - assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + assert 'timeframe' in config + assert log_has('Parameter -i/--timeframe detected ... Using timeframe: 1m ...', caplog) assert 'position_stacking' in config @@ -286,9 +286,9 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None: assert not backtesting.strategy.order_types["stoploss_on_exchange"] -def test_backtesting_init_no_ticker_interval(mocker, default_conf, caplog) -> None: +def test_backtesting_init_no_timeframe(mocker, default_conf, caplog) -> None: patch_exchange(mocker) - del default_conf['ticker_interval'] + del default_conf['timeframe'] default_conf['strategy_list'] = ['DefaultStrategy', 'SampleStrategy'] @@ -338,7 +338,7 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist', PropertyMock(return_value=['UNITTEST/BTC'])) - default_conf['ticker_interval'] = '1m' + default_conf['timeframe'] = '1m' default_conf['datadir'] = testdatadir default_conf['export'] = None default_conf['timerange'] = '-1510694220' @@ -368,7 +368,7 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist', PropertyMock(return_value=['UNITTEST/BTC'])) - default_conf['ticker_interval'] = "1m" + default_conf['timeframe'] = "1m" default_conf['datadir'] = testdatadir default_conf['export'] = None default_conf['timerange'] = '20180101-20180102' @@ -388,7 +388,7 @@ def test_backtesting_no_pair_left(default_conf, mocker, caplog, testdatadir) -> mocker.patch('freqtrade.pairlist.pairlistmanager.PairListManager.whitelist', PropertyMock(return_value=[])) - default_conf['ticker_interval'] = "1m" + default_conf['timeframe'] = "1m" default_conf['datadir'] = testdatadir default_conf['export'] = None default_conf['timerange'] = '20180101-20180102' @@ -454,7 +454,7 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: t["close_rate"], 6) < round(ln.iloc[0]["high"], 6)) -def test_backtest_1min_ticker_interval(default_conf, fee, mocker, testdatadir) -> None: +def test_backtest_1min_timeframe(default_conf, fee, mocker, testdatadir) -> None: default_conf['ask_strategy']['use_sell_signal'] = False mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) patch_exchange(mocker) @@ -535,7 +535,7 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir): mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) backtest_conf = _make_backtest_conf(mocker, conf=default_conf, pair='UNITTEST/BTC', datadir=testdatadir) - default_conf['ticker_interval'] = '1m' + default_conf['timeframe'] = '1m' backtesting = Backtesting(default_conf) backtesting.strategy.advise_buy = _trend_alternate # Override backtesting.strategy.advise_sell = _trend_alternate # Override @@ -574,7 +574,7 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir) # Remove data for one pair from the beginning of the data data[pair] = data[pair][tres:].reset_index() - default_conf['ticker_interval'] = '5m' + default_conf['timeframe'] = '5m' backtesting = Backtesting(default_conf) backtesting.strategy.advise_buy = _trend_alternate_hold # Override @@ -625,7 +625,7 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir): '--config', 'config.json', '--strategy', 'DefaultStrategy', '--datadir', str(testdatadir), - '--ticker-interval', '1m', + '--timeframe', '1m', '--timerange', '1510694220-1510700340', '--enable-position-stacking', '--disable-max-market-positions' @@ -634,7 +634,7 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir): start_backtesting(args) # check the logs, that will contain the backtest result exists = [ - 'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + 'Parameter -i/--timeframe detected ... Using timeframe: 1m ...', 'Ignoring max_open_trades (--disable-max-market-positions was used) ...', 'Parameter --timerange detected: 1510694220-1510700340 ...', f'Using data directory: {testdatadir} ...', @@ -678,7 +678,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): '--config', 'config.json', '--datadir', str(testdatadir), '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'), - '--ticker-interval', '1m', + '--timeframe', '1m', '--timerange', '1510694220-1510700340', '--enable-position-stacking', '--disable-max-market-positions', @@ -697,7 +697,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): # check the logs, that will contain the backtest result exists = [ - 'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + 'Parameter -i/--timeframe detected ... Using timeframe: 1m ...', 'Ignoring max_open_trades (--disable-max-market-positions was used) ...', 'Parameter --timerange detected: 1510694220-1510700340 ...', f'Using data directory: {testdatadir} ...', @@ -767,7 +767,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat '--config', 'config.json', '--datadir', str(testdatadir), '--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'), - '--ticker-interval', '1m', + '--timeframe', '1m', '--timerange', '1510694220-1510700340', '--enable-position-stacking', '--disable-max-market-positions', @@ -780,7 +780,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat # check the logs, that will contain the backtest result exists = [ - 'Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + 'Parameter -i/--timeframe detected ... Using timeframe: 1m ...', 'Ignoring max_open_trades (--disable-max-market-positions was used) ...', 'Parameter --timerange detected: 1510694220-1510700340 ...', f'Using data directory: {testdatadir} ...', diff --git a/tests/optimize/test_edge_cli.py b/tests/optimize/test_edge_cli.py index a5e468542..acec51f66 100644 --- a/tests/optimize/test_edge_cli.py +++ b/tests/optimize/test_edge_cli.py @@ -29,7 +29,7 @@ def test_setup_optimize_configuration_without_arguments(mocker, default_conf, ca assert 'pair_whitelist' in config['exchange'] assert 'datadir' in config assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config + assert 'timeframe' in config assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog) assert 'timerange' not in config @@ -48,7 +48,7 @@ def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> N '--config', 'config.json', '--strategy', 'DefaultStrategy', '--datadir', '/foo/bar', - '--ticker-interval', '1m', + '--timeframe', '1m', '--timerange', ':100', '--stoplosses=-0.01,-0.10,-0.001' ] @@ -62,8 +62,8 @@ def test_setup_edge_configuration_with_arguments(mocker, edge_conf, caplog) -> N assert 'datadir' in config assert config['runmode'] == RunMode.EDGE assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config - assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + assert 'timeframe' in config + assert log_has('Parameter -i/--timeframe detected ... Using timeframe: 1m ...', caplog) assert 'timerange' in config diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 90e047954..564725709 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -94,7 +94,7 @@ def test_setup_hyperopt_configuration_without_arguments(mocker, default_conf, ca assert 'pair_whitelist' in config['exchange'] assert 'datadir' in config assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config + assert 'timeframe' in config assert not log_has_re('Parameter -i/--ticker-interval detected .*', caplog) assert 'position_stacking' not in config @@ -117,7 +117,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', '--datadir', '/foo/bar', - '--ticker-interval', '1m', + '--timeframe', '1m', '--timerange', ':100', '--enable-position-stacking', '--disable-max-market-positions', @@ -136,8 +136,8 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo assert config['runmode'] == RunMode.HYPEROPT assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config - assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + assert 'timeframe' in config + assert log_has('Parameter -i/--timeframe detected ... Using timeframe: 1m ...', caplog) assert 'position_stacking' in config @@ -197,7 +197,8 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None: "Using populate_sell_trend from the strategy.", caplog) assert log_has("Hyperopt class does not provide populate_buy_trend() method. " "Using populate_buy_trend from the strategy.", caplog) - assert hasattr(x, "ticker_interval") + assert hasattr(x, "ticker_interval") # DEPRECATED + assert hasattr(x, "timeframe") def test_hyperoptresolver_wrongname(mocker, default_conf, caplog) -> None: @@ -544,7 +545,7 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: ) patch_exchange(mocker) # Co-test loading timeframe from strategy - del default_conf['ticker_interval'] + del default_conf['timeframe'] default_conf.update({'config': 'config.json.example', 'hyperopt': 'DefaultHyperOpt', 'epochs': 1, diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 88c82c5ea..0ffbaa72a 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -70,6 +70,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'max_rate': ANY, 'strategy': ANY, 'ticker_interval': ANY, + 'timeframe': ANY, 'open_order_id': ANY, 'close_date': None, 'close_date_hum': None, @@ -132,6 +133,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'max_rate': ANY, 'strategy': ANY, 'ticker_interval': ANY, + 'timeframe': ANY, 'open_order_id': ANY, 'close_date': None, 'close_date_hum': None, diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index a6d38cc9f..8e73eacf8 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -323,6 +323,7 @@ def test_api_show_config(botclient, mocker): assert 'dry_run' in rc.json assert rc.json['exchange'] == 'bittrex' assert rc.json['ticker_interval'] == '5m' + assert rc.json['timeframe'] == '5m' assert rc.json['state'] == 'running' assert not rc.json['trailing_stop'] assert 'bid_strategy' in rc.json @@ -567,6 +568,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets): 'sell_order_status': None, 'strategy': 'DefaultStrategy', 'ticker_interval': 5, + 'timeframe': 5, 'exchange': 'bittrex', }] @@ -690,6 +692,7 @@ def test_api_forcebuy(botclient, mocker, fee): 'sell_order_status': None, 'strategy': None, 'ticker_interval': None, + 'timeframe': None, 'exchange': 'bittrex', } diff --git a/tests/strategy/strats/default_strategy.py b/tests/strategy/strats/default_strategy.py index 7ea55d3f9..98842ff7c 100644 --- a/tests/strategy/strats/default_strategy.py +++ b/tests/strategy/strats/default_strategy.py @@ -29,7 +29,7 @@ class DefaultStrategy(IStrategy): stoploss = -0.10 # Optimal ticker interval for the strategy - ticker_interval = '5m' + timeframe = '5m' # Optional order type mapping order_types = { diff --git a/tests/strategy/strats/legacy_strategy.py b/tests/strategy/strats/legacy_strategy.py index 89ce3f8cb..9cbce0ad5 100644 --- a/tests/strategy/strats/legacy_strategy.py +++ b/tests/strategy/strats/legacy_strategy.py @@ -31,6 +31,7 @@ class TestStrategyLegacy(IStrategy): stoploss = -0.10 # Optimal ticker interval for the strategy + # Keep the legacy value here to test compatibility ticker_interval = '5m' def populate_indicators(self, dataframe: DataFrame) -> DataFrame: diff --git a/tests/strategy/test_default_strategy.py b/tests/strategy/test_default_strategy.py index 0b8ea9f85..1b1648db9 100644 --- a/tests/strategy/test_default_strategy.py +++ b/tests/strategy/test_default_strategy.py @@ -6,7 +6,7 @@ from .strats.default_strategy import DefaultStrategy def test_default_strategy_structure(): assert hasattr(DefaultStrategy, 'minimal_roi') assert hasattr(DefaultStrategy, 'stoploss') - assert hasattr(DefaultStrategy, 'ticker_interval') + assert hasattr(DefaultStrategy, 'timeframe') assert hasattr(DefaultStrategy, 'populate_indicators') assert hasattr(DefaultStrategy, 'populate_buy_trend') assert hasattr(DefaultStrategy, 'populate_sell_trend') @@ -18,7 +18,7 @@ def test_default_strategy(result): metadata = {'pair': 'ETH/BTC'} assert type(strategy.minimal_roi) is dict assert type(strategy.stoploss) is float - assert type(strategy.ticker_interval) is str + assert type(strategy.timeframe) is str indicators = strategy.populate_indicators(result, metadata) assert type(indicators) is DataFrame assert type(strategy.populate_buy_trend(indicators, metadata)) is DataFrame diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index e5539099b..59b4d5902 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -54,12 +54,12 @@ def test_returns_latest_signal(mocker, default_conf, ohlcv_history): def test_get_signal_empty(default_conf, mocker, caplog): - assert (False, False) == _STRATEGY.get_signal('foo', default_conf['ticker_interval'], + assert (False, False) == _STRATEGY.get_signal('foo', default_conf['timeframe'], DataFrame()) assert log_has('Empty candle (OHLCV) data for pair foo', caplog) caplog.clear() - assert (False, False) == _STRATEGY.get_signal('bar', default_conf['ticker_interval'], + assert (False, False) == _STRATEGY.get_signal('bar', default_conf['timeframe'], []) assert log_has('Empty candle (OHLCV) data for pair bar', caplog) @@ -70,7 +70,7 @@ def test_get_signal_exception_valueerror(default_conf, mocker, caplog, ohlcv_his _STRATEGY, '_analyze_ticker_internal', side_effect=ValueError('xyz') ) - assert (False, False) == _STRATEGY.get_signal('foo', default_conf['ticker_interval'], + assert (False, False) == _STRATEGY.get_signal('foo', default_conf['timeframe'], ohlcv_history) assert log_has_re(r'Strategy caused the following exception: xyz.*', caplog) @@ -83,7 +83,7 @@ def test_get_signal_empty_dataframe(default_conf, mocker, caplog, ohlcv_history) ) mocker.patch.object(_STRATEGY, 'assert_df') - assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['ticker_interval'], + assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['timeframe'], ohlcv_history) assert log_has('Empty dataframe for pair xyz', caplog) @@ -104,7 +104,7 @@ def test_get_signal_old_dataframe(default_conf, mocker, caplog, ohlcv_history): return_value=mocked_history ) mocker.patch.object(_STRATEGY, 'assert_df') - assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['ticker_interval'], + assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['timeframe'], ohlcv_history) assert log_has('Outdated history for pair xyz. Last tick is 16 minutes old', caplog) @@ -124,7 +124,7 @@ def test_assert_df_raise(default_conf, mocker, caplog, ohlcv_history): _STRATEGY, 'assert_df', side_effect=StrategyError('Dataframe returned...') ) - assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['ticker_interval'], + assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['timeframe'], ohlcv_history) assert log_has('Unable to analyze candle (OHLCV) data for pair xyz: Dataframe returned...', caplog) diff --git a/tests/strategy/test_strategy.py b/tests/strategy/test_strategy.py index 13ca68bf0..240f3d8ec 100644 --- a/tests/strategy/test_strategy.py +++ b/tests/strategy/test_strategy.py @@ -105,8 +105,9 @@ def test_strategy(result, default_conf): assert strategy.stoploss == -0.10 assert default_conf['stoploss'] == -0.10 + assert strategy.timeframe == '5m' assert strategy.ticker_interval == '5m' - assert default_conf['ticker_interval'] == '5m' + assert default_conf['timeframe'] == '5m' df_indicators = strategy.advise_indicators(result, metadata=metadata) assert 'adx' in df_indicators @@ -176,19 +177,19 @@ def test_strategy_override_trailing_stop_positive(caplog, default_conf): caplog) -def test_strategy_override_ticker_interval(caplog, default_conf): +def test_strategy_override_timeframe(caplog, default_conf): caplog.set_level(logging.INFO) default_conf.update({ 'strategy': 'DefaultStrategy', - 'ticker_interval': 60, + 'timeframe': 60, 'stake_currency': 'ETH' }) strategy = StrategyResolver.load_strategy(default_conf) - assert strategy.ticker_interval == 60 + assert strategy.timeframe == 60 assert strategy.stake_currency == 'ETH' - assert log_has("Override strategy 'ticker_interval' with value in config file: 60.", + assert log_has("Override strategy 'timeframe' with value in config file: 60.", caplog) @@ -357,8 +358,9 @@ def test_deprecate_populate_indicators(result, default_conf): @pytest.mark.filterwarnings("ignore:deprecated") -def test_call_deprecated_function(result, monkeypatch, default_conf): +def test_call_deprecated_function(result, monkeypatch, default_conf, caplog): default_location = Path(__file__).parent / "strats" + del default_conf['timeframe'] default_conf.update({'strategy': 'TestStrategyLegacy', 'strategy_path': default_location}) strategy = StrategyResolver.load_strategy(default_conf) @@ -369,6 +371,8 @@ def test_call_deprecated_function(result, monkeypatch, default_conf): assert strategy._buy_fun_len == 2 assert strategy._sell_fun_len == 2 assert strategy.INTERFACE_VERSION == 1 + assert strategy.timeframe == '5m' + assert strategy.ticker_interval == '5m' indicator_df = strategy.advise_indicators(result, metadata=metadata) assert isinstance(indicator_df, DataFrame) @@ -382,6 +386,9 @@ def test_call_deprecated_function(result, monkeypatch, default_conf): assert isinstance(selldf, DataFrame) assert 'sell' in selldf + assert log_has("DEPRECATED: Please migrate to using 'timeframe' instead of 'ticker_interval'.", + caplog) + def test_strategy_interface_versioning(result, monkeypatch, default_conf): default_conf.update({'strategy': 'DefaultStrategy'}) diff --git a/tests/test_arguments.py b/tests/test_arguments.py index 0052a61d0..457683598 100644 --- a/tests/test_arguments.py +++ b/tests/test_arguments.py @@ -131,7 +131,7 @@ def test_parse_args_backtesting_custom() -> None: assert call_args["verbosity"] == 0 assert call_args["command"] == 'backtesting' assert call_args["func"] is not None - assert call_args["ticker_interval"] == '1m' + assert call_args["timeframe"] == '1m' assert type(call_args["strategy_list"]) is list assert len(call_args["strategy_list"]) == 2 diff --git a/tests/test_configuration.py b/tests/test_configuration.py index dcb5e2ed0..689e62ab9 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -87,7 +87,7 @@ def test_load_config_file_error_range(default_conf, mocker, caplog) -> None: assert isinstance(x, str) assert (x == '{"max_open_trades": 1, "stake_currency": "BTC", ' '"stake_amount": .001, "fiat_display_currency": "USD", ' - '"ticker_interval": "5m", "dry_run": true, ') + '"timeframe": "5m", "dry_run": true, "cance') def test__args_to_config(caplog): @@ -401,8 +401,8 @@ def test_setup_configuration_without_arguments(mocker, default_conf, caplog) -> assert 'datadir' in config assert 'user_data_dir' in config assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config - assert not log_has('Parameter -i/--ticker-interval detected ...', caplog) + assert 'timeframe' in config + assert not log_has('Parameter -i/--timeframe detected ...', caplog) assert 'position_stacking' not in config assert not log_has('Parameter --enable-position-stacking detected ...', caplog) @@ -448,8 +448,8 @@ def test_setup_configuration_with_arguments(mocker, default_conf, caplog) -> Non assert log_has('Using user-data directory: {} ...'.format(Path("/tmp/freqtrade")), caplog) assert 'user_data_dir' in config - assert 'ticker_interval' in config - assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + assert 'timeframe' in config + assert log_has('Parameter -i/--timeframe detected ... Using timeframe: 1m ...', caplog) assert 'position_stacking' in config @@ -494,8 +494,8 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non assert 'pair_whitelist' in config['exchange'] assert 'datadir' in config assert log_has('Using data directory: {} ...'.format(config['datadir']), caplog) - assert 'ticker_interval' in config - assert log_has('Parameter -i/--ticker-interval detected ... Using ticker_interval: 1m ...', + assert 'timeframe' in config + assert log_has('Parameter -i/--timeframe detected ... Using timeframe: 1m ...', caplog) assert 'strategy_list' in config @@ -1140,3 +1140,15 @@ def test_process_deprecated_setting(mocker, default_conf, caplog): 'sectionB', 'deprecated_setting') assert not log_has_re('DEPRECATED', caplog) assert default_conf['sectionA']['new_setting'] == 'valA' + + +def test_process_deprecated_ticker_interval(mocker, default_conf, caplog): + message = "DEPRECATED: Please use 'timeframe' instead of 'ticker_interval." + process_temporary_deprecated_settings(default_conf) + assert not log_has(message, caplog) + + del default_conf['timeframe'] + default_conf['ticker_interval'] = '15m' + process_temporary_deprecated_settings(default_conf) + assert log_has(message, caplog) + assert default_conf['ticker_interval'] == '15m' diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index dc5a5c7d3..5d83c893e 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -924,7 +924,7 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None: assert refresh_mock.call_count == 1 assert ("BTC/ETH", "1m") in refresh_mock.call_args[0][0] assert ("ETH/USDT", "1h") in refresh_mock.call_args[0][0] - assert ("ETH/BTC", default_conf["ticker_interval"]) in refresh_mock.call_args[0][0] + assert ("ETH/BTC", default_conf["timeframe"]) in refresh_mock.call_args[0][0] @pytest.mark.parametrize("side,ask,bid,last,last_ab,expected", [ diff --git a/tests/test_main.py b/tests/test_main.py index 48cc47104..d5309ae3f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -35,12 +35,12 @@ def test_parse_args_backtesting(mocker) -> None: main(['backtesting']) assert backtesting_mock.call_count == 1 call_args = backtesting_mock.call_args[0][0] - assert call_args["config"] == ['config.json'] - assert call_args["verbosity"] == 0 - assert call_args["command"] == 'backtesting' - assert call_args["func"] is not None - assert callable(call_args["func"]) - assert call_args["ticker_interval"] is None + assert call_args['config'] == ['config.json'] + assert call_args['verbosity'] == 0 + assert call_args['command'] == 'backtesting' + assert call_args['func'] is not None + assert callable(call_args['func']) + assert call_args['timeframe'] is None def test_main_start_hyperopt(mocker) -> None: diff --git a/tests/test_persistence.py b/tests/test_persistence.py index fe2912486..8dd27e53a 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -469,6 +469,7 @@ def test_migrate_old(mocker, default_conf, fee): assert trade.fee_open_currency is None assert trade.fee_close_cost is None assert trade.fee_close_currency is None + assert trade.timeframe is None trade = Trade.query.filter(Trade.id == 2).first() assert trade.close_rate is not None @@ -512,11 +513,11 @@ def test_migrate_new(mocker, default_conf, fee, caplog): );""" insert_table_old = """INSERT INTO trades (exchange, pair, is_open, fee, open_rate, stake_amount, amount, open_date, - stop_loss, initial_stop_loss, max_rate) + stop_loss, initial_stop_loss, max_rate, ticker_interval) VALUES ('binance', 'ETC/BTC', 1, {fee}, 0.00258580, {stake}, {amount}, '2019-11-28 12:44:24.000000', - 0.0, 0.0, 0.0) + 0.0, 0.0, 0.0, '5m') """.format(fee=fee.return_value, stake=default_conf.get("stake_amount"), amount=amount @@ -554,7 +555,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): assert trade.initial_stop_loss == 0.0 assert trade.sell_reason is None assert trade.strategy is None - assert trade.ticker_interval is None + assert trade.timeframe == '5m' assert trade.stoploss_order_id is None assert trade.stoploss_last_update is None assert log_has("trying trades_bak1", caplog) @@ -776,6 +777,7 @@ def test_to_json(default_conf, fee): 'max_rate': None, 'strategy': None, 'ticker_interval': None, + 'timeframe': None, 'exchange': 'bittrex', } @@ -837,6 +839,7 @@ def test_to_json(default_conf, fee): 'sell_order_status': None, 'strategy': None, 'ticker_interval': None, + 'timeframe': None, 'exchange': 'bittrex', } diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 150329c52..05805eb24 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -47,7 +47,7 @@ def generate_empty_figure(): def test_init_plotscript(default_conf, mocker, testdatadir): default_conf['timerange'] = "20180110-20180112" default_conf['trade_source'] = "file" - default_conf['ticker_interval'] = "5m" + default_conf['timeframe'] = "5m" default_conf["datadir"] = testdatadir default_conf['exportfilename'] = testdatadir / "backtest-result_test.json" ret = init_plotscript(default_conf) diff --git a/tests/testdata/backtest-result_test copy.json b/tests/testdata/backtest-result_test copy.json new file mode 100644 index 000000000..0395830d4 --- /dev/null +++ b/tests/testdata/backtest-result_test copy.json @@ -0,0 +1,7 @@ +{ + "ASDF": {, + "trades": [], + "metrics":[], + } +} +[["TRX/BTC",0.03990025,1515568500.0,1515568800.0,27,5,9.64e-05,0.00010074887218045112,false,"roi"],["ADA/BTC",0.03990025,1515568500.0,1515569400.0,27,15,4.756e-05,4.9705563909774425e-05,false,"roi"],["XLM/BTC",0.03990025,1515569100.0,1515569700.0,29,10,3.339e-05,3.489631578947368e-05,false,"roi"],["TRX/BTC",0.03990025,1515569100.0,1515570000.0,29,15,9.696e-05,0.00010133413533834584,false,"roi"],["ETH/BTC",-0.0,1515569700.0,1515573300.0,31,60,0.0943,0.09477268170426063,false,"roi"],["XMR/BTC",0.00997506,1515570000.0,1515571800.0,32,30,0.02719607,0.02760503345864661,false,"roi"],["ZEC/BTC",0.0,1515572100.0,1515578100.0,39,100,0.04634952,0.046581848421052625,false,"roi"],["NXT/BTC",-0.0,1515595500.0,1515599400.0,117,65,3.066e-05,3.081368421052631e-05,false,"roi"],["LTC/BTC",0.0,1515602100.0,1515604500.0,139,40,0.0168999,0.016984611278195488,false,"roi"],["ETH/BTC",-0.0,1515602400.0,1515604800.0,140,40,0.09132568,0.0917834528320802,false,"roi"],["ETH/BTC",-0.0,1515610200.0,1515613500.0,166,55,0.08898003,0.08942604518796991,false,"roi"],["ETH/BTC",0.0,1515622500.0,1515625200.0,207,45,0.08560008,0.08602915308270676,false,"roi"],["ETC/BTC",0.00997506,1515624600.0,1515626400.0,214,30,0.00249083,0.0025282860902255634,false,"roi"],["NXT/BTC",-0.0,1515626100.0,1515629700.0,219,60,3.022e-05,3.037147869674185e-05,false,"roi"],["ETC/BTC",0.01995012,1515627600.0,1515629100.0,224,25,0.002437,0.0024980776942355883,false,"roi"],["ZEC/BTC",0.00997506,1515628800.0,1515630900.0,228,35,0.04771803,0.04843559436090225,false,"roi"],["XLM/BTC",-0.10448878,1515642000.0,1515644700.0,272,45,3.651e-05,3.2859000000000005e-05,false,"stop_loss"],["ETH/BTC",0.00997506,1515642900.0,1515644700.0,275,30,0.08824105,0.08956798308270676,false,"roi"],["ETC/BTC",-0.0,1515643200.0,1515646200.0,276,50,0.00243,0.002442180451127819,false,"roi"],["ZEC/BTC",0.01995012,1515645000.0,1515646500.0,282,25,0.04545064,0.046589753784461146,false,"roi"],["XLM/BTC",0.01995012,1515645000.0,1515646200.0,282,20,3.372e-05,3.456511278195488e-05,false,"roi"],["XMR/BTC",0.01995012,1515646500.0,1515647700.0,287,20,0.02644,0.02710265664160401,false,"roi"],["ETH/BTC",-0.0,1515669600.0,1515672000.0,364,40,0.08812,0.08856170426065162,false,"roi"],["XMR/BTC",-0.0,1515670500.0,1515672900.0,367,40,0.02683577,0.026970285137844607,false,"roi"],["ADA/BTC",0.01995012,1515679200.0,1515680700.0,396,25,4.919e-05,5.04228320802005e-05,false,"roi"],["ETH/BTC",-0.0,1515698700.0,1515702900.0,461,70,0.08784896,0.08828930566416039,false,"roi"],["ADA/BTC",-0.0,1515710100.0,1515713400.0,499,55,5.105e-05,5.130588972431077e-05,false,"roi"],["XLM/BTC",0.00997506,1515711300.0,1515713100.0,503,30,3.96e-05,4.019548872180451e-05,false,"roi"],["NXT/BTC",-0.0,1515711300.0,1515713700.0,503,40,2.885e-05,2.899461152882205e-05,false,"roi"],["XMR/BTC",0.00997506,1515713400.0,1515715500.0,510,35,0.02645,0.026847744360902256,false,"roi"],["ZEC/BTC",-0.0,1515714900.0,1515719700.0,515,80,0.048,0.04824060150375939,false,"roi"],["XLM/BTC",0.01995012,1515791700.0,1515793200.0,771,25,4.692e-05,4.809593984962405e-05,false,"roi"],["ETC/BTC",-0.0,1515804900.0,1515824400.0,815,325,0.00256966,0.0025825405012531327,false,"roi"],["ADA/BTC",0.0,1515840900.0,1515843300.0,935,40,6.262e-05,6.293388471177944e-05,false,"roi"],["XLM/BTC",0.0,1515848700.0,1516025400.0,961,2945,4.73e-05,4.753709273182957e-05,false,"roi"],["ADA/BTC",-0.0,1515850200.0,1515854700.0,966,75,6.063e-05,6.0933909774436085e-05,false,"roi"],["TRX/BTC",-0.0,1515850800.0,1515886200.0,968,590,0.00011082,0.00011137548872180449,false,"roi"],["ADA/BTC",-0.0,1515856500.0,1515858900.0,987,40,5.93e-05,5.9597243107769415e-05,false,"roi"],["ZEC/BTC",-0.0,1515861000.0,1515863400.0,1002,40,0.04850003,0.04874313791979949,false,"roi"],["ETH/BTC",-0.0,1515881100.0,1515911100.0,1069,500,0.09825019,0.09874267215538847,false,"roi"],["ADA/BTC",0.0,1515889200.0,1515970500.0,1096,1355,6.018e-05,6.048165413533834e-05,false,"roi"],["ETH/BTC",-0.0,1515933900.0,1515936300.0,1245,40,0.09758999,0.0980791628822055,false,"roi"],["ETC/BTC",0.00997506,1515943800.0,1515945600.0,1278,30,0.00311,0.0031567669172932328,false,"roi"],["ETC/BTC",-0.0,1515962700.0,1515968100.0,1341,90,0.00312401,0.003139669197994987,false,"roi"],["LTC/BTC",0.0,1515972900.0,1515976200.0,1375,55,0.0174679,0.017555458395989976,false,"roi"],["DASH/BTC",-0.0,1515973500.0,1515975900.0,1377,40,0.07346846,0.07383672295739348,false,"roi"],["ETH/BTC",-0.0,1515983100.0,1515985500.0,1409,40,0.097994,0.09848519799498745,false,"roi"],["ETH/BTC",-0.0,1516000800.0,1516003200.0,1468,40,0.09659,0.09707416040100249,false,"roi"],["TRX/BTC",0.00997506,1516004400.0,1516006500.0,1480,35,9.987e-05,0.00010137180451127818,false,"roi"],["ETH/BTC",0.0,1516018200.0,1516071000.0,1526,880,0.0948969,0.09537257368421052,false,"roi"],["DASH/BTC",-0.0,1516025400.0,1516038000.0,1550,210,0.071,0.07135588972431077,false,"roi"],["ZEC/BTC",-0.0,1516026600.0,1516029000.0,1554,40,0.04600501,0.046235611553884705,false,"roi"],["TRX/BTC",-0.0,1516039800.0,1516044300.0,1598,75,9.438e-05,9.485308270676691e-05,false,"roi"],["XMR/BTC",-0.0,1516041300.0,1516043700.0,1603,40,0.03040001,0.030552391002506264,false,"roi"],["ADA/BTC",-0.10448878,1516047900.0,1516091100.0,1625,720,5.837e-05,5.2533e-05,false,"stop_loss"],["ZEC/BTC",-0.0,1516048800.0,1516053600.0,1628,80,0.046036,0.04626675689223057,false,"roi"],["ETC/BTC",-0.0,1516062600.0,1516065000.0,1674,40,0.0028685,0.0028828784461152877,false,"roi"],["DASH/BTC",0.0,1516065300.0,1516070100.0,1683,80,0.06731755,0.0676549813283208,false,"roi"],["ETH/BTC",0.0,1516088700.0,1516092000.0,1761,55,0.09217614,0.09263817578947368,false,"roi"],["LTC/BTC",0.01995012,1516091700.0,1516092900.0,1771,20,0.0165,0.016913533834586467,false,"roi"],["TRX/BTC",0.03990025,1516091700.0,1516092000.0,1771,5,7.953e-05,8.311781954887218e-05,false,"roi"],["ZEC/BTC",-0.0,1516092300.0,1516096200.0,1773,65,0.045202,0.04542857644110275,false,"roi"],["ADA/BTC",0.00997506,1516094100.0,1516095900.0,1779,30,5.248e-05,5.326917293233082e-05,false,"roi"],["XMR/BTC",0.0,1516094100.0,1516096500.0,1779,40,0.02892318,0.02906815834586466,false,"roi"],["ADA/BTC",0.01995012,1516096200.0,1516097400.0,1786,20,5.158e-05,5.287273182957392e-05,false,"roi"],["ZEC/BTC",0.00997506,1516097100.0,1516099200.0,1789,35,0.04357584,0.044231115789473675,false,"roi"],["XMR/BTC",0.00997506,1516097100.0,1516098900.0,1789,30,0.02828232,0.02870761804511278,false,"roi"],["ADA/BTC",0.00997506,1516110300.0,1516112400.0,1833,35,5.362e-05,5.4426315789473676e-05,false,"roi"],["ADA/BTC",-0.0,1516123800.0,1516127100.0,1878,55,5.302e-05,5.328576441102756e-05,false,"roi"],["ETH/BTC",0.00997506,1516126500.0,1516128300.0,1887,30,0.09129999,0.09267292218045112,false,"roi"],["XLM/BTC",0.01995012,1516126500.0,1516127700.0,1887,20,3.808e-05,3.903438596491228e-05,false,"roi"],["XMR/BTC",0.00997506,1516129200.0,1516131000.0,1896,30,0.02811012,0.028532828571428567,false,"roi"],["ETC/BTC",-0.10448878,1516137900.0,1516141500.0,1925,60,0.00258379,0.002325411,false,"stop_loss"],["NXT/BTC",-0.10448878,1516137900.0,1516142700.0,1925,80,2.559e-05,2.3031e-05,false,"stop_loss"],["TRX/BTC",-0.10448878,1516138500.0,1516141500.0,1927,50,7.62e-05,6.858e-05,false,"stop_loss"],["LTC/BTC",0.03990025,1516141800.0,1516142400.0,1938,10,0.0151,0.015781203007518795,false,"roi"],["ETC/BTC",0.03990025,1516141800.0,1516142100.0,1938,5,0.00229844,0.002402129022556391,false,"roi"],["ETC/BTC",0.03990025,1516142400.0,1516142700.0,1940,5,0.00235676,0.00246308,false,"roi"],["DASH/BTC",0.01995012,1516142700.0,1516143900.0,1941,20,0.0630692,0.06464988170426066,false,"roi"],["NXT/BTC",0.03990025,1516143000.0,1516143300.0,1942,5,2.2e-05,2.2992481203007514e-05,false,"roi"],["ADA/BTC",0.00997506,1516159800.0,1516161600.0,1998,30,4.974e-05,5.048796992481203e-05,false,"roi"],["TRX/BTC",0.01995012,1516161300.0,1516162500.0,2003,20,7.108e-05,7.28614536340852e-05,false,"roi"],["ZEC/BTC",-0.0,1516181700.0,1516184100.0,2071,40,0.04327,0.04348689223057644,false,"roi"],["ADA/BTC",-0.0,1516184400.0,1516208400.0,2080,400,4.997e-05,5.022047619047618e-05,false,"roi"],["DASH/BTC",-0.0,1516185000.0,1516188300.0,2082,55,0.06836818,0.06871087764411027,false,"roi"],["XLM/BTC",-0.0,1516185000.0,1516187400.0,2082,40,3.63e-05,3.648195488721804e-05,false,"roi"],["XMR/BTC",-0.0,1516192200.0,1516226700.0,2106,575,0.0281,0.02824085213032581,false,"roi"],["ETH/BTC",-0.0,1516192500.0,1516208100.0,2107,260,0.08651001,0.08694364413533832,false,"roi"],["ADA/BTC",-0.0,1516251600.0,1516254900.0,2304,55,5.633e-05,5.6612355889724306e-05,false,"roi"],["DASH/BTC",0.00997506,1516252800.0,1516254900.0,2308,35,0.06988494,0.07093584135338346,false,"roi"],["ADA/BTC",-0.0,1516260900.0,1516263300.0,2335,40,5.545e-05,5.572794486215538e-05,false,"roi"],["LTC/BTC",-0.0,1516266000.0,1516268400.0,2352,40,0.01633527,0.016417151052631574,false,"roi"],["ETC/BTC",-0.0,1516293600.0,1516296000.0,2444,40,0.00269734,0.0027108605012531326,false,"roi"],["XLM/BTC",0.01995012,1516298700.0,1516300200.0,2461,25,4.475e-05,4.587155388471177e-05,false,"roi"],["NXT/BTC",0.00997506,1516299900.0,1516301700.0,2465,30,2.79e-05,2.8319548872180444e-05,false,"roi"],["ZEC/BTC",0.0,1516306200.0,1516308600.0,2486,40,0.04439326,0.04461578260651629,false,"roi"],["XLM/BTC",0.0,1516311000.0,1516322100.0,2502,185,4.49e-05,4.51250626566416e-05,false,"roi"],["XMR/BTC",-0.0,1516312500.0,1516338300.0,2507,430,0.02855,0.028693107769423555,false,"roi"],["ADA/BTC",0.0,1516313400.0,1516315800.0,2510,40,5.796e-05,5.8250526315789473e-05,false,"roi"],["ZEC/BTC",0.0,1516319400.0,1516321800.0,2530,40,0.04340323,0.04362079005012531,false,"roi"],["ZEC/BTC",0.0,1516380300.0,1516383300.0,2733,50,0.04454455,0.04476783095238095,false,"roi"],["ADA/BTC",-0.0,1516382100.0,1516391700.0,2739,160,5.62e-05,5.648170426065162e-05,false,"roi"],["XLM/BTC",-0.0,1516382400.0,1516392900.0,2740,175,4.339e-05,4.360749373433584e-05,false,"roi"],["TRX/BTC",0.0,1516423500.0,1516469700.0,2877,770,0.0001009,0.00010140576441102757,false,"roi"],["ETC/BTC",-0.0,1516423800.0,1516461300.0,2878,625,0.00270505,0.002718609147869674,false,"roi"],["XMR/BTC",-0.0,1516423800.0,1516431600.0,2878,130,0.03000002,0.030150396040100245,false,"roi"],["ADA/BTC",-0.0,1516438800.0,1516441200.0,2928,40,5.46e-05,5.4873684210526304e-05,false,"roi"],["XMR/BTC",-0.10448878,1516472700.0,1516852200.0,3041,6325,0.03082222,0.027739998000000002,false,"stop_loss"],["ETH/BTC",-0.0,1516487100.0,1516490100.0,3089,50,0.08969999,0.09014961401002504,false,"roi"],["LTC/BTC",0.0,1516503000.0,1516545000.0,3142,700,0.01632501,0.01640683962406015,false,"roi"],["DASH/BTC",-0.0,1516530000.0,1516532400.0,3232,40,0.070538,0.07089157393483708,false,"roi"],["ADA/BTC",-0.0,1516549800.0,1516560300.0,3298,175,5.301e-05,5.3275714285714276e-05,false,"roi"],["XLM/BTC",0.0,1516551600.0,1516554000.0,3304,40,3.955e-05,3.9748245614035085e-05,false,"roi"],["ETC/BTC",0.00997506,1516569300.0,1516571100.0,3363,30,0.00258505,0.002623922932330827,false,"roi"],["XLM/BTC",-0.0,1516569300.0,1516571700.0,3363,40,3.903e-05,3.922563909774435e-05,false,"roi"],["ADA/BTC",-0.0,1516581300.0,1516617300.0,3403,600,5.236e-05,5.262245614035087e-05,false,"roi"],["TRX/BTC",0.0,1516584600.0,1516587000.0,3414,40,9.028e-05,9.073253132832079e-05,false,"roi"],["ETC/BTC",-0.0,1516623900.0,1516631700.0,3545,130,0.002687,0.002700468671679198,false,"roi"],["XLM/BTC",-0.0,1516626900.0,1516629300.0,3555,40,4.168e-05,4.1888922305764405e-05,false,"roi"],["TRX/BTC",0.00997506,1516629600.0,1516631400.0,3564,30,8.821e-05,8.953646616541353e-05,false,"roi"],["ADA/BTC",-0.0,1516636500.0,1516639200.0,3587,45,5.172e-05,5.1979248120300745e-05,false,"roi"],["NXT/BTC",0.01995012,1516637100.0,1516638300.0,3589,20,3.026e-05,3.101839598997494e-05,false,"roi"],["DASH/BTC",0.0,1516650600.0,1516666200.0,3634,260,0.07064,0.07099408521303258,false,"roi"],["LTC/BTC",0.0,1516656300.0,1516658700.0,3653,40,0.01644483,0.01652726022556391,false,"roi"],["XLM/BTC",0.00997506,1516665900.0,1516667700.0,3685,30,4.331e-05,4.3961278195488714e-05,false,"roi"],["NXT/BTC",0.01995012,1516672200.0,1516673700.0,3706,25,3.2e-05,3.2802005012531326e-05,false,"roi"],["ETH/BTC",0.0,1516681500.0,1516684500.0,3737,50,0.09167706,0.09213659413533835,false,"roi"],["DASH/BTC",0.0,1516692900.0,1516698000.0,3775,85,0.0692498,0.06959691679197995,false,"roi"],["NXT/BTC",0.0,1516704600.0,1516712700.0,3814,135,3.182e-05,3.197949874686716e-05,false,"roi"],["ZEC/BTC",-0.0,1516705500.0,1516723500.0,3817,300,0.04088,0.04108491228070175,false,"roi"],["ADA/BTC",-0.0,1516719300.0,1516721700.0,3863,40,5.15e-05,5.175814536340851e-05,false,"roi"],["ETH/BTC",0.0,1516725300.0,1516752300.0,3883,450,0.09071698,0.09117170170426064,false,"roi"],["NXT/BTC",-0.0,1516728300.0,1516733100.0,3893,80,3.128e-05,3.1436791979949865e-05,false,"roi"],["TRX/BTC",-0.0,1516738500.0,1516744800.0,3927,105,9.555e-05,9.602894736842104e-05,false,"roi"],["ZEC/BTC",-0.0,1516746600.0,1516749000.0,3954,40,0.04080001,0.041004521328320796,false,"roi"],["ADA/BTC",-0.0,1516751400.0,1516764900.0,3970,225,5.163e-05,5.1888796992481196e-05,false,"roi"],["ZEC/BTC",0.0,1516753200.0,1516758600.0,3976,90,0.04040781,0.04061035541353383,false,"roi"],["ADA/BTC",-0.0,1516776300.0,1516778700.0,4053,40,5.132e-05,5.157724310776942e-05,false,"roi"],["ADA/BTC",0.03990025,1516803300.0,1516803900.0,4143,10,5.198e-05,5.432496240601503e-05,false,"roi"],["NXT/BTC",-0.0,1516805400.0,1516811700.0,4150,105,3.054e-05,3.069308270676692e-05,false,"roi"],["TRX/BTC",0.0,1516806600.0,1516810500.0,4154,65,9.263e-05,9.309431077694235e-05,false,"roi"],["ADA/BTC",-0.0,1516833600.0,1516836300.0,4244,45,5.514e-05,5.5416390977443596e-05,false,"roi"],["XLM/BTC",0.0,1516841400.0,1516843800.0,4270,40,4.921e-05,4.9456666666666664e-05,false,"roi"],["ETC/BTC",0.0,1516868100.0,1516882500.0,4359,240,0.0026,0.002613032581453634,false,"roi"],["XMR/BTC",-0.0,1516875900.0,1516896900.0,4385,350,0.02799871,0.028139054411027563,false,"roi"],["ZEC/BTC",-0.0,1516878000.0,1516880700.0,4392,45,0.04078902,0.0409934762406015,false,"roi"],["NXT/BTC",-0.0,1516885500.0,1516887900.0,4417,40,2.89e-05,2.904486215538847e-05,false,"roi"],["ZEC/BTC",-0.0,1516886400.0,1516889100.0,4420,45,0.041103,0.041309030075187964,false,"roi"],["XLM/BTC",0.00997506,1516895100.0,1516896900.0,4449,30,5.428e-05,5.5096240601503756e-05,false,"roi"],["XLM/BTC",-0.0,1516902300.0,1516922100.0,4473,330,5.414e-05,5.441137844611528e-05,false,"roi"],["ZEC/BTC",-0.0,1516914900.0,1516917300.0,4515,40,0.04140777,0.0416153277443609,false,"roi"],["ETC/BTC",0.0,1516932300.0,1516934700.0,4573,40,0.00254309,0.002555837318295739,false,"roi"],["ADA/BTC",-0.0,1516935300.0,1516979400.0,4583,735,5.607e-05,5.6351052631578935e-05,false,"roi"],["ETC/BTC",0.0,1516947000.0,1516958700.0,4622,195,0.00253806,0.0025507821052631577,false,"roi"],["ZEC/BTC",-0.0,1516951500.0,1516960500.0,4637,150,0.0415,0.04170802005012531,false,"roi"],["XLM/BTC",0.00997506,1516960500.0,1516962300.0,4667,30,5.321e-05,5.401015037593984e-05,false,"roi"],["XMR/BTC",-0.0,1516982700.0,1516985100.0,4741,40,0.02772046,0.02785940967418546,false,"roi"],["ETH/BTC",0.0,1517009700.0,1517012100.0,4831,40,0.09461341,0.09508766268170425,false,"roi"],["XLM/BTC",-0.0,1517013300.0,1517016600.0,4843,55,5.615e-05,5.643145363408521e-05,false,"roi"],["ADA/BTC",-0.07877175,1517013900.0,1517287500.0,4845,4560,5.556e-05,5.144e-05,true,"force_sell"],["DASH/BTC",-0.0,1517020200.0,1517052300.0,4866,535,0.06900001,0.06934587471177944,false,"roi"],["ETH/BTC",-0.0,1517034300.0,1517036700.0,4913,40,0.09449985,0.09497353345864659,false,"roi"],["ZEC/BTC",-0.04815133,1517046000.0,1517287200.0,4952,4020,0.0410697,0.03928809,true,"force_sell"],["XMR/BTC",-0.0,1517053500.0,1517056200.0,4977,45,0.0285,0.02864285714285714,false,"roi"],["XMR/BTC",-0.0,1517056500.0,1517066700.0,4987,170,0.02866372,0.02880739779448621,false,"roi"],["ETH/BTC",-0.0,1517068200.0,1517071800.0,5026,60,0.095381,0.09585910025062655,false,"roi"],["DASH/BTC",-0.0,1517072700.0,1517075100.0,5041,40,0.06759092,0.06792972160401002,false,"roi"],["ETC/BTC",-0.0,1517096400.0,1517101500.0,5120,85,0.00258501,0.002597967443609022,false,"roi"],["DASH/BTC",-0.0,1517106300.0,1517127000.0,5153,345,0.06698502,0.0673207845112782,false,"roi"],["DASH/BTC",-0.0,1517135100.0,1517157000.0,5249,365,0.0677177,0.06805713709273183,false,"roi"],["XLM/BTC",0.0,1517171700.0,1517175300.0,5371,60,5.215e-05,5.2411403508771925e-05,false,"roi"],["ETC/BTC",0.00997506,1517176800.0,1517178600.0,5388,30,0.00273809,0.002779264285714285,false,"roi"],["ETC/BTC",0.00997506,1517184000.0,1517185800.0,5412,30,0.00274632,0.002787618045112782,false,"roi"],["LTC/BTC",0.0,1517192100.0,1517194800.0,5439,45,0.01622478,0.016306107218045113,false,"roi"],["DASH/BTC",-0.0,1517195100.0,1517197500.0,5449,40,0.069,0.06934586466165413,false,"roi"],["TRX/BTC",-0.0,1517203200.0,1517208900.0,5476,95,8.755e-05,8.798884711779448e-05,false,"roi"],["DASH/BTC",-0.0,1517209200.0,1517253900.0,5496,745,0.06825763,0.06859977350877192,false,"roi"],["DASH/BTC",-0.0,1517255100.0,1517257500.0,5649,40,0.06713892,0.06747545593984962,false,"roi"],["TRX/BTC",-0.0199116,1517268600.0,1517287500.0,5694,315,8.934e-05,8.8e-05,true,"force_sell"]]