From ce5ba1bb6e8c5792ee3a0922e74bf57e7990bd60 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Fri, 15 Jan 2021 00:14:11 +0000 Subject: [PATCH 001/158] Adding Conda installation process --- docs/installation.md | 239 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 227 insertions(+), 12 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index a23399441..d5a564544 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -110,9 +110,9 @@ OS Specific steps are listed first, the [Common](#common) section below is neces This image comes with python3.7 preinstalled, making it easy to get freqtrade up and running. Tested using a Raspberry Pi 3 with the Raspbian Buster lite image, all updates applied. - - ``` bash + + ```bash sudo apt-get install python3-venv libatlas-base-dev cmake # Use pywheels.org to speed up installation sudo echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > tee /etc/pip.conf @@ -185,7 +185,7 @@ git checkout stable #### 4. Install python dependencies -``` bash +```bash python3 -m pip install --upgrade pip python3 -m pip install -e . ``` @@ -218,19 +218,234 @@ On Linux, as an optional post-installation task, you may wish to setup the bot t ------ -### Anaconda +## Conda (Miniconda or Anaconda) -Freqtrade can also be installed using Anaconda (or Miniconda). +Freqtrade can also be installed with Miniconda or Anaconda. +Conda is a package manager and virtual environment manager in one. +The purpose of installing Conda (Miniconda or Anaconda) is to automatically prepare and manage the extensive library dependencies of the Freqtrade program. -!!! Note - This requires the [ta-lib](#1-install-ta-lib) C-library to be installed first. See below. +You can start with any clean distribution of Debian-based Linux distributions, which includes Ubuntu Linux. +For other popular Linux distributions, see: https://distrowatch.com/ or https://www.ubuntupit.com/best-debian-based-linux-distributions/ -``` bash -conda env create -f environment.yml +Installation requirement: Your Linux is a Debian based distribution with bash terminal + +To get know more about Conda check : https://linuxnetmag.com/miniconda-vs-anaconda/ + +Shortly : Conda < Miniconda < Anaconda + +https://www.dunderdata.com/blog/anaconda-is-bloated-set-up-a-lean-robust-data-science-environment-with-miniconda-and-conda-forge + +The difference lies in the number of packages that need to be installed upfront: how heavy/light the installation is. Difference is like ~1:8. It is recommended to install Miniconda instead of Anaconda. + +#### 1. Instal Conda + +##### Download conda file: + +installation file of chosen distribution you can find here + +https://docs.conda.io/en/latest/miniconda.html + +##### Verify file integrity with SHA256 checksum: + +official SHA256 checksum can be found here + +https://docs.conda.io/en/latest/miniconda_hashes.html + +Navigate to the directory with your file, and run SHA256 checksum of your file, check with following command + +```bash +sha256sum ./Miniconda3-number-of-the-package ``` +both checksum suppose to match + +##### Install conda: + +While in directory with your file, install conda + +```bash +bash ./Miniconda3-number-of-the-package +``` + +Confirm with yes all questions + +After installation, it is mandatory to turn your terminal OFF and ON again. + +CTRL + D (close terminal), CTRL + ALT + T (open terminal) + +#### 2. Prepare Conda environment + + +enter the conda base environment: + +```bash +conda activate base +``` + +If you want, you can prevent the (base) conda environment from being activated automatically as well. + +```bash +conda config --set auto_activate_base false +``` + + +##### Change the channels with upgrades: + +Conda as a package manager can download new packages from "channels". The best developed Conda channel, is not the default channel and is called `conda-forge`. The code below switches to it. + +```bash +# adding forge +conda config --env --add channels conda-forge + +# make it strict +conda config --env --set channel_priority strict +``` + +You can check the status of conda with the following code. + +```bash +conda info +conda config --show channels +conda config --show channel_priority +``` + +#### 3. Freqtrade Conda Environment + +Now you have conda, but only base environment, + +```bash# download freqtrade +conda env list +``` + +It is time to setup environment of the Freqtrade itself: + + +Conda `create` command, installs all nested dependencies, for the selected libraries automatically + +general structure of installation command is: + +```bash +conda create -n [name of the environment] [python version] [packages] +``` + +so it can be + +```bash +conda create -n freqtrade-conda python=3.8 pandas numpy ta-lib git wheel virtualenv +``` + +or if you expect, to use later jupiter for [data-analysis](data-analysis.md), use + +```bash +conda create -n freqtrade-jupyter-conda python=3.8 pandas numpy ta-lib git wheel virtualenv jupyter +``` + +the same works for [docker](docker.md), for spyder and other useful programs. + +Further read on the topic: + +https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 + +https://metager.de/meta/meta.ger3?eingabe=ardsdatascience+guide+to+conda+environment + +!!! NOTE: +It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent package into the old environment, +takes less time than installing a large, heavy dependent package into the old environment. + +##### Enter/exit freqtrade-conda venv: + +to enter choosen conda environment + +```bash +conda activate freqtrade-conda + +``` + +to exit conda environment + +```bash +conda deactivate +``` + +#### 4. Freqtrade Instalation + +Within the newly created freqtrade-conda environment, download and install Freqtrade. To process --install command, may take a few minutes + +```bash +# download freqtrade +git clone https://github.com/freqtrade/freqtrade.git + +# enter downloaded directory 'freqtrade' +cd freqtrade + +# run setup +./setup.sh --install +``` + +Create virtual environment (yes, python3-venv environment, inside conda-environment), where Freqtrade program can run. + +Running python3-venv seems to be requirement of the Freqtrade program itself. + +```bash +# create venv environment, inside hidden directory /freqtrede/.env +python3 -m venv ./.env/ + +# run the python3-venv environment +source ./.env/bin/activate + +# install last required package +pip install -e . +``` + +##### pip install within conda, a reminder: + +The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. +However, they are rare + +That is, why the conda-forge channel is preferred: (and if no library is available in conda, you have to use pip) + +* more libraries are available (less need for pip) +* conda-forge works better with pip +* the libraries are newer + + +#### 5. You are ready + +You are ready to run, create the user directory and configuration file, run the program dry to verify that everything is working, and run a backtest to double check. + +```bash +freqtrade create-userdir --userdir user_data +freqtrade new-config --config config.json +freqtrade download-data -t 5m 15m 1h --days 100 +freqtrade trade --strategy SampleStrategy +freqtrade backtesting -s SampleStrategy +``` + +important shortcuts + +```bash +# activate base environment +conda activate + +# activate freqtrade-conda environment +conda activate freqtrade-conda + +#deactivate any conda environments +conda deactivate + +# list installed conda environments +conda env list + +# activation/deactivate the venv +source ./.env/bin/activate +deactivate +``` + +Happy trading! + + ----- -## Troubleshooting +## Troubleshooting ### MacOS installation error @@ -239,7 +454,7 @@ Newer versions of MacOS may have installation failed with errors like `error: co This error will require explicit installation of the SDK Headers, which are not installed by default in this version of MacOS. For MacOS 10.14, this can be accomplished with the below command. -``` bash +```bash open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg ``` @@ -252,7 +467,7 @@ The errors you'll see happen during installation and are related to the installa You can install the necessary libraries with the following command: -``` bash +```bash brew install hdf5 c-blosc ``` From a271c9e98ef68224ce5e75cd332fc7208fa12c47 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:24:22 +0000 Subject: [PATCH 002/158] Update installation.md --- docs/installation.md | 93 ++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 60 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index d5a564544..5b56afcaf 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -220,61 +220,38 @@ On Linux, as an optional post-installation task, you may wish to setup the bot t ## Conda (Miniconda or Anaconda) -Freqtrade can also be installed with Miniconda or Anaconda. -Conda is a package manager and virtual environment manager in one. -The purpose of installing Conda (Miniconda or Anaconda) is to automatically prepare and manage the extensive library dependencies of the Freqtrade program. +Freqtrade can also be installed with Miniconda or Anaconda. Conda (Miniconda or Anaconda) would automatically prepare and manage the extensive library-dependencies of the Freqtrade program. -You can start with any clean distribution of Debian-based Linux distributions, which includes Ubuntu Linux. -For other popular Linux distributions, see: https://distrowatch.com/ or https://www.ubuntupit.com/best-debian-based-linux-distributions/ +##### What is Conda? -Installation requirement: Your Linux is a Debian based distribution with bash terminal +It is (1) Package, (2) dependency and (3) environment management for any language : https://docs.conda.io/projects/conda/en/latest/index.html -To get know more about Conda check : https://linuxnetmag.com/miniconda-vs-anaconda/ +Shortly : Conda < Miniconda < Anaconda. Check : https://linuxnetmag.com/miniconda-vs-anaconda/ -Shortly : Conda < Miniconda < Anaconda +It is recommended to install Miniconda, not Anaconda. The difference between both lies in the amount of packages that would be installed upfront. Difference is at least like 1:8. https://www.dunderdata.com/blog/anaconda-is-bloated-set-up-a-lean-robust-data-science-environment-with-miniconda-and-conda-forge -The difference lies in the number of packages that need to be installed upfront: how heavy/light the installation is. Difference is like ~1:8. It is recommended to install Miniconda instead of Anaconda. #### 1. Instal Conda -##### Download conda file: +3 step installation instruction can be found here : +https://conda.io/projects/conda/en/latest/user-guide/install/linux.html#install-linux-silent -installation file of chosen distribution you can find here +Confirm with `yes` all questions. After installation, it is mandatory to turn your terminal OFF and ON again. -https://docs.conda.io/en/latest/miniconda.html - -##### Verify file integrity with SHA256 checksum: - -official SHA256 checksum can be found here - -https://docs.conda.io/en/latest/miniconda_hashes.html - -Navigate to the directory with your file, and run SHA256 checksum of your file, check with following command - -```bash -sha256sum ./Miniconda3-number-of-the-package -``` - -both checksum suppose to match - -##### Install conda: - -While in directory with your file, install conda - -```bash -bash ./Miniconda3-number-of-the-package -``` - -Confirm with yes all questions - -After installation, it is mandatory to turn your terminal OFF and ON again. - -CTRL + D (close terminal), CTRL + ALT + T (open terminal) #### 2. Prepare Conda environment +##### Change the channels with upgrades: + +After opening terminal, you already will be in default `base` conda environment + +If you want, you can prevent the (base) conda environment from being activated automatically. + +```bash +conda config --set auto_activate_base false +``` enter the conda base environment: @@ -282,15 +259,6 @@ enter the conda base environment: conda activate base ``` -If you want, you can prevent the (base) conda environment from being activated automatically as well. - -```bash -conda config --set auto_activate_base false -``` - - -##### Change the channels with upgrades: - Conda as a package manager can download new packages from "channels". The best developed Conda channel, is not the default channel and is called `conda-forge`. The code below switches to it. ```bash @@ -311,16 +279,15 @@ conda config --show channel_priority #### 3. Freqtrade Conda Environment -Now you have conda, but only base environment, +Now you have conda, but only (base) environment, -```bash# download freqtrade +```bash conda env list ``` It is time to setup environment of the Freqtrade itself: - -Conda `create` command, installs all nested dependencies, for the selected libraries automatically +The conda command `create -n` automatically installs all nested dependencies for the selected libraries general structure of installation command is: @@ -340,7 +307,7 @@ or if you expect, to use later jupiter for [data-analysis](data-analysis.md), us conda create -n freqtrade-jupyter-conda python=3.8 pandas numpy ta-lib git wheel virtualenv jupyter ``` -the same works for [docker](docker.md), for spyder and other useful programs. +the same works: for [docker](docker.md), for spyder and other useful programs. Further read on the topic: @@ -348,9 +315,10 @@ https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db9 https://metager.de/meta/meta.ger3?eingabe=ardsdatascience+guide+to+conda+environment -!!! NOTE: -It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent package into the old environment, -takes less time than installing a large, heavy dependent package into the old environment. +!!! Note "New heavy packages" + It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment, + + Example: Spyder ##### Enter/exit freqtrade-conda venv: @@ -414,11 +382,16 @@ That is, why the conda-forge channel is preferred: (and if no library is availab You are ready to run, create the user directory and configuration file, run the program dry to verify that everything is working, and run a backtest to double check. ```bash +# Prerequisite freqtrade create-userdir --userdir user_data + +# set up config file +# make sure to run it set the `dry_run : true` as you start freqtrade new-config --config config.json -freqtrade download-data -t 5m 15m 1h --days 100 -freqtrade trade --strategy SampleStrategy -freqtrade backtesting -s SampleStrategy + + +# run `dry_run` trades +freqtrade trade --strategy SampleStrategy ``` important shortcuts From 9ad0817105f3406788fbe2cdd49d24bbad2c5ce1 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:27:25 +0000 Subject: [PATCH 003/158] Update installation.md --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 5b56afcaf..25bbaa1dd 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -379,7 +379,7 @@ That is, why the conda-forge channel is preferred: (and if no library is availab #### 5. You are ready -You are ready to run, create the user directory and configuration file, run the program dry to verify that everything is working, and run a backtest to double check. +You are ready to run, create the user directory and configuration file [Bot Configuration](configuration.md), run the program `dry` to verify that everything is working, and run a backtest to double check. ```bash # Prerequisite From 63be27f6716ef53e68db66541e511060f1b7cd85 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:28:23 +0000 Subject: [PATCH 004/158] Update installation.md --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 25bbaa1dd..90ea714c2 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -379,7 +379,7 @@ That is, why the conda-forge channel is preferred: (and if no library is availab #### 5. You are ready -You are ready to run, create the user directory and configuration file [Bot Configuration](configuration.md), run the program `dry` to verify that everything is working, and run a backtest to double check. +You are ready to run, create the user directory and configuration file [Bot Configuration](configuration.md), run the program `dry_run: True` to verify that everything works, and run a backtest to double check. ```bash # Prerequisite From 73206a919447339f334aa8ff68bbd0a3e14eb37f Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:35:42 +0000 Subject: [PATCH 005/158] Update installation.md --- docs/installation.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 90ea714c2..aa4cde12d 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -224,7 +224,7 @@ Freqtrade can also be installed with Miniconda or Anaconda. Conda (Miniconda or ##### What is Conda? -It is (1) Package, (2) dependency and (3) environment management for any language : https://docs.conda.io/projects/conda/en/latest/index.html +It is: (1) package, (2) dependency and (3) environment management for any programming language : https://docs.conda.io/projects/conda/en/latest/index.html Shortly : Conda < Miniconda < Anaconda. Check : https://linuxnetmag.com/miniconda-vs-anaconda/ @@ -316,9 +316,8 @@ https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db9 https://metager.de/meta/meta.ger3?eingabe=ardsdatascience+guide+to+conda+environment !!! Note "New heavy packages" - It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment, + It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder - Example: Spyder ##### Enter/exit freqtrade-conda venv: @@ -379,7 +378,7 @@ That is, why the conda-forge channel is preferred: (and if no library is availab #### 5. You are ready -You are ready to run, create the user directory and configuration file [Bot Configuration](configuration.md), run the program `dry_run: True` to verify that everything works, and run a backtest to double check. +You are ready to run, create the user directory and configuration file [Bot Configuration](configuration.md), run the program `dry_run: True` to verify that everything is working, and run a backtest to double check. ```bash # Prerequisite From f9dd74585eadae5948313bd5d5288a191c4ebea5 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:39:11 +0000 Subject: [PATCH 006/158] Update installation.md --- docs/installation.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index aa4cde12d..65020831f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -328,15 +328,17 @@ conda activate freqtrade-conda ``` -to exit conda environment +to exit conda environment. ```bash conda deactivate ``` +Don't do it now however and stay in conda environment. + #### 4. Freqtrade Instalation -Within the newly created freqtrade-conda environment, download and install Freqtrade. To process --install command, may take a few minutes +When in `freqtrade-conda` environment, download and install freqtrade. Command `./setup.sh --install`, will take few minutes. ```bash # download freqtrade From 172a629c5853b97362ee879144a3e7f71e2bb790 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sat, 16 Jan 2021 22:41:37 +0000 Subject: [PATCH 007/158] Update installation.md --- docs/installation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 65020831f..129ad1e36 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -369,12 +369,12 @@ pip install -e . ##### pip install within conda, a reminder: The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. -However, they are rare +However, they are rare. -That is, why the conda-forge channel is preferred: (and if no library is available in conda, you have to use pip) +Nevertherless, that is why, the `conda-forge` channel is preferred: -* more libraries are available (less need for pip) -* conda-forge works better with pip +* more libraries are available (less need for `pip`) +* `conda-forge` works better with `pip` * the libraries are newer From 3b51545d234d5d83ef1aabacfd2e1f930827e9b7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jan 2021 12:43:27 +0100 Subject: [PATCH 008/158] Add trade_duration to to_json --- freqtrade/persistence/models.py | 3 +++ tests/rpc/test_rpc.py | 2 ++ tests/test_persistence.py | 2 ++ 3 files changed, 7 insertions(+) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index e803b4383..492d2b941 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -302,6 +302,9 @@ class Trade(_DECL_BASE): 'close_profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, 'close_profit_abs': self.close_profit_abs, # Deprecated + # TODO: should this be in minutes or seconds?? + 'trade_duration': (int((self.close_date - self.open_date).total_seconds() // 60) + if self.close_date else None), 'profit_ratio': self.close_profit, 'profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, 'profit_abs': self.close_profit_abs, diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 8ec356d54..69d79159a 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -80,6 +80,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'amount': 91.07468123, 'amount_requested': 91.07468123, 'stake_amount': 0.001, + 'trade_duration': None, 'close_profit': None, 'close_profit_pct': None, 'close_profit_abs': None, @@ -144,6 +145,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'current_rate': ANY, 'amount': 91.07468123, 'amount_requested': 91.07468123, + 'trade_duration': ANY, 'stake_amount': 0.001, 'close_profit': None, 'close_profit_pct': None, diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 7487b2ef5..76c6ec9f6 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -815,6 +815,7 @@ def test_to_json(default_conf, fee): 'amount': 123.0, 'amount_requested': 123.0, 'stake_amount': 0.001, + 'trade_duration': None, 'close_profit': None, 'close_profit_pct': None, 'close_profit_abs': None, @@ -869,6 +870,7 @@ def test_to_json(default_conf, fee): 'amount': 100.0, 'amount_requested': 101.0, 'stake_amount': 0.001, + 'trade_duration': 60, 'stop_loss_abs': None, 'stop_loss_pct': None, 'stop_loss_ratio': None, From 48977493bb7bacaa37dfaf040be074ab080ec095 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jan 2021 12:50:20 +0100 Subject: [PATCH 009/158] Backtesting does not need to convert to BacktestResult object --- freqtrade/optimize/backtesting.py | 57 +++++++++---------------- freqtrade/optimize/optimize_reports.py | 2 +- tests/optimize/test_backtesting.py | 6 +-- tests/optimize/test_optimize_reports.py | 2 +- 4 files changed, 25 insertions(+), 42 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 106d0f200..176ed34c5 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -9,7 +9,7 @@ from copy import deepcopy from datetime import datetime, timedelta, timezone from typing import Any, Dict, List, NamedTuple, Optional, Tuple -from pandas import DataFrame +from pandas import DataFrame, to_datetime from freqtrade.configuration import TimeRange, remove_credentials, validate_config_consistency from freqtrade.constants import DATETIME_PRINT_FORMAT @@ -264,7 +264,7 @@ class Backtesting: else: return sell_row[OPEN_IDX] - def _get_sell_trade_entry(self, trade: Trade, sell_row: Tuple) -> Optional[BacktestResult]: + def _get_sell_trade_entry(self, trade: Trade, sell_row: Tuple) -> Optional[Trade]: sell = self.strategy.should_sell(trade, sell_row[OPEN_IDX], sell_row[DATE_IDX], sell_row[BUY_IDX], sell_row[SELL_IDX], @@ -276,25 +276,12 @@ class Backtesting: trade.close_date = sell_row[DATE_IDX] trade.sell_reason = sell.sell_type trade.close(closerate, show_msg=False) + return trade - return BacktestResult(pair=trade.pair, - profit_percent=trade.calc_profit_ratio(rate=closerate), - profit_abs=trade.calc_profit(rate=closerate), - open_date=trade.open_date, - open_rate=trade.open_rate, - open_fee=self.fee, - close_date=sell_row[DATE_IDX], - close_rate=closerate, - close_fee=self.fee, - amount=trade.amount, - trade_duration=trade_dur, - open_at_end=False, - sell_reason=sell.sell_type - ) return None def handle_left_open(self, open_trades: Dict[str, List[Trade]], - data: Dict[str, List[Tuple]]) -> List[BacktestResult]: + data: Dict[str, List[Tuple]]) -> List[Trade]: """ Handling of left open trades at the end of backtesting """ @@ -304,24 +291,11 @@ class Backtesting: for trade in open_trades[pair]: sell_row = data[pair][-1] - trade_entry = BacktestResult(pair=trade.pair, - profit_percent=trade.calc_profit_ratio( - rate=sell_row[OPEN_IDX]), - profit_abs=trade.calc_profit(sell_row[OPEN_IDX]), - open_date=trade.open_date, - open_rate=trade.open_rate, - open_fee=self.fee, - close_date=sell_row[DATE_IDX], - close_rate=sell_row[OPEN_IDX], - close_fee=self.fee, - amount=trade.amount, - trade_duration=int(( - sell_row[DATE_IDX] - trade.open_date - ).total_seconds() // 60), - open_at_end=True, - sell_reason=SellType.FORCE_SELL - ) - trades.append(trade_entry) + trade.close_date = sell_row[DATE_IDX] + trade.sell_reason = SellType.FORCE_SELL + trade.close(sell_row[OPEN_IDX], show_msg=False) + trade.is_open = True + trades.append(trade) return trades def backtest(self, processed: Dict, stake_amount: float, @@ -348,7 +322,7 @@ class Backtesting: f"start_date: {start_date}, end_date: {end_date}, " f"max_open_trades: {max_open_trades}, position_stacking: {position_stacking}" ) - trades = [] + trades: List[Trade] = [] self.prepare_backtest(enable_protections) # Use dict of lists with data for performance @@ -429,7 +403,16 @@ class Backtesting: trades += self.handle_left_open(open_trades, data=data) - return DataFrame.from_records(trades, columns=BacktestResult._fields) + cols = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', + 'open_fee', 'close_fee', 'trade_duration', + 'profit_ratio', 'profit_percent', 'profit_abs', 'sell_reason', + 'initial_stop_loss_abs', 'initial_stop_loss_ratio' 'stop_loss', 'stop_loss_ratio', + 'min_rate', 'max_rate', 'is_open', ] + df = DataFrame.from_records([t.to_json() for t in trades], columns=cols) + if len(df) > 0: + df.loc[:, 'close_date'] = to_datetime(df['close_date'], utc=True) + df.loc[:, 'open_date'] = to_datetime(df['open_date'], utc=True) + return df def backtest_one_strategy(self, strat: IStrategy, data: Dict[str, Any], timerange: TimeRange): logger.info("Running backtesting for Strategy %s", strat.get_strategy_name()) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 96ddb91a0..1a4c2f269 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -253,7 +253,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], results=results) left_open_results = generate_pair_metrics(btdata, stake_currency=stake_currency, max_open_trades=max_open_trades, - results=results.loc[results['open_at_end']], + results=results.loc[results['is_open']], skip_nan=True) daily_stats = generate_daily_stats(results) best_pair = max([pair for pair in pair_results if pair['key'] != 'TOTAL'], diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index e55e166d9..fcac05a26 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -629,7 +629,7 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir): # 100 buys signals assert len(results) == 100 # One trade was force-closed at the end - assert len(results.loc[results.open_at_end]) == 0 + assert len(results.loc[results['is_open']]) == 0 @pytest.mark.parametrize("pair", ['ADA/BTC', 'LTC/BTC']) @@ -811,7 +811,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'close_date': pd.to_datetime(['2018-01-29 20:45:00', '2018-01-30 05:35:00', ], utc=True), 'trade_duration': [235, 40], - 'open_at_end': [False, False], + 'is_open': [False, False], 'open_rate': [0.104445, 0.10302485], 'close_rate': [0.104969, 0.103541], 'sell_reason': [SellType.ROI, SellType.ROI] @@ -827,7 +827,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat '2018-01-30 05:35:00', '2018-01-30 08:30:00'], utc=True), 'trade_duration': [47, 40, 20], - 'open_at_end': [False, False, False], + 'is_open': [False, False, False], 'open_rate': [0.104445, 0.10302485, 0.122541], 'close_rate': [0.104969, 0.103541, 0.123541], 'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index f184cb125..30dda1152 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -72,7 +72,7 @@ def test_generate_backtest_stats(default_conf, testdatadir): "open_rate": [0.002543, 0.003003, 0.003089, 0.003214], "close_rate": [0.002546, 0.003014, 0.003103, 0.003217], "trade_duration": [123, 34, 31, 14], - "open_at_end": [False, False, False, True], + "is_open": [False, False, False, True], "sell_reason": [SellType.ROI, SellType.STOP_LOSS, SellType.ROI, SellType.FORCE_SELL] }), From 8ee264bc59cce3f44c6949b2b1ca1d93090e7e79 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jan 2021 13:02:48 +0100 Subject: [PATCH 010/158] Don't use profit_percent for backtesting results anymore --- freqtrade/optimize/backtesting.py | 29 ++-------------- freqtrade/optimize/default_hyperopt_loss.py | 2 +- freqtrade/optimize/hyperopt.py | 12 +++---- .../optimize/hyperopt_loss_onlyprofit.py | 2 +- freqtrade/optimize/hyperopt_loss_sharpe.py | 2 +- .../optimize/hyperopt_loss_sharpe_daily.py | 10 +++--- freqtrade/optimize/hyperopt_loss_sortino.py | 4 +-- .../optimize/hyperopt_loss_sortino_daily.py | 12 +++---- freqtrade/optimize/optimize_reports.py | 34 +++++++++---------- freqtrade/plot/plotting.py | 14 ++++---- freqtrade/templates/sample_hyperopt_loss.py | 4 +-- tests/optimize/conftest.py | 2 +- tests/optimize/test_backtest_detail.py | 2 +- tests/optimize/test_backtesting.py | 6 ++-- tests/optimize/test_hyperopt.py | 4 +-- tests/optimize/test_hyperoptloss.py | 24 ++++++------- tests/optimize/test_optimize_reports.py | 16 ++++----- 17 files changed, 78 insertions(+), 101 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 176ed34c5..08dbdffc4 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -3,11 +3,12 @@ """ This module contains the backtesting logic """ +from freqtrade.data.btanalysis import BT_DATA_COLUMNS import logging from collections import defaultdict from copy import deepcopy from datetime import datetime, timedelta, timezone -from typing import Any, Dict, List, NamedTuple, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple from pandas import DataFrame, to_datetime @@ -41,25 +42,6 @@ LOW_IDX = 5 HIGH_IDX = 6 -class BacktestResult(NamedTuple): - """ - NamedTuple Defining BacktestResults inputs. - """ - pair: str - profit_percent: float - profit_abs: float - open_date: datetime - open_rate: float - open_fee: float - close_date: datetime - close_rate: float - close_fee: float - amount: float - trade_duration: float - open_at_end: bool - sell_reason: SellType - - class Backtesting: """ Backtesting class, this class contains all the logic to run a backtest @@ -403,12 +385,7 @@ class Backtesting: trades += self.handle_left_open(open_trades, data=data) - cols = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', - 'open_fee', 'close_fee', 'trade_duration', - 'profit_ratio', 'profit_percent', 'profit_abs', 'sell_reason', - 'initial_stop_loss_abs', 'initial_stop_loss_ratio' 'stop_loss', 'stop_loss_ratio', - 'min_rate', 'max_rate', 'is_open', ] - df = DataFrame.from_records([t.to_json() for t in trades], columns=cols) + df = DataFrame.from_records([t.to_json() for t in trades], columns=BT_DATA_COLUMNS) if len(df) > 0: df.loc[:, 'close_date'] = to_datetime(df['close_date'], utc=True) df.loc[:, 'open_date'] = to_datetime(df['open_date'], utc=True) diff --git a/freqtrade/optimize/default_hyperopt_loss.py b/freqtrade/optimize/default_hyperopt_loss.py index 9dbdc4403..3712fd9a6 100644 --- a/freqtrade/optimize/default_hyperopt_loss.py +++ b/freqtrade/optimize/default_hyperopt_loss.py @@ -42,7 +42,7 @@ class ShortTradeDurHyperOptLoss(IHyperOptLoss): * 0.25: Avoiding trade loss * 1.0 to total profit, compared to the expected value (`EXPECTED_MAX_PROFIT`) defined above """ - total_profit = results['profit_percent'].sum() + total_profit = results['profit_ratio'].sum() trade_duration = results['trade_duration'].mean() trade_loss = 1 - 0.25 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.8) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index d4b9f4c3b..20140492d 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -574,19 +574,19 @@ class Hyperopt: } def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: - wins = len(backtesting_results[backtesting_results.profit_percent > 0]) - draws = len(backtesting_results[backtesting_results.profit_percent == 0]) - losses = len(backtesting_results[backtesting_results.profit_percent < 0]) + wins = len(backtesting_results[backtesting_results['profit_ratio'] > 0]) + draws = len(backtesting_results[backtesting_results['profit_ratio'] == 0]) + losses = len(backtesting_results[backtesting_results['profit_ratio'] < 0]) return { 'trade_count': len(backtesting_results.index), 'wins': wins, 'draws': draws, 'losses': losses, 'winsdrawslosses': f"{wins:>4} {draws:>4} {losses:>4}", - 'avg_profit': backtesting_results.profit_percent.mean() * 100.0, - 'median_profit': backtesting_results.profit_percent.median() * 100.0, + 'avg_profit': backtesting_results['profit_ratio'].mean() * 100.0, + 'median_profit': backtesting_results['profit_ratio'].median() * 100.0, 'total_profit': backtesting_results.profit_abs.sum(), - 'profit': backtesting_results.profit_percent.sum() * 100.0, + 'profit': backtesting_results['profit_ratio'].sum() * 100.0, 'duration': backtesting_results.trade_duration.mean(), } diff --git a/freqtrade/optimize/hyperopt_loss_onlyprofit.py b/freqtrade/optimize/hyperopt_loss_onlyprofit.py index 43176dbad..33f3f5bc6 100644 --- a/freqtrade/optimize/hyperopt_loss_onlyprofit.py +++ b/freqtrade/optimize/hyperopt_loss_onlyprofit.py @@ -34,5 +34,5 @@ class OnlyProfitHyperOptLoss(IHyperOptLoss): """ Objective function, returns smaller number for better results. """ - total_profit = results['profit_percent'].sum() + total_profit = results['profit_ratio'].sum() return 1 - total_profit / EXPECTED_MAX_PROFIT diff --git a/freqtrade/optimize/hyperopt_loss_sharpe.py b/freqtrade/optimize/hyperopt_loss_sharpe.py index 232fb33b6..2c8ae552d 100644 --- a/freqtrade/optimize/hyperopt_loss_sharpe.py +++ b/freqtrade/optimize/hyperopt_loss_sharpe.py @@ -28,7 +28,7 @@ class SharpeHyperOptLoss(IHyperOptLoss): Uses Sharpe Ratio calculation. """ - total_profit = results["profit_percent"] + total_profit = results["profit_ratio"] days_period = (max_date - min_date).days # adding slippage of 0.1% per trade diff --git a/freqtrade/optimize/hyperopt_loss_sharpe_daily.py b/freqtrade/optimize/hyperopt_loss_sharpe_daily.py index bcba73a7f..9520123ee 100644 --- a/freqtrade/optimize/hyperopt_loss_sharpe_daily.py +++ b/freqtrade/optimize/hyperopt_loss_sharpe_daily.py @@ -34,9 +34,9 @@ class SharpeHyperOptLossDaily(IHyperOptLoss): annual_risk_free_rate = 0.0 risk_free_rate = annual_risk_free_rate / days_in_year - # apply slippage per trade to profit_percent - results.loc[:, 'profit_percent_after_slippage'] = \ - results['profit_percent'] - slippage_per_trade_ratio + # apply slippage per trade to profit_ratio + results.loc[:, 'profit_ratio_after_slippage'] = \ + results['profit_ratio'] - slippage_per_trade_ratio # create the index within the min_date and end max_date t_index = date_range(start=min_date, end=max_date, freq=resample_freq, @@ -44,10 +44,10 @@ class SharpeHyperOptLossDaily(IHyperOptLoss): sum_daily = ( results.resample(resample_freq, on='close_date').agg( - {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0) + {"profit_ratio_after_slippage": sum}).reindex(t_index).fillna(0) ) - total_profit = sum_daily["profit_percent_after_slippage"] - risk_free_rate + total_profit = sum_daily["profit_ratio_after_slippage"] - risk_free_rate expected_returns_mean = total_profit.mean() up_stdev = total_profit.std() diff --git a/freqtrade/optimize/hyperopt_loss_sortino.py b/freqtrade/optimize/hyperopt_loss_sortino.py index c0ff0773a..b231370dd 100644 --- a/freqtrade/optimize/hyperopt_loss_sortino.py +++ b/freqtrade/optimize/hyperopt_loss_sortino.py @@ -28,7 +28,7 @@ class SortinoHyperOptLoss(IHyperOptLoss): Uses Sortino Ratio calculation. """ - total_profit = results["profit_percent"] + total_profit = results["profit_ratio"] days_period = (max_date - min_date).days # adding slippage of 0.1% per trade @@ -36,7 +36,7 @@ class SortinoHyperOptLoss(IHyperOptLoss): expected_returns_mean = total_profit.sum() / days_period results['downside_returns'] = 0 - results.loc[total_profit < 0, 'downside_returns'] = results['profit_percent'] + results.loc[total_profit < 0, 'downside_returns'] = results['profit_ratio'] down_stdev = np.std(results['downside_returns']) if down_stdev != 0: diff --git a/freqtrade/optimize/hyperopt_loss_sortino_daily.py b/freqtrade/optimize/hyperopt_loss_sortino_daily.py index 3b099a253..fac96664d 100644 --- a/freqtrade/optimize/hyperopt_loss_sortino_daily.py +++ b/freqtrade/optimize/hyperopt_loss_sortino_daily.py @@ -36,9 +36,9 @@ class SortinoHyperOptLossDaily(IHyperOptLoss): days_in_year = 365 minimum_acceptable_return = 0.0 - # apply slippage per trade to profit_percent - results.loc[:, 'profit_percent_after_slippage'] = \ - results['profit_percent'] - slippage_per_trade_ratio + # apply slippage per trade to profit_ratio + results.loc[:, 'profit_ratio_after_slippage'] = \ + results['profit_ratio'] - slippage_per_trade_ratio # create the index within the min_date and end max_date t_index = date_range(start=min_date, end=max_date, freq=resample_freq, @@ -46,17 +46,17 @@ class SortinoHyperOptLossDaily(IHyperOptLoss): sum_daily = ( results.resample(resample_freq, on='close_date').agg( - {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0) + {"profit_ratio_after_slippage": sum}).reindex(t_index).fillna(0) ) - total_profit = sum_daily["profit_percent_after_slippage"] - minimum_acceptable_return + total_profit = sum_daily["profit_ratio_after_slippage"] - minimum_acceptable_return expected_returns_mean = total_profit.mean() sum_daily['downside_returns'] = 0 sum_daily.loc[total_profit < 0, 'downside_returns'] = total_profit total_downside = sum_daily['downside_returns'] # Here total_downside contains min(0, P - MAR) values, - # where P = sum_daily["profit_percent_after_slippage"] + # where P = sum_daily["profit_ratio_after_slippage"] down_stdev = math.sqrt((total_downside**2).sum() / len(total_downside)) if down_stdev != 0: diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 1a4c2f269..4a9e833e7 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -58,14 +58,14 @@ def _generate_result_line(result: DataFrame, max_open_trades: int, first_column: """ Generate one result dict, with "first_column" as key. """ - profit_sum = result['profit_percent'].sum() + profit_sum = result['profit_ratio'].sum() profit_total = profit_sum / max_open_trades return { 'key': first_column, 'trades': len(result), - 'profit_mean': result['profit_percent'].mean() if len(result) > 0 else 0.0, - 'profit_mean_pct': result['profit_percent'].mean() * 100.0 if len(result) > 0 else 0.0, + 'profit_mean': result['profit_ratio'].mean() if len(result) > 0 else 0.0, + 'profit_mean_pct': result['profit_ratio'].mean() * 100.0 if len(result) > 0 else 0.0, 'profit_sum': profit_sum, 'profit_sum_pct': round(profit_sum * 100.0, 2), 'profit_total_abs': result['profit_abs'].sum(), @@ -124,8 +124,8 @@ def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List for reason, count in results['sell_reason'].value_counts().iteritems(): result = results.loc[results['sell_reason'] == reason] - profit_mean = result['profit_percent'].mean() - profit_sum = result['profit_percent'].sum() + profit_mean = result['profit_ratio'].mean() + profit_sum = result['profit_ratio'].sum() profit_total = profit_sum / max_open_trades tabular_data.append( @@ -150,7 +150,7 @@ def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List def generate_strategy_metrics(all_results: Dict) -> List[Dict]: """ Generate summary per strategy - :param all_results: Dict of containing results for all strategies + :param all_results: Dict of containing results for all strategies :return: List of Dicts containing the metrics per Strategy """ @@ -199,15 +199,15 @@ def generate_daily_stats(results: DataFrame) -> Dict[str, Any]: 'winner_holding_avg': timedelta(), 'loser_holding_avg': timedelta(), } - daily_profit = results.resample('1d', on='close_date')['profit_percent'].sum() + daily_profit = results.resample('1d', on='close_date')['profit_ratio'].sum() worst = min(daily_profit) best = max(daily_profit) winning_days = sum(daily_profit > 0) draw_days = sum(daily_profit == 0) losing_days = sum(daily_profit < 0) - winning_trades = results.loc[results['profit_percent'] > 0] - losing_trades = results.loc[results['profit_percent'] < 0] + winning_trades = results.loc[results['profit_ratio'] > 0] + losing_trades = results.loc[results['profit_ratio'] < 0] return { 'backtest_best_day': best, @@ -273,8 +273,8 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], 'sell_reason_summary': sell_reason_stats, 'left_open_trades': left_open_results, 'total_trades': len(results), - 'profit_mean': results['profit_percent'].mean() if len(results) > 0 else 0, - 'profit_total': results['profit_percent'].sum(), + 'profit_mean': results['profit_ratio'].mean() if len(results) > 0 else 0, + 'profit_total': results['profit_ratio'].sum(), 'profit_total_abs': results['profit_abs'].sum(), 'backtest_start': min_date.datetime, 'backtest_start_ts': min_date.int_timestamp * 1000, @@ -314,7 +314,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], try: max_drawdown, drawdown_start, drawdown_end = calculate_max_drawdown( - results, value_col='profit_percent') + results, value_col='profit_ratio') strat_stats.update({ 'max_drawdown': max_drawdown, 'drawdown_start': drawdown_start, @@ -392,7 +392,7 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: Generate summary table per strategy :param stake_currency: stake-currency - used to correctly name headers :param max_open_trades: Maximum allowed open trades used for backtest - :param all_results: Dict of containing results for all strategies + :param all_results: Dict of containing results for all strategies :return: pretty printed table with tabulate as string """ floatfmt = _get_line_floatfmt() @@ -409,8 +409,8 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: def text_table_add_metrics(strat_results: Dict) -> str: if len(strat_results['trades']) > 0: - best_trade = max(strat_results['trades'], key=lambda x: x['profit_percent']) - worst_trade = min(strat_results['trades'], key=lambda x: x['profit_percent']) + best_trade = max(strat_results['trades'], key=lambda x: x['profit_ratio']) + worst_trade = min(strat_results['trades'], key=lambda x: x['profit_ratio']) metrics = [ ('Backtesting from', strat_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strat_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), @@ -424,9 +424,9 @@ def text_table_add_metrics(strat_results: Dict) -> str: f"{round(strat_results['best_pair']['profit_sum_pct'], 2)}%"), ('Worst Pair', f"{strat_results['worst_pair']['key']} " f"{round(strat_results['worst_pair']['profit_sum_pct'], 2)}%"), - ('Best trade', f"{best_trade['pair']} {round(best_trade['profit_percent'] * 100, 2)}%"), + ('Best trade', f"{best_trade['pair']} {round(best_trade['profit_ratio'] * 100, 2)}%"), ('Worst trade', f"{worst_trade['pair']} " - f"{round(worst_trade['profit_percent'] * 100, 2)}%"), + f"{round(worst_trade['profit_ratio'] * 100, 2)}%"), ('Best day', f"{round(strat_results['backtest_best_day'] * 100, 2)}%"), ('Worst day', f"{round(strat_results['backtest_worst_day'] * 100, 2)}%"), diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 996c5276c..f45ba9b25 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -175,7 +175,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: # Trades can be empty if trades is not None and len(trades) > 0: # Create description for sell summarizing the trade - trades['desc'] = trades.apply(lambda row: f"{round(row['profit_percent'] * 100, 1)}%, " + trades['desc'] = trades.apply(lambda row: f"{round(row['profit_ratio'] * 100, 1)}%, " f"{row['sell_reason']}, " f"{row['trade_duration']} min", axis=1) @@ -195,9 +195,9 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: ) trade_sells = go.Scatter( - x=trades.loc[trades['profit_percent'] > 0, "close_date"], - y=trades.loc[trades['profit_percent'] > 0, "close_rate"], - text=trades.loc[trades['profit_percent'] > 0, "desc"], + x=trades.loc[trades['profit_ratio'] > 0, "close_date"], + y=trades.loc[trades['profit_ratio'] > 0, "close_rate"], + text=trades.loc[trades['profit_ratio'] > 0, "desc"], mode='markers', name='Sell - Profit', marker=dict( @@ -208,9 +208,9 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: ) ) trade_sells_loss = go.Scatter( - x=trades.loc[trades['profit_percent'] <= 0, "close_date"], - y=trades.loc[trades['profit_percent'] <= 0, "close_rate"], - text=trades.loc[trades['profit_percent'] <= 0, "desc"], + x=trades.loc[trades['profit_ratio'] <= 0, "close_date"], + y=trades.loc[trades['profit_ratio'] <= 0, "close_rate"], + text=trades.loc[trades['profit_ratio'] <= 0, "desc"], mode='markers', name='Sell - Loss', marker=dict( diff --git a/freqtrade/templates/sample_hyperopt_loss.py b/freqtrade/templates/sample_hyperopt_loss.py index 59e6d814a..a2b28f948 100644 --- a/freqtrade/templates/sample_hyperopt_loss.py +++ b/freqtrade/templates/sample_hyperopt_loss.py @@ -39,8 +39,8 @@ class SampleHyperOptLoss(IHyperOptLoss): """ Objective function, returns smaller number for better results """ - total_profit = results.profit_percent.sum() - trade_duration = results.trade_duration.mean() + total_profit = results['profit_ratio'].sum() + trade_duration = results['trade_duration'].mean() trade_loss = 1 - 0.25 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.8) profit_loss = max(0, 1 - total_profit / EXPECTED_MAX_PROFIT) diff --git a/tests/optimize/conftest.py b/tests/optimize/conftest.py index f06b0ecd3..df6f22e01 100644 --- a/tests/optimize/conftest.py +++ b/tests/optimize/conftest.py @@ -37,7 +37,7 @@ def hyperopt_results(): return pd.DataFrame( { 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], - 'profit_percent': [-0.1, 0.2, 0.3], + 'profit_ratio': [-0.1, 0.2, 0.3], 'profit_abs': [-0.2, 0.4, 0.6], 'trade_duration': [10, 30, 10], 'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.ROI], diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 720ed8c13..daf7c2053 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -510,7 +510,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None: ) assert len(results) == len(data.trades) - assert round(results["profit_percent"].sum(), 3) == round(data.profit_perc, 3) + assert round(results["profit_ratio"].sum(), 3) == round(data.profit_perc, 3) for c, trade in enumerate(data.trades): res = results.iloc[c] diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index fcac05a26..54eeb7929 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -469,7 +469,7 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: expected = pd.DataFrame( {'pair': [pair, pair], - 'profit_percent': [0.0, 0.0], + 'profit_ratio': [0.0, 0.0], 'profit_abs': [0.0, 0.0], 'open_date': pd.to_datetime([Arrow(2018, 1, 29, 18, 40, 0).datetime, Arrow(2018, 1, 30, 3, 30, 0).datetime], utc=True @@ -803,7 +803,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat patch_exchange(mocker) backtestmock = MagicMock(side_effect=[ pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC'], - 'profit_percent': [0.0, 0.0], + 'profit_ratio': [0.0, 0.0], 'profit_abs': [0.0, 0.0], 'open_date': pd.to_datetime(['2018-01-29 18:40:00', '2018-01-30 03:30:00', ], utc=True @@ -817,7 +817,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat 'sell_reason': [SellType.ROI, SellType.ROI] }), pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'], - 'profit_percent': [0.03, 0.01, 0.1], + 'profit_ratio': [0.03, 0.01, 0.1], 'profit_abs': [0.01, 0.02, 0.2], 'open_date': pd.to_datetime(['2018-01-29 18:40:00', '2018-01-30 03:30:00', diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 82be894d3..89c7305b6 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -427,7 +427,7 @@ def test_format_results(hyperopt): ('LTC/BTC', 1, 1, 123), ('XPR/BTC', -1, -2, -246) ] - labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration'] + labels = ['currency', 'profit_ratio', 'profit_abs', 'trade_duration'] df = pd.DataFrame.from_records(trades, columns=labels) results_metrics = hyperopt._calculate_results_metrics(df) results_explanation = hyperopt._format_results_explanation_string(results_metrics) @@ -567,7 +567,7 @@ def test_generate_optimizer(mocker, hyperopt_conf) -> None: trades = [ ('TRX/BTC', 0.023117, 0.000233, 100) ] - labels = ['currency', 'profit_percent', 'profit_abs', 'trade_duration'] + labels = ['currency', 'profit_ratio', 'profit_abs', 'trade_duration'] backtest_result = pd.DataFrame.from_records(trades, columns=labels) mocker.patch( diff --git a/tests/optimize/test_hyperoptloss.py b/tests/optimize/test_hyperoptloss.py index f7910e6d6..73feeb007 100644 --- a/tests/optimize/test_hyperoptloss.py +++ b/tests/optimize/test_hyperoptloss.py @@ -60,9 +60,9 @@ def test_loss_calculation_prefer_shorter_trades(hyperopt_conf, hyperopt_results) def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) -> None: results_over = hyperopt_results.copy() - results_over['profit_percent'] = hyperopt_results['profit_percent'] * 2 + results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 results_under = hyperopt_results.copy() - results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 + results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 hl = HyperOptLossResolver.load_hyperoptloss(hyperopt_conf) correct = hl.hyperopt_loss_function(hyperopt_results, 600, @@ -77,9 +77,9 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) -> def test_sharpe_loss_prefers_higher_profits(default_conf, hyperopt_results) -> None: results_over = hyperopt_results.copy() - results_over['profit_percent'] = hyperopt_results['profit_percent'] * 2 + results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 results_under = hyperopt_results.copy() - results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 + results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 default_conf.update({'hyperopt_loss': 'SharpeHyperOptLoss'}) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) @@ -95,9 +95,9 @@ def test_sharpe_loss_prefers_higher_profits(default_conf, hyperopt_results) -> N def test_sharpe_loss_daily_prefers_higher_profits(default_conf, hyperopt_results) -> None: results_over = hyperopt_results.copy() - results_over['profit_percent'] = hyperopt_results['profit_percent'] * 2 + results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 results_under = hyperopt_results.copy() - results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 + results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 default_conf.update({'hyperopt_loss': 'SharpeHyperOptLossDaily'}) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) @@ -113,9 +113,9 @@ def test_sharpe_loss_daily_prefers_higher_profits(default_conf, hyperopt_results def test_sortino_loss_prefers_higher_profits(default_conf, hyperopt_results) -> None: results_over = hyperopt_results.copy() - results_over['profit_percent'] = hyperopt_results['profit_percent'] * 2 + results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 results_under = hyperopt_results.copy() - results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 + results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 default_conf.update({'hyperopt_loss': 'SortinoHyperOptLoss'}) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) @@ -131,9 +131,9 @@ def test_sortino_loss_prefers_higher_profits(default_conf, hyperopt_results) -> def test_sortino_loss_daily_prefers_higher_profits(default_conf, hyperopt_results) -> None: results_over = hyperopt_results.copy() - results_over['profit_percent'] = hyperopt_results['profit_percent'] * 2 + results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 results_under = hyperopt_results.copy() - results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 + results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 default_conf.update({'hyperopt_loss': 'SortinoHyperOptLossDaily'}) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) @@ -149,9 +149,9 @@ def test_sortino_loss_daily_prefers_higher_profits(default_conf, hyperopt_result def test_onlyprofit_loss_prefers_higher_profits(default_conf, hyperopt_results) -> None: results_over = hyperopt_results.copy() - results_over['profit_percent'] = hyperopt_results['profit_percent'] * 2 + results_over['profit_ratio'] = hyperopt_results['profit_ratio'] * 2 results_under = hyperopt_results.copy() - results_under['profit_percent'] = hyperopt_results['profit_percent'] / 2 + results_under['profit_ratio'] = hyperopt_results['profit_ratio'] / 2 default_conf.update({'hyperopt_loss': 'OnlyProfitHyperOptLoss'}) hl = HyperOptLossResolver.load_hyperoptloss(default_conf) diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 30dda1152..51a78c7cc 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -27,7 +27,7 @@ def test_text_table_bt_results(): results = pd.DataFrame( { 'pair': ['ETH/BTC', 'ETH/BTC'], - 'profit_percent': [0.1, 0.2], + 'profit_ratio': [0.1, 0.2], 'profit_abs': [0.2, 0.4], 'trade_duration': [10, 30], 'wins': [2, 0], @@ -59,7 +59,7 @@ def test_generate_backtest_stats(default_conf, testdatadir): results = {'DefStrat': { 'results': pd.DataFrame({"pair": ["UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC"], - "profit_percent": [0.003312, 0.010801, 0.013803, 0.002780], + "profit_ratio": [0.003312, 0.010801, 0.013803, 0.002780], "profit_abs": [0.000003, 0.000011, 0.000014, 0.000003], "open_date": [Arrow(2017, 11, 14, 19, 32, 00).datetime, Arrow(2017, 11, 14, 21, 36, 00).datetime, @@ -103,7 +103,7 @@ def test_generate_backtest_stats(default_conf, testdatadir): results = {'DefStrat': { 'results': pd.DataFrame( {"pair": ["UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC"], - "profit_percent": [0.003312, 0.010801, -0.013803, 0.002780], + "profit_ratio": [0.003312, 0.010801, -0.013803, 0.002780], "profit_abs": [0.000003, 0.000011, -0.000014, 0.000003], "open_date": [Arrow(2017, 11, 14, 19, 32, 00).datetime, Arrow(2017, 11, 14, 21, 36, 00).datetime, @@ -179,7 +179,7 @@ def test_generate_pair_metrics(): results = pd.DataFrame( { 'pair': ['ETH/BTC', 'ETH/BTC'], - 'profit_percent': [0.1, 0.2], + 'profit_ratio': [0.1, 0.2], 'profit_abs': [0.2, 0.4], 'trade_duration': [10, 30], 'wins': [2, 0], @@ -227,7 +227,7 @@ def test_text_table_sell_reason(): results = pd.DataFrame( { 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], - 'profit_percent': [0.1, 0.2, -0.1], + 'profit_ratio': [0.1, 0.2, -0.1], 'profit_abs': [0.2, 0.4, -0.2], 'trade_duration': [10, 30, 10], 'wins': [2, 0, 0], @@ -259,7 +259,7 @@ def test_generate_sell_reason_stats(): results = pd.DataFrame( { 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], - 'profit_percent': [0.1, 0.2, -0.1], + 'profit_ratio': [0.1, 0.2, -0.1], 'profit_abs': [0.2, 0.4, -0.2], 'trade_duration': [10, 30, 10], 'wins': [2, 0, 0], @@ -295,7 +295,7 @@ def test_text_table_strategy(default_conf): results['TestStrategy1'] = {'results': pd.DataFrame( { 'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], - 'profit_percent': [0.1, 0.2, 0.3], + 'profit_ratio': [0.1, 0.2, 0.3], 'profit_abs': [0.2, 0.4, 0.5], 'trade_duration': [10, 30, 10], 'wins': [2, 0, 0], @@ -307,7 +307,7 @@ def test_text_table_strategy(default_conf): results['TestStrategy2'] = {'results': pd.DataFrame( { 'pair': ['LTC/BTC', 'LTC/BTC', 'LTC/BTC'], - 'profit_percent': [0.4, 0.2, 0.3], + 'profit_ratio': [0.4, 0.2, 0.3], 'profit_abs': [0.4, 0.4, 0.5], 'trade_duration': [15, 30, 15], 'wins': [4, 1, 0], From deb8432d3395b6db8c03991e1321e3d144d2a580 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 23 Jan 2021 20:49:49 +0100 Subject: [PATCH 011/158] Streamline trade to dataframe conversion --- freqtrade/data/btanalysis.py | 67 ++++++++++++++++--------------- freqtrade/optimize/backtesting.py | 8 +--- tests/data/test_btanalysis.py | 14 +++---- 3 files changed, 43 insertions(+), 46 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 2b51f5371..20977e447 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -2,9 +2,8 @@ Helpers when analyzing backtest data """ import logging -from datetime import timezone from pathlib import Path -from typing import Any, Dict, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Tuple, Union import numpy as np import pandas as pd @@ -16,9 +15,21 @@ from freqtrade.persistence import Trade, init_db logger = logging.getLogger(__name__) -# must align with columns in backtest.py -BT_DATA_COLUMNS = ["pair", "profit_percent", "open_date", "close_date", "index", "trade_duration", - "open_rate", "close_rate", "open_at_end", "sell_reason"] +# Old format - maybe remove? +BT_DATA_COLUMNS_OLD = ["pair", "profit_percent", "open_date", "close_date", "index", + "trade_duration", "open_rate", "close_rate", "open_at_end", "sell_reason"] + +# Mid-term format, crated by BacktestResult Named Tuple +BT_DATA_COLUMNS_MID = ['pair', 'profit_percent', 'open_date', 'close_date', 'trade_duration', + 'open_rate', 'close_rate', 'open_at_end', 'sell_reason', 'fee_open', + 'fee_close', 'amount', 'profit_abs', 'profit_ratio'] + +# Newest format +BT_DATA_COLUMNS = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', + 'fee_open', 'fee_close', 'trade_duration', + 'profit_ratio', 'profit_abs', 'sell_reason', + 'initial_stop_loss_abs', 'initial_stop_loss_ratio', 'stop_loss_abs', + 'stop_loss_ratio', 'min_rate', 'max_rate', 'is_open', ] def get_latest_optimize_filename(directory: Union[Path, str], variant: str) -> str: @@ -154,7 +165,7 @@ def load_backtest_data(filename: Union[Path, str], strategy: Optional[str] = Non ) else: # old format - only with lists. - df = pd.DataFrame(data, columns=BT_DATA_COLUMNS) + df = pd.DataFrame(data, columns=BT_DATA_COLUMNS_OLD) df['open_date'] = pd.to_datetime(df['open_date'], unit='s', @@ -166,7 +177,10 @@ def load_backtest_data(filename: Union[Path, str], strategy: Optional[str] = Non utc=True, infer_datetime_format=True ) + # Create compatibility with new format df['profit_abs'] = df['close_rate'] - df['open_rate'] + if 'profit_ratio' not in df.columns: + df['profit_ratio'] = df['profit_percent'] df = df.sort_values("open_date").reset_index(drop=True) return df @@ -209,6 +223,19 @@ def evaluate_result_multi(results: pd.DataFrame, timeframe: str, return df_final[df_final['open_trades'] > max_open_trades] +def trade_list_to_dataframe(trades: List[Trade]) -> pd.DataFrame: + """ + Convert list of Trade objects to pandas Dataframe + :param trades: List of trade objects + :return: Dataframe with BT_DATA_COLUMNS + """ + df = pd.DataFrame.from_records([t.to_json() for t in trades], columns=BT_DATA_COLUMNS) + if len(df) > 0: + df.loc[:, 'close_date'] = pd.to_datetime(df['close_date'], utc=True) + df.loc[:, 'open_date'] = pd.to_datetime(df['open_date'], utc=True) + return df + + def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataFrame: """ Load trades from a DB (using dburl) @@ -219,36 +246,10 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF """ init_db(db_url, clean_open_orders=False) - columns = ["pair", "open_date", "close_date", "profit", "profit_percent", - "open_rate", "close_rate", "amount", "trade_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", "timeframe"] - filters = [] if strategy: filters.append(Trade.strategy == strategy) - - trades = pd.DataFrame([(t.pair, - t.open_date.replace(tzinfo=timezone.utc), - t.close_date.replace(tzinfo=timezone.utc) if t.close_date else None, - t.calc_profit(), t.calc_profit_ratio(), - t.open_rate, t.close_rate, t.amount, - (round((t.close_date.timestamp() - t.open_date.timestamp()) / 60, 2) - if t.close_date else None), - t.sell_reason, - t.fee_open, t.fee_close, - t.open_rate_requested, - t.close_rate_requested, - t.stake_amount, - t.max_rate, - t.min_rate, - t.id, t.exchange, - t.stop_loss, t.initial_stop_loss, - t.strategy, t.timeframe - ) - for t in Trade.get_trades(filters).all()], - columns=columns) + trades = trade_list_to_dataframe(Trade.get_trades(filters).all()) return trades diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 08dbdffc4..875538731 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -3,7 +3,7 @@ """ This module contains the backtesting logic """ -from freqtrade.data.btanalysis import BT_DATA_COLUMNS +from freqtrade.data.btanalysis import BT_DATA_COLUMNS, trade_list_to_dataframe import logging from collections import defaultdict from copy import deepcopy @@ -385,11 +385,7 @@ class Backtesting: trades += self.handle_left_open(open_trades, data=data) - df = DataFrame.from_records([t.to_json() for t in trades], columns=BT_DATA_COLUMNS) - if len(df) > 0: - df.loc[:, 'close_date'] = to_datetime(df['close_date'], utc=True) - df.loc[:, 'open_date'] = to_datetime(df['open_date'], utc=True) - return df + return trade_list_to_dataframe(trades) def backtest_one_strategy(self, strat: IStrategy, data: Dict[str, Any], timerange: TimeRange): logger.info("Running backtesting for Strategy %s", strat.get_strategy_name()) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index cdd5c08d2..9d6a31955 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -7,14 +7,14 @@ from pandas import DataFrame, DateOffset, Timestamp, to_datetime from freqtrade.configuration import TimeRange from freqtrade.constants import LAST_BT_RESULT_FN -from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, analyze_trade_parallelism, - calculate_market_change, calculate_max_drawdown, +from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_MID, BT_DATA_COLUMNS_OLD, + analyze_trade_parallelism, calculate_market_change, + calculate_max_drawdown, combine_dataframes_with_mean, create_cum_profit, extract_trades_of_period, get_latest_backtest_filename, get_latest_hyperopt_file, load_backtest_data, load_trades, load_trades_from_db) from freqtrade.data.history import load_data, load_pair_history -from freqtrade.optimize.backtesting import BacktestResult from tests.conftest import create_mock_trades from tests.conftest_trades import MOCK_TRADE_COUNT @@ -55,7 +55,7 @@ def test_load_backtest_data_old_format(testdatadir): filename = testdatadir / "backtest-result_test.json" bt_data = load_backtest_data(filename) assert isinstance(bt_data, DataFrame) - assert list(bt_data.columns) == BT_DATA_COLUMNS + ["profit_abs"] + assert list(bt_data.columns) == BT_DATA_COLUMNS_OLD + ['profit_abs', 'profit_ratio'] assert len(bt_data) == 179 # Test loading from string (must yield same result) @@ -71,7 +71,7 @@ def test_load_backtest_data_new_format(testdatadir): filename = testdatadir / "backtest-result_new.json" bt_data = load_backtest_data(filename) assert isinstance(bt_data, DataFrame) - assert set(bt_data.columns) == set(list(BacktestResult._fields) + ["profit_abs"]) + assert set(bt_data.columns) == set(BT_DATA_COLUMNS_MID) assert len(bt_data) == 179 # Test loading from string (must yield same result) @@ -95,7 +95,7 @@ def test_load_backtest_data_multi(testdatadir): for strategy in ('DefaultStrategy', 'TestStrategy'): bt_data = load_backtest_data(filename, strategy=strategy) assert isinstance(bt_data, DataFrame) - assert set(bt_data.columns) == set(list(BacktestResult._fields) + ["profit_abs"]) + assert set(bt_data.columns) == set(BT_DATA_COLUMNS_MID) assert len(bt_data) == 179 # Test loading from string (must yield same result) @@ -122,7 +122,7 @@ def test_load_trades_from_db(default_conf, fee, mocker): assert isinstance(trades, DataFrame) assert "pair" in trades.columns assert "open_date" in trades.columns - assert "profit_percent" in trades.columns + assert "profit_ratio" in trades.columns for col in BT_DATA_COLUMNS: if col not in ['index', 'open_at_end']: From 9af89786ba450119a40b8e7da94ff11c8a3acbed Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sun, 24 Jan 2021 17:03:56 +0000 Subject: [PATCH 012/158] update installation.md ma --- docs/installation.md | 129 +++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 85 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 129ad1e36..b1a730666 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -218,7 +218,7 @@ On Linux, as an optional post-installation task, you may wish to setup the bot t ------ -## Conda (Miniconda or Anaconda) +## Installation with Conda (Miniconda or Anaconda) Freqtrade can also be installed with Miniconda or Anaconda. Conda (Miniconda or Anaconda) would automatically prepare and manage the extensive library-dependencies of the Freqtrade program. @@ -228,9 +228,7 @@ It is: (1) package, (2) dependency and (3) environment management for any progra Shortly : Conda < Miniconda < Anaconda. Check : https://linuxnetmag.com/miniconda-vs-anaconda/ -It is recommended to install Miniconda, not Anaconda. The difference between both lies in the amount of packages that would be installed upfront. Difference is at least like 1:8. - -https://www.dunderdata.com/blog/anaconda-is-bloated-set-up-a-lean-robust-data-science-environment-with-miniconda-and-conda-forge +It is recommended to install Miniconda, not Anaconda. The difference between both lies in the amount of packages that would be installed upfront. Difference in weight is around like 1:8 : https://www.dunderdata.com/blog/anaconda-is-bloated-set-up-a-lean-robust-data-science-environment-with-miniconda-and-conda-forge #### 1. Instal Conda @@ -243,6 +241,25 @@ Confirm with `yes` all questions. After installation, it is mandatory to turn yo #### 2. Prepare Conda environment +##### Enter/exit freqtrade-conda venv: + +To check available environments, do + +```bash +conda env list +``` + +to enter or exit choosen conda environment + +```bash +# Enter environemt : `freqtrade-conda`, note that, this one, does not exist yet, and will be created in next steps +conda activate freqtrade-conda + +# Exit +conda deactivate + +``` + ##### Change the channels with upgrades: After opening terminal, you already will be in default `base` conda environment @@ -253,12 +270,6 @@ If you want, you can prevent the (base) conda environment from being activated a conda config --set auto_activate_base false ``` -enter the conda base environment: - -```bash -conda activate base -``` - Conda as a package manager can download new packages from "channels". The best developed Conda channel, is not the default channel and is called `conda-forge`. The code below switches to it. ```bash @@ -277,38 +288,41 @@ conda config --show channels conda config --show channel_priority ``` -#### 3. Freqtrade Conda Environment +#### 3. Freqtrade Instalation -Now you have conda, but only (base) environment, +Download and install freqtrade. ```bash -conda env list +# download freqtrade +git clone https://github.com/freqtrade/freqtrade.git + +# enter downloaded directory 'freqtrade' +cd freqtrade ``` -It is time to setup environment of the Freqtrade itself: +#### 4. Freqtrade Conda Environment + + +It is time to setup the working environment of the Freqtrade itself: The conda command `create -n` automatically installs all nested dependencies for the selected libraries general structure of installation command is: ```bash +# choose your own packages conda create -n [name of the environment] [python version] [packages] + +# point to packages in file +conda create -n [name of the environment] -f [file] ``` -so it can be +For installig freqtrade with conda, we would use file `environment.yml` which exist in freqtrade directory ```bash -conda create -n freqtrade-conda python=3.8 pandas numpy ta-lib git wheel virtualenv +conda create -n freqtrade-conda -f environment.yml ``` -or if you expect, to use later jupiter for [data-analysis](data-analysis.md), use - -```bash -conda create -n freqtrade-jupyter-conda python=3.8 pandas numpy ta-lib git wheel virtualenv jupyter -``` - -the same works: for [docker](docker.md), for spyder and other useful programs. - Further read on the topic: https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 @@ -319,59 +333,12 @@ https://metager.de/meta/meta.ger3?eingabe=ardsdatascience+guide+to+conda+environ It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder -##### Enter/exit freqtrade-conda venv: - -to enter choosen conda environment - -```bash -conda activate freqtrade-conda - -``` - -to exit conda environment. - -```bash -conda deactivate -``` - -Don't do it now however and stay in conda environment. - -#### 4. Freqtrade Instalation - -When in `freqtrade-conda` environment, download and install freqtrade. Command `./setup.sh --install`, will take few minutes. - -```bash -# download freqtrade -git clone https://github.com/freqtrade/freqtrade.git - -# enter downloaded directory 'freqtrade' -cd freqtrade - -# run setup -./setup.sh --install -``` - -Create virtual environment (yes, python3-venv environment, inside conda-environment), where Freqtrade program can run. - -Running python3-venv seems to be requirement of the Freqtrade program itself. - -```bash -# create venv environment, inside hidden directory /freqtrede/.env -python3 -m venv ./.env/ - -# run the python3-venv environment -source ./.env/bin/activate - -# install last required package -pip install -e . -``` - ##### pip install within conda, a reminder: The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. -However, they are rare. +However, they are rare. https://www.anaconda.com/blog/using-pip-in-a-conda-environment -Nevertherless, that is why, the `conda-forge` channel is preferred: +Nevertherless, that is why, the `conda-forge` channel is preferred: * more libraries are available (less need for `pip`) * `conda-forge` works better with `pip` @@ -389,15 +356,14 @@ freqtrade create-userdir --userdir user_data # set up config file # make sure to run it set the `dry_run : true` as you start freqtrade new-config --config config.json - - -# run `dry_run` trades -freqtrade trade --strategy SampleStrategy ``` important shortcuts ```bash +# list installed conda environments +conda env list + # activate base environment conda activate @@ -405,14 +371,7 @@ conda activate conda activate freqtrade-conda #deactivate any conda environments -conda deactivate - -# list installed conda environments -conda env list - -# activation/deactivate the venv -source ./.env/bin/activate -deactivate +conda deactivate ``` Happy trading! From 2c2a33b2e8918a5b2ebd44f11300768cefd5f334 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sun, 24 Jan 2021 17:06:40 +0000 Subject: [PATCH 013/158] updated environemnt.ylm --- environment.yml | 113 ++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 51 deletions(-) diff --git a/environment.yml b/environment.yml index 746c4b912..38ca2d089 100644 --- a/environment.yml +++ b/environment.yml @@ -1,60 +1,71 @@ name: freqtrade channels: - - defaults + # - defaults - conda-forge dependencies: - # Required for app - - python>=3.7 - - pip - - wheel - - numpy - - pandas - - SQLAlchemy - - arrow - - requests - - urllib3 - - wrapt - - jsonschema - - tabulate - - python-rapidjson - - flask - - python-dotenv - - cachetools - - python-telegram-bot - # Optional for plotting - - plotly - # Optional for hyperopt - - scipy - - scikit-optimize - - scikit-learn - - filelock - - joblib - # Optional for development - - flake8 - - pytest - - pytest-mock - - pytest-asyncio - - pytest-cov - - coveralls - - mypy - # Useful for jupyter - - jupyter - - ipykernel - - isort - - yapf - - pip: - # Required for app - - cython - - pycoingecko - - ccxt +# 1/4 req main + - python>=3.7 + - numpy + - pandas + - pip + + - aiohttp + - SQLAlchemy + - python-telegram-bot + - arrow + - cachetools + - requests + - urllib3 + - wrapt + - jsonschema - TA-Lib - - py_find_1st + - tabulate + - jinja2 + - blosc - sdnotify - # Optional for develpment - - flake8-tidy-imports - - flake8-type-annotations - - pytest-random-order - - -e . + - fastapi + - uvicorn + - pyjwt + - colorama + - questionary + - prompt-toolkit + # ============================ + # 2/4 req dev + - coveralls + - flake8 + - mypy + - pytest + - pytest-asyncio + - pytest-cov + - pytest-mock= + - isort + - nbconvert + + # ============================ + # 3/4 req hyperopt + + - scipy + - scikit-learn + - filelock + - scikit-optimize + - joblib + - progressbar2 + # ============================ + # 4/4 req plot + + - plotly + - jupyter + + - pip: + - pycoingecko + - py_find_1st + - tables + - pytest-random-order + - flake8-type-annotations + - ccxt + - flake8-tidy-imports + - -e . + # - python-rapidjso From 789a980a3071eb547cb1de36924d4d55331e8f75 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Jan 2021 09:56:27 +0100 Subject: [PATCH 014/158] Fix tests for new export format --- freqtrade/data/btanalysis.py | 2 ++ freqtrade/optimize/backtesting.py | 4 +-- tests/optimize/test_backtesting.py | 27 ++++++++++++------- .../testdata/backtest-result_multistrat.json | 2 +- tests/testdata/backtest-result_new.json | 2 +- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 20977e447..c004a4d23 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -26,6 +26,7 @@ BT_DATA_COLUMNS_MID = ['pair', 'profit_percent', 'open_date', 'close_date', 'tra # Newest format BT_DATA_COLUMNS = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', + 'open_rate', 'close_rate', 'fee_open', 'fee_close', 'trade_duration', 'profit_ratio', 'profit_abs', 'sell_reason', 'initial_stop_loss_abs', 'initial_stop_loss_ratio', 'stop_loss_abs', @@ -233,6 +234,7 @@ def trade_list_to_dataframe(trades: List[Trade]) -> pd.DataFrame: if len(df) > 0: df.loc[:, 'close_date'] = pd.to_datetime(df['close_date'], utc=True) df.loc[:, 'open_date'] = pd.to_datetime(df['open_date'], utc=True) + df.loc[:, 'close_rate'] = df['close_rate'].astype('float64') return df diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 875538731..3186313e1 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -3,18 +3,18 @@ """ This module contains the backtesting logic """ -from freqtrade.data.btanalysis import BT_DATA_COLUMNS, trade_list_to_dataframe import logging from collections import defaultdict from copy import deepcopy from datetime import datetime, timedelta, timezone from typing import Any, Dict, List, Optional, Tuple -from pandas import DataFrame, to_datetime +from pandas import DataFrame from freqtrade.configuration import TimeRange, remove_credentials, validate_config_consistency from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.data import history +from freqtrade.data.btanalysis import trade_list_to_dataframe from freqtrade.data.converter import trim_dataframe from freqtrade.data.dataprovider import DataProvider from freqtrade.exceptions import OperationalException diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 54eeb7929..5f811e2e5 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -445,7 +445,7 @@ def test_backtesting_pairlist_list(default_conf, mocker, caplog, testdatadir, ti Backtesting(default_conf) -def test_backtest(default_conf, fee, mocker, testdatadir) -> None: +def test_backtest_one(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) @@ -469,21 +469,28 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: expected = pd.DataFrame( {'pair': [pair, pair], - 'profit_ratio': [0.0, 0.0], - 'profit_abs': [0.0, 0.0], + 'stake_amount': [0.001, 0.001], + 'amount': [0.00957442, 0.0097064], 'open_date': pd.to_datetime([Arrow(2018, 1, 29, 18, 40, 0).datetime, Arrow(2018, 1, 30, 3, 30, 0).datetime], utc=True ), - 'open_rate': [0.104445, 0.10302485], - 'open_fee': [0.0025, 0.0025], 'close_date': pd.to_datetime([Arrow(2018, 1, 29, 22, 35, 0).datetime, Arrow(2018, 1, 30, 4, 10, 0).datetime], utc=True), + 'open_rate': [0.104445, 0.10302485], 'close_rate': [0.104969, 0.103541], - 'close_fee': [0.0025, 0.0025], - 'amount': [0.00957442, 0.0097064], + 'fee_open': [0.0025, 0.0025], + 'fee_close': [0.0025, 0.0025], 'trade_duration': [235, 40], - 'open_at_end': [False, False], - 'sell_reason': [SellType.ROI, SellType.ROI] + 'profit_ratio': [0.0, 0.0], + 'profit_abs': [0.0, 0.0], + 'sell_reason': [SellType.ROI, SellType.ROI], + 'initial_stop_loss_abs': [0.0940005, 0.09272236], + 'initial_stop_loss_ratio': [-0.1, -0.1], + 'stop_loss_abs': [0.0940005, 0.09272236], + 'stop_loss_ratio': [-0.1, -0.1], + 'min_rate': [0.1038, 0.10302485], + 'max_rate': [0.10501, 0.1038888], + 'is_open': [False, False], }) pd.testing.assert_frame_equal(results, expected) data_pair = processed[pair] @@ -737,7 +744,7 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir): def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): patch_exchange(mocker) - backtestmock = MagicMock(return_value=pd.DataFrame(columns=BT_DATA_COLUMNS + ['profit_abs'])) + backtestmock = MagicMock(return_value=pd.DataFrame(columns=BT_DATA_COLUMNS)) mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', PropertyMock(return_value=['UNITTEST/BTC'])) mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest', backtestmock) diff --git a/tests/testdata/backtest-result_multistrat.json b/tests/testdata/backtest-result_multistrat.json index 0e5386ef3..6999050b6 100644 --- a/tests/testdata/backtest-result_multistrat.json +++ b/tests/testdata/backtest-result_multistrat.json @@ -1 +1 @@ -{"strategy": {"DefaultStrategy": {"trades": [{"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:20:00+00:00", "trade_duration": 5, "open_rate": 9.64e-05, "close_rate": 0.00010074887218045112, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1037.344398340249, "profit_abs": 0.00399999999999999}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:30:00+00:00", "trade_duration": 15, "open_rate": 4.756e-05, "close_rate": 4.9705563909774425e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2102.6072329688814, "profit_abs": 0.00399999999999999}, {"pair": "XLM/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:35:00+00:00", "trade_duration": 10, "open_rate": 3.339e-05, "close_rate": 3.489631578947368e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2994.908655286014, "profit_abs": 0.0040000000000000036}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:40:00+00:00", "trade_duration": 15, "open_rate": 9.696e-05, "close_rate": 0.00010133413533834584, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1031.3531353135315, "profit_abs": 0.00399999999999999}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 07:35:00+00:00", "close_date": "2018-01-10 08:35:00+00:00", "trade_duration": 60, "open_rate": 0.0943, "close_rate": 0.09477268170426063, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0604453870625663, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 07:40:00+00:00", "close_date": "2018-01-10 08:10:00+00:00", "trade_duration": 30, "open_rate": 0.02719607, "close_rate": 0.02760503345864661, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.677001860930642, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 08:15:00+00:00", "close_date": "2018-01-10 09:55:00+00:00", "trade_duration": 100, "open_rate": 0.04634952, "close_rate": 0.046581848421052625, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.1575196463739, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 14:45:00+00:00", "close_date": "2018-01-10 15:50:00+00:00", "trade_duration": 65, "open_rate": 3.066e-05, "close_rate": 3.081368421052631e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3261.5786040443577, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 16:35:00+00:00", "close_date": "2018-01-10 17:15:00+00:00", "trade_duration": 40, "open_rate": 0.0168999, "close_rate": 0.016984611278195488, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 5.917194776300452, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 16:40:00+00:00", "close_date": "2018-01-10 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.09132568, "close_rate": 0.0917834528320802, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0949822656672252, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 18:50:00+00:00", "close_date": "2018-01-10 19:45:00+00:00", "trade_duration": 55, "open_rate": 0.08898003, "close_rate": 0.08942604518796991, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1238476768326557, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 22:15:00+00:00", "close_date": "2018-01-10 23:00:00+00:00", "trade_duration": 45, "open_rate": 0.08560008, "close_rate": 0.08602915308270676, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1682232072680307, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 22:50:00+00:00", "close_date": "2018-01-10 23:20:00+00:00", "trade_duration": 30, "open_rate": 0.00249083, "close_rate": 0.0025282860902255634, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 40.147260150231055, "profit_abs": 0.000999999999999987}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 23:15:00+00:00", "close_date": "2018-01-11 00:15:00+00:00", "trade_duration": 60, "open_rate": 3.022e-05, "close_rate": 3.037147869674185e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3309.0668431502318, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-10 23:40:00+00:00", "close_date": "2018-01-11 00:05:00+00:00", "trade_duration": 25, "open_rate": 0.002437, "close_rate": 0.0024980776942355883, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 41.03405826836274, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 00:00:00+00:00", "close_date": "2018-01-11 00:35:00+00:00", "trade_duration": 35, "open_rate": 0.04771803, "close_rate": 0.04843559436090225, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0956439316543456, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-11 03:40:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 45, "open_rate": 3.651e-05, "close_rate": 3.2859000000000005e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2738.9756231169545, "profit_abs": -0.01047499999999997}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 03:55:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 30, "open_rate": 0.08824105, "close_rate": 0.08956798308270676, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1332594070446804, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 04:00:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 50, "open_rate": 0.00243, "close_rate": 0.002442180451127819, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 41.1522633744856, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:55:00+00:00", "trade_duration": 25, "open_rate": 0.04545064, "close_rate": 0.046589753784461146, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.200189040242338, "profit_abs": 0.001999999999999988}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 20, "open_rate": 3.372e-05, "close_rate": 3.456511278195488e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2965.599051008304, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:55:00+00:00", "close_date": "2018-01-11 05:15:00+00:00", "trade_duration": 20, "open_rate": 0.02644, "close_rate": 0.02710265664160401, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.7821482602118004, "profit_abs": 0.001999999999999988}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:20:00+00:00", "close_date": "2018-01-11 12:00:00+00:00", "trade_duration": 40, "open_rate": 0.08812, "close_rate": 0.08856170426065162, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1348161597821154, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:35:00+00:00", "close_date": "2018-01-11 12:15:00+00:00", "trade_duration": 40, "open_rate": 0.02683577, "close_rate": 0.026970285137844607, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.7263696923919087, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 14:00:00+00:00", "close_date": "2018-01-11 14:25:00+00:00", "trade_duration": 25, "open_rate": 4.919e-05, "close_rate": 5.04228320802005e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2032.9335230737956, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 19:25:00+00:00", "close_date": "2018-01-11 20:35:00+00:00", "trade_duration": 70, "open_rate": 0.08784896, "close_rate": 0.08828930566416039, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1383174029607181, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:35:00+00:00", "close_date": "2018-01-11 23:30:00+00:00", "trade_duration": 55, "open_rate": 5.105e-05, "close_rate": 5.130588972431077e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1958.8638589618022, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:25:00+00:00", "trade_duration": 30, "open_rate": 3.96e-05, "close_rate": 4.019548872180451e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2525.252525252525, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:35:00+00:00", "trade_duration": 40, "open_rate": 2.885e-05, "close_rate": 2.899461152882205e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3466.204506065858, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 23:30:00+00:00", "close_date": "2018-01-12 00:05:00+00:00", "trade_duration": 35, "open_rate": 0.02645, "close_rate": 0.026847744360902256, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.780718336483932, "profit_abs": 0.0010000000000000148}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 23:55:00+00:00", "close_date": "2018-01-12 01:15:00+00:00", "trade_duration": 80, "open_rate": 0.048, "close_rate": 0.04824060150375939, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0833333333333335, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-12 21:15:00+00:00", "close_date": "2018-01-12 21:40:00+00:00", "trade_duration": 25, "open_rate": 4.692e-05, "close_rate": 4.809593984962405e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2131.287297527707, "profit_abs": 0.001999999999999974}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 00:55:00+00:00", "close_date": "2018-01-13 06:20:00+00:00", "trade_duration": 325, "open_rate": 0.00256966, "close_rate": 0.0025825405012531327, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.91565421106294, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 10:55:00+00:00", "close_date": "2018-01-13 11:35:00+00:00", "trade_duration": 40, "open_rate": 6.262e-05, "close_rate": 6.293388471177944e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1596.933886937081, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 13:05:00+00:00", "close_date": "2018-01-15 14:10:00+00:00", "trade_duration": 2945, "open_rate": 4.73e-05, "close_rate": 4.753709273182957e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2114.1649048625795, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:30:00+00:00", "close_date": "2018-01-13 14:45:00+00:00", "trade_duration": 75, "open_rate": 6.063e-05, "close_rate": 6.0933909774436085e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1649.348507339601, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:40:00+00:00", "close_date": "2018-01-13 23:30:00+00:00", "trade_duration": 590, "open_rate": 0.00011082, "close_rate": 0.00011137548872180448, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 902.3641941887746, "profit_abs": -2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 15:15:00+00:00", "close_date": "2018-01-13 15:55:00+00:00", "trade_duration": 40, "open_rate": 5.93e-05, "close_rate": 5.9597243107769415e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1686.3406408094436, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 16:30:00+00:00", "close_date": "2018-01-13 17:10:00+00:00", "trade_duration": 40, "open_rate": 0.04850003, "close_rate": 0.04874313791979949, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0618543947292407, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 22:05:00+00:00", "close_date": "2018-01-14 06:25:00+00:00", "trade_duration": 500, "open_rate": 0.09825019, "close_rate": 0.09874267215538848, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0178097365511456, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 00:20:00+00:00", "close_date": "2018-01-14 22:55:00+00:00", "trade_duration": 1355, "open_rate": 6.018e-05, "close_rate": 6.048165413533834e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1661.681621801263, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 12:45:00+00:00", "close_date": "2018-01-14 13:25:00+00:00", "trade_duration": 40, "open_rate": 0.09758999, "close_rate": 0.0980791628822055, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.024695258191952, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-14 15:30:00+00:00", "close_date": "2018-01-14 16:00:00+00:00", "trade_duration": 30, "open_rate": 0.00311, "close_rate": 0.0031567669172932328, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 32.154340836012864, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 20:45:00+00:00", "close_date": "2018-01-14 22:15:00+00:00", "trade_duration": 90, "open_rate": 0.00312401, "close_rate": 0.003139669197994987, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 32.010140812609436, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 23:35:00+00:00", "close_date": "2018-01-15 00:30:00+00:00", "trade_duration": 55, "open_rate": 0.0174679, "close_rate": 0.017555458395989976, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 5.724786608579165, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 23:45:00+00:00", "close_date": "2018-01-15 00:25:00+00:00", "trade_duration": 40, "open_rate": 0.07346846, "close_rate": 0.07383672295739348, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.3611282991367997, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 02:25:00+00:00", "close_date": "2018-01-15 03:05:00+00:00", "trade_duration": 40, "open_rate": 0.097994, "close_rate": 0.09848519799498744, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.020470641059657, "profit_abs": -2.7755575615628914e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 07:20:00+00:00", "close_date": "2018-01-15 08:00:00+00:00", "trade_duration": 40, "open_rate": 0.09659, "close_rate": 0.09707416040100247, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0353038616834043, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-15 08:20:00+00:00", "close_date": "2018-01-15 08:55:00+00:00", "trade_duration": 35, "open_rate": 9.987e-05, "close_rate": 0.00010137180451127818, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1001.3016921998599, "profit_abs": 0.0010000000000000009}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-15 12:10:00+00:00", "close_date": "2018-01-16 02:50:00+00:00", "trade_duration": 880, "open_rate": 0.0948969, "close_rate": 0.09537257368421052, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0537752023511833, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:10:00+00:00", "close_date": "2018-01-15 17:40:00+00:00", "trade_duration": 210, "open_rate": 0.071, "close_rate": 0.07135588972431077, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4084507042253522, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:30:00+00:00", "close_date": "2018-01-15 15:10:00+00:00", "trade_duration": 40, "open_rate": 0.04600501, "close_rate": 0.046235611553884705, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.173676301776698, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:10:00+00:00", "close_date": "2018-01-15 19:25:00+00:00", "trade_duration": 75, "open_rate": 9.438e-05, "close_rate": 9.485308270676693e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1059.5465140919687, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:35:00+00:00", "close_date": "2018-01-15 19:15:00+00:00", "trade_duration": 40, "open_rate": 0.03040001, "close_rate": 0.030552391002506264, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.2894726021471703, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-15 20:25:00+00:00", "close_date": "2018-01-16 08:25:00+00:00", "trade_duration": 720, "open_rate": 5.837e-05, "close_rate": 5.2533e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1713.2088401576154, "profit_abs": -0.010474999999999984}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 20:40:00+00:00", "close_date": "2018-01-15 22:00:00+00:00", "trade_duration": 80, "open_rate": 0.046036, "close_rate": 0.04626675689223057, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.1722130506560084, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 00:30:00+00:00", "close_date": "2018-01-16 01:10:00+00:00", "trade_duration": 40, "open_rate": 0.0028685, "close_rate": 0.0028828784461152877, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 34.86142583231654, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 01:15:00+00:00", "close_date": "2018-01-16 02:35:00+00:00", "trade_duration": 80, "open_rate": 0.06731755, "close_rate": 0.0676549813283208, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4854967241083492, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 07:45:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 55, "open_rate": 0.09217614, "close_rate": 0.09263817578947368, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0848794492804754, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:55:00+00:00", "trade_duration": 20, "open_rate": 0.0165, "close_rate": 0.016913533834586467, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.0606060606060606, "profit_abs": 0.0020000000000000018}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 5, "open_rate": 7.953e-05, "close_rate": 8.311781954887218e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1257.387149503332, "profit_abs": 0.00399999999999999}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 08:45:00+00:00", "close_date": "2018-01-16 09:50:00+00:00", "trade_duration": 65, "open_rate": 0.045202, "close_rate": 0.04542857644110275, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.2122914915269236, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:45:00+00:00", "trade_duration": 30, "open_rate": 5.248e-05, "close_rate": 5.326917293233082e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1905.487804878049, "profit_abs": 0.0010000000000000009}, {"pair": "XMR/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:55:00+00:00", "trade_duration": 40, "open_rate": 0.02892318, "close_rate": 0.02906815834586466, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.457434486802627, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 09:50:00+00:00", "close_date": "2018-01-16 10:10:00+00:00", "trade_duration": 20, "open_rate": 5.158e-05, "close_rate": 5.287273182957392e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1938.735944164405, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:35:00+00:00", "trade_duration": 30, "open_rate": 0.02828232, "close_rate": 0.02870761804511278, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5357778286929786, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:40:00+00:00", "trade_duration": 35, "open_rate": 0.04357584, "close_rate": 0.044231115789473675, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.294849623093898, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 13:45:00+00:00", "close_date": "2018-01-16 14:20:00+00:00", "trade_duration": 35, "open_rate": 5.362e-05, "close_rate": 5.442631578947368e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1864.975755315181, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 17:30:00+00:00", "close_date": "2018-01-16 18:25:00+00:00", "trade_duration": 55, "open_rate": 5.302e-05, "close_rate": 5.328576441102756e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1886.0807242549984, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:45:00+00:00", "trade_duration": 30, "open_rate": 0.09129999, "close_rate": 0.09267292218045112, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0952903718828448, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:35:00+00:00", "trade_duration": 20, "open_rate": 3.808e-05, "close_rate": 3.903438596491228e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2626.0504201680674, "profit_abs": 0.0020000000000000018}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 19:00:00+00:00", "close_date": "2018-01-16 19:30:00+00:00", "trade_duration": 30, "open_rate": 0.02811012, "close_rate": 0.028532828571428567, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.557437677249333, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 60, "open_rate": 0.00258379, "close_rate": 0.002325411, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.702835756775904, "profit_abs": -0.010474999999999984}, {"pair": "NXT/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 80, "open_rate": 2.559e-05, "close_rate": 2.3031e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3907.7764751856193, "profit_abs": -0.010474999999999998}, {"pair": "TRX/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:35:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 50, "open_rate": 7.62e-05, "close_rate": 6.858e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1312.3359580052495, "profit_abs": -0.010474999999999984}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:35:00+00:00", "trade_duration": 5, "open_rate": 0.00229844, "close_rate": 0.002402129022556391, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 43.507770487809125, "profit_abs": 0.004000000000000017}, {"pair": "LTC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:40:00+00:00", "trade_duration": 10, "open_rate": 0.0151, "close_rate": 0.015781203007518795, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.622516556291391, "profit_abs": 0.00399999999999999}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:40:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 5, "open_rate": 0.00235676, "close_rate": 0.00246308, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 42.431134269081284, "profit_abs": 0.0040000000000000036}, {"pair": "DASH/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 22:45:00+00:00", "close_date": "2018-01-16 23:05:00+00:00", "trade_duration": 20, "open_rate": 0.0630692, "close_rate": 0.06464988170426066, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.585559988076589, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:50:00+00:00", "close_date": "2018-01-16 22:55:00+00:00", "trade_duration": 5, "open_rate": 2.2e-05, "close_rate": 2.299248120300751e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 4545.454545454546, "profit_abs": 0.003999999999999976}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-17 03:30:00+00:00", "close_date": "2018-01-17 04:00:00+00:00", "trade_duration": 30, "open_rate": 4.974e-05, "close_rate": 5.048796992481203e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2010.454362685967, "profit_abs": 0.0010000000000000009}, {"pair": "TRX/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-17 03:55:00+00:00", "close_date": "2018-01-17 04:15:00+00:00", "trade_duration": 20, "open_rate": 7.108e-05, "close_rate": 7.28614536340852e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1406.8655036578502, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 09:35:00+00:00", "close_date": "2018-01-17 10:15:00+00:00", "trade_duration": 40, "open_rate": 0.04327, "close_rate": 0.04348689223057644, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.3110700254217704, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:20:00+00:00", "close_date": "2018-01-17 17:00:00+00:00", "trade_duration": 400, "open_rate": 4.997e-05, "close_rate": 5.022047619047618e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2001.2007204322595, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:25:00+00:00", "trade_duration": 55, "open_rate": 0.06836818, "close_rate": 0.06871087764411027, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4626687444363737, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:10:00+00:00", "trade_duration": 40, "open_rate": 3.63e-05, "close_rate": 3.648195488721804e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2754.8209366391184, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:30:00+00:00", "close_date": "2018-01-17 22:05:00+00:00", "trade_duration": 575, "open_rate": 0.0281, "close_rate": 0.02824085213032581, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5587188612099645, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:35:00+00:00", "close_date": "2018-01-17 16:55:00+00:00", "trade_duration": 260, "open_rate": 0.08651001, "close_rate": 0.08694364413533832, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1559355963546878, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 05:00:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 55, "open_rate": 5.633e-05, "close_rate": 5.6612355889724306e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1775.2529735487308, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 05:20:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 35, "open_rate": 0.06988494, "close_rate": 0.07093584135338346, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.430923457900944, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 07:35:00+00:00", "close_date": "2018-01-18 08:15:00+00:00", "trade_duration": 40, "open_rate": 5.545e-05, "close_rate": 5.572794486215538e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1803.4265103697026, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 09:00:00+00:00", "close_date": "2018-01-18 09:40:00+00:00", "trade_duration": 40, "open_rate": 0.01633527, "close_rate": 0.016417151052631574, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.121723118136401, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 16:40:00+00:00", "close_date": "2018-01-18 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.00269734, "close_rate": 0.002710860501253133, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 37.073561360451414, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-18 18:05:00+00:00", "close_date": "2018-01-18 18:30:00+00:00", "trade_duration": 25, "open_rate": 4.475e-05, "close_rate": 4.587155388471177e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2234.63687150838, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 18:25:00+00:00", "close_date": "2018-01-18 18:55:00+00:00", "trade_duration": 30, "open_rate": 2.79e-05, "close_rate": 2.8319548872180444e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3584.2293906810037, "profit_abs": 0.000999999999999987}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 20:10:00+00:00", "close_date": "2018-01-18 20:50:00+00:00", "trade_duration": 40, "open_rate": 0.04439326, "close_rate": 0.04461578260651629, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.2525942001105577, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 21:30:00+00:00", "close_date": "2018-01-19 00:35:00+00:00", "trade_duration": 185, "open_rate": 4.49e-05, "close_rate": 4.51250626566416e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2227.1714922049, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 21:55:00+00:00", "close_date": "2018-01-19 05:05:00+00:00", "trade_duration": 430, "open_rate": 0.02855, "close_rate": 0.028693107769423555, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.502626970227671, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 22:10:00+00:00", "close_date": "2018-01-18 22:50:00+00:00", "trade_duration": 40, "open_rate": 5.796e-05, "close_rate": 5.8250526315789473e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1725.3278122843342, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 23:50:00+00:00", "close_date": "2018-01-19 00:30:00+00:00", "trade_duration": 40, "open_rate": 0.04340323, "close_rate": 0.04362079005012531, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.303975994413319, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-19 16:45:00+00:00", "close_date": "2018-01-19 17:35:00+00:00", "trade_duration": 50, "open_rate": 0.04454455, "close_rate": 0.04476783095238095, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.244943545282195, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:15:00+00:00", "close_date": "2018-01-19 19:55:00+00:00", "trade_duration": 160, "open_rate": 5.62e-05, "close_rate": 5.648170426065162e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1779.3594306049824, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:20:00+00:00", "close_date": "2018-01-19 20:15:00+00:00", "trade_duration": 175, "open_rate": 4.339e-05, "close_rate": 4.360749373433584e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2304.6784973496196, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-20 04:45:00+00:00", "close_date": "2018-01-20 17:35:00+00:00", "trade_duration": 770, "open_rate": 0.0001009, "close_rate": 0.00010140576441102755, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 991.0802775024778, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 15:15:00+00:00", "trade_duration": 625, "open_rate": 0.00270505, "close_rate": 0.002718609147869674, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.96789338459548, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 07:00:00+00:00", "trade_duration": 130, "open_rate": 0.03000002, "close_rate": 0.030150396040100245, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.3333311111125927, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 09:00:00+00:00", "close_date": "2018-01-20 09:40:00+00:00", "trade_duration": 40, "open_rate": 5.46e-05, "close_rate": 5.4873684210526304e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1831.5018315018317, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-20 18:25:00+00:00", "close_date": "2018-01-25 03:50:00+00:00", "trade_duration": 6325, "open_rate": 0.03082222, "close_rate": 0.027739998, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.244412634781012, "profit_abs": -0.010474999999999998}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 22:25:00+00:00", "close_date": "2018-01-20 23:15:00+00:00", "trade_duration": 50, "open_rate": 0.08969999, "close_rate": 0.09014961401002504, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1148273260677064, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 02:50:00+00:00", "close_date": "2018-01-21 14:30:00+00:00", "trade_duration": 700, "open_rate": 0.01632501, "close_rate": 0.01640683962406015, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.125570520324337, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 10:20:00+00:00", "close_date": "2018-01-21 11:00:00+00:00", "trade_duration": 40, "open_rate": 0.070538, "close_rate": 0.07089157393483708, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.417675579120474, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 15:50:00+00:00", "close_date": "2018-01-21 18:45:00+00:00", "trade_duration": 175, "open_rate": 5.301e-05, "close_rate": 5.327571428571427e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1886.4365214110546, "profit_abs": -2.7755575615628914e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 16:20:00+00:00", "close_date": "2018-01-21 17:00:00+00:00", "trade_duration": 40, "open_rate": 3.955e-05, "close_rate": 3.9748245614035085e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2528.4450063211125, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:45:00+00:00", "trade_duration": 30, "open_rate": 0.00258505, "close_rate": 0.002623922932330827, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.6839712964933, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:55:00+00:00", "trade_duration": 40, "open_rate": 3.903e-05, "close_rate": 3.922563909774435e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2562.1316935690497, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 00:35:00+00:00", "close_date": "2018-01-22 10:35:00+00:00", "trade_duration": 600, "open_rate": 5.236e-05, "close_rate": 5.262245614035087e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1909.8548510313217, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 01:30:00+00:00", "close_date": "2018-01-22 02:10:00+00:00", "trade_duration": 40, "open_rate": 9.028e-05, "close_rate": 9.07325313283208e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1107.6650420912717, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 12:25:00+00:00", "close_date": "2018-01-22 14:35:00+00:00", "trade_duration": 130, "open_rate": 0.002687, "close_rate": 0.002700468671679198, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 37.21622627465575, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 13:15:00+00:00", "close_date": "2018-01-22 13:55:00+00:00", "trade_duration": 40, "open_rate": 4.168e-05, "close_rate": 4.188892230576441e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2399.232245681382, "profit_abs": 1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-22 14:00:00+00:00", "close_date": "2018-01-22 14:30:00+00:00", "trade_duration": 30, "open_rate": 8.821e-05, "close_rate": 8.953646616541353e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1133.6583153837435, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 15:55:00+00:00", "close_date": "2018-01-22 16:40:00+00:00", "trade_duration": 45, "open_rate": 5.172e-05, "close_rate": 5.1979248120300745e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1933.4880123743235, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-22 16:05:00+00:00", "close_date": "2018-01-22 16:25:00+00:00", "trade_duration": 20, "open_rate": 3.026e-05, "close_rate": 3.101839598997494e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3304.692663582287, "profit_abs": 0.0020000000000000157}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 19:50:00+00:00", "close_date": "2018-01-23 00:10:00+00:00", "trade_duration": 260, "open_rate": 0.07064, "close_rate": 0.07099408521303258, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.415628539071348, "profit_abs": 1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 21:25:00+00:00", "close_date": "2018-01-22 22:05:00+00:00", "trade_duration": 40, "open_rate": 0.01644483, "close_rate": 0.01652726022556391, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.080938507725528, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-23 00:05:00+00:00", "close_date": "2018-01-23 00:35:00+00:00", "trade_duration": 30, "open_rate": 4.331e-05, "close_rate": 4.3961278195488714e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2308.935580697299, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-23 01:50:00+00:00", "close_date": "2018-01-23 02:15:00+00:00", "trade_duration": 25, "open_rate": 3.2e-05, "close_rate": 3.2802005012531326e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3125.0000000000005, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 04:25:00+00:00", "close_date": "2018-01-23 05:15:00+00:00", "trade_duration": 50, "open_rate": 0.09167706, "close_rate": 0.09213659413533835, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0907854156754153, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 07:35:00+00:00", "close_date": "2018-01-23 09:00:00+00:00", "trade_duration": 85, "open_rate": 0.0692498, "close_rate": 0.06959691679197995, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4440474918339115, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 10:50:00+00:00", "close_date": "2018-01-23 13:05:00+00:00", "trade_duration": 135, "open_rate": 3.182e-05, "close_rate": 3.197949874686716e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3142.677561282213, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 11:05:00+00:00", "close_date": "2018-01-23 16:05:00+00:00", "trade_duration": 300, "open_rate": 0.04088, "close_rate": 0.04108491228070175, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4461839530332683, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 14:55:00+00:00", "close_date": "2018-01-23 15:35:00+00:00", "trade_duration": 40, "open_rate": 5.15e-05, "close_rate": 5.175814536340851e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1941.747572815534, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 16:35:00+00:00", "close_date": "2018-01-24 00:05:00+00:00", "trade_duration": 450, "open_rate": 0.09071698, "close_rate": 0.09117170170426064, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1023294646713329, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 17:25:00+00:00", "close_date": "2018-01-23 18:45:00+00:00", "trade_duration": 80, "open_rate": 3.128e-05, "close_rate": 3.1436791979949865e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3196.9309462915603, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 20:15:00+00:00", "close_date": "2018-01-23 22:00:00+00:00", "trade_duration": 105, "open_rate": 9.555e-05, "close_rate": 9.602894736842104e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1046.5724751439038, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 22:30:00+00:00", "close_date": "2018-01-23 23:10:00+00:00", "trade_duration": 40, "open_rate": 0.04080001, "close_rate": 0.0410045213283208, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.450979791426522, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 23:50:00+00:00", "close_date": "2018-01-24 03:35:00+00:00", "trade_duration": 225, "open_rate": 5.163e-05, "close_rate": 5.18887969924812e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1936.8584156498162, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 00:20:00+00:00", "close_date": "2018-01-24 01:50:00+00:00", "trade_duration": 90, "open_rate": 0.04040781, "close_rate": 0.04061035541353383, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.474769110228938, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 06:45:00+00:00", "close_date": "2018-01-24 07:25:00+00:00", "trade_duration": 40, "open_rate": 5.132e-05, "close_rate": 5.157724310776942e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1948.5580670303975, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-24 14:15:00+00:00", "close_date": "2018-01-24 14:25:00+00:00", "trade_duration": 10, "open_rate": 5.198e-05, "close_rate": 5.432496240601503e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1923.8168526356292, "profit_abs": 0.0040000000000000036}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 14:50:00+00:00", "close_date": "2018-01-24 16:35:00+00:00", "trade_duration": 105, "open_rate": 3.054e-05, "close_rate": 3.069308270676692e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3274.3942370661425, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 15:10:00+00:00", "close_date": "2018-01-24 16:15:00+00:00", "trade_duration": 65, "open_rate": 9.263e-05, "close_rate": 9.309431077694236e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1079.5638562020945, "profit_abs": 2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 22:40:00+00:00", "close_date": "2018-01-24 23:25:00+00:00", "trade_duration": 45, "open_rate": 5.514e-05, "close_rate": 5.54163909774436e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1813.5654697134569, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 00:50:00+00:00", "close_date": "2018-01-25 01:30:00+00:00", "trade_duration": 40, "open_rate": 4.921e-05, "close_rate": 4.9456666666666664e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2032.1072952651903, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 08:15:00+00:00", "close_date": "2018-01-25 12:15:00+00:00", "trade_duration": 240, "open_rate": 0.0026, "close_rate": 0.002613032581453634, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.46153846153847, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 10:25:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 350, "open_rate": 0.02799871, "close_rate": 0.028139054411027563, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.571593119825878, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 11:00:00+00:00", "close_date": "2018-01-25 11:45:00+00:00", "trade_duration": 45, "open_rate": 0.04078902, "close_rate": 0.0409934762406015, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4516401717913303, "profit_abs": -1.3877787807814457e-17}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:05:00+00:00", "close_date": "2018-01-25 13:45:00+00:00", "trade_duration": 40, "open_rate": 2.89e-05, "close_rate": 2.904486215538847e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3460.2076124567475, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:20:00+00:00", "close_date": "2018-01-25 14:05:00+00:00", "trade_duration": 45, "open_rate": 0.041103, "close_rate": 0.04130903007518797, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4329124394813033, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-25 15:45:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 30, "open_rate": 5.428e-05, "close_rate": 5.509624060150376e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1842.2991893883568, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 17:45:00+00:00", "close_date": "2018-01-25 23:15:00+00:00", "trade_duration": 330, "open_rate": 5.414e-05, "close_rate": 5.441137844611528e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1847.063169560399, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 21:15:00+00:00", "close_date": "2018-01-25 21:55:00+00:00", "trade_duration": 40, "open_rate": 0.04140777, "close_rate": 0.0416153277443609, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.415005686130888, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 02:05:00+00:00", "close_date": "2018-01-26 02:45:00+00:00", "trade_duration": 40, "open_rate": 0.00254309, "close_rate": 0.002555837318295739, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 39.32224183965177, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 02:55:00+00:00", "close_date": "2018-01-26 15:10:00+00:00", "trade_duration": 735, "open_rate": 5.607e-05, "close_rate": 5.6351052631578935e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1783.4849295523454, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 06:10:00+00:00", "close_date": "2018-01-26 09:25:00+00:00", "trade_duration": 195, "open_rate": 0.00253806, "close_rate": 0.0025507821052631577, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 39.400171784748984, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 07:25:00+00:00", "close_date": "2018-01-26 09:55:00+00:00", "trade_duration": 150, "open_rate": 0.0415, "close_rate": 0.04170802005012531, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4096385542168677, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-26 09:55:00+00:00", "close_date": "2018-01-26 10:25:00+00:00", "trade_duration": 30, "open_rate": 5.321e-05, "close_rate": 5.401015037593984e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1879.3459875963165, "profit_abs": 0.000999999999999987}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 16:05:00+00:00", "close_date": "2018-01-26 16:45:00+00:00", "trade_duration": 40, "open_rate": 0.02772046, "close_rate": 0.02785940967418546, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.6074437437185387, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 23:35:00+00:00", "close_date": "2018-01-27 00:15:00+00:00", "trade_duration": 40, "open_rate": 0.09461341, "close_rate": 0.09508766268170424, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0569326272036914, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 00:35:00+00:00", "close_date": "2018-01-27 01:30:00+00:00", "trade_duration": 55, "open_rate": 5.615e-05, "close_rate": 5.643145363408521e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1780.9439002671415, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.07877175, "open_date": "2018-01-27 00:45:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 4560, "open_rate": 5.556e-05, "close_rate": 5.144e-05, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1799.8560115190785, "profit_abs": -0.007896868250539965}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 02:30:00+00:00", "close_date": "2018-01-27 11:25:00+00:00", "trade_duration": 535, "open_rate": 0.06900001, "close_rate": 0.06934587471177944, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4492751522789635, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 06:25:00+00:00", "close_date": "2018-01-27 07:05:00+00:00", "trade_duration": 40, "open_rate": 0.09449985, "close_rate": 0.0949735334586466, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.058202737887944, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.04815133, "open_date": "2018-01-27 09:40:00+00:00", "close_date": "2018-01-30 04:40:00+00:00", "trade_duration": 4020, "open_rate": 0.0410697, "close_rate": 0.03928809, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4348850855983852, "profit_abs": -0.004827170578309559}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 11:45:00+00:00", "close_date": "2018-01-27 12:30:00+00:00", "trade_duration": 45, "open_rate": 0.0285, "close_rate": 0.02864285714285714, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5087719298245617, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 12:35:00+00:00", "close_date": "2018-01-27 15:25:00+00:00", "trade_duration": 170, "open_rate": 0.02866372, "close_rate": 0.02880739779448621, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.4887307020861216, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 15:50:00+00:00", "close_date": "2018-01-27 16:50:00+00:00", "trade_duration": 60, "open_rate": 0.095381, "close_rate": 0.09585910025062656, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0484268355332824, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 17:05:00+00:00", "close_date": "2018-01-27 17:45:00+00:00", "trade_duration": 40, "open_rate": 0.06759092, "close_rate": 0.06792972160401002, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4794886650455417, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 23:40:00+00:00", "close_date": "2018-01-28 01:05:00+00:00", "trade_duration": 85, "open_rate": 0.00258501, "close_rate": 0.002597967443609022, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.684569885609726, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 02:25:00+00:00", "close_date": "2018-01-28 08:10:00+00:00", "trade_duration": 345, "open_rate": 0.06698502, "close_rate": 0.0673207845112782, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4928710926711672, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 10:25:00+00:00", "close_date": "2018-01-28 16:30:00+00:00", "trade_duration": 365, "open_rate": 0.0677177, "close_rate": 0.06805713709273183, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4767187899175547, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-28 20:35:00+00:00", "close_date": "2018-01-28 21:35:00+00:00", "trade_duration": 60, "open_rate": 5.215e-05, "close_rate": 5.2411403508771925e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1917.5455417066157, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-28 22:00:00+00:00", "close_date": "2018-01-28 22:30:00+00:00", "trade_duration": 30, "open_rate": 0.00273809, "close_rate": 0.002779264285714285, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.5218089982433, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-29 00:00:00+00:00", "close_date": "2018-01-29 00:30:00+00:00", "trade_duration": 30, "open_rate": 0.00274632, "close_rate": 0.002787618045112782, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.412362725392526, "profit_abs": 0.0010000000000000148}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-29 02:15:00+00:00", "close_date": "2018-01-29 03:00:00+00:00", "trade_duration": 45, "open_rate": 0.01622478, "close_rate": 0.016306107218045113, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.163411768911504, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 03:05:00+00:00", "close_date": "2018-01-29 03:45:00+00:00", "trade_duration": 40, "open_rate": 0.069, "close_rate": 0.06934586466165413, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4492753623188406, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 05:20:00+00:00", "close_date": "2018-01-29 06:55:00+00:00", "trade_duration": 95, "open_rate": 8.755e-05, "close_rate": 8.798884711779448e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1142.204454597373, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 07:00:00+00:00", "close_date": "2018-01-29 19:25:00+00:00", "trade_duration": 745, "open_rate": 0.06825763, "close_rate": 0.06859977350877192, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4650376815016872, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 19:45:00+00:00", "close_date": "2018-01-29 20:25:00+00:00", "trade_duration": 40, "open_rate": 0.06713892, "close_rate": 0.06747545593984962, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4894490408841845, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0199116, "open_date": "2018-01-29 23:30:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 315, "open_rate": 8.934e-05, "close_rate": 8.8e-05, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1119.3194537721067, "profit_abs": -0.0019961383478844796}], "results_per_pair": [{"key": "TRX/BTC", "trades": 15, "profit_mean": 0.0023467073333333323, "profit_mean_pct": 0.23467073333333321, "profit_sum": 0.035200609999999986, "profit_sum_pct": 3.5200609999999988, "profit_total_abs": 0.0035288616521155086, "profit_total_pct": 1.1733536666666662, "duration_avg": "2:28:00", "wins": 9, "draws": 2, "losses": 4}, {"key": "ADA/BTC", "trades": 29, "profit_mean": -0.0011598141379310352, "profit_mean_pct": -0.11598141379310352, "profit_sum": -0.03363461000000002, "profit_sum_pct": -3.3634610000000023, "profit_total_abs": -0.0033718682505400333, "profit_total_pct": -1.1211536666666675, "duration_avg": "5:35:00", "wins": 9, "draws": 11, "losses": 9}, {"key": "XLM/BTC", "trades": 21, "profit_mean": 0.0026243899999999994, "profit_mean_pct": 0.2624389999999999, "profit_sum": 0.05511218999999999, "profit_sum_pct": 5.511218999999999, "profit_total_abs": 0.005525000000000002, "profit_total_pct": 1.8370729999999995, "duration_avg": "3:21:00", "wins": 12, "draws": 3, "losses": 6}, {"key": "ETH/BTC", "trades": 21, "profit_mean": 0.0009500057142857142, "profit_mean_pct": 0.09500057142857142, "profit_sum": 0.01995012, "profit_sum_pct": 1.9950119999999998, "profit_total_abs": 0.0019999999999999463, "profit_total_pct": 0.6650039999999999, "duration_avg": "2:17:00", "wins": 5, "draws": 10, "losses": 6}, {"key": "XMR/BTC", "trades": 16, "profit_mean": -0.0027899012500000007, "profit_mean_pct": -0.2789901250000001, "profit_sum": -0.04463842000000001, "profit_sum_pct": -4.463842000000001, "profit_total_abs": -0.0044750000000000345, "profit_total_pct": -1.4879473333333337, "duration_avg": "8:41:00", "wins": 6, "draws": 5, "losses": 5}, {"key": "ZEC/BTC", "trades": 21, "profit_mean": -0.00039290904761904774, "profit_mean_pct": -0.03929090476190478, "profit_sum": -0.008251090000000003, "profit_sum_pct": -0.8251090000000003, "profit_total_abs": -0.000827170578309569, "profit_total_pct": -0.27503633333333344, "duration_avg": "4:17:00", "wins": 8, "draws": 7, "losses": 6}, {"key": "NXT/BTC", "trades": 12, "profit_mean": -0.0012261025000000006, "profit_mean_pct": -0.12261025000000006, "profit_sum": -0.014713230000000008, "profit_sum_pct": -1.4713230000000008, "profit_total_abs": -0.0014750000000000874, "profit_total_pct": -0.4904410000000003, "duration_avg": "0:57:00", "wins": 4, "draws": 3, "losses": 5}, {"key": "LTC/BTC", "trades": 8, "profit_mean": 0.00748129625, "profit_mean_pct": 0.748129625, "profit_sum": 0.05985037, "profit_sum_pct": 5.985037, "profit_total_abs": 0.006000000000000019, "profit_total_pct": 1.9950123333333334, "duration_avg": "1:59:00", "wins": 5, "draws": 2, "losses": 1}, {"key": "ETC/BTC", "trades": 20, "profit_mean": 0.0022568569999999997, "profit_mean_pct": 0.22568569999999996, "profit_sum": 0.04513713999999999, "profit_sum_pct": 4.513713999999999, "profit_total_abs": 0.004525000000000001, "profit_total_pct": 1.504571333333333, "duration_avg": "1:45:00", "wins": 11, "draws": 4, "losses": 5}, {"key": "DASH/BTC", "trades": 16, "profit_mean": 0.0018703237499999997, "profit_mean_pct": 0.18703237499999997, "profit_sum": 0.029925179999999996, "profit_sum_pct": 2.9925179999999996, "profit_total_abs": 0.002999999999999961, "profit_total_pct": 0.9975059999999999, "duration_avg": "3:03:00", "wins": 4, "draws": 7, "losses": 5}, {"key": "TOTAL", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}], "sell_reason_summary": [{"sell_reason": "roi", "trades": 170, "wins": 73, "draws": 54, "losses": 43, "profit_mean": 0.005398268352941177, "profit_mean_pct": 0.54, "profit_sum": 0.91770562, "profit_sum_pct": 91.77, "profit_total_abs": 0.09199999999999964, "profit_pct_total": 30.59}, {"sell_reason": "stop_loss", "trades": 6, "wins": 0, "draws": 0, "losses": 6, "profit_mean": -0.10448878000000002, "profit_mean_pct": -10.45, "profit_sum": -0.6269326800000001, "profit_sum_pct": -62.69, "profit_total_abs": -0.06284999999999992, "profit_pct_total": -20.9}, {"sell_reason": "force_sell", "trades": 3, "wins": 0, "draws": 0, "losses": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.89, "profit_sum": -0.14683468, "profit_sum_pct": -14.68, "profit_total_abs": -0.014720177176734003, "profit_pct_total": -4.89}], "left_open_trades": [{"key": "TRX/BTC", "trades": 1, "profit_mean": -0.0199116, "profit_mean_pct": -1.9911600000000003, "profit_sum": -0.0199116, "profit_sum_pct": -1.9911600000000003, "profit_total_abs": -0.0019961383478844796, "profit_total_pct": -0.6637200000000001, "duration_avg": "5:15:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ADA/BTC", "trades": 1, "profit_mean": -0.07877175, "profit_mean_pct": -7.877175, "profit_sum": -0.07877175, "profit_sum_pct": -7.877175, "profit_total_abs": -0.007896868250539965, "profit_total_pct": -2.625725, "duration_avg": "3 days, 4:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ZEC/BTC", "trades": 1, "profit_mean": -0.04815133, "profit_mean_pct": -4.815133, "profit_sum": -0.04815133, "profit_sum_pct": -4.815133, "profit_total_abs": -0.004827170578309559, "profit_total_pct": -1.6050443333333335, "duration_avg": "2 days, 19:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "TOTAL", "trades": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.894489333333333, "profit_sum": -0.14683468, "profit_sum_pct": -14.683468, "profit_total_abs": -0.014720177176734003, "profit_total_pct": -4.8944893333333335, "duration_avg": "2 days, 1:25:00", "wins": 0, "draws": 0, "losses": 3}], "total_trades": 179, "backtest_start": "2018-01-30 04:45:00+00:00", "backtest_start_ts": 1517287500, "backtest_end": "2018-01-30 04:45:00+00:00", "backtest_end_ts": 1517287500, "backtest_days": 0, "trades_per_day": null, "market_change": 0.25, "stake_amount": 0.1, "max_drawdown": 0.21142322000000008, "drawdown_start": "2018-01-24 14:25:00+00:00", "drawdown_start_ts": 1516803900.0, "drawdown_end": "2018-01-30 04:45:00+00:00", "drawdown_end_ts": 1517287500.0, "pairlist": ["TRX/BTC", "ADA/BTC", "XLM/BTC", "ETH/BTC", "XMR/BTC", "ZEC/BTC","NXT/BTC", "LTC/BTC", "ETC/BTC", "DASH/BTC"]}, "TestStrategy": {"trades": [{"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:20:00+00:00", "trade_duration": 5, "open_rate": 9.64e-05, "close_rate": 0.00010074887218045112, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1037.344398340249, "profit_abs": 0.00399999999999999}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:30:00+00:00", "trade_duration": 15, "open_rate": 4.756e-05, "close_rate": 4.9705563909774425e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2102.6072329688814, "profit_abs": 0.00399999999999999}, {"pair": "XLM/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:35:00+00:00", "trade_duration": 10, "open_rate": 3.339e-05, "close_rate": 3.489631578947368e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2994.908655286014, "profit_abs": 0.0040000000000000036}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:40:00+00:00", "trade_duration": 15, "open_rate": 9.696e-05, "close_rate": 0.00010133413533834584, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1031.3531353135315, "profit_abs": 0.00399999999999999}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 07:35:00+00:00", "close_date": "2018-01-10 08:35:00+00:00", "trade_duration": 60, "open_rate": 0.0943, "close_rate": 0.09477268170426063, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0604453870625663, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 07:40:00+00:00", "close_date": "2018-01-10 08:10:00+00:00", "trade_duration": 30, "open_rate": 0.02719607, "close_rate": 0.02760503345864661, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.677001860930642, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 08:15:00+00:00", "close_date": "2018-01-10 09:55:00+00:00", "trade_duration": 100, "open_rate": 0.04634952, "close_rate": 0.046581848421052625, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.1575196463739, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 14:45:00+00:00", "close_date": "2018-01-10 15:50:00+00:00", "trade_duration": 65, "open_rate": 3.066e-05, "close_rate": 3.081368421052631e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3261.5786040443577, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 16:35:00+00:00", "close_date": "2018-01-10 17:15:00+00:00", "trade_duration": 40, "open_rate": 0.0168999, "close_rate": 0.016984611278195488, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 5.917194776300452, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 16:40:00+00:00", "close_date": "2018-01-10 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.09132568, "close_rate": 0.0917834528320802, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0949822656672252, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 18:50:00+00:00", "close_date": "2018-01-10 19:45:00+00:00", "trade_duration": 55, "open_rate": 0.08898003, "close_rate": 0.08942604518796991, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1238476768326557, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 22:15:00+00:00", "close_date": "2018-01-10 23:00:00+00:00", "trade_duration": 45, "open_rate": 0.08560008, "close_rate": 0.08602915308270676, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1682232072680307, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 22:50:00+00:00", "close_date": "2018-01-10 23:20:00+00:00", "trade_duration": 30, "open_rate": 0.00249083, "close_rate": 0.0025282860902255634, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 40.147260150231055, "profit_abs": 0.000999999999999987}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 23:15:00+00:00", "close_date": "2018-01-11 00:15:00+00:00", "trade_duration": 60, "open_rate": 3.022e-05, "close_rate": 3.037147869674185e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3309.0668431502318, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-10 23:40:00+00:00", "close_date": "2018-01-11 00:05:00+00:00", "trade_duration": 25, "open_rate": 0.002437, "close_rate": 0.0024980776942355883, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 41.03405826836274, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 00:00:00+00:00", "close_date": "2018-01-11 00:35:00+00:00", "trade_duration": 35, "open_rate": 0.04771803, "close_rate": 0.04843559436090225, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0956439316543456, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-11 03:40:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 45, "open_rate": 3.651e-05, "close_rate": 3.2859000000000005e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2738.9756231169545, "profit_abs": -0.01047499999999997}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 03:55:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 30, "open_rate": 0.08824105, "close_rate": 0.08956798308270676, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1332594070446804, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 04:00:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 50, "open_rate": 0.00243, "close_rate": 0.002442180451127819, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 41.1522633744856, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:55:00+00:00", "trade_duration": 25, "open_rate": 0.04545064, "close_rate": 0.046589753784461146, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.200189040242338, "profit_abs": 0.001999999999999988}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 20, "open_rate": 3.372e-05, "close_rate": 3.456511278195488e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2965.599051008304, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:55:00+00:00", "close_date": "2018-01-11 05:15:00+00:00", "trade_duration": 20, "open_rate": 0.02644, "close_rate": 0.02710265664160401, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.7821482602118004, "profit_abs": 0.001999999999999988}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:20:00+00:00", "close_date": "2018-01-11 12:00:00+00:00", "trade_duration": 40, "open_rate": 0.08812, "close_rate": 0.08856170426065162, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1348161597821154, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:35:00+00:00", "close_date": "2018-01-11 12:15:00+00:00", "trade_duration": 40, "open_rate": 0.02683577, "close_rate": 0.026970285137844607, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.7263696923919087, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 14:00:00+00:00", "close_date": "2018-01-11 14:25:00+00:00", "trade_duration": 25, "open_rate": 4.919e-05, "close_rate": 5.04228320802005e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2032.9335230737956, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 19:25:00+00:00", "close_date": "2018-01-11 20:35:00+00:00", "trade_duration": 70, "open_rate": 0.08784896, "close_rate": 0.08828930566416039, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1383174029607181, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:35:00+00:00", "close_date": "2018-01-11 23:30:00+00:00", "trade_duration": 55, "open_rate": 5.105e-05, "close_rate": 5.130588972431077e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1958.8638589618022, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:25:00+00:00", "trade_duration": 30, "open_rate": 3.96e-05, "close_rate": 4.019548872180451e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2525.252525252525, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:35:00+00:00", "trade_duration": 40, "open_rate": 2.885e-05, "close_rate": 2.899461152882205e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3466.204506065858, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 23:30:00+00:00", "close_date": "2018-01-12 00:05:00+00:00", "trade_duration": 35, "open_rate": 0.02645, "close_rate": 0.026847744360902256, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.780718336483932, "profit_abs": 0.0010000000000000148}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 23:55:00+00:00", "close_date": "2018-01-12 01:15:00+00:00", "trade_duration": 80, "open_rate": 0.048, "close_rate": 0.04824060150375939, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0833333333333335, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-12 21:15:00+00:00", "close_date": "2018-01-12 21:40:00+00:00", "trade_duration": 25, "open_rate": 4.692e-05, "close_rate": 4.809593984962405e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2131.287297527707, "profit_abs": 0.001999999999999974}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 00:55:00+00:00", "close_date": "2018-01-13 06:20:00+00:00", "trade_duration": 325, "open_rate": 0.00256966, "close_rate": 0.0025825405012531327, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.91565421106294, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 10:55:00+00:00", "close_date": "2018-01-13 11:35:00+00:00", "trade_duration": 40, "open_rate": 6.262e-05, "close_rate": 6.293388471177944e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1596.933886937081, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 13:05:00+00:00", "close_date": "2018-01-15 14:10:00+00:00", "trade_duration": 2945, "open_rate": 4.73e-05, "close_rate": 4.753709273182957e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2114.1649048625795, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:30:00+00:00", "close_date": "2018-01-13 14:45:00+00:00", "trade_duration": 75, "open_rate": 6.063e-05, "close_rate": 6.0933909774436085e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1649.348507339601, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:40:00+00:00", "close_date": "2018-01-13 23:30:00+00:00", "trade_duration": 590, "open_rate": 0.00011082, "close_rate": 0.00011137548872180448, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 902.3641941887746, "profit_abs": -2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 15:15:00+00:00", "close_date": "2018-01-13 15:55:00+00:00", "trade_duration": 40, "open_rate": 5.93e-05, "close_rate": 5.9597243107769415e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1686.3406408094436, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 16:30:00+00:00", "close_date": "2018-01-13 17:10:00+00:00", "trade_duration": 40, "open_rate": 0.04850003, "close_rate": 0.04874313791979949, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0618543947292407, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 22:05:00+00:00", "close_date": "2018-01-14 06:25:00+00:00", "trade_duration": 500, "open_rate": 0.09825019, "close_rate": 0.09874267215538848, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0178097365511456, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 00:20:00+00:00", "close_date": "2018-01-14 22:55:00+00:00", "trade_duration": 1355, "open_rate": 6.018e-05, "close_rate": 6.048165413533834e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1661.681621801263, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 12:45:00+00:00", "close_date": "2018-01-14 13:25:00+00:00", "trade_duration": 40, "open_rate": 0.09758999, "close_rate": 0.0980791628822055, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.024695258191952, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-14 15:30:00+00:00", "close_date": "2018-01-14 16:00:00+00:00", "trade_duration": 30, "open_rate": 0.00311, "close_rate": 0.0031567669172932328, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 32.154340836012864, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 20:45:00+00:00", "close_date": "2018-01-14 22:15:00+00:00", "trade_duration": 90, "open_rate": 0.00312401, "close_rate": 0.003139669197994987, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 32.010140812609436, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 23:35:00+00:00", "close_date": "2018-01-15 00:30:00+00:00", "trade_duration": 55, "open_rate": 0.0174679, "close_rate": 0.017555458395989976, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 5.724786608579165, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 23:45:00+00:00", "close_date": "2018-01-15 00:25:00+00:00", "trade_duration": 40, "open_rate": 0.07346846, "close_rate": 0.07383672295739348, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.3611282991367997, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 02:25:00+00:00", "close_date": "2018-01-15 03:05:00+00:00", "trade_duration": 40, "open_rate": 0.097994, "close_rate": 0.09848519799498744, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.020470641059657, "profit_abs": -2.7755575615628914e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 07:20:00+00:00", "close_date": "2018-01-15 08:00:00+00:00", "trade_duration": 40, "open_rate": 0.09659, "close_rate": 0.09707416040100247, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0353038616834043, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-15 08:20:00+00:00", "close_date": "2018-01-15 08:55:00+00:00", "trade_duration": 35, "open_rate": 9.987e-05, "close_rate": 0.00010137180451127818, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1001.3016921998599, "profit_abs": 0.0010000000000000009}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-15 12:10:00+00:00", "close_date": "2018-01-16 02:50:00+00:00", "trade_duration": 880, "open_rate": 0.0948969, "close_rate": 0.09537257368421052, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0537752023511833, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:10:00+00:00", "close_date": "2018-01-15 17:40:00+00:00", "trade_duration": 210, "open_rate": 0.071, "close_rate": 0.07135588972431077, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4084507042253522, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:30:00+00:00", "close_date": "2018-01-15 15:10:00+00:00", "trade_duration": 40, "open_rate": 0.04600501, "close_rate": 0.046235611553884705, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.173676301776698, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:10:00+00:00", "close_date": "2018-01-15 19:25:00+00:00", "trade_duration": 75, "open_rate": 9.438e-05, "close_rate": 9.485308270676693e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1059.5465140919687, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:35:00+00:00", "close_date": "2018-01-15 19:15:00+00:00", "trade_duration": 40, "open_rate": 0.03040001, "close_rate": 0.030552391002506264, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.2894726021471703, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-15 20:25:00+00:00", "close_date": "2018-01-16 08:25:00+00:00", "trade_duration": 720, "open_rate": 5.837e-05, "close_rate": 5.2533e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1713.2088401576154, "profit_abs": -0.010474999999999984}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 20:40:00+00:00", "close_date": "2018-01-15 22:00:00+00:00", "trade_duration": 80, "open_rate": 0.046036, "close_rate": 0.04626675689223057, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.1722130506560084, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 00:30:00+00:00", "close_date": "2018-01-16 01:10:00+00:00", "trade_duration": 40, "open_rate": 0.0028685, "close_rate": 0.0028828784461152877, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 34.86142583231654, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 01:15:00+00:00", "close_date": "2018-01-16 02:35:00+00:00", "trade_duration": 80, "open_rate": 0.06731755, "close_rate": 0.0676549813283208, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4854967241083492, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 07:45:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 55, "open_rate": 0.09217614, "close_rate": 0.09263817578947368, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0848794492804754, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:55:00+00:00", "trade_duration": 20, "open_rate": 0.0165, "close_rate": 0.016913533834586467, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.0606060606060606, "profit_abs": 0.0020000000000000018}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 5, "open_rate": 7.953e-05, "close_rate": 8.311781954887218e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1257.387149503332, "profit_abs": 0.00399999999999999}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 08:45:00+00:00", "close_date": "2018-01-16 09:50:00+00:00", "trade_duration": 65, "open_rate": 0.045202, "close_rate": 0.04542857644110275, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.2122914915269236, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:45:00+00:00", "trade_duration": 30, "open_rate": 5.248e-05, "close_rate": 5.326917293233082e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1905.487804878049, "profit_abs": 0.0010000000000000009}, {"pair": "XMR/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:55:00+00:00", "trade_duration": 40, "open_rate": 0.02892318, "close_rate": 0.02906815834586466, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.457434486802627, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 09:50:00+00:00", "close_date": "2018-01-16 10:10:00+00:00", "trade_duration": 20, "open_rate": 5.158e-05, "close_rate": 5.287273182957392e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1938.735944164405, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:35:00+00:00", "trade_duration": 30, "open_rate": 0.02828232, "close_rate": 0.02870761804511278, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5357778286929786, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:40:00+00:00", "trade_duration": 35, "open_rate": 0.04357584, "close_rate": 0.044231115789473675, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.294849623093898, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 13:45:00+00:00", "close_date": "2018-01-16 14:20:00+00:00", "trade_duration": 35, "open_rate": 5.362e-05, "close_rate": 5.442631578947368e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1864.975755315181, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 17:30:00+00:00", "close_date": "2018-01-16 18:25:00+00:00", "trade_duration": 55, "open_rate": 5.302e-05, "close_rate": 5.328576441102756e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1886.0807242549984, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:45:00+00:00", "trade_duration": 30, "open_rate": 0.09129999, "close_rate": 0.09267292218045112, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0952903718828448, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:35:00+00:00", "trade_duration": 20, "open_rate": 3.808e-05, "close_rate": 3.903438596491228e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2626.0504201680674, "profit_abs": 0.0020000000000000018}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 19:00:00+00:00", "close_date": "2018-01-16 19:30:00+00:00", "trade_duration": 30, "open_rate": 0.02811012, "close_rate": 0.028532828571428567, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.557437677249333, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 60, "open_rate": 0.00258379, "close_rate": 0.002325411, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.702835756775904, "profit_abs": -0.010474999999999984}, {"pair": "NXT/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 80, "open_rate": 2.559e-05, "close_rate": 2.3031e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3907.7764751856193, "profit_abs": -0.010474999999999998}, {"pair": "TRX/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:35:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 50, "open_rate": 7.62e-05, "close_rate": 6.858e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1312.3359580052495, "profit_abs": -0.010474999999999984}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:35:00+00:00", "trade_duration": 5, "open_rate": 0.00229844, "close_rate": 0.002402129022556391, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 43.507770487809125, "profit_abs": 0.004000000000000017}, {"pair": "LTC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:40:00+00:00", "trade_duration": 10, "open_rate": 0.0151, "close_rate": 0.015781203007518795, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.622516556291391, "profit_abs": 0.00399999999999999}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:40:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 5, "open_rate": 0.00235676, "close_rate": 0.00246308, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 42.431134269081284, "profit_abs": 0.0040000000000000036}, {"pair": "DASH/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 22:45:00+00:00", "close_date": "2018-01-16 23:05:00+00:00", "trade_duration": 20, "open_rate": 0.0630692, "close_rate": 0.06464988170426066, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.585559988076589, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:50:00+00:00", "close_date": "2018-01-16 22:55:00+00:00", "trade_duration": 5, "open_rate": 2.2e-05, "close_rate": 2.299248120300751e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 4545.454545454546, "profit_abs": 0.003999999999999976}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-17 03:30:00+00:00", "close_date": "2018-01-17 04:00:00+00:00", "trade_duration": 30, "open_rate": 4.974e-05, "close_rate": 5.048796992481203e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2010.454362685967, "profit_abs": 0.0010000000000000009}, {"pair": "TRX/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-17 03:55:00+00:00", "close_date": "2018-01-17 04:15:00+00:00", "trade_duration": 20, "open_rate": 7.108e-05, "close_rate": 7.28614536340852e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1406.8655036578502, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 09:35:00+00:00", "close_date": "2018-01-17 10:15:00+00:00", "trade_duration": 40, "open_rate": 0.04327, "close_rate": 0.04348689223057644, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.3110700254217704, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:20:00+00:00", "close_date": "2018-01-17 17:00:00+00:00", "trade_duration": 400, "open_rate": 4.997e-05, "close_rate": 5.022047619047618e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2001.2007204322595, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:25:00+00:00", "trade_duration": 55, "open_rate": 0.06836818, "close_rate": 0.06871087764411027, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4626687444363737, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:10:00+00:00", "trade_duration": 40, "open_rate": 3.63e-05, "close_rate": 3.648195488721804e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2754.8209366391184, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:30:00+00:00", "close_date": "2018-01-17 22:05:00+00:00", "trade_duration": 575, "open_rate": 0.0281, "close_rate": 0.02824085213032581, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5587188612099645, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:35:00+00:00", "close_date": "2018-01-17 16:55:00+00:00", "trade_duration": 260, "open_rate": 0.08651001, "close_rate": 0.08694364413533832, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1559355963546878, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 05:00:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 55, "open_rate": 5.633e-05, "close_rate": 5.6612355889724306e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1775.2529735487308, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 05:20:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 35, "open_rate": 0.06988494, "close_rate": 0.07093584135338346, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.430923457900944, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 07:35:00+00:00", "close_date": "2018-01-18 08:15:00+00:00", "trade_duration": 40, "open_rate": 5.545e-05, "close_rate": 5.572794486215538e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1803.4265103697026, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 09:00:00+00:00", "close_date": "2018-01-18 09:40:00+00:00", "trade_duration": 40, "open_rate": 0.01633527, "close_rate": 0.016417151052631574, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.121723118136401, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 16:40:00+00:00", "close_date": "2018-01-18 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.00269734, "close_rate": 0.002710860501253133, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 37.073561360451414, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-18 18:05:00+00:00", "close_date": "2018-01-18 18:30:00+00:00", "trade_duration": 25, "open_rate": 4.475e-05, "close_rate": 4.587155388471177e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2234.63687150838, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 18:25:00+00:00", "close_date": "2018-01-18 18:55:00+00:00", "trade_duration": 30, "open_rate": 2.79e-05, "close_rate": 2.8319548872180444e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3584.2293906810037, "profit_abs": 0.000999999999999987}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 20:10:00+00:00", "close_date": "2018-01-18 20:50:00+00:00", "trade_duration": 40, "open_rate": 0.04439326, "close_rate": 0.04461578260651629, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.2525942001105577, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 21:30:00+00:00", "close_date": "2018-01-19 00:35:00+00:00", "trade_duration": 185, "open_rate": 4.49e-05, "close_rate": 4.51250626566416e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2227.1714922049, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 21:55:00+00:00", "close_date": "2018-01-19 05:05:00+00:00", "trade_duration": 430, "open_rate": 0.02855, "close_rate": 0.028693107769423555, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.502626970227671, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 22:10:00+00:00", "close_date": "2018-01-18 22:50:00+00:00", "trade_duration": 40, "open_rate": 5.796e-05, "close_rate": 5.8250526315789473e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1725.3278122843342, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 23:50:00+00:00", "close_date": "2018-01-19 00:30:00+00:00", "trade_duration": 40, "open_rate": 0.04340323, "close_rate": 0.04362079005012531, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.303975994413319, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-19 16:45:00+00:00", "close_date": "2018-01-19 17:35:00+00:00", "trade_duration": 50, "open_rate": 0.04454455, "close_rate": 0.04476783095238095, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.244943545282195, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:15:00+00:00", "close_date": "2018-01-19 19:55:00+00:00", "trade_duration": 160, "open_rate": 5.62e-05, "close_rate": 5.648170426065162e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1779.3594306049824, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:20:00+00:00", "close_date": "2018-01-19 20:15:00+00:00", "trade_duration": 175, "open_rate": 4.339e-05, "close_rate": 4.360749373433584e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2304.6784973496196, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-20 04:45:00+00:00", "close_date": "2018-01-20 17:35:00+00:00", "trade_duration": 770, "open_rate": 0.0001009, "close_rate": 0.00010140576441102755, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 991.0802775024778, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 15:15:00+00:00", "trade_duration": 625, "open_rate": 0.00270505, "close_rate": 0.002718609147869674, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.96789338459548, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 07:00:00+00:00", "trade_duration": 130, "open_rate": 0.03000002, "close_rate": 0.030150396040100245, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.3333311111125927, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 09:00:00+00:00", "close_date": "2018-01-20 09:40:00+00:00", "trade_duration": 40, "open_rate": 5.46e-05, "close_rate": 5.4873684210526304e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1831.5018315018317, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-20 18:25:00+00:00", "close_date": "2018-01-25 03:50:00+00:00", "trade_duration": 6325, "open_rate": 0.03082222, "close_rate": 0.027739998, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.244412634781012, "profit_abs": -0.010474999999999998}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 22:25:00+00:00", "close_date": "2018-01-20 23:15:00+00:00", "trade_duration": 50, "open_rate": 0.08969999, "close_rate": 0.09014961401002504, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1148273260677064, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 02:50:00+00:00", "close_date": "2018-01-21 14:30:00+00:00", "trade_duration": 700, "open_rate": 0.01632501, "close_rate": 0.01640683962406015, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.125570520324337, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 10:20:00+00:00", "close_date": "2018-01-21 11:00:00+00:00", "trade_duration": 40, "open_rate": 0.070538, "close_rate": 0.07089157393483708, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.417675579120474, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 15:50:00+00:00", "close_date": "2018-01-21 18:45:00+00:00", "trade_duration": 175, "open_rate": 5.301e-05, "close_rate": 5.327571428571427e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1886.4365214110546, "profit_abs": -2.7755575615628914e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 16:20:00+00:00", "close_date": "2018-01-21 17:00:00+00:00", "trade_duration": 40, "open_rate": 3.955e-05, "close_rate": 3.9748245614035085e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2528.4450063211125, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:45:00+00:00", "trade_duration": 30, "open_rate": 0.00258505, "close_rate": 0.002623922932330827, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.6839712964933, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:55:00+00:00", "trade_duration": 40, "open_rate": 3.903e-05, "close_rate": 3.922563909774435e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2562.1316935690497, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 00:35:00+00:00", "close_date": "2018-01-22 10:35:00+00:00", "trade_duration": 600, "open_rate": 5.236e-05, "close_rate": 5.262245614035087e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1909.8548510313217, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 01:30:00+00:00", "close_date": "2018-01-22 02:10:00+00:00", "trade_duration": 40, "open_rate": 9.028e-05, "close_rate": 9.07325313283208e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1107.6650420912717, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 12:25:00+00:00", "close_date": "2018-01-22 14:35:00+00:00", "trade_duration": 130, "open_rate": 0.002687, "close_rate": 0.002700468671679198, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 37.21622627465575, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 13:15:00+00:00", "close_date": "2018-01-22 13:55:00+00:00", "trade_duration": 40, "open_rate": 4.168e-05, "close_rate": 4.188892230576441e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2399.232245681382, "profit_abs": 1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-22 14:00:00+00:00", "close_date": "2018-01-22 14:30:00+00:00", "trade_duration": 30, "open_rate": 8.821e-05, "close_rate": 8.953646616541353e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1133.6583153837435, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 15:55:00+00:00", "close_date": "2018-01-22 16:40:00+00:00", "trade_duration": 45, "open_rate": 5.172e-05, "close_rate": 5.1979248120300745e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1933.4880123743235, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-22 16:05:00+00:00", "close_date": "2018-01-22 16:25:00+00:00", "trade_duration": 20, "open_rate": 3.026e-05, "close_rate": 3.101839598997494e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3304.692663582287, "profit_abs": 0.0020000000000000157}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 19:50:00+00:00", "close_date": "2018-01-23 00:10:00+00:00", "trade_duration": 260, "open_rate": 0.07064, "close_rate": 0.07099408521303258, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.415628539071348, "profit_abs": 1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 21:25:00+00:00", "close_date": "2018-01-22 22:05:00+00:00", "trade_duration": 40, "open_rate": 0.01644483, "close_rate": 0.01652726022556391, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.080938507725528, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-23 00:05:00+00:00", "close_date": "2018-01-23 00:35:00+00:00", "trade_duration": 30, "open_rate": 4.331e-05, "close_rate": 4.3961278195488714e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2308.935580697299, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-23 01:50:00+00:00", "close_date": "2018-01-23 02:15:00+00:00", "trade_duration": 25, "open_rate": 3.2e-05, "close_rate": 3.2802005012531326e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3125.0000000000005, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 04:25:00+00:00", "close_date": "2018-01-23 05:15:00+00:00", "trade_duration": 50, "open_rate": 0.09167706, "close_rate": 0.09213659413533835, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0907854156754153, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 07:35:00+00:00", "close_date": "2018-01-23 09:00:00+00:00", "trade_duration": 85, "open_rate": 0.0692498, "close_rate": 0.06959691679197995, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4440474918339115, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 10:50:00+00:00", "close_date": "2018-01-23 13:05:00+00:00", "trade_duration": 135, "open_rate": 3.182e-05, "close_rate": 3.197949874686716e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3142.677561282213, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 11:05:00+00:00", "close_date": "2018-01-23 16:05:00+00:00", "trade_duration": 300, "open_rate": 0.04088, "close_rate": 0.04108491228070175, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4461839530332683, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 14:55:00+00:00", "close_date": "2018-01-23 15:35:00+00:00", "trade_duration": 40, "open_rate": 5.15e-05, "close_rate": 5.175814536340851e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1941.747572815534, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 16:35:00+00:00", "close_date": "2018-01-24 00:05:00+00:00", "trade_duration": 450, "open_rate": 0.09071698, "close_rate": 0.09117170170426064, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1023294646713329, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 17:25:00+00:00", "close_date": "2018-01-23 18:45:00+00:00", "trade_duration": 80, "open_rate": 3.128e-05, "close_rate": 3.1436791979949865e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3196.9309462915603, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 20:15:00+00:00", "close_date": "2018-01-23 22:00:00+00:00", "trade_duration": 105, "open_rate": 9.555e-05, "close_rate": 9.602894736842104e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1046.5724751439038, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 22:30:00+00:00", "close_date": "2018-01-23 23:10:00+00:00", "trade_duration": 40, "open_rate": 0.04080001, "close_rate": 0.0410045213283208, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.450979791426522, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 23:50:00+00:00", "close_date": "2018-01-24 03:35:00+00:00", "trade_duration": 225, "open_rate": 5.163e-05, "close_rate": 5.18887969924812e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1936.8584156498162, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 00:20:00+00:00", "close_date": "2018-01-24 01:50:00+00:00", "trade_duration": 90, "open_rate": 0.04040781, "close_rate": 0.04061035541353383, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.474769110228938, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 06:45:00+00:00", "close_date": "2018-01-24 07:25:00+00:00", "trade_duration": 40, "open_rate": 5.132e-05, "close_rate": 5.157724310776942e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1948.5580670303975, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-24 14:15:00+00:00", "close_date": "2018-01-24 14:25:00+00:00", "trade_duration": 10, "open_rate": 5.198e-05, "close_rate": 5.432496240601503e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1923.8168526356292, "profit_abs": 0.0040000000000000036}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 14:50:00+00:00", "close_date": "2018-01-24 16:35:00+00:00", "trade_duration": 105, "open_rate": 3.054e-05, "close_rate": 3.069308270676692e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3274.3942370661425, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 15:10:00+00:00", "close_date": "2018-01-24 16:15:00+00:00", "trade_duration": 65, "open_rate": 9.263e-05, "close_rate": 9.309431077694236e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1079.5638562020945, "profit_abs": 2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 22:40:00+00:00", "close_date": "2018-01-24 23:25:00+00:00", "trade_duration": 45, "open_rate": 5.514e-05, "close_rate": 5.54163909774436e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1813.5654697134569, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 00:50:00+00:00", "close_date": "2018-01-25 01:30:00+00:00", "trade_duration": 40, "open_rate": 4.921e-05, "close_rate": 4.9456666666666664e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2032.1072952651903, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 08:15:00+00:00", "close_date": "2018-01-25 12:15:00+00:00", "trade_duration": 240, "open_rate": 0.0026, "close_rate": 0.002613032581453634, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.46153846153847, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 10:25:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 350, "open_rate": 0.02799871, "close_rate": 0.028139054411027563, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.571593119825878, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 11:00:00+00:00", "close_date": "2018-01-25 11:45:00+00:00", "trade_duration": 45, "open_rate": 0.04078902, "close_rate": 0.0409934762406015, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4516401717913303, "profit_abs": -1.3877787807814457e-17}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:05:00+00:00", "close_date": "2018-01-25 13:45:00+00:00", "trade_duration": 40, "open_rate": 2.89e-05, "close_rate": 2.904486215538847e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3460.2076124567475, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:20:00+00:00", "close_date": "2018-01-25 14:05:00+00:00", "trade_duration": 45, "open_rate": 0.041103, "close_rate": 0.04130903007518797, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4329124394813033, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-25 15:45:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 30, "open_rate": 5.428e-05, "close_rate": 5.509624060150376e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1842.2991893883568, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 17:45:00+00:00", "close_date": "2018-01-25 23:15:00+00:00", "trade_duration": 330, "open_rate": 5.414e-05, "close_rate": 5.441137844611528e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1847.063169560399, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 21:15:00+00:00", "close_date": "2018-01-25 21:55:00+00:00", "trade_duration": 40, "open_rate": 0.04140777, "close_rate": 0.0416153277443609, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.415005686130888, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 02:05:00+00:00", "close_date": "2018-01-26 02:45:00+00:00", "trade_duration": 40, "open_rate": 0.00254309, "close_rate": 0.002555837318295739, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 39.32224183965177, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 02:55:00+00:00", "close_date": "2018-01-26 15:10:00+00:00", "trade_duration": 735, "open_rate": 5.607e-05, "close_rate": 5.6351052631578935e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1783.4849295523454, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 06:10:00+00:00", "close_date": "2018-01-26 09:25:00+00:00", "trade_duration": 195, "open_rate": 0.00253806, "close_rate": 0.0025507821052631577, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 39.400171784748984, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 07:25:00+00:00", "close_date": "2018-01-26 09:55:00+00:00", "trade_duration": 150, "open_rate": 0.0415, "close_rate": 0.04170802005012531, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4096385542168677, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-26 09:55:00+00:00", "close_date": "2018-01-26 10:25:00+00:00", "trade_duration": 30, "open_rate": 5.321e-05, "close_rate": 5.401015037593984e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1879.3459875963165, "profit_abs": 0.000999999999999987}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 16:05:00+00:00", "close_date": "2018-01-26 16:45:00+00:00", "trade_duration": 40, "open_rate": 0.02772046, "close_rate": 0.02785940967418546, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.6074437437185387, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 23:35:00+00:00", "close_date": "2018-01-27 00:15:00+00:00", "trade_duration": 40, "open_rate": 0.09461341, "close_rate": 0.09508766268170424, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0569326272036914, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 00:35:00+00:00", "close_date": "2018-01-27 01:30:00+00:00", "trade_duration": 55, "open_rate": 5.615e-05, "close_rate": 5.643145363408521e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1780.9439002671415, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.07877175, "open_date": "2018-01-27 00:45:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 4560, "open_rate": 5.556e-05, "close_rate": 5.144e-05, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1799.8560115190785, "profit_abs": -0.007896868250539965}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 02:30:00+00:00", "close_date": "2018-01-27 11:25:00+00:00", "trade_duration": 535, "open_rate": 0.06900001, "close_rate": 0.06934587471177944, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4492751522789635, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 06:25:00+00:00", "close_date": "2018-01-27 07:05:00+00:00", "trade_duration": 40, "open_rate": 0.09449985, "close_rate": 0.0949735334586466, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.058202737887944, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.04815133, "open_date": "2018-01-27 09:40:00+00:00", "close_date": "2018-01-30 04:40:00+00:00", "trade_duration": 4020, "open_rate": 0.0410697, "close_rate": 0.03928809, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4348850855983852, "profit_abs": -0.004827170578309559}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 11:45:00+00:00", "close_date": "2018-01-27 12:30:00+00:00", "trade_duration": 45, "open_rate": 0.0285, "close_rate": 0.02864285714285714, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5087719298245617, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 12:35:00+00:00", "close_date": "2018-01-27 15:25:00+00:00", "trade_duration": 170, "open_rate": 0.02866372, "close_rate": 0.02880739779448621, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.4887307020861216, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 15:50:00+00:00", "close_date": "2018-01-27 16:50:00+00:00", "trade_duration": 60, "open_rate": 0.095381, "close_rate": 0.09585910025062656, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0484268355332824, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 17:05:00+00:00", "close_date": "2018-01-27 17:45:00+00:00", "trade_duration": 40, "open_rate": 0.06759092, "close_rate": 0.06792972160401002, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4794886650455417, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 23:40:00+00:00", "close_date": "2018-01-28 01:05:00+00:00", "trade_duration": 85, "open_rate": 0.00258501, "close_rate": 0.002597967443609022, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.684569885609726, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 02:25:00+00:00", "close_date": "2018-01-28 08:10:00+00:00", "trade_duration": 345, "open_rate": 0.06698502, "close_rate": 0.0673207845112782, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4928710926711672, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 10:25:00+00:00", "close_date": "2018-01-28 16:30:00+00:00", "trade_duration": 365, "open_rate": 0.0677177, "close_rate": 0.06805713709273183, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4767187899175547, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-28 20:35:00+00:00", "close_date": "2018-01-28 21:35:00+00:00", "trade_duration": 60, "open_rate": 5.215e-05, "close_rate": 5.2411403508771925e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1917.5455417066157, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-28 22:00:00+00:00", "close_date": "2018-01-28 22:30:00+00:00", "trade_duration": 30, "open_rate": 0.00273809, "close_rate": 0.002779264285714285, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.5218089982433, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-29 00:00:00+00:00", "close_date": "2018-01-29 00:30:00+00:00", "trade_duration": 30, "open_rate": 0.00274632, "close_rate": 0.002787618045112782, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.412362725392526, "profit_abs": 0.0010000000000000148}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-29 02:15:00+00:00", "close_date": "2018-01-29 03:00:00+00:00", "trade_duration": 45, "open_rate": 0.01622478, "close_rate": 0.016306107218045113, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.163411768911504, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 03:05:00+00:00", "close_date": "2018-01-29 03:45:00+00:00", "trade_duration": 40, "open_rate": 0.069, "close_rate": 0.06934586466165413, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4492753623188406, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 05:20:00+00:00", "close_date": "2018-01-29 06:55:00+00:00", "trade_duration": 95, "open_rate": 8.755e-05, "close_rate": 8.798884711779448e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1142.204454597373, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 07:00:00+00:00", "close_date": "2018-01-29 19:25:00+00:00", "trade_duration": 745, "open_rate": 0.06825763, "close_rate": 0.06859977350877192, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4650376815016872, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 19:45:00+00:00", "close_date": "2018-01-29 20:25:00+00:00", "trade_duration": 40, "open_rate": 0.06713892, "close_rate": 0.06747545593984962, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4894490408841845, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0199116, "open_date": "2018-01-29 23:30:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 315, "open_rate": 8.934e-05, "close_rate": 8.8e-05, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1119.3194537721067, "profit_abs": -0.0019961383478844796}], "results_per_pair": [{"key": "TRX/BTC", "trades": 15, "profit_mean": 0.0023467073333333323, "profit_mean_pct": 0.23467073333333321, "profit_sum": 0.035200609999999986, "profit_sum_pct": 3.5200609999999988, "profit_total_abs": 0.0035288616521155086, "profit_total_pct": 1.1733536666666662, "duration_avg": "2:28:00", "wins": 9, "draws": 2, "losses": 4}, {"key": "ADA/BTC", "trades": 29, "profit_mean": -0.0011598141379310352, "profit_mean_pct": -0.11598141379310352, "profit_sum": -0.03363461000000002, "profit_sum_pct": -3.3634610000000023, "profit_total_abs": -0.0033718682505400333, "profit_total_pct": -1.1211536666666675, "duration_avg": "5:35:00", "wins": 9, "draws": 11, "losses": 9}, {"key": "XLM/BTC", "trades": 21, "profit_mean": 0.0026243899999999994, "profit_mean_pct": 0.2624389999999999, "profit_sum": 0.05511218999999999, "profit_sum_pct": 5.511218999999999, "profit_total_abs": 0.005525000000000002, "profit_total_pct": 1.8370729999999995, "duration_avg": "3:21:00", "wins": 12, "draws": 3, "losses": 6}, {"key": "ETH/BTC", "trades": 21, "profit_mean": 0.0009500057142857142, "profit_mean_pct": 0.09500057142857142, "profit_sum": 0.01995012, "profit_sum_pct": 1.9950119999999998, "profit_total_abs": 0.0019999999999999463, "profit_total_pct": 0.6650039999999999, "duration_avg": "2:17:00", "wins": 5, "draws": 10, "losses": 6}, {"key": "XMR/BTC", "trades": 16, "profit_mean": -0.0027899012500000007, "profit_mean_pct": -0.2789901250000001, "profit_sum": -0.04463842000000001, "profit_sum_pct": -4.463842000000001, "profit_total_abs": -0.0044750000000000345, "profit_total_pct": -1.4879473333333337, "duration_avg": "8:41:00", "wins": 6, "draws": 5, "losses": 5}, {"key": "ZEC/BTC", "trades": 21, "profit_mean": -0.00039290904761904774, "profit_mean_pct": -0.03929090476190478, "profit_sum": -0.008251090000000003, "profit_sum_pct": -0.8251090000000003, "profit_total_abs": -0.000827170578309569, "profit_total_pct": -0.27503633333333344, "duration_avg": "4:17:00", "wins": 8, "draws": 7, "losses": 6}, {"key": "NXT/BTC", "trades": 12, "profit_mean": -0.0012261025000000006, "profit_mean_pct": -0.12261025000000006, "profit_sum": -0.014713230000000008, "profit_sum_pct": -1.4713230000000008, "profit_total_abs": -0.0014750000000000874, "profit_total_pct": -0.4904410000000003, "duration_avg": "0:57:00", "wins": 4, "draws": 3, "losses": 5}, {"key": "LTC/BTC", "trades": 8, "profit_mean": 0.00748129625, "profit_mean_pct": 0.748129625, "profit_sum": 0.05985037, "profit_sum_pct": 5.985037, "profit_total_abs": 0.006000000000000019, "profit_total_pct": 1.9950123333333334, "duration_avg": "1:59:00", "wins": 5, "draws": 2, "losses": 1}, {"key": "ETC/BTC", "trades": 20, "profit_mean": 0.0022568569999999997, "profit_mean_pct": 0.22568569999999996, "profit_sum": 0.04513713999999999, "profit_sum_pct": 4.513713999999999, "profit_total_abs": 0.004525000000000001, "profit_total_pct": 1.504571333333333, "duration_avg": "1:45:00", "wins": 11, "draws": 4, "losses": 5}, {"key": "DASH/BTC", "trades": 16, "profit_mean": 0.0018703237499999997, "profit_mean_pct": 0.18703237499999997, "profit_sum": 0.029925179999999996, "profit_sum_pct": 2.9925179999999996, "profit_total_abs": 0.002999999999999961, "profit_total_pct": 0.9975059999999999, "duration_avg": "3:03:00", "wins": 4, "draws": 7, "losses": 5}, {"key": "TOTAL", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}], "sell_reason_summary": [{"sell_reason": "roi", "trades": 170, "wins": 73, "draws": 54, "losses": 43, "profit_mean": 0.005398268352941177, "profit_mean_pct": 0.54, "profit_sum": 0.91770562, "profit_sum_pct": 91.77, "profit_total_abs": 0.09199999999999964, "profit_pct_total": 30.59}, {"sell_reason": "stop_loss", "trades": 6, "wins": 0, "draws": 0, "losses": 6, "profit_mean": -0.10448878000000002, "profit_mean_pct": -10.45, "profit_sum": -0.6269326800000001, "profit_sum_pct": -62.69, "profit_total_abs": -0.06284999999999992, "profit_pct_total": -20.9}, {"sell_reason": "force_sell", "trades": 3, "wins": 0, "draws": 0, "losses": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.89, "profit_sum": -0.14683468, "profit_sum_pct": -14.68, "profit_total_abs": -0.014720177176734003, "profit_pct_total": -4.89}], "left_open_trades": [{"key": "TRX/BTC", "trades": 1, "profit_mean": -0.0199116, "profit_mean_pct": -1.9911600000000003, "profit_sum": -0.0199116, "profit_sum_pct": -1.9911600000000003, "profit_total_abs": -0.0019961383478844796, "profit_total_pct": -0.6637200000000001, "duration_avg": "5:15:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ADA/BTC", "trades": 1, "profit_mean": -0.07877175, "profit_mean_pct": -7.877175, "profit_sum": -0.07877175, "profit_sum_pct": -7.877175, "profit_total_abs": -0.007896868250539965, "profit_total_pct": -2.625725, "duration_avg": "3 days, 4:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ZEC/BTC", "trades": 1, "profit_mean": -0.04815133, "profit_mean_pct": -4.815133, "profit_sum": -0.04815133, "profit_sum_pct": -4.815133, "profit_total_abs": -0.004827170578309559, "profit_total_pct": -1.6050443333333335, "duration_avg": "2 days, 19:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "TOTAL", "trades": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.894489333333333, "profit_sum": -0.14683468, "profit_sum_pct": -14.683468, "profit_total_abs": -0.014720177176734003, "profit_total_pct": -4.8944893333333335, "duration_avg": "2 days, 1:25:00", "wins": 0, "draws": 0, "losses": 3}], "total_trades": 179, "backtest_start": "2018-01-30 04:45:00+00:00", "backtest_start_ts": 1517287500, "backtest_end": "2018-01-30 04:45:00+00:00", "backtest_end_ts": 1517287500, "backtest_days": 0, "trades_per_day": null, "market_change": 0.25, "stake_amount": 0.1, "max_drawdown": 0.21142322000000008, "drawdown_start": "2018-01-24 14:25:00+00:00", "drawdown_start_ts": 1516803900.0, "drawdown_end": "2018-01-30 04:45:00+00:00", "drawdown_end_ts": 1517287500.0,"pairlist": ["TRX/BTC", "ADA/BTC", "XLM/BTC", "ETH/BTC", "XMR/BTC", "ZEC/BTC","NXT/BTC", "LTC/BTC", "ETC/BTC", "DASH/BTC"]}}, "strategy_comparison": [{"key": "DefaultStrategy", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}, {"key": "TestStrategy", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}]} +{"strategy": {"DefaultStrategy": {"trades": [{"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:20:00+00:00", "trade_duration": 5, "open_rate": 9.64e-05, "close_rate": 0.00010074887218045112, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1037.344398340249, "profit_abs": 0.00399999999999999}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:30:00+00:00", "trade_duration": 15, "open_rate": 4.756e-05, "close_rate": 4.9705563909774425e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2102.6072329688814, "profit_abs": 0.00399999999999999}, {"pair": "XLM/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:35:00+00:00", "trade_duration": 10, "open_rate": 3.339e-05, "close_rate": 3.489631578947368e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2994.908655286014, "profit_abs": 0.0040000000000000036}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:40:00+00:00", "trade_duration": 15, "open_rate": 9.696e-05, "close_rate": 0.00010133413533834584, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1031.3531353135315, "profit_abs": 0.00399999999999999}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 07:35:00+00:00", "close_date": "2018-01-10 08:35:00+00:00", "trade_duration": 60, "open_rate": 0.0943, "close_rate": 0.09477268170426063, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0604453870625663, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 07:40:00+00:00", "close_date": "2018-01-10 08:10:00+00:00", "trade_duration": 30, "open_rate": 0.02719607, "close_rate": 0.02760503345864661, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.677001860930642, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 08:15:00+00:00", "close_date": "2018-01-10 09:55:00+00:00", "trade_duration": 100, "open_rate": 0.04634952, "close_rate": 0.046581848421052625, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.1575196463739, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 14:45:00+00:00", "close_date": "2018-01-10 15:50:00+00:00", "trade_duration": 65, "open_rate": 3.066e-05, "close_rate": 3.081368421052631e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3261.5786040443577, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 16:35:00+00:00", "close_date": "2018-01-10 17:15:00+00:00", "trade_duration": 40, "open_rate": 0.0168999, "close_rate": 0.016984611278195488, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 5.917194776300452, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 16:40:00+00:00", "close_date": "2018-01-10 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.09132568, "close_rate": 0.0917834528320802, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0949822656672252, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 18:50:00+00:00", "close_date": "2018-01-10 19:45:00+00:00", "trade_duration": 55, "open_rate": 0.08898003, "close_rate": 0.08942604518796991, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1238476768326557, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 22:15:00+00:00", "close_date": "2018-01-10 23:00:00+00:00", "trade_duration": 45, "open_rate": 0.08560008, "close_rate": 0.08602915308270676, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1682232072680307, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 22:50:00+00:00", "close_date": "2018-01-10 23:20:00+00:00", "trade_duration": 30, "open_rate": 0.00249083, "close_rate": 0.0025282860902255634, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 40.147260150231055, "profit_abs": 0.000999999999999987}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 23:15:00+00:00", "close_date": "2018-01-11 00:15:00+00:00", "trade_duration": 60, "open_rate": 3.022e-05, "close_rate": 3.037147869674185e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3309.0668431502318, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-10 23:40:00+00:00", "close_date": "2018-01-11 00:05:00+00:00", "trade_duration": 25, "open_rate": 0.002437, "close_rate": 0.0024980776942355883, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 41.03405826836274, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 00:00:00+00:00", "close_date": "2018-01-11 00:35:00+00:00", "trade_duration": 35, "open_rate": 0.04771803, "close_rate": 0.04843559436090225, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0956439316543456, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-11 03:40:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 45, "open_rate": 3.651e-05, "close_rate": 3.2859000000000005e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2738.9756231169545, "profit_abs": -0.01047499999999997}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 03:55:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 30, "open_rate": 0.08824105, "close_rate": 0.08956798308270676, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1332594070446804, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 04:00:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 50, "open_rate": 0.00243, "close_rate": 0.002442180451127819, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 41.1522633744856, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:55:00+00:00", "trade_duration": 25, "open_rate": 0.04545064, "close_rate": 0.046589753784461146, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.200189040242338, "profit_abs": 0.001999999999999988}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 20, "open_rate": 3.372e-05, "close_rate": 3.456511278195488e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2965.599051008304, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:55:00+00:00", "close_date": "2018-01-11 05:15:00+00:00", "trade_duration": 20, "open_rate": 0.02644, "close_rate": 0.02710265664160401, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.7821482602118004, "profit_abs": 0.001999999999999988}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:20:00+00:00", "close_date": "2018-01-11 12:00:00+00:00", "trade_duration": 40, "open_rate": 0.08812, "close_rate": 0.08856170426065162, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1348161597821154, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:35:00+00:00", "close_date": "2018-01-11 12:15:00+00:00", "trade_duration": 40, "open_rate": 0.02683577, "close_rate": 0.026970285137844607, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.7263696923919087, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 14:00:00+00:00", "close_date": "2018-01-11 14:25:00+00:00", "trade_duration": 25, "open_rate": 4.919e-05, "close_rate": 5.04228320802005e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2032.9335230737956, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 19:25:00+00:00", "close_date": "2018-01-11 20:35:00+00:00", "trade_duration": 70, "open_rate": 0.08784896, "close_rate": 0.08828930566416039, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1383174029607181, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:35:00+00:00", "close_date": "2018-01-11 23:30:00+00:00", "trade_duration": 55, "open_rate": 5.105e-05, "close_rate": 5.130588972431077e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1958.8638589618022, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:25:00+00:00", "trade_duration": 30, "open_rate": 3.96e-05, "close_rate": 4.019548872180451e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2525.252525252525, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:35:00+00:00", "trade_duration": 40, "open_rate": 2.885e-05, "close_rate": 2.899461152882205e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3466.204506065858, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 23:30:00+00:00", "close_date": "2018-01-12 00:05:00+00:00", "trade_duration": 35, "open_rate": 0.02645, "close_rate": 0.026847744360902256, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.780718336483932, "profit_abs": 0.0010000000000000148}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 23:55:00+00:00", "close_date": "2018-01-12 01:15:00+00:00", "trade_duration": 80, "open_rate": 0.048, "close_rate": 0.04824060150375939, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0833333333333335, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-12 21:15:00+00:00", "close_date": "2018-01-12 21:40:00+00:00", "trade_duration": 25, "open_rate": 4.692e-05, "close_rate": 4.809593984962405e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2131.287297527707, "profit_abs": 0.001999999999999974}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 00:55:00+00:00", "close_date": "2018-01-13 06:20:00+00:00", "trade_duration": 325, "open_rate": 0.00256966, "close_rate": 0.0025825405012531327, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.91565421106294, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 10:55:00+00:00", "close_date": "2018-01-13 11:35:00+00:00", "trade_duration": 40, "open_rate": 6.262e-05, "close_rate": 6.293388471177944e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1596.933886937081, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 13:05:00+00:00", "close_date": "2018-01-15 14:10:00+00:00", "trade_duration": 2945, "open_rate": 4.73e-05, "close_rate": 4.753709273182957e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2114.1649048625795, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:30:00+00:00", "close_date": "2018-01-13 14:45:00+00:00", "trade_duration": 75, "open_rate": 6.063e-05, "close_rate": 6.0933909774436085e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1649.348507339601, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:40:00+00:00", "close_date": "2018-01-13 23:30:00+00:00", "trade_duration": 590, "open_rate": 0.00011082, "close_rate": 0.00011137548872180448, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 902.3641941887746, "profit_abs": -2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 15:15:00+00:00", "close_date": "2018-01-13 15:55:00+00:00", "trade_duration": 40, "open_rate": 5.93e-05, "close_rate": 5.9597243107769415e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1686.3406408094436, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 16:30:00+00:00", "close_date": "2018-01-13 17:10:00+00:00", "trade_duration": 40, "open_rate": 0.04850003, "close_rate": 0.04874313791979949, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0618543947292407, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 22:05:00+00:00", "close_date": "2018-01-14 06:25:00+00:00", "trade_duration": 500, "open_rate": 0.09825019, "close_rate": 0.09874267215538848, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0178097365511456, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 00:20:00+00:00", "close_date": "2018-01-14 22:55:00+00:00", "trade_duration": 1355, "open_rate": 6.018e-05, "close_rate": 6.048165413533834e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1661.681621801263, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 12:45:00+00:00", "close_date": "2018-01-14 13:25:00+00:00", "trade_duration": 40, "open_rate": 0.09758999, "close_rate": 0.0980791628822055, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.024695258191952, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-14 15:30:00+00:00", "close_date": "2018-01-14 16:00:00+00:00", "trade_duration": 30, "open_rate": 0.00311, "close_rate": 0.0031567669172932328, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 32.154340836012864, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 20:45:00+00:00", "close_date": "2018-01-14 22:15:00+00:00", "trade_duration": 90, "open_rate": 0.00312401, "close_rate": 0.003139669197994987, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 32.010140812609436, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 23:35:00+00:00", "close_date": "2018-01-15 00:30:00+00:00", "trade_duration": 55, "open_rate": 0.0174679, "close_rate": 0.017555458395989976, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 5.724786608579165, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 23:45:00+00:00", "close_date": "2018-01-15 00:25:00+00:00", "trade_duration": 40, "open_rate": 0.07346846, "close_rate": 0.07383672295739348, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.3611282991367997, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 02:25:00+00:00", "close_date": "2018-01-15 03:05:00+00:00", "trade_duration": 40, "open_rate": 0.097994, "close_rate": 0.09848519799498744, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.020470641059657, "profit_abs": -2.7755575615628914e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 07:20:00+00:00", "close_date": "2018-01-15 08:00:00+00:00", "trade_duration": 40, "open_rate": 0.09659, "close_rate": 0.09707416040100247, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0353038616834043, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-15 08:20:00+00:00", "close_date": "2018-01-15 08:55:00+00:00", "trade_duration": 35, "open_rate": 9.987e-05, "close_rate": 0.00010137180451127818, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1001.3016921998599, "profit_abs": 0.0010000000000000009}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-15 12:10:00+00:00", "close_date": "2018-01-16 02:50:00+00:00", "trade_duration": 880, "open_rate": 0.0948969, "close_rate": 0.09537257368421052, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0537752023511833, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:10:00+00:00", "close_date": "2018-01-15 17:40:00+00:00", "trade_duration": 210, "open_rate": 0.071, "close_rate": 0.07135588972431077, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4084507042253522, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:30:00+00:00", "close_date": "2018-01-15 15:10:00+00:00", "trade_duration": 40, "open_rate": 0.04600501, "close_rate": 0.046235611553884705, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.173676301776698, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:10:00+00:00", "close_date": "2018-01-15 19:25:00+00:00", "trade_duration": 75, "open_rate": 9.438e-05, "close_rate": 9.485308270676693e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1059.5465140919687, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:35:00+00:00", "close_date": "2018-01-15 19:15:00+00:00", "trade_duration": 40, "open_rate": 0.03040001, "close_rate": 0.030552391002506264, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.2894726021471703, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-15 20:25:00+00:00", "close_date": "2018-01-16 08:25:00+00:00", "trade_duration": 720, "open_rate": 5.837e-05, "close_rate": 5.2533e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1713.2088401576154, "profit_abs": -0.010474999999999984}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 20:40:00+00:00", "close_date": "2018-01-15 22:00:00+00:00", "trade_duration": 80, "open_rate": 0.046036, "close_rate": 0.04626675689223057, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.1722130506560084, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 00:30:00+00:00", "close_date": "2018-01-16 01:10:00+00:00", "trade_duration": 40, "open_rate": 0.0028685, "close_rate": 0.0028828784461152877, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 34.86142583231654, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 01:15:00+00:00", "close_date": "2018-01-16 02:35:00+00:00", "trade_duration": 80, "open_rate": 0.06731755, "close_rate": 0.0676549813283208, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4854967241083492, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 07:45:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 55, "open_rate": 0.09217614, "close_rate": 0.09263817578947368, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0848794492804754, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:55:00+00:00", "trade_duration": 20, "open_rate": 0.0165, "close_rate": 0.016913533834586467, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.0606060606060606, "profit_abs": 0.0020000000000000018}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 5, "open_rate": 7.953e-05, "close_rate": 8.311781954887218e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1257.387149503332, "profit_abs": 0.00399999999999999}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 08:45:00+00:00", "close_date": "2018-01-16 09:50:00+00:00", "trade_duration": 65, "open_rate": 0.045202, "close_rate": 0.04542857644110275, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.2122914915269236, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:45:00+00:00", "trade_duration": 30, "open_rate": 5.248e-05, "close_rate": 5.326917293233082e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1905.487804878049, "profit_abs": 0.0010000000000000009}, {"pair": "XMR/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:55:00+00:00", "trade_duration": 40, "open_rate": 0.02892318, "close_rate": 0.02906815834586466, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.457434486802627, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 09:50:00+00:00", "close_date": "2018-01-16 10:10:00+00:00", "trade_duration": 20, "open_rate": 5.158e-05, "close_rate": 5.287273182957392e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1938.735944164405, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:35:00+00:00", "trade_duration": 30, "open_rate": 0.02828232, "close_rate": 0.02870761804511278, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5357778286929786, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:40:00+00:00", "trade_duration": 35, "open_rate": 0.04357584, "close_rate": 0.044231115789473675, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.294849623093898, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 13:45:00+00:00", "close_date": "2018-01-16 14:20:00+00:00", "trade_duration": 35, "open_rate": 5.362e-05, "close_rate": 5.442631578947368e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1864.975755315181, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 17:30:00+00:00", "close_date": "2018-01-16 18:25:00+00:00", "trade_duration": 55, "open_rate": 5.302e-05, "close_rate": 5.328576441102756e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1886.0807242549984, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:45:00+00:00", "trade_duration": 30, "open_rate": 0.09129999, "close_rate": 0.09267292218045112, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0952903718828448, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:35:00+00:00", "trade_duration": 20, "open_rate": 3.808e-05, "close_rate": 3.903438596491228e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2626.0504201680674, "profit_abs": 0.0020000000000000018}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 19:00:00+00:00", "close_date": "2018-01-16 19:30:00+00:00", "trade_duration": 30, "open_rate": 0.02811012, "close_rate": 0.028532828571428567, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.557437677249333, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 60, "open_rate": 0.00258379, "close_rate": 0.002325411, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.702835756775904, "profit_abs": -0.010474999999999984}, {"pair": "NXT/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 80, "open_rate": 2.559e-05, "close_rate": 2.3031e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3907.7764751856193, "profit_abs": -0.010474999999999998}, {"pair": "TRX/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:35:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 50, "open_rate": 7.62e-05, "close_rate": 6.858e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1312.3359580052495, "profit_abs": -0.010474999999999984}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:35:00+00:00", "trade_duration": 5, "open_rate": 0.00229844, "close_rate": 0.002402129022556391, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 43.507770487809125, "profit_abs": 0.004000000000000017}, {"pair": "LTC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:40:00+00:00", "trade_duration": 10, "open_rate": 0.0151, "close_rate": 0.015781203007518795, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.622516556291391, "profit_abs": 0.00399999999999999}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:40:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 5, "open_rate": 0.00235676, "close_rate": 0.00246308, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 42.431134269081284, "profit_abs": 0.0040000000000000036}, {"pair": "DASH/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 22:45:00+00:00", "close_date": "2018-01-16 23:05:00+00:00", "trade_duration": 20, "open_rate": 0.0630692, "close_rate": 0.06464988170426066, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.585559988076589, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:50:00+00:00", "close_date": "2018-01-16 22:55:00+00:00", "trade_duration": 5, "open_rate": 2.2e-05, "close_rate": 2.299248120300751e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 4545.454545454546, "profit_abs": 0.003999999999999976}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-17 03:30:00+00:00", "close_date": "2018-01-17 04:00:00+00:00", "trade_duration": 30, "open_rate": 4.974e-05, "close_rate": 5.048796992481203e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2010.454362685967, "profit_abs": 0.0010000000000000009}, {"pair": "TRX/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-17 03:55:00+00:00", "close_date": "2018-01-17 04:15:00+00:00", "trade_duration": 20, "open_rate": 7.108e-05, "close_rate": 7.28614536340852e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1406.8655036578502, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 09:35:00+00:00", "close_date": "2018-01-17 10:15:00+00:00", "trade_duration": 40, "open_rate": 0.04327, "close_rate": 0.04348689223057644, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.3110700254217704, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:20:00+00:00", "close_date": "2018-01-17 17:00:00+00:00", "trade_duration": 400, "open_rate": 4.997e-05, "close_rate": 5.022047619047618e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2001.2007204322595, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:25:00+00:00", "trade_duration": 55, "open_rate": 0.06836818, "close_rate": 0.06871087764411027, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4626687444363737, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:10:00+00:00", "trade_duration": 40, "open_rate": 3.63e-05, "close_rate": 3.648195488721804e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2754.8209366391184, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:30:00+00:00", "close_date": "2018-01-17 22:05:00+00:00", "trade_duration": 575, "open_rate": 0.0281, "close_rate": 0.02824085213032581, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5587188612099645, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:35:00+00:00", "close_date": "2018-01-17 16:55:00+00:00", "trade_duration": 260, "open_rate": 0.08651001, "close_rate": 0.08694364413533832, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1559355963546878, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 05:00:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 55, "open_rate": 5.633e-05, "close_rate": 5.6612355889724306e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1775.2529735487308, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 05:20:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 35, "open_rate": 0.06988494, "close_rate": 0.07093584135338346, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.430923457900944, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 07:35:00+00:00", "close_date": "2018-01-18 08:15:00+00:00", "trade_duration": 40, "open_rate": 5.545e-05, "close_rate": 5.572794486215538e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1803.4265103697026, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 09:00:00+00:00", "close_date": "2018-01-18 09:40:00+00:00", "trade_duration": 40, "open_rate": 0.01633527, "close_rate": 0.016417151052631574, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.121723118136401, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 16:40:00+00:00", "close_date": "2018-01-18 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.00269734, "close_rate": 0.002710860501253133, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 37.073561360451414, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-18 18:05:00+00:00", "close_date": "2018-01-18 18:30:00+00:00", "trade_duration": 25, "open_rate": 4.475e-05, "close_rate": 4.587155388471177e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2234.63687150838, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 18:25:00+00:00", "close_date": "2018-01-18 18:55:00+00:00", "trade_duration": 30, "open_rate": 2.79e-05, "close_rate": 2.8319548872180444e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3584.2293906810037, "profit_abs": 0.000999999999999987}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 20:10:00+00:00", "close_date": "2018-01-18 20:50:00+00:00", "trade_duration": 40, "open_rate": 0.04439326, "close_rate": 0.04461578260651629, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.2525942001105577, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 21:30:00+00:00", "close_date": "2018-01-19 00:35:00+00:00", "trade_duration": 185, "open_rate": 4.49e-05, "close_rate": 4.51250626566416e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2227.1714922049, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 21:55:00+00:00", "close_date": "2018-01-19 05:05:00+00:00", "trade_duration": 430, "open_rate": 0.02855, "close_rate": 0.028693107769423555, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.502626970227671, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 22:10:00+00:00", "close_date": "2018-01-18 22:50:00+00:00", "trade_duration": 40, "open_rate": 5.796e-05, "close_rate": 5.8250526315789473e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1725.3278122843342, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 23:50:00+00:00", "close_date": "2018-01-19 00:30:00+00:00", "trade_duration": 40, "open_rate": 0.04340323, "close_rate": 0.04362079005012531, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.303975994413319, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-19 16:45:00+00:00", "close_date": "2018-01-19 17:35:00+00:00", "trade_duration": 50, "open_rate": 0.04454455, "close_rate": 0.04476783095238095, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.244943545282195, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:15:00+00:00", "close_date": "2018-01-19 19:55:00+00:00", "trade_duration": 160, "open_rate": 5.62e-05, "close_rate": 5.648170426065162e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1779.3594306049824, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:20:00+00:00", "close_date": "2018-01-19 20:15:00+00:00", "trade_duration": 175, "open_rate": 4.339e-05, "close_rate": 4.360749373433584e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2304.6784973496196, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-20 04:45:00+00:00", "close_date": "2018-01-20 17:35:00+00:00", "trade_duration": 770, "open_rate": 0.0001009, "close_rate": 0.00010140576441102755, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 991.0802775024778, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 15:15:00+00:00", "trade_duration": 625, "open_rate": 0.00270505, "close_rate": 0.002718609147869674, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.96789338459548, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 07:00:00+00:00", "trade_duration": 130, "open_rate": 0.03000002, "close_rate": 0.030150396040100245, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.3333311111125927, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 09:00:00+00:00", "close_date": "2018-01-20 09:40:00+00:00", "trade_duration": 40, "open_rate": 5.46e-05, "close_rate": 5.4873684210526304e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1831.5018315018317, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-20 18:25:00+00:00", "close_date": "2018-01-25 03:50:00+00:00", "trade_duration": 6325, "open_rate": 0.03082222, "close_rate": 0.027739998, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.244412634781012, "profit_abs": -0.010474999999999998}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 22:25:00+00:00", "close_date": "2018-01-20 23:15:00+00:00", "trade_duration": 50, "open_rate": 0.08969999, "close_rate": 0.09014961401002504, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1148273260677064, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 02:50:00+00:00", "close_date": "2018-01-21 14:30:00+00:00", "trade_duration": 700, "open_rate": 0.01632501, "close_rate": 0.01640683962406015, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.125570520324337, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 10:20:00+00:00", "close_date": "2018-01-21 11:00:00+00:00", "trade_duration": 40, "open_rate": 0.070538, "close_rate": 0.07089157393483708, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.417675579120474, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 15:50:00+00:00", "close_date": "2018-01-21 18:45:00+00:00", "trade_duration": 175, "open_rate": 5.301e-05, "close_rate": 5.327571428571427e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1886.4365214110546, "profit_abs": -2.7755575615628914e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 16:20:00+00:00", "close_date": "2018-01-21 17:00:00+00:00", "trade_duration": 40, "open_rate": 3.955e-05, "close_rate": 3.9748245614035085e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2528.4450063211125, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:45:00+00:00", "trade_duration": 30, "open_rate": 0.00258505, "close_rate": 0.002623922932330827, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.6839712964933, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:55:00+00:00", "trade_duration": 40, "open_rate": 3.903e-05, "close_rate": 3.922563909774435e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2562.1316935690497, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 00:35:00+00:00", "close_date": "2018-01-22 10:35:00+00:00", "trade_duration": 600, "open_rate": 5.236e-05, "close_rate": 5.262245614035087e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1909.8548510313217, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 01:30:00+00:00", "close_date": "2018-01-22 02:10:00+00:00", "trade_duration": 40, "open_rate": 9.028e-05, "close_rate": 9.07325313283208e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1107.6650420912717, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 12:25:00+00:00", "close_date": "2018-01-22 14:35:00+00:00", "trade_duration": 130, "open_rate": 0.002687, "close_rate": 0.002700468671679198, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 37.21622627465575, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 13:15:00+00:00", "close_date": "2018-01-22 13:55:00+00:00", "trade_duration": 40, "open_rate": 4.168e-05, "close_rate": 4.188892230576441e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2399.232245681382, "profit_abs": 1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-22 14:00:00+00:00", "close_date": "2018-01-22 14:30:00+00:00", "trade_duration": 30, "open_rate": 8.821e-05, "close_rate": 8.953646616541353e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1133.6583153837435, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 15:55:00+00:00", "close_date": "2018-01-22 16:40:00+00:00", "trade_duration": 45, "open_rate": 5.172e-05, "close_rate": 5.1979248120300745e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1933.4880123743235, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-22 16:05:00+00:00", "close_date": "2018-01-22 16:25:00+00:00", "trade_duration": 20, "open_rate": 3.026e-05, "close_rate": 3.101839598997494e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3304.692663582287, "profit_abs": 0.0020000000000000157}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 19:50:00+00:00", "close_date": "2018-01-23 00:10:00+00:00", "trade_duration": 260, "open_rate": 0.07064, "close_rate": 0.07099408521303258, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.415628539071348, "profit_abs": 1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 21:25:00+00:00", "close_date": "2018-01-22 22:05:00+00:00", "trade_duration": 40, "open_rate": 0.01644483, "close_rate": 0.01652726022556391, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.080938507725528, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-23 00:05:00+00:00", "close_date": "2018-01-23 00:35:00+00:00", "trade_duration": 30, "open_rate": 4.331e-05, "close_rate": 4.3961278195488714e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2308.935580697299, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-23 01:50:00+00:00", "close_date": "2018-01-23 02:15:00+00:00", "trade_duration": 25, "open_rate": 3.2e-05, "close_rate": 3.2802005012531326e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3125.0000000000005, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 04:25:00+00:00", "close_date": "2018-01-23 05:15:00+00:00", "trade_duration": 50, "open_rate": 0.09167706, "close_rate": 0.09213659413533835, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0907854156754153, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 07:35:00+00:00", "close_date": "2018-01-23 09:00:00+00:00", "trade_duration": 85, "open_rate": 0.0692498, "close_rate": 0.06959691679197995, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4440474918339115, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 10:50:00+00:00", "close_date": "2018-01-23 13:05:00+00:00", "trade_duration": 135, "open_rate": 3.182e-05, "close_rate": 3.197949874686716e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3142.677561282213, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 11:05:00+00:00", "close_date": "2018-01-23 16:05:00+00:00", "trade_duration": 300, "open_rate": 0.04088, "close_rate": 0.04108491228070175, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4461839530332683, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 14:55:00+00:00", "close_date": "2018-01-23 15:35:00+00:00", "trade_duration": 40, "open_rate": 5.15e-05, "close_rate": 5.175814536340851e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1941.747572815534, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 16:35:00+00:00", "close_date": "2018-01-24 00:05:00+00:00", "trade_duration": 450, "open_rate": 0.09071698, "close_rate": 0.09117170170426064, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1023294646713329, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 17:25:00+00:00", "close_date": "2018-01-23 18:45:00+00:00", "trade_duration": 80, "open_rate": 3.128e-05, "close_rate": 3.1436791979949865e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3196.9309462915603, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 20:15:00+00:00", "close_date": "2018-01-23 22:00:00+00:00", "trade_duration": 105, "open_rate": 9.555e-05, "close_rate": 9.602894736842104e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1046.5724751439038, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 22:30:00+00:00", "close_date": "2018-01-23 23:10:00+00:00", "trade_duration": 40, "open_rate": 0.04080001, "close_rate": 0.0410045213283208, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.450979791426522, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 23:50:00+00:00", "close_date": "2018-01-24 03:35:00+00:00", "trade_duration": 225, "open_rate": 5.163e-05, "close_rate": 5.18887969924812e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1936.8584156498162, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 00:20:00+00:00", "close_date": "2018-01-24 01:50:00+00:00", "trade_duration": 90, "open_rate": 0.04040781, "close_rate": 0.04061035541353383, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.474769110228938, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 06:45:00+00:00", "close_date": "2018-01-24 07:25:00+00:00", "trade_duration": 40, "open_rate": 5.132e-05, "close_rate": 5.157724310776942e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1948.5580670303975, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-24 14:15:00+00:00", "close_date": "2018-01-24 14:25:00+00:00", "trade_duration": 10, "open_rate": 5.198e-05, "close_rate": 5.432496240601503e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1923.8168526356292, "profit_abs": 0.0040000000000000036}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 14:50:00+00:00", "close_date": "2018-01-24 16:35:00+00:00", "trade_duration": 105, "open_rate": 3.054e-05, "close_rate": 3.069308270676692e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3274.3942370661425, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 15:10:00+00:00", "close_date": "2018-01-24 16:15:00+00:00", "trade_duration": 65, "open_rate": 9.263e-05, "close_rate": 9.309431077694236e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1079.5638562020945, "profit_abs": 2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 22:40:00+00:00", "close_date": "2018-01-24 23:25:00+00:00", "trade_duration": 45, "open_rate": 5.514e-05, "close_rate": 5.54163909774436e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1813.5654697134569, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 00:50:00+00:00", "close_date": "2018-01-25 01:30:00+00:00", "trade_duration": 40, "open_rate": 4.921e-05, "close_rate": 4.9456666666666664e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2032.1072952651903, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 08:15:00+00:00", "close_date": "2018-01-25 12:15:00+00:00", "trade_duration": 240, "open_rate": 0.0026, "close_rate": 0.002613032581453634, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.46153846153847, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 10:25:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 350, "open_rate": 0.02799871, "close_rate": 0.028139054411027563, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.571593119825878, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 11:00:00+00:00", "close_date": "2018-01-25 11:45:00+00:00", "trade_duration": 45, "open_rate": 0.04078902, "close_rate": 0.0409934762406015, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4516401717913303, "profit_abs": -1.3877787807814457e-17}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:05:00+00:00", "close_date": "2018-01-25 13:45:00+00:00", "trade_duration": 40, "open_rate": 2.89e-05, "close_rate": 2.904486215538847e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3460.2076124567475, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:20:00+00:00", "close_date": "2018-01-25 14:05:00+00:00", "trade_duration": 45, "open_rate": 0.041103, "close_rate": 0.04130903007518797, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4329124394813033, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-25 15:45:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 30, "open_rate": 5.428e-05, "close_rate": 5.509624060150376e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1842.2991893883568, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 17:45:00+00:00", "close_date": "2018-01-25 23:15:00+00:00", "trade_duration": 330, "open_rate": 5.414e-05, "close_rate": 5.441137844611528e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1847.063169560399, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 21:15:00+00:00", "close_date": "2018-01-25 21:55:00+00:00", "trade_duration": 40, "open_rate": 0.04140777, "close_rate": 0.0416153277443609, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.415005686130888, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 02:05:00+00:00", "close_date": "2018-01-26 02:45:00+00:00", "trade_duration": 40, "open_rate": 0.00254309, "close_rate": 0.002555837318295739, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 39.32224183965177, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 02:55:00+00:00", "close_date": "2018-01-26 15:10:00+00:00", "trade_duration": 735, "open_rate": 5.607e-05, "close_rate": 5.6351052631578935e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1783.4849295523454, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 06:10:00+00:00", "close_date": "2018-01-26 09:25:00+00:00", "trade_duration": 195, "open_rate": 0.00253806, "close_rate": 0.0025507821052631577, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 39.400171784748984, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 07:25:00+00:00", "close_date": "2018-01-26 09:55:00+00:00", "trade_duration": 150, "open_rate": 0.0415, "close_rate": 0.04170802005012531, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4096385542168677, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-26 09:55:00+00:00", "close_date": "2018-01-26 10:25:00+00:00", "trade_duration": 30, "open_rate": 5.321e-05, "close_rate": 5.401015037593984e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1879.3459875963165, "profit_abs": 0.000999999999999987}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 16:05:00+00:00", "close_date": "2018-01-26 16:45:00+00:00", "trade_duration": 40, "open_rate": 0.02772046, "close_rate": 0.02785940967418546, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.6074437437185387, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 23:35:00+00:00", "close_date": "2018-01-27 00:15:00+00:00", "trade_duration": 40, "open_rate": 0.09461341, "close_rate": 0.09508766268170424, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0569326272036914, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 00:35:00+00:00", "close_date": "2018-01-27 01:30:00+00:00", "trade_duration": 55, "open_rate": 5.615e-05, "close_rate": 5.643145363408521e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1780.9439002671415, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.07877175, "open_date": "2018-01-27 00:45:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 4560, "open_rate": 5.556e-05, "close_rate": 5.144e-05, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1799.8560115190785, "profit_abs": -0.007896868250539965}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 02:30:00+00:00", "close_date": "2018-01-27 11:25:00+00:00", "trade_duration": 535, "open_rate": 0.06900001, "close_rate": 0.06934587471177944, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4492751522789635, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 06:25:00+00:00", "close_date": "2018-01-27 07:05:00+00:00", "trade_duration": 40, "open_rate": 0.09449985, "close_rate": 0.0949735334586466, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.058202737887944, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.04815133, "open_date": "2018-01-27 09:40:00+00:00", "close_date": "2018-01-30 04:40:00+00:00", "trade_duration": 4020, "open_rate": 0.0410697, "close_rate": 0.03928809, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4348850855983852, "profit_abs": -0.004827170578309559}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 11:45:00+00:00", "close_date": "2018-01-27 12:30:00+00:00", "trade_duration": 45, "open_rate": 0.0285, "close_rate": 0.02864285714285714, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5087719298245617, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 12:35:00+00:00", "close_date": "2018-01-27 15:25:00+00:00", "trade_duration": 170, "open_rate": 0.02866372, "close_rate": 0.02880739779448621, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.4887307020861216, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 15:50:00+00:00", "close_date": "2018-01-27 16:50:00+00:00", "trade_duration": 60, "open_rate": 0.095381, "close_rate": 0.09585910025062656, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0484268355332824, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 17:05:00+00:00", "close_date": "2018-01-27 17:45:00+00:00", "trade_duration": 40, "open_rate": 0.06759092, "close_rate": 0.06792972160401002, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4794886650455417, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 23:40:00+00:00", "close_date": "2018-01-28 01:05:00+00:00", "trade_duration": 85, "open_rate": 0.00258501, "close_rate": 0.002597967443609022, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.684569885609726, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 02:25:00+00:00", "close_date": "2018-01-28 08:10:00+00:00", "trade_duration": 345, "open_rate": 0.06698502, "close_rate": 0.0673207845112782, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4928710926711672, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 10:25:00+00:00", "close_date": "2018-01-28 16:30:00+00:00", "trade_duration": 365, "open_rate": 0.0677177, "close_rate": 0.06805713709273183, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4767187899175547, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-28 20:35:00+00:00", "close_date": "2018-01-28 21:35:00+00:00", "trade_duration": 60, "open_rate": 5.215e-05, "close_rate": 5.2411403508771925e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1917.5455417066157, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-28 22:00:00+00:00", "close_date": "2018-01-28 22:30:00+00:00", "trade_duration": 30, "open_rate": 0.00273809, "close_rate": 0.002779264285714285, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.5218089982433, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-29 00:00:00+00:00", "close_date": "2018-01-29 00:30:00+00:00", "trade_duration": 30, "open_rate": 0.00274632, "close_rate": 0.002787618045112782, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.412362725392526, "profit_abs": 0.0010000000000000148}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-29 02:15:00+00:00", "close_date": "2018-01-29 03:00:00+00:00", "trade_duration": 45, "open_rate": 0.01622478, "close_rate": 0.016306107218045113, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.163411768911504, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 03:05:00+00:00", "close_date": "2018-01-29 03:45:00+00:00", "trade_duration": 40, "open_rate": 0.069, "close_rate": 0.06934586466165413, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4492753623188406, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 05:20:00+00:00", "close_date": "2018-01-29 06:55:00+00:00", "trade_duration": 95, "open_rate": 8.755e-05, "close_rate": 8.798884711779448e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1142.204454597373, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 07:00:00+00:00", "close_date": "2018-01-29 19:25:00+00:00", "trade_duration": 745, "open_rate": 0.06825763, "close_rate": 0.06859977350877192, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4650376815016872, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 19:45:00+00:00", "close_date": "2018-01-29 20:25:00+00:00", "trade_duration": 40, "open_rate": 0.06713892, "close_rate": 0.06747545593984962, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4894490408841845, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0199116, "open_date": "2018-01-29 23:30:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 315, "open_rate": 8.934e-05, "close_rate": 8.8e-05, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1119.3194537721067, "profit_abs": -0.0019961383478844796}], "results_per_pair": [{"key": "TRX/BTC", "trades": 15, "profit_mean": 0.0023467073333333323, "profit_mean_pct": 0.23467073333333321, "profit_sum": 0.035200609999999986, "profit_sum_pct": 3.5200609999999988, "profit_total_abs": 0.0035288616521155086, "profit_total_pct": 1.1733536666666662, "duration_avg": "2:28:00", "wins": 9, "draws": 2, "losses": 4}, {"key": "ADA/BTC", "trades": 29, "profit_mean": -0.0011598141379310352, "profit_mean_pct": -0.11598141379310352, "profit_sum": -0.03363461000000002, "profit_sum_pct": -3.3634610000000023, "profit_total_abs": -0.0033718682505400333, "profit_total_pct": -1.1211536666666675, "duration_avg": "5:35:00", "wins": 9, "draws": 11, "losses": 9}, {"key": "XLM/BTC", "trades": 21, "profit_mean": 0.0026243899999999994, "profit_mean_pct": 0.2624389999999999, "profit_sum": 0.05511218999999999, "profit_sum_pct": 5.511218999999999, "profit_total_abs": 0.005525000000000002, "profit_total_pct": 1.8370729999999995, "duration_avg": "3:21:00", "wins": 12, "draws": 3, "losses": 6}, {"key": "ETH/BTC", "trades": 21, "profit_mean": 0.0009500057142857142, "profit_mean_pct": 0.09500057142857142, "profit_sum": 0.01995012, "profit_sum_pct": 1.9950119999999998, "profit_total_abs": 0.0019999999999999463, "profit_total_pct": 0.6650039999999999, "duration_avg": "2:17:00", "wins": 5, "draws": 10, "losses": 6}, {"key": "XMR/BTC", "trades": 16, "profit_mean": -0.0027899012500000007, "profit_mean_pct": -0.2789901250000001, "profit_sum": -0.04463842000000001, "profit_sum_pct": -4.463842000000001, "profit_total_abs": -0.0044750000000000345, "profit_total_pct": -1.4879473333333337, "duration_avg": "8:41:00", "wins": 6, "draws": 5, "losses": 5}, {"key": "ZEC/BTC", "trades": 21, "profit_mean": -0.00039290904761904774, "profit_mean_pct": -0.03929090476190478, "profit_sum": -0.008251090000000003, "profit_sum_pct": -0.8251090000000003, "profit_total_abs": -0.000827170578309569, "profit_total_pct": -0.27503633333333344, "duration_avg": "4:17:00", "wins": 8, "draws": 7, "losses": 6}, {"key": "NXT/BTC", "trades": 12, "profit_mean": -0.0012261025000000006, "profit_mean_pct": -0.12261025000000006, "profit_sum": -0.014713230000000008, "profit_sum_pct": -1.4713230000000008, "profit_total_abs": -0.0014750000000000874, "profit_total_pct": -0.4904410000000003, "duration_avg": "0:57:00", "wins": 4, "draws": 3, "losses": 5}, {"key": "LTC/BTC", "trades": 8, "profit_mean": 0.00748129625, "profit_mean_pct": 0.748129625, "profit_sum": 0.05985037, "profit_sum_pct": 5.985037, "profit_total_abs": 0.006000000000000019, "profit_total_pct": 1.9950123333333334, "duration_avg": "1:59:00", "wins": 5, "draws": 2, "losses": 1}, {"key": "ETC/BTC", "trades": 20, "profit_mean": 0.0022568569999999997, "profit_mean_pct": 0.22568569999999996, "profit_sum": 0.04513713999999999, "profit_sum_pct": 4.513713999999999, "profit_total_abs": 0.004525000000000001, "profit_total_pct": 1.504571333333333, "duration_avg": "1:45:00", "wins": 11, "draws": 4, "losses": 5}, {"key": "DASH/BTC", "trades": 16, "profit_mean": 0.0018703237499999997, "profit_mean_pct": 0.18703237499999997, "profit_sum": 0.029925179999999996, "profit_sum_pct": 2.9925179999999996, "profit_total_abs": 0.002999999999999961, "profit_total_pct": 0.9975059999999999, "duration_avg": "3:03:00", "wins": 4, "draws": 7, "losses": 5}, {"key": "TOTAL", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}], "sell_reason_summary": [{"sell_reason": "roi", "trades": 170, "wins": 73, "draws": 54, "losses": 43, "profit_mean": 0.005398268352941177, "profit_mean_pct": 0.54, "profit_sum": 0.91770562, "profit_sum_pct": 91.77, "profit_total_abs": 0.09199999999999964, "profit_pct_total": 30.59}, {"sell_reason": "stop_loss", "trades": 6, "wins": 0, "draws": 0, "losses": 6, "profit_mean": -0.10448878000000002, "profit_mean_pct": -10.45, "profit_sum": -0.6269326800000001, "profit_sum_pct": -62.69, "profit_total_abs": -0.06284999999999992, "profit_pct_total": -20.9}, {"sell_reason": "force_sell", "trades": 3, "wins": 0, "draws": 0, "losses": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.89, "profit_sum": -0.14683468, "profit_sum_pct": -14.68, "profit_total_abs": -0.014720177176734003, "profit_pct_total": -4.89}], "left_open_trades": [{"key": "TRX/BTC", "trades": 1, "profit_mean": -0.0199116, "profit_mean_pct": -1.9911600000000003, "profit_sum": -0.0199116, "profit_sum_pct": -1.9911600000000003, "profit_total_abs": -0.0019961383478844796, "profit_total_pct": -0.6637200000000001, "duration_avg": "5:15:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ADA/BTC", "trades": 1, "profit_mean": -0.07877175, "profit_mean_pct": -7.877175, "profit_sum": -0.07877175, "profit_sum_pct": -7.877175, "profit_total_abs": -0.007896868250539965, "profit_total_pct": -2.625725, "duration_avg": "3 days, 4:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ZEC/BTC", "trades": 1, "profit_mean": -0.04815133, "profit_mean_pct": -4.815133, "profit_sum": -0.04815133, "profit_sum_pct": -4.815133, "profit_total_abs": -0.004827170578309559, "profit_total_pct": -1.6050443333333335, "duration_avg": "2 days, 19:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "TOTAL", "trades": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.894489333333333, "profit_sum": -0.14683468, "profit_sum_pct": -14.683468, "profit_total_abs": -0.014720177176734003, "profit_total_pct": -4.8944893333333335, "duration_avg": "2 days, 1:25:00", "wins": 0, "draws": 0, "losses": 3}], "total_trades": 179, "backtest_start": "2018-01-30 04:45:00+00:00", "backtest_start_ts": 1517287500, "backtest_end": "2018-01-30 04:45:00+00:00", "backtest_end_ts": 1517287500, "backtest_days": 0, "trades_per_day": null, "market_change": 0.25, "stake_amount": 0.1, "max_drawdown": 0.21142322000000008, "drawdown_start": "2018-01-24 14:25:00+00:00", "drawdown_start_ts": 1516803900.0, "drawdown_end": "2018-01-30 04:45:00+00:00", "drawdown_end_ts": 1517287500.0, "pairlist": ["TRX/BTC", "ADA/BTC", "XLM/BTC", "ETH/BTC", "XMR/BTC", "ZEC/BTC","NXT/BTC", "LTC/BTC", "ETC/BTC", "DASH/BTC"]}, "TestStrategy": {"trades": [{"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:20:00+00:00", "trade_duration": 5, "open_rate": 9.64e-05, "close_rate": 0.00010074887218045112, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1037.344398340249, "profit_abs": 0.00399999999999999}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:30:00+00:00", "trade_duration": 15, "open_rate": 4.756e-05, "close_rate": 4.9705563909774425e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2102.6072329688814, "profit_abs": 0.00399999999999999}, {"pair": "XLM/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:35:00+00:00", "trade_duration": 10, "open_rate": 3.339e-05, "close_rate": 3.489631578947368e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2994.908655286014, "profit_abs": 0.0040000000000000036}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:40:00+00:00", "trade_duration": 15, "open_rate": 9.696e-05, "close_rate": 0.00010133413533834584, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1031.3531353135315, "profit_abs": 0.00399999999999999}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 07:35:00+00:00", "close_date": "2018-01-10 08:35:00+00:00", "trade_duration": 60, "open_rate": 0.0943, "close_rate": 0.09477268170426063, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0604453870625663, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 07:40:00+00:00", "close_date": "2018-01-10 08:10:00+00:00", "trade_duration": 30, "open_rate": 0.02719607, "close_rate": 0.02760503345864661, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.677001860930642, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 08:15:00+00:00", "close_date": "2018-01-10 09:55:00+00:00", "trade_duration": 100, "open_rate": 0.04634952, "close_rate": 0.046581848421052625, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.1575196463739, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 14:45:00+00:00", "close_date": "2018-01-10 15:50:00+00:00", "trade_duration": 65, "open_rate": 3.066e-05, "close_rate": 3.081368421052631e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3261.5786040443577, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 16:35:00+00:00", "close_date": "2018-01-10 17:15:00+00:00", "trade_duration": 40, "open_rate": 0.0168999, "close_rate": 0.016984611278195488, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 5.917194776300452, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 16:40:00+00:00", "close_date": "2018-01-10 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.09132568, "close_rate": 0.0917834528320802, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0949822656672252, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 18:50:00+00:00", "close_date": "2018-01-10 19:45:00+00:00", "trade_duration": 55, "open_rate": 0.08898003, "close_rate": 0.08942604518796991, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1238476768326557, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 22:15:00+00:00", "close_date": "2018-01-10 23:00:00+00:00", "trade_duration": 45, "open_rate": 0.08560008, "close_rate": 0.08602915308270676, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1682232072680307, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 22:50:00+00:00", "close_date": "2018-01-10 23:20:00+00:00", "trade_duration": 30, "open_rate": 0.00249083, "close_rate": 0.0025282860902255634, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 40.147260150231055, "profit_abs": 0.000999999999999987}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 23:15:00+00:00", "close_date": "2018-01-11 00:15:00+00:00", "trade_duration": 60, "open_rate": 3.022e-05, "close_rate": 3.037147869674185e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3309.0668431502318, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-10 23:40:00+00:00", "close_date": "2018-01-11 00:05:00+00:00", "trade_duration": 25, "open_rate": 0.002437, "close_rate": 0.0024980776942355883, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 41.03405826836274, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 00:00:00+00:00", "close_date": "2018-01-11 00:35:00+00:00", "trade_duration": 35, "open_rate": 0.04771803, "close_rate": 0.04843559436090225, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0956439316543456, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-11 03:40:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 45, "open_rate": 3.651e-05, "close_rate": 3.2859000000000005e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2738.9756231169545, "profit_abs": -0.01047499999999997}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 03:55:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 30, "open_rate": 0.08824105, "close_rate": 0.08956798308270676, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1332594070446804, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 04:00:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 50, "open_rate": 0.00243, "close_rate": 0.002442180451127819, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 41.1522633744856, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:55:00+00:00", "trade_duration": 25, "open_rate": 0.04545064, "close_rate": 0.046589753784461146, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.200189040242338, "profit_abs": 0.001999999999999988}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 20, "open_rate": 3.372e-05, "close_rate": 3.456511278195488e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2965.599051008304, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:55:00+00:00", "close_date": "2018-01-11 05:15:00+00:00", "trade_duration": 20, "open_rate": 0.02644, "close_rate": 0.02710265664160401, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.7821482602118004, "profit_abs": 0.001999999999999988}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:20:00+00:00", "close_date": "2018-01-11 12:00:00+00:00", "trade_duration": 40, "open_rate": 0.08812, "close_rate": 0.08856170426065162, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1348161597821154, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:35:00+00:00", "close_date": "2018-01-11 12:15:00+00:00", "trade_duration": 40, "open_rate": 0.02683577, "close_rate": 0.026970285137844607, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.7263696923919087, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 14:00:00+00:00", "close_date": "2018-01-11 14:25:00+00:00", "trade_duration": 25, "open_rate": 4.919e-05, "close_rate": 5.04228320802005e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2032.9335230737956, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 19:25:00+00:00", "close_date": "2018-01-11 20:35:00+00:00", "trade_duration": 70, "open_rate": 0.08784896, "close_rate": 0.08828930566416039, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1383174029607181, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:35:00+00:00", "close_date": "2018-01-11 23:30:00+00:00", "trade_duration": 55, "open_rate": 5.105e-05, "close_rate": 5.130588972431077e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1958.8638589618022, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:25:00+00:00", "trade_duration": 30, "open_rate": 3.96e-05, "close_rate": 4.019548872180451e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2525.252525252525, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:35:00+00:00", "trade_duration": 40, "open_rate": 2.885e-05, "close_rate": 2.899461152882205e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3466.204506065858, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 23:30:00+00:00", "close_date": "2018-01-12 00:05:00+00:00", "trade_duration": 35, "open_rate": 0.02645, "close_rate": 0.026847744360902256, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.780718336483932, "profit_abs": 0.0010000000000000148}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 23:55:00+00:00", "close_date": "2018-01-12 01:15:00+00:00", "trade_duration": 80, "open_rate": 0.048, "close_rate": 0.04824060150375939, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0833333333333335, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-12 21:15:00+00:00", "close_date": "2018-01-12 21:40:00+00:00", "trade_duration": 25, "open_rate": 4.692e-05, "close_rate": 4.809593984962405e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2131.287297527707, "profit_abs": 0.001999999999999974}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 00:55:00+00:00", "close_date": "2018-01-13 06:20:00+00:00", "trade_duration": 325, "open_rate": 0.00256966, "close_rate": 0.0025825405012531327, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.91565421106294, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 10:55:00+00:00", "close_date": "2018-01-13 11:35:00+00:00", "trade_duration": 40, "open_rate": 6.262e-05, "close_rate": 6.293388471177944e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1596.933886937081, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 13:05:00+00:00", "close_date": "2018-01-15 14:10:00+00:00", "trade_duration": 2945, "open_rate": 4.73e-05, "close_rate": 4.753709273182957e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2114.1649048625795, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:30:00+00:00", "close_date": "2018-01-13 14:45:00+00:00", "trade_duration": 75, "open_rate": 6.063e-05, "close_rate": 6.0933909774436085e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1649.348507339601, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:40:00+00:00", "close_date": "2018-01-13 23:30:00+00:00", "trade_duration": 590, "open_rate": 0.00011082, "close_rate": 0.00011137548872180448, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 902.3641941887746, "profit_abs": -2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 15:15:00+00:00", "close_date": "2018-01-13 15:55:00+00:00", "trade_duration": 40, "open_rate": 5.93e-05, "close_rate": 5.9597243107769415e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1686.3406408094436, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 16:30:00+00:00", "close_date": "2018-01-13 17:10:00+00:00", "trade_duration": 40, "open_rate": 0.04850003, "close_rate": 0.04874313791979949, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0618543947292407, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 22:05:00+00:00", "close_date": "2018-01-14 06:25:00+00:00", "trade_duration": 500, "open_rate": 0.09825019, "close_rate": 0.09874267215538848, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0178097365511456, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 00:20:00+00:00", "close_date": "2018-01-14 22:55:00+00:00", "trade_duration": 1355, "open_rate": 6.018e-05, "close_rate": 6.048165413533834e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1661.681621801263, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 12:45:00+00:00", "close_date": "2018-01-14 13:25:00+00:00", "trade_duration": 40, "open_rate": 0.09758999, "close_rate": 0.0980791628822055, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.024695258191952, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-14 15:30:00+00:00", "close_date": "2018-01-14 16:00:00+00:00", "trade_duration": 30, "open_rate": 0.00311, "close_rate": 0.0031567669172932328, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 32.154340836012864, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 20:45:00+00:00", "close_date": "2018-01-14 22:15:00+00:00", "trade_duration": 90, "open_rate": 0.00312401, "close_rate": 0.003139669197994987, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 32.010140812609436, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 23:35:00+00:00", "close_date": "2018-01-15 00:30:00+00:00", "trade_duration": 55, "open_rate": 0.0174679, "close_rate": 0.017555458395989976, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 5.724786608579165, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 23:45:00+00:00", "close_date": "2018-01-15 00:25:00+00:00", "trade_duration": 40, "open_rate": 0.07346846, "close_rate": 0.07383672295739348, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.3611282991367997, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 02:25:00+00:00", "close_date": "2018-01-15 03:05:00+00:00", "trade_duration": 40, "open_rate": 0.097994, "close_rate": 0.09848519799498744, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.020470641059657, "profit_abs": -2.7755575615628914e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 07:20:00+00:00", "close_date": "2018-01-15 08:00:00+00:00", "trade_duration": 40, "open_rate": 0.09659, "close_rate": 0.09707416040100247, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0353038616834043, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-15 08:20:00+00:00", "close_date": "2018-01-15 08:55:00+00:00", "trade_duration": 35, "open_rate": 9.987e-05, "close_rate": 0.00010137180451127818, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1001.3016921998599, "profit_abs": 0.0010000000000000009}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-15 12:10:00+00:00", "close_date": "2018-01-16 02:50:00+00:00", "trade_duration": 880, "open_rate": 0.0948969, "close_rate": 0.09537257368421052, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0537752023511833, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:10:00+00:00", "close_date": "2018-01-15 17:40:00+00:00", "trade_duration": 210, "open_rate": 0.071, "close_rate": 0.07135588972431077, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4084507042253522, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:30:00+00:00", "close_date": "2018-01-15 15:10:00+00:00", "trade_duration": 40, "open_rate": 0.04600501, "close_rate": 0.046235611553884705, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.173676301776698, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:10:00+00:00", "close_date": "2018-01-15 19:25:00+00:00", "trade_duration": 75, "open_rate": 9.438e-05, "close_rate": 9.485308270676693e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1059.5465140919687, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:35:00+00:00", "close_date": "2018-01-15 19:15:00+00:00", "trade_duration": 40, "open_rate": 0.03040001, "close_rate": 0.030552391002506264, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.2894726021471703, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-15 20:25:00+00:00", "close_date": "2018-01-16 08:25:00+00:00", "trade_duration": 720, "open_rate": 5.837e-05, "close_rate": 5.2533e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1713.2088401576154, "profit_abs": -0.010474999999999984}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 20:40:00+00:00", "close_date": "2018-01-15 22:00:00+00:00", "trade_duration": 80, "open_rate": 0.046036, "close_rate": 0.04626675689223057, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.1722130506560084, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 00:30:00+00:00", "close_date": "2018-01-16 01:10:00+00:00", "trade_duration": 40, "open_rate": 0.0028685, "close_rate": 0.0028828784461152877, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 34.86142583231654, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 01:15:00+00:00", "close_date": "2018-01-16 02:35:00+00:00", "trade_duration": 80, "open_rate": 0.06731755, "close_rate": 0.0676549813283208, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4854967241083492, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 07:45:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 55, "open_rate": 0.09217614, "close_rate": 0.09263817578947368, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0848794492804754, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:55:00+00:00", "trade_duration": 20, "open_rate": 0.0165, "close_rate": 0.016913533834586467, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.0606060606060606, "profit_abs": 0.0020000000000000018}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 5, "open_rate": 7.953e-05, "close_rate": 8.311781954887218e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1257.387149503332, "profit_abs": 0.00399999999999999}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 08:45:00+00:00", "close_date": "2018-01-16 09:50:00+00:00", "trade_duration": 65, "open_rate": 0.045202, "close_rate": 0.04542857644110275, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.2122914915269236, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:45:00+00:00", "trade_duration": 30, "open_rate": 5.248e-05, "close_rate": 5.326917293233082e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1905.487804878049, "profit_abs": 0.0010000000000000009}, {"pair": "XMR/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:55:00+00:00", "trade_duration": 40, "open_rate": 0.02892318, "close_rate": 0.02906815834586466, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.457434486802627, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 09:50:00+00:00", "close_date": "2018-01-16 10:10:00+00:00", "trade_duration": 20, "open_rate": 5.158e-05, "close_rate": 5.287273182957392e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1938.735944164405, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:35:00+00:00", "trade_duration": 30, "open_rate": 0.02828232, "close_rate": 0.02870761804511278, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5357778286929786, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:40:00+00:00", "trade_duration": 35, "open_rate": 0.04357584, "close_rate": 0.044231115789473675, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.294849623093898, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 13:45:00+00:00", "close_date": "2018-01-16 14:20:00+00:00", "trade_duration": 35, "open_rate": 5.362e-05, "close_rate": 5.442631578947368e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1864.975755315181, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 17:30:00+00:00", "close_date": "2018-01-16 18:25:00+00:00", "trade_duration": 55, "open_rate": 5.302e-05, "close_rate": 5.328576441102756e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1886.0807242549984, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:45:00+00:00", "trade_duration": 30, "open_rate": 0.09129999, "close_rate": 0.09267292218045112, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0952903718828448, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:35:00+00:00", "trade_duration": 20, "open_rate": 3.808e-05, "close_rate": 3.903438596491228e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2626.0504201680674, "profit_abs": 0.0020000000000000018}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 19:00:00+00:00", "close_date": "2018-01-16 19:30:00+00:00", "trade_duration": 30, "open_rate": 0.02811012, "close_rate": 0.028532828571428567, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.557437677249333, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 60, "open_rate": 0.00258379, "close_rate": 0.002325411, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.702835756775904, "profit_abs": -0.010474999999999984}, {"pair": "NXT/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 80, "open_rate": 2.559e-05, "close_rate": 2.3031e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3907.7764751856193, "profit_abs": -0.010474999999999998}, {"pair": "TRX/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:35:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 50, "open_rate": 7.62e-05, "close_rate": 6.858e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1312.3359580052495, "profit_abs": -0.010474999999999984}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:35:00+00:00", "trade_duration": 5, "open_rate": 0.00229844, "close_rate": 0.002402129022556391, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 43.507770487809125, "profit_abs": 0.004000000000000017}, {"pair": "LTC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:40:00+00:00", "trade_duration": 10, "open_rate": 0.0151, "close_rate": 0.015781203007518795, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.622516556291391, "profit_abs": 0.00399999999999999}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:40:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 5, "open_rate": 0.00235676, "close_rate": 0.00246308, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 42.431134269081284, "profit_abs": 0.0040000000000000036}, {"pair": "DASH/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 22:45:00+00:00", "close_date": "2018-01-16 23:05:00+00:00", "trade_duration": 20, "open_rate": 0.0630692, "close_rate": 0.06464988170426066, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.585559988076589, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:50:00+00:00", "close_date": "2018-01-16 22:55:00+00:00", "trade_duration": 5, "open_rate": 2.2e-05, "close_rate": 2.299248120300751e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 4545.454545454546, "profit_abs": 0.003999999999999976}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-17 03:30:00+00:00", "close_date": "2018-01-17 04:00:00+00:00", "trade_duration": 30, "open_rate": 4.974e-05, "close_rate": 5.048796992481203e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2010.454362685967, "profit_abs": 0.0010000000000000009}, {"pair": "TRX/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-17 03:55:00+00:00", "close_date": "2018-01-17 04:15:00+00:00", "trade_duration": 20, "open_rate": 7.108e-05, "close_rate": 7.28614536340852e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1406.8655036578502, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 09:35:00+00:00", "close_date": "2018-01-17 10:15:00+00:00", "trade_duration": 40, "open_rate": 0.04327, "close_rate": 0.04348689223057644, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.3110700254217704, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:20:00+00:00", "close_date": "2018-01-17 17:00:00+00:00", "trade_duration": 400, "open_rate": 4.997e-05, "close_rate": 5.022047619047618e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2001.2007204322595, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:25:00+00:00", "trade_duration": 55, "open_rate": 0.06836818, "close_rate": 0.06871087764411027, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4626687444363737, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:10:00+00:00", "trade_duration": 40, "open_rate": 3.63e-05, "close_rate": 3.648195488721804e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2754.8209366391184, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:30:00+00:00", "close_date": "2018-01-17 22:05:00+00:00", "trade_duration": 575, "open_rate": 0.0281, "close_rate": 0.02824085213032581, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5587188612099645, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:35:00+00:00", "close_date": "2018-01-17 16:55:00+00:00", "trade_duration": 260, "open_rate": 0.08651001, "close_rate": 0.08694364413533832, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1559355963546878, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 05:00:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 55, "open_rate": 5.633e-05, "close_rate": 5.6612355889724306e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1775.2529735487308, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 05:20:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 35, "open_rate": 0.06988494, "close_rate": 0.07093584135338346, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.430923457900944, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 07:35:00+00:00", "close_date": "2018-01-18 08:15:00+00:00", "trade_duration": 40, "open_rate": 5.545e-05, "close_rate": 5.572794486215538e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1803.4265103697026, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 09:00:00+00:00", "close_date": "2018-01-18 09:40:00+00:00", "trade_duration": 40, "open_rate": 0.01633527, "close_rate": 0.016417151052631574, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.121723118136401, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 16:40:00+00:00", "close_date": "2018-01-18 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.00269734, "close_rate": 0.002710860501253133, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 37.073561360451414, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-18 18:05:00+00:00", "close_date": "2018-01-18 18:30:00+00:00", "trade_duration": 25, "open_rate": 4.475e-05, "close_rate": 4.587155388471177e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2234.63687150838, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 18:25:00+00:00", "close_date": "2018-01-18 18:55:00+00:00", "trade_duration": 30, "open_rate": 2.79e-05, "close_rate": 2.8319548872180444e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3584.2293906810037, "profit_abs": 0.000999999999999987}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 20:10:00+00:00", "close_date": "2018-01-18 20:50:00+00:00", "trade_duration": 40, "open_rate": 0.04439326, "close_rate": 0.04461578260651629, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.2525942001105577, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 21:30:00+00:00", "close_date": "2018-01-19 00:35:00+00:00", "trade_duration": 185, "open_rate": 4.49e-05, "close_rate": 4.51250626566416e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2227.1714922049, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 21:55:00+00:00", "close_date": "2018-01-19 05:05:00+00:00", "trade_duration": 430, "open_rate": 0.02855, "close_rate": 0.028693107769423555, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.502626970227671, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 22:10:00+00:00", "close_date": "2018-01-18 22:50:00+00:00", "trade_duration": 40, "open_rate": 5.796e-05, "close_rate": 5.8250526315789473e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1725.3278122843342, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 23:50:00+00:00", "close_date": "2018-01-19 00:30:00+00:00", "trade_duration": 40, "open_rate": 0.04340323, "close_rate": 0.04362079005012531, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.303975994413319, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-19 16:45:00+00:00", "close_date": "2018-01-19 17:35:00+00:00", "trade_duration": 50, "open_rate": 0.04454455, "close_rate": 0.04476783095238095, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.244943545282195, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:15:00+00:00", "close_date": "2018-01-19 19:55:00+00:00", "trade_duration": 160, "open_rate": 5.62e-05, "close_rate": 5.648170426065162e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1779.3594306049824, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:20:00+00:00", "close_date": "2018-01-19 20:15:00+00:00", "trade_duration": 175, "open_rate": 4.339e-05, "close_rate": 4.360749373433584e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2304.6784973496196, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-20 04:45:00+00:00", "close_date": "2018-01-20 17:35:00+00:00", "trade_duration": 770, "open_rate": 0.0001009, "close_rate": 0.00010140576441102755, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 991.0802775024778, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 15:15:00+00:00", "trade_duration": 625, "open_rate": 0.00270505, "close_rate": 0.002718609147869674, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.96789338459548, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 07:00:00+00:00", "trade_duration": 130, "open_rate": 0.03000002, "close_rate": 0.030150396040100245, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.3333311111125927, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 09:00:00+00:00", "close_date": "2018-01-20 09:40:00+00:00", "trade_duration": 40, "open_rate": 5.46e-05, "close_rate": 5.4873684210526304e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1831.5018315018317, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-20 18:25:00+00:00", "close_date": "2018-01-25 03:50:00+00:00", "trade_duration": 6325, "open_rate": 0.03082222, "close_rate": 0.027739998, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.244412634781012, "profit_abs": -0.010474999999999998}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 22:25:00+00:00", "close_date": "2018-01-20 23:15:00+00:00", "trade_duration": 50, "open_rate": 0.08969999, "close_rate": 0.09014961401002504, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1148273260677064, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 02:50:00+00:00", "close_date": "2018-01-21 14:30:00+00:00", "trade_duration": 700, "open_rate": 0.01632501, "close_rate": 0.01640683962406015, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.125570520324337, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 10:20:00+00:00", "close_date": "2018-01-21 11:00:00+00:00", "trade_duration": 40, "open_rate": 0.070538, "close_rate": 0.07089157393483708, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.417675579120474, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 15:50:00+00:00", "close_date": "2018-01-21 18:45:00+00:00", "trade_duration": 175, "open_rate": 5.301e-05, "close_rate": 5.327571428571427e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1886.4365214110546, "profit_abs": -2.7755575615628914e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 16:20:00+00:00", "close_date": "2018-01-21 17:00:00+00:00", "trade_duration": 40, "open_rate": 3.955e-05, "close_rate": 3.9748245614035085e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2528.4450063211125, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:45:00+00:00", "trade_duration": 30, "open_rate": 0.00258505, "close_rate": 0.002623922932330827, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.6839712964933, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:55:00+00:00", "trade_duration": 40, "open_rate": 3.903e-05, "close_rate": 3.922563909774435e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2562.1316935690497, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 00:35:00+00:00", "close_date": "2018-01-22 10:35:00+00:00", "trade_duration": 600, "open_rate": 5.236e-05, "close_rate": 5.262245614035087e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1909.8548510313217, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 01:30:00+00:00", "close_date": "2018-01-22 02:10:00+00:00", "trade_duration": 40, "open_rate": 9.028e-05, "close_rate": 9.07325313283208e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1107.6650420912717, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 12:25:00+00:00", "close_date": "2018-01-22 14:35:00+00:00", "trade_duration": 130, "open_rate": 0.002687, "close_rate": 0.002700468671679198, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 37.21622627465575, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 13:15:00+00:00", "close_date": "2018-01-22 13:55:00+00:00", "trade_duration": 40, "open_rate": 4.168e-05, "close_rate": 4.188892230576441e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2399.232245681382, "profit_abs": 1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-22 14:00:00+00:00", "close_date": "2018-01-22 14:30:00+00:00", "trade_duration": 30, "open_rate": 8.821e-05, "close_rate": 8.953646616541353e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1133.6583153837435, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 15:55:00+00:00", "close_date": "2018-01-22 16:40:00+00:00", "trade_duration": 45, "open_rate": 5.172e-05, "close_rate": 5.1979248120300745e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1933.4880123743235, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-22 16:05:00+00:00", "close_date": "2018-01-22 16:25:00+00:00", "trade_duration": 20, "open_rate": 3.026e-05, "close_rate": 3.101839598997494e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3304.692663582287, "profit_abs": 0.0020000000000000157}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 19:50:00+00:00", "close_date": "2018-01-23 00:10:00+00:00", "trade_duration": 260, "open_rate": 0.07064, "close_rate": 0.07099408521303258, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.415628539071348, "profit_abs": 1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 21:25:00+00:00", "close_date": "2018-01-22 22:05:00+00:00", "trade_duration": 40, "open_rate": 0.01644483, "close_rate": 0.01652726022556391, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.080938507725528, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-23 00:05:00+00:00", "close_date": "2018-01-23 00:35:00+00:00", "trade_duration": 30, "open_rate": 4.331e-05, "close_rate": 4.3961278195488714e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2308.935580697299, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-23 01:50:00+00:00", "close_date": "2018-01-23 02:15:00+00:00", "trade_duration": 25, "open_rate": 3.2e-05, "close_rate": 3.2802005012531326e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3125.0000000000005, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 04:25:00+00:00", "close_date": "2018-01-23 05:15:00+00:00", "trade_duration": 50, "open_rate": 0.09167706, "close_rate": 0.09213659413533835, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0907854156754153, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 07:35:00+00:00", "close_date": "2018-01-23 09:00:00+00:00", "trade_duration": 85, "open_rate": 0.0692498, "close_rate": 0.06959691679197995, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4440474918339115, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 10:50:00+00:00", "close_date": "2018-01-23 13:05:00+00:00", "trade_duration": 135, "open_rate": 3.182e-05, "close_rate": 3.197949874686716e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3142.677561282213, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 11:05:00+00:00", "close_date": "2018-01-23 16:05:00+00:00", "trade_duration": 300, "open_rate": 0.04088, "close_rate": 0.04108491228070175, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4461839530332683, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 14:55:00+00:00", "close_date": "2018-01-23 15:35:00+00:00", "trade_duration": 40, "open_rate": 5.15e-05, "close_rate": 5.175814536340851e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1941.747572815534, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 16:35:00+00:00", "close_date": "2018-01-24 00:05:00+00:00", "trade_duration": 450, "open_rate": 0.09071698, "close_rate": 0.09117170170426064, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1023294646713329, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 17:25:00+00:00", "close_date": "2018-01-23 18:45:00+00:00", "trade_duration": 80, "open_rate": 3.128e-05, "close_rate": 3.1436791979949865e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3196.9309462915603, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 20:15:00+00:00", "close_date": "2018-01-23 22:00:00+00:00", "trade_duration": 105, "open_rate": 9.555e-05, "close_rate": 9.602894736842104e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1046.5724751439038, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 22:30:00+00:00", "close_date": "2018-01-23 23:10:00+00:00", "trade_duration": 40, "open_rate": 0.04080001, "close_rate": 0.0410045213283208, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.450979791426522, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 23:50:00+00:00", "close_date": "2018-01-24 03:35:00+00:00", "trade_duration": 225, "open_rate": 5.163e-05, "close_rate": 5.18887969924812e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1936.8584156498162, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 00:20:00+00:00", "close_date": "2018-01-24 01:50:00+00:00", "trade_duration": 90, "open_rate": 0.04040781, "close_rate": 0.04061035541353383, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.474769110228938, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 06:45:00+00:00", "close_date": "2018-01-24 07:25:00+00:00", "trade_duration": 40, "open_rate": 5.132e-05, "close_rate": 5.157724310776942e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1948.5580670303975, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-24 14:15:00+00:00", "close_date": "2018-01-24 14:25:00+00:00", "trade_duration": 10, "open_rate": 5.198e-05, "close_rate": 5.432496240601503e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1923.8168526356292, "profit_abs": 0.0040000000000000036}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 14:50:00+00:00", "close_date": "2018-01-24 16:35:00+00:00", "trade_duration": 105, "open_rate": 3.054e-05, "close_rate": 3.069308270676692e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3274.3942370661425, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 15:10:00+00:00", "close_date": "2018-01-24 16:15:00+00:00", "trade_duration": 65, "open_rate": 9.263e-05, "close_rate": 9.309431077694236e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1079.5638562020945, "profit_abs": 2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 22:40:00+00:00", "close_date": "2018-01-24 23:25:00+00:00", "trade_duration": 45, "open_rate": 5.514e-05, "close_rate": 5.54163909774436e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1813.5654697134569, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 00:50:00+00:00", "close_date": "2018-01-25 01:30:00+00:00", "trade_duration": 40, "open_rate": 4.921e-05, "close_rate": 4.9456666666666664e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2032.1072952651903, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 08:15:00+00:00", "close_date": "2018-01-25 12:15:00+00:00", "trade_duration": 240, "open_rate": 0.0026, "close_rate": 0.002613032581453634, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.46153846153847, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 10:25:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 350, "open_rate": 0.02799871, "close_rate": 0.028139054411027563, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.571593119825878, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 11:00:00+00:00", "close_date": "2018-01-25 11:45:00+00:00", "trade_duration": 45, "open_rate": 0.04078902, "close_rate": 0.0409934762406015, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4516401717913303, "profit_abs": -1.3877787807814457e-17}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:05:00+00:00", "close_date": "2018-01-25 13:45:00+00:00", "trade_duration": 40, "open_rate": 2.89e-05, "close_rate": 2.904486215538847e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3460.2076124567475, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:20:00+00:00", "close_date": "2018-01-25 14:05:00+00:00", "trade_duration": 45, "open_rate": 0.041103, "close_rate": 0.04130903007518797, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4329124394813033, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-25 15:45:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 30, "open_rate": 5.428e-05, "close_rate": 5.509624060150376e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1842.2991893883568, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 17:45:00+00:00", "close_date": "2018-01-25 23:15:00+00:00", "trade_duration": 330, "open_rate": 5.414e-05, "close_rate": 5.441137844611528e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1847.063169560399, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 21:15:00+00:00", "close_date": "2018-01-25 21:55:00+00:00", "trade_duration": 40, "open_rate": 0.04140777, "close_rate": 0.0416153277443609, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.415005686130888, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 02:05:00+00:00", "close_date": "2018-01-26 02:45:00+00:00", "trade_duration": 40, "open_rate": 0.00254309, "close_rate": 0.002555837318295739, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 39.32224183965177, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 02:55:00+00:00", "close_date": "2018-01-26 15:10:00+00:00", "trade_duration": 735, "open_rate": 5.607e-05, "close_rate": 5.6351052631578935e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1783.4849295523454, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 06:10:00+00:00", "close_date": "2018-01-26 09:25:00+00:00", "trade_duration": 195, "open_rate": 0.00253806, "close_rate": 0.0025507821052631577, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 39.400171784748984, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 07:25:00+00:00", "close_date": "2018-01-26 09:55:00+00:00", "trade_duration": 150, "open_rate": 0.0415, "close_rate": 0.04170802005012531, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4096385542168677, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-26 09:55:00+00:00", "close_date": "2018-01-26 10:25:00+00:00", "trade_duration": 30, "open_rate": 5.321e-05, "close_rate": 5.401015037593984e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1879.3459875963165, "profit_abs": 0.000999999999999987}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 16:05:00+00:00", "close_date": "2018-01-26 16:45:00+00:00", "trade_duration": 40, "open_rate": 0.02772046, "close_rate": 0.02785940967418546, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.6074437437185387, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 23:35:00+00:00", "close_date": "2018-01-27 00:15:00+00:00", "trade_duration": 40, "open_rate": 0.09461341, "close_rate": 0.09508766268170424, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0569326272036914, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 00:35:00+00:00", "close_date": "2018-01-27 01:30:00+00:00", "trade_duration": 55, "open_rate": 5.615e-05, "close_rate": 5.643145363408521e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1780.9439002671415, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.07877175, "open_date": "2018-01-27 00:45:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 4560, "open_rate": 5.556e-05, "close_rate": 5.144e-05, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1799.8560115190785, "profit_abs": -0.007896868250539965}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 02:30:00+00:00", "close_date": "2018-01-27 11:25:00+00:00", "trade_duration": 535, "open_rate": 0.06900001, "close_rate": 0.06934587471177944, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4492751522789635, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 06:25:00+00:00", "close_date": "2018-01-27 07:05:00+00:00", "trade_duration": 40, "open_rate": 0.09449985, "close_rate": 0.0949735334586466, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.058202737887944, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.04815133, "open_date": "2018-01-27 09:40:00+00:00", "close_date": "2018-01-30 04:40:00+00:00", "trade_duration": 4020, "open_rate": 0.0410697, "close_rate": 0.03928809, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4348850855983852, "profit_abs": -0.004827170578309559}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 11:45:00+00:00", "close_date": "2018-01-27 12:30:00+00:00", "trade_duration": 45, "open_rate": 0.0285, "close_rate": 0.02864285714285714, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5087719298245617, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 12:35:00+00:00", "close_date": "2018-01-27 15:25:00+00:00", "trade_duration": 170, "open_rate": 0.02866372, "close_rate": 0.02880739779448621, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.4887307020861216, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 15:50:00+00:00", "close_date": "2018-01-27 16:50:00+00:00", "trade_duration": 60, "open_rate": 0.095381, "close_rate": 0.09585910025062656, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0484268355332824, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 17:05:00+00:00", "close_date": "2018-01-27 17:45:00+00:00", "trade_duration": 40, "open_rate": 0.06759092, "close_rate": 0.06792972160401002, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4794886650455417, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 23:40:00+00:00", "close_date": "2018-01-28 01:05:00+00:00", "trade_duration": 85, "open_rate": 0.00258501, "close_rate": 0.002597967443609022, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.684569885609726, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 02:25:00+00:00", "close_date": "2018-01-28 08:10:00+00:00", "trade_duration": 345, "open_rate": 0.06698502, "close_rate": 0.0673207845112782, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4928710926711672, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 10:25:00+00:00", "close_date": "2018-01-28 16:30:00+00:00", "trade_duration": 365, "open_rate": 0.0677177, "close_rate": 0.06805713709273183, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4767187899175547, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-28 20:35:00+00:00", "close_date": "2018-01-28 21:35:00+00:00", "trade_duration": 60, "open_rate": 5.215e-05, "close_rate": 5.2411403508771925e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1917.5455417066157, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-28 22:00:00+00:00", "close_date": "2018-01-28 22:30:00+00:00", "trade_duration": 30, "open_rate": 0.00273809, "close_rate": 0.002779264285714285, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.5218089982433, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-29 00:00:00+00:00", "close_date": "2018-01-29 00:30:00+00:00", "trade_duration": 30, "open_rate": 0.00274632, "close_rate": 0.002787618045112782, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.412362725392526, "profit_abs": 0.0010000000000000148}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-29 02:15:00+00:00", "close_date": "2018-01-29 03:00:00+00:00", "trade_duration": 45, "open_rate": 0.01622478, "close_rate": 0.016306107218045113, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.163411768911504, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 03:05:00+00:00", "close_date": "2018-01-29 03:45:00+00:00", "trade_duration": 40, "open_rate": 0.069, "close_rate": 0.06934586466165413, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4492753623188406, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 05:20:00+00:00", "close_date": "2018-01-29 06:55:00+00:00", "trade_duration": 95, "open_rate": 8.755e-05, "close_rate": 8.798884711779448e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1142.204454597373, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 07:00:00+00:00", "close_date": "2018-01-29 19:25:00+00:00", "trade_duration": 745, "open_rate": 0.06825763, "close_rate": 0.06859977350877192, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4650376815016872, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 19:45:00+00:00", "close_date": "2018-01-29 20:25:00+00:00", "trade_duration": 40, "open_rate": 0.06713892, "close_rate": 0.06747545593984962, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4894490408841845, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0199116, "open_date": "2018-01-29 23:30:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 315, "open_rate": 8.934e-05, "close_rate": 8.8e-05, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1119.3194537721067, "profit_abs": -0.0019961383478844796}], "results_per_pair": [{"key": "TRX/BTC", "trades": 15, "profit_mean": 0.0023467073333333323, "profit_mean_pct": 0.23467073333333321, "profit_sum": 0.035200609999999986, "profit_sum_pct": 3.5200609999999988, "profit_total_abs": 0.0035288616521155086, "profit_total_pct": 1.1733536666666662, "duration_avg": "2:28:00", "wins": 9, "draws": 2, "losses": 4}, {"key": "ADA/BTC", "trades": 29, "profit_mean": -0.0011598141379310352, "profit_mean_pct": -0.11598141379310352, "profit_sum": -0.03363461000000002, "profit_sum_pct": -3.3634610000000023, "profit_total_abs": -0.0033718682505400333, "profit_total_pct": -1.1211536666666675, "duration_avg": "5:35:00", "wins": 9, "draws": 11, "losses": 9}, {"key": "XLM/BTC", "trades": 21, "profit_mean": 0.0026243899999999994, "profit_mean_pct": 0.2624389999999999, "profit_sum": 0.05511218999999999, "profit_sum_pct": 5.511218999999999, "profit_total_abs": 0.005525000000000002, "profit_total_pct": 1.8370729999999995, "duration_avg": "3:21:00", "wins": 12, "draws": 3, "losses": 6}, {"key": "ETH/BTC", "trades": 21, "profit_mean": 0.0009500057142857142, "profit_mean_pct": 0.09500057142857142, "profit_sum": 0.01995012, "profit_sum_pct": 1.9950119999999998, "profit_total_abs": 0.0019999999999999463, "profit_total_pct": 0.6650039999999999, "duration_avg": "2:17:00", "wins": 5, "draws": 10, "losses": 6}, {"key": "XMR/BTC", "trades": 16, "profit_mean": -0.0027899012500000007, "profit_mean_pct": -0.2789901250000001, "profit_sum": -0.04463842000000001, "profit_sum_pct": -4.463842000000001, "profit_total_abs": -0.0044750000000000345, "profit_total_pct": -1.4879473333333337, "duration_avg": "8:41:00", "wins": 6, "draws": 5, "losses": 5}, {"key": "ZEC/BTC", "trades": 21, "profit_mean": -0.00039290904761904774, "profit_mean_pct": -0.03929090476190478, "profit_sum": -0.008251090000000003, "profit_sum_pct": -0.8251090000000003, "profit_total_abs": -0.000827170578309569, "profit_total_pct": -0.27503633333333344, "duration_avg": "4:17:00", "wins": 8, "draws": 7, "losses": 6}, {"key": "NXT/BTC", "trades": 12, "profit_mean": -0.0012261025000000006, "profit_mean_pct": -0.12261025000000006, "profit_sum": -0.014713230000000008, "profit_sum_pct": -1.4713230000000008, "profit_total_abs": -0.0014750000000000874, "profit_total_pct": -0.4904410000000003, "duration_avg": "0:57:00", "wins": 4, "draws": 3, "losses": 5}, {"key": "LTC/BTC", "trades": 8, "profit_mean": 0.00748129625, "profit_mean_pct": 0.748129625, "profit_sum": 0.05985037, "profit_sum_pct": 5.985037, "profit_total_abs": 0.006000000000000019, "profit_total_pct": 1.9950123333333334, "duration_avg": "1:59:00", "wins": 5, "draws": 2, "losses": 1}, {"key": "ETC/BTC", "trades": 20, "profit_mean": 0.0022568569999999997, "profit_mean_pct": 0.22568569999999996, "profit_sum": 0.04513713999999999, "profit_sum_pct": 4.513713999999999, "profit_total_abs": 0.004525000000000001, "profit_total_pct": 1.504571333333333, "duration_avg": "1:45:00", "wins": 11, "draws": 4, "losses": 5}, {"key": "DASH/BTC", "trades": 16, "profit_mean": 0.0018703237499999997, "profit_mean_pct": 0.18703237499999997, "profit_sum": 0.029925179999999996, "profit_sum_pct": 2.9925179999999996, "profit_total_abs": 0.002999999999999961, "profit_total_pct": 0.9975059999999999, "duration_avg": "3:03:00", "wins": 4, "draws": 7, "losses": 5}, {"key": "TOTAL", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}], "sell_reason_summary": [{"sell_reason": "roi", "trades": 170, "wins": 73, "draws": 54, "losses": 43, "profit_mean": 0.005398268352941177, "profit_mean_pct": 0.54, "profit_sum": 0.91770562, "profit_sum_pct": 91.77, "profit_total_abs": 0.09199999999999964, "profit_pct_total": 30.59}, {"sell_reason": "stop_loss", "trades": 6, "wins": 0, "draws": 0, "losses": 6, "profit_mean": -0.10448878000000002, "profit_mean_pct": -10.45, "profit_sum": -0.6269326800000001, "profit_sum_pct": -62.69, "profit_total_abs": -0.06284999999999992, "profit_pct_total": -20.9}, {"sell_reason": "force_sell", "trades": 3, "wins": 0, "draws": 0, "losses": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.89, "profit_sum": -0.14683468, "profit_sum_pct": -14.68, "profit_total_abs": -0.014720177176734003, "profit_pct_total": -4.89}], "left_open_trades": [{"key": "TRX/BTC", "trades": 1, "profit_mean": -0.0199116, "profit_mean_pct": -1.9911600000000003, "profit_sum": -0.0199116, "profit_sum_pct": -1.9911600000000003, "profit_total_abs": -0.0019961383478844796, "profit_total_pct": -0.6637200000000001, "duration_avg": "5:15:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ADA/BTC", "trades": 1, "profit_mean": -0.07877175, "profit_mean_pct": -7.877175, "profit_sum": -0.07877175, "profit_sum_pct": -7.877175, "profit_total_abs": -0.007896868250539965, "profit_total_pct": -2.625725, "duration_avg": "3 days, 4:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ZEC/BTC", "trades": 1, "profit_mean": -0.04815133, "profit_mean_pct": -4.815133, "profit_sum": -0.04815133, "profit_sum_pct": -4.815133, "profit_total_abs": -0.004827170578309559, "profit_total_pct": -1.6050443333333335, "duration_avg": "2 days, 19:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "TOTAL", "trades": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.894489333333333, "profit_sum": -0.14683468, "profit_sum_pct": -14.683468, "profit_total_abs": -0.014720177176734003, "profit_total_pct": -4.8944893333333335, "duration_avg": "2 days, 1:25:00", "wins": 0, "draws": 0, "losses": 3}], "total_trades": 179, "backtest_start": "2018-01-30 04:45:00+00:00", "backtest_start_ts": 1517287500, "backtest_end": "2018-01-30 04:45:00+00:00", "backtest_end_ts": 1517287500, "backtest_days": 0, "trades_per_day": null, "market_change": 0.25, "stake_amount": 0.1, "max_drawdown": 0.21142322000000008, "drawdown_start": "2018-01-24 14:25:00+00:00", "drawdown_start_ts": 1516803900.0, "drawdown_end": "2018-01-30 04:45:00+00:00", "drawdown_end_ts": 1517287500.0,"pairlist": ["TRX/BTC", "ADA/BTC", "XLM/BTC", "ETH/BTC", "XMR/BTC", "ZEC/BTC","NXT/BTC", "LTC/BTC", "ETC/BTC", "DASH/BTC"]}}, "strategy_comparison": [{"key": "DefaultStrategy", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}, {"key": "TestStrategy", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}]} diff --git a/tests/testdata/backtest-result_new.json b/tests/testdata/backtest-result_new.json index f004e879a..5334bf80e 100644 --- a/tests/testdata/backtest-result_new.json +++ b/tests/testdata/backtest-result_new.json @@ -1 +1 @@ -{"strategy": {"DefaultStrategy": {"trades": [{"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:20:00+00:00", "trade_duration": 5, "open_rate": 9.64e-05, "close_rate": 0.00010074887218045112, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1037.344398340249, "profit_abs": 0.00399999999999999}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:30:00+00:00", "trade_duration": 15, "open_rate": 4.756e-05, "close_rate": 4.9705563909774425e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2102.6072329688814, "profit_abs": 0.00399999999999999}, {"pair": "XLM/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:35:00+00:00", "trade_duration": 10, "open_rate": 3.339e-05, "close_rate": 3.489631578947368e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2994.908655286014, "profit_abs": 0.0040000000000000036}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:40:00+00:00", "trade_duration": 15, "open_rate": 9.696e-05, "close_rate": 0.00010133413533834584, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1031.3531353135315, "profit_abs": 0.00399999999999999}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 07:35:00+00:00", "close_date": "2018-01-10 08:35:00+00:00", "trade_duration": 60, "open_rate": 0.0943, "close_rate": 0.09477268170426063, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0604453870625663, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 07:40:00+00:00", "close_date": "2018-01-10 08:10:00+00:00", "trade_duration": 30, "open_rate": 0.02719607, "close_rate": 0.02760503345864661, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.677001860930642, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 08:15:00+00:00", "close_date": "2018-01-10 09:55:00+00:00", "trade_duration": 100, "open_rate": 0.04634952, "close_rate": 0.046581848421052625, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.1575196463739, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 14:45:00+00:00", "close_date": "2018-01-10 15:50:00+00:00", "trade_duration": 65, "open_rate": 3.066e-05, "close_rate": 3.081368421052631e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3261.5786040443577, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 16:35:00+00:00", "close_date": "2018-01-10 17:15:00+00:00", "trade_duration": 40, "open_rate": 0.0168999, "close_rate": 0.016984611278195488, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 5.917194776300452, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 16:40:00+00:00", "close_date": "2018-01-10 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.09132568, "close_rate": 0.0917834528320802, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0949822656672252, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 18:50:00+00:00", "close_date": "2018-01-10 19:45:00+00:00", "trade_duration": 55, "open_rate": 0.08898003, "close_rate": 0.08942604518796991, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1238476768326557, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 22:15:00+00:00", "close_date": "2018-01-10 23:00:00+00:00", "trade_duration": 45, "open_rate": 0.08560008, "close_rate": 0.08602915308270676, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1682232072680307, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 22:50:00+00:00", "close_date": "2018-01-10 23:20:00+00:00", "trade_duration": 30, "open_rate": 0.00249083, "close_rate": 0.0025282860902255634, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 40.147260150231055, "profit_abs": 0.000999999999999987}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 23:15:00+00:00", "close_date": "2018-01-11 00:15:00+00:00", "trade_duration": 60, "open_rate": 3.022e-05, "close_rate": 3.037147869674185e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3309.0668431502318, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-10 23:40:00+00:00", "close_date": "2018-01-11 00:05:00+00:00", "trade_duration": 25, "open_rate": 0.002437, "close_rate": 0.0024980776942355883, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 41.03405826836274, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 00:00:00+00:00", "close_date": "2018-01-11 00:35:00+00:00", "trade_duration": 35, "open_rate": 0.04771803, "close_rate": 0.04843559436090225, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0956439316543456, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-11 03:40:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 45, "open_rate": 3.651e-05, "close_rate": 3.2859000000000005e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2738.9756231169545, "profit_abs": -0.01047499999999997}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 03:55:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 30, "open_rate": 0.08824105, "close_rate": 0.08956798308270676, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1332594070446804, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 04:00:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 50, "open_rate": 0.00243, "close_rate": 0.002442180451127819, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 41.1522633744856, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:55:00+00:00", "trade_duration": 25, "open_rate": 0.04545064, "close_rate": 0.046589753784461146, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.200189040242338, "profit_abs": 0.001999999999999988}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 20, "open_rate": 3.372e-05, "close_rate": 3.456511278195488e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2965.599051008304, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:55:00+00:00", "close_date": "2018-01-11 05:15:00+00:00", "trade_duration": 20, "open_rate": 0.02644, "close_rate": 0.02710265664160401, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.7821482602118004, "profit_abs": 0.001999999999999988}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:20:00+00:00", "close_date": "2018-01-11 12:00:00+00:00", "trade_duration": 40, "open_rate": 0.08812, "close_rate": 0.08856170426065162, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1348161597821154, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:35:00+00:00", "close_date": "2018-01-11 12:15:00+00:00", "trade_duration": 40, "open_rate": 0.02683577, "close_rate": 0.026970285137844607, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.7263696923919087, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 14:00:00+00:00", "close_date": "2018-01-11 14:25:00+00:00", "trade_duration": 25, "open_rate": 4.919e-05, "close_rate": 5.04228320802005e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2032.9335230737956, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 19:25:00+00:00", "close_date": "2018-01-11 20:35:00+00:00", "trade_duration": 70, "open_rate": 0.08784896, "close_rate": 0.08828930566416039, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1383174029607181, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:35:00+00:00", "close_date": "2018-01-11 23:30:00+00:00", "trade_duration": 55, "open_rate": 5.105e-05, "close_rate": 5.130588972431077e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1958.8638589618022, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:25:00+00:00", "trade_duration": 30, "open_rate": 3.96e-05, "close_rate": 4.019548872180451e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2525.252525252525, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:35:00+00:00", "trade_duration": 40, "open_rate": 2.885e-05, "close_rate": 2.899461152882205e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3466.204506065858, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 23:30:00+00:00", "close_date": "2018-01-12 00:05:00+00:00", "trade_duration": 35, "open_rate": 0.02645, "close_rate": 0.026847744360902256, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.780718336483932, "profit_abs": 0.0010000000000000148}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 23:55:00+00:00", "close_date": "2018-01-12 01:15:00+00:00", "trade_duration": 80, "open_rate": 0.048, "close_rate": 0.04824060150375939, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0833333333333335, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-12 21:15:00+00:00", "close_date": "2018-01-12 21:40:00+00:00", "trade_duration": 25, "open_rate": 4.692e-05, "close_rate": 4.809593984962405e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2131.287297527707, "profit_abs": 0.001999999999999974}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 00:55:00+00:00", "close_date": "2018-01-13 06:20:00+00:00", "trade_duration": 325, "open_rate": 0.00256966, "close_rate": 0.0025825405012531327, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.91565421106294, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 10:55:00+00:00", "close_date": "2018-01-13 11:35:00+00:00", "trade_duration": 40, "open_rate": 6.262e-05, "close_rate": 6.293388471177944e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1596.933886937081, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 13:05:00+00:00", "close_date": "2018-01-15 14:10:00+00:00", "trade_duration": 2945, "open_rate": 4.73e-05, "close_rate": 4.753709273182957e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2114.1649048625795, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:30:00+00:00", "close_date": "2018-01-13 14:45:00+00:00", "trade_duration": 75, "open_rate": 6.063e-05, "close_rate": 6.0933909774436085e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1649.348507339601, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:40:00+00:00", "close_date": "2018-01-13 23:30:00+00:00", "trade_duration": 590, "open_rate": 0.00011082, "close_rate": 0.00011137548872180448, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 902.3641941887746, "profit_abs": -2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 15:15:00+00:00", "close_date": "2018-01-13 15:55:00+00:00", "trade_duration": 40, "open_rate": 5.93e-05, "close_rate": 5.9597243107769415e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1686.3406408094436, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 16:30:00+00:00", "close_date": "2018-01-13 17:10:00+00:00", "trade_duration": 40, "open_rate": 0.04850003, "close_rate": 0.04874313791979949, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.0618543947292407, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 22:05:00+00:00", "close_date": "2018-01-14 06:25:00+00:00", "trade_duration": 500, "open_rate": 0.09825019, "close_rate": 0.09874267215538848, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0178097365511456, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 00:20:00+00:00", "close_date": "2018-01-14 22:55:00+00:00", "trade_duration": 1355, "open_rate": 6.018e-05, "close_rate": 6.048165413533834e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1661.681621801263, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 12:45:00+00:00", "close_date": "2018-01-14 13:25:00+00:00", "trade_duration": 40, "open_rate": 0.09758999, "close_rate": 0.0980791628822055, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.024695258191952, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-14 15:30:00+00:00", "close_date": "2018-01-14 16:00:00+00:00", "trade_duration": 30, "open_rate": 0.00311, "close_rate": 0.0031567669172932328, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 32.154340836012864, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 20:45:00+00:00", "close_date": "2018-01-14 22:15:00+00:00", "trade_duration": 90, "open_rate": 0.00312401, "close_rate": 0.003139669197994987, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 32.010140812609436, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 23:35:00+00:00", "close_date": "2018-01-15 00:30:00+00:00", "trade_duration": 55, "open_rate": 0.0174679, "close_rate": 0.017555458395989976, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 5.724786608579165, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 23:45:00+00:00", "close_date": "2018-01-15 00:25:00+00:00", "trade_duration": 40, "open_rate": 0.07346846, "close_rate": 0.07383672295739348, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.3611282991367997, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 02:25:00+00:00", "close_date": "2018-01-15 03:05:00+00:00", "trade_duration": 40, "open_rate": 0.097994, "close_rate": 0.09848519799498744, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.020470641059657, "profit_abs": -2.7755575615628914e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 07:20:00+00:00", "close_date": "2018-01-15 08:00:00+00:00", "trade_duration": 40, "open_rate": 0.09659, "close_rate": 0.09707416040100247, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0353038616834043, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-15 08:20:00+00:00", "close_date": "2018-01-15 08:55:00+00:00", "trade_duration": 35, "open_rate": 9.987e-05, "close_rate": 0.00010137180451127818, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1001.3016921998599, "profit_abs": 0.0010000000000000009}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-15 12:10:00+00:00", "close_date": "2018-01-16 02:50:00+00:00", "trade_duration": 880, "open_rate": 0.0948969, "close_rate": 0.09537257368421052, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0537752023511833, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:10:00+00:00", "close_date": "2018-01-15 17:40:00+00:00", "trade_duration": 210, "open_rate": 0.071, "close_rate": 0.07135588972431077, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4084507042253522, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:30:00+00:00", "close_date": "2018-01-15 15:10:00+00:00", "trade_duration": 40, "open_rate": 0.04600501, "close_rate": 0.046235611553884705, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.173676301776698, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:10:00+00:00", "close_date": "2018-01-15 19:25:00+00:00", "trade_duration": 75, "open_rate": 9.438e-05, "close_rate": 9.485308270676693e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1059.5465140919687, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:35:00+00:00", "close_date": "2018-01-15 19:15:00+00:00", "trade_duration": 40, "open_rate": 0.03040001, "close_rate": 0.030552391002506264, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.2894726021471703, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-15 20:25:00+00:00", "close_date": "2018-01-16 08:25:00+00:00", "trade_duration": 720, "open_rate": 5.837e-05, "close_rate": 5.2533e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1713.2088401576154, "profit_abs": -0.010474999999999984}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 20:40:00+00:00", "close_date": "2018-01-15 22:00:00+00:00", "trade_duration": 80, "open_rate": 0.046036, "close_rate": 0.04626675689223057, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.1722130506560084, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 00:30:00+00:00", "close_date": "2018-01-16 01:10:00+00:00", "trade_duration": 40, "open_rate": 0.0028685, "close_rate": 0.0028828784461152877, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 34.86142583231654, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 01:15:00+00:00", "close_date": "2018-01-16 02:35:00+00:00", "trade_duration": 80, "open_rate": 0.06731755, "close_rate": 0.0676549813283208, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4854967241083492, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 07:45:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 55, "open_rate": 0.09217614, "close_rate": 0.09263817578947368, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0848794492804754, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:55:00+00:00", "trade_duration": 20, "open_rate": 0.0165, "close_rate": 0.016913533834586467, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.0606060606060606, "profit_abs": 0.0020000000000000018}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 5, "open_rate": 7.953e-05, "close_rate": 8.311781954887218e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1257.387149503332, "profit_abs": 0.00399999999999999}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 08:45:00+00:00", "close_date": "2018-01-16 09:50:00+00:00", "trade_duration": 65, "open_rate": 0.045202, "close_rate": 0.04542857644110275, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.2122914915269236, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:45:00+00:00", "trade_duration": 30, "open_rate": 5.248e-05, "close_rate": 5.326917293233082e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1905.487804878049, "profit_abs": 0.0010000000000000009}, {"pair": "XMR/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:55:00+00:00", "trade_duration": 40, "open_rate": 0.02892318, "close_rate": 0.02906815834586466, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.457434486802627, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 09:50:00+00:00", "close_date": "2018-01-16 10:10:00+00:00", "trade_duration": 20, "open_rate": 5.158e-05, "close_rate": 5.287273182957392e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1938.735944164405, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:35:00+00:00", "trade_duration": 30, "open_rate": 0.02828232, "close_rate": 0.02870761804511278, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5357778286929786, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:40:00+00:00", "trade_duration": 35, "open_rate": 0.04357584, "close_rate": 0.044231115789473675, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.294849623093898, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 13:45:00+00:00", "close_date": "2018-01-16 14:20:00+00:00", "trade_duration": 35, "open_rate": 5.362e-05, "close_rate": 5.442631578947368e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1864.975755315181, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 17:30:00+00:00", "close_date": "2018-01-16 18:25:00+00:00", "trade_duration": 55, "open_rate": 5.302e-05, "close_rate": 5.328576441102756e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1886.0807242549984, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:45:00+00:00", "trade_duration": 30, "open_rate": 0.09129999, "close_rate": 0.09267292218045112, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0952903718828448, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:35:00+00:00", "trade_duration": 20, "open_rate": 3.808e-05, "close_rate": 3.903438596491228e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2626.0504201680674, "profit_abs": 0.0020000000000000018}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 19:00:00+00:00", "close_date": "2018-01-16 19:30:00+00:00", "trade_duration": 30, "open_rate": 0.02811012, "close_rate": 0.028532828571428567, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.557437677249333, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 60, "open_rate": 0.00258379, "close_rate": 0.002325411, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.702835756775904, "profit_abs": -0.010474999999999984}, {"pair": "NXT/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 80, "open_rate": 2.559e-05, "close_rate": 2.3031e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3907.7764751856193, "profit_abs": -0.010474999999999998}, {"pair": "TRX/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:35:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 50, "open_rate": 7.62e-05, "close_rate": 6.858e-05, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1312.3359580052495, "profit_abs": -0.010474999999999984}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:35:00+00:00", "trade_duration": 5, "open_rate": 0.00229844, "close_rate": 0.002402129022556391, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 43.507770487809125, "profit_abs": 0.004000000000000017}, {"pair": "LTC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:40:00+00:00", "trade_duration": 10, "open_rate": 0.0151, "close_rate": 0.015781203007518795, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.622516556291391, "profit_abs": 0.00399999999999999}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:40:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 5, "open_rate": 0.00235676, "close_rate": 0.00246308, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 42.431134269081284, "profit_abs": 0.0040000000000000036}, {"pair": "DASH/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 22:45:00+00:00", "close_date": "2018-01-16 23:05:00+00:00", "trade_duration": 20, "open_rate": 0.0630692, "close_rate": 0.06464988170426066, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.585559988076589, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:50:00+00:00", "close_date": "2018-01-16 22:55:00+00:00", "trade_duration": 5, "open_rate": 2.2e-05, "close_rate": 2.299248120300751e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 4545.454545454546, "profit_abs": 0.003999999999999976}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-17 03:30:00+00:00", "close_date": "2018-01-17 04:00:00+00:00", "trade_duration": 30, "open_rate": 4.974e-05, "close_rate": 5.048796992481203e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2010.454362685967, "profit_abs": 0.0010000000000000009}, {"pair": "TRX/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-17 03:55:00+00:00", "close_date": "2018-01-17 04:15:00+00:00", "trade_duration": 20, "open_rate": 7.108e-05, "close_rate": 7.28614536340852e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1406.8655036578502, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 09:35:00+00:00", "close_date": "2018-01-17 10:15:00+00:00", "trade_duration": 40, "open_rate": 0.04327, "close_rate": 0.04348689223057644, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.3110700254217704, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:20:00+00:00", "close_date": "2018-01-17 17:00:00+00:00", "trade_duration": 400, "open_rate": 4.997e-05, "close_rate": 5.022047619047618e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2001.2007204322595, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:25:00+00:00", "trade_duration": 55, "open_rate": 0.06836818, "close_rate": 0.06871087764411027, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4626687444363737, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:10:00+00:00", "trade_duration": 40, "open_rate": 3.63e-05, "close_rate": 3.648195488721804e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2754.8209366391184, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:30:00+00:00", "close_date": "2018-01-17 22:05:00+00:00", "trade_duration": 575, "open_rate": 0.0281, "close_rate": 0.02824085213032581, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5587188612099645, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:35:00+00:00", "close_date": "2018-01-17 16:55:00+00:00", "trade_duration": 260, "open_rate": 0.08651001, "close_rate": 0.08694364413533832, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1559355963546878, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 05:00:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 55, "open_rate": 5.633e-05, "close_rate": 5.6612355889724306e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1775.2529735487308, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 05:20:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 35, "open_rate": 0.06988494, "close_rate": 0.07093584135338346, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.430923457900944, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 07:35:00+00:00", "close_date": "2018-01-18 08:15:00+00:00", "trade_duration": 40, "open_rate": 5.545e-05, "close_rate": 5.572794486215538e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1803.4265103697026, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 09:00:00+00:00", "close_date": "2018-01-18 09:40:00+00:00", "trade_duration": 40, "open_rate": 0.01633527, "close_rate": 0.016417151052631574, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.121723118136401, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 16:40:00+00:00", "close_date": "2018-01-18 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.00269734, "close_rate": 0.002710860501253133, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 37.073561360451414, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-18 18:05:00+00:00", "close_date": "2018-01-18 18:30:00+00:00", "trade_duration": 25, "open_rate": 4.475e-05, "close_rate": 4.587155388471177e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2234.63687150838, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 18:25:00+00:00", "close_date": "2018-01-18 18:55:00+00:00", "trade_duration": 30, "open_rate": 2.79e-05, "close_rate": 2.8319548872180444e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3584.2293906810037, "profit_abs": 0.000999999999999987}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 20:10:00+00:00", "close_date": "2018-01-18 20:50:00+00:00", "trade_duration": 40, "open_rate": 0.04439326, "close_rate": 0.04461578260651629, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.2525942001105577, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 21:30:00+00:00", "close_date": "2018-01-19 00:35:00+00:00", "trade_duration": 185, "open_rate": 4.49e-05, "close_rate": 4.51250626566416e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2227.1714922049, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 21:55:00+00:00", "close_date": "2018-01-19 05:05:00+00:00", "trade_duration": 430, "open_rate": 0.02855, "close_rate": 0.028693107769423555, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.502626970227671, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 22:10:00+00:00", "close_date": "2018-01-18 22:50:00+00:00", "trade_duration": 40, "open_rate": 5.796e-05, "close_rate": 5.8250526315789473e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1725.3278122843342, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 23:50:00+00:00", "close_date": "2018-01-19 00:30:00+00:00", "trade_duration": 40, "open_rate": 0.04340323, "close_rate": 0.04362079005012531, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.303975994413319, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-19 16:45:00+00:00", "close_date": "2018-01-19 17:35:00+00:00", "trade_duration": 50, "open_rate": 0.04454455, "close_rate": 0.04476783095238095, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.244943545282195, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:15:00+00:00", "close_date": "2018-01-19 19:55:00+00:00", "trade_duration": 160, "open_rate": 5.62e-05, "close_rate": 5.648170426065162e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1779.3594306049824, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:20:00+00:00", "close_date": "2018-01-19 20:15:00+00:00", "trade_duration": 175, "open_rate": 4.339e-05, "close_rate": 4.360749373433584e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2304.6784973496196, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-20 04:45:00+00:00", "close_date": "2018-01-20 17:35:00+00:00", "trade_duration": 770, "open_rate": 0.0001009, "close_rate": 0.00010140576441102755, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 991.0802775024778, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 15:15:00+00:00", "trade_duration": 625, "open_rate": 0.00270505, "close_rate": 0.002718609147869674, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.96789338459548, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 07:00:00+00:00", "trade_duration": 130, "open_rate": 0.03000002, "close_rate": 0.030150396040100245, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.3333311111125927, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 09:00:00+00:00", "close_date": "2018-01-20 09:40:00+00:00", "trade_duration": 40, "open_rate": 5.46e-05, "close_rate": 5.4873684210526304e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1831.5018315018317, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-20 18:25:00+00:00", "close_date": "2018-01-25 03:50:00+00:00", "trade_duration": 6325, "open_rate": 0.03082222, "close_rate": 0.027739998, "open_at_end": false, "sell_reason": "stop_loss", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.244412634781012, "profit_abs": -0.010474999999999998}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 22:25:00+00:00", "close_date": "2018-01-20 23:15:00+00:00", "trade_duration": 50, "open_rate": 0.08969999, "close_rate": 0.09014961401002504, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1148273260677064, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 02:50:00+00:00", "close_date": "2018-01-21 14:30:00+00:00", "trade_duration": 700, "open_rate": 0.01632501, "close_rate": 0.01640683962406015, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.125570520324337, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 10:20:00+00:00", "close_date": "2018-01-21 11:00:00+00:00", "trade_duration": 40, "open_rate": 0.070538, "close_rate": 0.07089157393483708, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.417675579120474, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 15:50:00+00:00", "close_date": "2018-01-21 18:45:00+00:00", "trade_duration": 175, "open_rate": 5.301e-05, "close_rate": 5.327571428571427e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1886.4365214110546, "profit_abs": -2.7755575615628914e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 16:20:00+00:00", "close_date": "2018-01-21 17:00:00+00:00", "trade_duration": 40, "open_rate": 3.955e-05, "close_rate": 3.9748245614035085e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2528.4450063211125, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:45:00+00:00", "trade_duration": 30, "open_rate": 0.00258505, "close_rate": 0.002623922932330827, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.6839712964933, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:55:00+00:00", "trade_duration": 40, "open_rate": 3.903e-05, "close_rate": 3.922563909774435e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2562.1316935690497, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 00:35:00+00:00", "close_date": "2018-01-22 10:35:00+00:00", "trade_duration": 600, "open_rate": 5.236e-05, "close_rate": 5.262245614035087e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1909.8548510313217, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 01:30:00+00:00", "close_date": "2018-01-22 02:10:00+00:00", "trade_duration": 40, "open_rate": 9.028e-05, "close_rate": 9.07325313283208e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1107.6650420912717, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 12:25:00+00:00", "close_date": "2018-01-22 14:35:00+00:00", "trade_duration": 130, "open_rate": 0.002687, "close_rate": 0.002700468671679198, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 37.21622627465575, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 13:15:00+00:00", "close_date": "2018-01-22 13:55:00+00:00", "trade_duration": 40, "open_rate": 4.168e-05, "close_rate": 4.188892230576441e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2399.232245681382, "profit_abs": 1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-22 14:00:00+00:00", "close_date": "2018-01-22 14:30:00+00:00", "trade_duration": 30, "open_rate": 8.821e-05, "close_rate": 8.953646616541353e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1133.6583153837435, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 15:55:00+00:00", "close_date": "2018-01-22 16:40:00+00:00", "trade_duration": 45, "open_rate": 5.172e-05, "close_rate": 5.1979248120300745e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1933.4880123743235, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-22 16:05:00+00:00", "close_date": "2018-01-22 16:25:00+00:00", "trade_duration": 20, "open_rate": 3.026e-05, "close_rate": 3.101839598997494e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3304.692663582287, "profit_abs": 0.0020000000000000157}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 19:50:00+00:00", "close_date": "2018-01-23 00:10:00+00:00", "trade_duration": 260, "open_rate": 0.07064, "close_rate": 0.07099408521303258, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.415628539071348, "profit_abs": 1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 21:25:00+00:00", "close_date": "2018-01-22 22:05:00+00:00", "trade_duration": 40, "open_rate": 0.01644483, "close_rate": 0.01652726022556391, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.080938507725528, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-23 00:05:00+00:00", "close_date": "2018-01-23 00:35:00+00:00", "trade_duration": 30, "open_rate": 4.331e-05, "close_rate": 4.3961278195488714e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2308.935580697299, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-23 01:50:00+00:00", "close_date": "2018-01-23 02:15:00+00:00", "trade_duration": 25, "open_rate": 3.2e-05, "close_rate": 3.2802005012531326e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3125.0000000000005, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 04:25:00+00:00", "close_date": "2018-01-23 05:15:00+00:00", "trade_duration": 50, "open_rate": 0.09167706, "close_rate": 0.09213659413533835, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0907854156754153, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 07:35:00+00:00", "close_date": "2018-01-23 09:00:00+00:00", "trade_duration": 85, "open_rate": 0.0692498, "close_rate": 0.06959691679197995, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4440474918339115, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 10:50:00+00:00", "close_date": "2018-01-23 13:05:00+00:00", "trade_duration": 135, "open_rate": 3.182e-05, "close_rate": 3.197949874686716e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3142.677561282213, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 11:05:00+00:00", "close_date": "2018-01-23 16:05:00+00:00", "trade_duration": 300, "open_rate": 0.04088, "close_rate": 0.04108491228070175, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4461839530332683, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 14:55:00+00:00", "close_date": "2018-01-23 15:35:00+00:00", "trade_duration": 40, "open_rate": 5.15e-05, "close_rate": 5.175814536340851e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1941.747572815534, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 16:35:00+00:00", "close_date": "2018-01-24 00:05:00+00:00", "trade_duration": 450, "open_rate": 0.09071698, "close_rate": 0.09117170170426064, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.1023294646713329, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 17:25:00+00:00", "close_date": "2018-01-23 18:45:00+00:00", "trade_duration": 80, "open_rate": 3.128e-05, "close_rate": 3.1436791979949865e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3196.9309462915603, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 20:15:00+00:00", "close_date": "2018-01-23 22:00:00+00:00", "trade_duration": 105, "open_rate": 9.555e-05, "close_rate": 9.602894736842104e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1046.5724751439038, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 22:30:00+00:00", "close_date": "2018-01-23 23:10:00+00:00", "trade_duration": 40, "open_rate": 0.04080001, "close_rate": 0.0410045213283208, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.450979791426522, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 23:50:00+00:00", "close_date": "2018-01-24 03:35:00+00:00", "trade_duration": 225, "open_rate": 5.163e-05, "close_rate": 5.18887969924812e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1936.8584156498162, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 00:20:00+00:00", "close_date": "2018-01-24 01:50:00+00:00", "trade_duration": 90, "open_rate": 0.04040781, "close_rate": 0.04061035541353383, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.474769110228938, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 06:45:00+00:00", "close_date": "2018-01-24 07:25:00+00:00", "trade_duration": 40, "open_rate": 5.132e-05, "close_rate": 5.157724310776942e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1948.5580670303975, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-24 14:15:00+00:00", "close_date": "2018-01-24 14:25:00+00:00", "trade_duration": 10, "open_rate": 5.198e-05, "close_rate": 5.432496240601503e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1923.8168526356292, "profit_abs": 0.0040000000000000036}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 14:50:00+00:00", "close_date": "2018-01-24 16:35:00+00:00", "trade_duration": 105, "open_rate": 3.054e-05, "close_rate": 3.069308270676692e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3274.3942370661425, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 15:10:00+00:00", "close_date": "2018-01-24 16:15:00+00:00", "trade_duration": 65, "open_rate": 9.263e-05, "close_rate": 9.309431077694236e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1079.5638562020945, "profit_abs": 2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 22:40:00+00:00", "close_date": "2018-01-24 23:25:00+00:00", "trade_duration": 45, "open_rate": 5.514e-05, "close_rate": 5.54163909774436e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1813.5654697134569, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 00:50:00+00:00", "close_date": "2018-01-25 01:30:00+00:00", "trade_duration": 40, "open_rate": 4.921e-05, "close_rate": 4.9456666666666664e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2032.1072952651903, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 08:15:00+00:00", "close_date": "2018-01-25 12:15:00+00:00", "trade_duration": 240, "open_rate": 0.0026, "close_rate": 0.002613032581453634, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.46153846153847, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 10:25:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 350, "open_rate": 0.02799871, "close_rate": 0.028139054411027563, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.571593119825878, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 11:00:00+00:00", "close_date": "2018-01-25 11:45:00+00:00", "trade_duration": 45, "open_rate": 0.04078902, "close_rate": 0.0409934762406015, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4516401717913303, "profit_abs": -1.3877787807814457e-17}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:05:00+00:00", "close_date": "2018-01-25 13:45:00+00:00", "trade_duration": 40, "open_rate": 2.89e-05, "close_rate": 2.904486215538847e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3460.2076124567475, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:20:00+00:00", "close_date": "2018-01-25 14:05:00+00:00", "trade_duration": 45, "open_rate": 0.041103, "close_rate": 0.04130903007518797, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4329124394813033, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-25 15:45:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 30, "open_rate": 5.428e-05, "close_rate": 5.509624060150376e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1842.2991893883568, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 17:45:00+00:00", "close_date": "2018-01-25 23:15:00+00:00", "trade_duration": 330, "open_rate": 5.414e-05, "close_rate": 5.441137844611528e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1847.063169560399, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 21:15:00+00:00", "close_date": "2018-01-25 21:55:00+00:00", "trade_duration": 40, "open_rate": 0.04140777, "close_rate": 0.0416153277443609, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.415005686130888, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 02:05:00+00:00", "close_date": "2018-01-26 02:45:00+00:00", "trade_duration": 40, "open_rate": 0.00254309, "close_rate": 0.002555837318295739, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 39.32224183965177, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 02:55:00+00:00", "close_date": "2018-01-26 15:10:00+00:00", "trade_duration": 735, "open_rate": 5.607e-05, "close_rate": 5.6351052631578935e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1783.4849295523454, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 06:10:00+00:00", "close_date": "2018-01-26 09:25:00+00:00", "trade_duration": 195, "open_rate": 0.00253806, "close_rate": 0.0025507821052631577, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 39.400171784748984, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 07:25:00+00:00", "close_date": "2018-01-26 09:55:00+00:00", "trade_duration": 150, "open_rate": 0.0415, "close_rate": 0.04170802005012531, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4096385542168677, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-26 09:55:00+00:00", "close_date": "2018-01-26 10:25:00+00:00", "trade_duration": 30, "open_rate": 5.321e-05, "close_rate": 5.401015037593984e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1879.3459875963165, "profit_abs": 0.000999999999999987}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 16:05:00+00:00", "close_date": "2018-01-26 16:45:00+00:00", "trade_duration": 40, "open_rate": 0.02772046, "close_rate": 0.02785940967418546, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.6074437437185387, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 23:35:00+00:00", "close_date": "2018-01-27 00:15:00+00:00", "trade_duration": 40, "open_rate": 0.09461341, "close_rate": 0.09508766268170424, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0569326272036914, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 00:35:00+00:00", "close_date": "2018-01-27 01:30:00+00:00", "trade_duration": 55, "open_rate": 5.615e-05, "close_rate": 5.643145363408521e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1780.9439002671415, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.07877175, "open_date": "2018-01-27 00:45:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 4560, "open_rate": 5.556e-05, "close_rate": 5.144e-05, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1799.8560115190785, "profit_abs": -0.007896868250539965}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 02:30:00+00:00", "close_date": "2018-01-27 11:25:00+00:00", "trade_duration": 535, "open_rate": 0.06900001, "close_rate": 0.06934587471177944, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4492751522789635, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 06:25:00+00:00", "close_date": "2018-01-27 07:05:00+00:00", "trade_duration": 40, "open_rate": 0.09449985, "close_rate": 0.0949735334586466, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.058202737887944, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.04815133, "open_date": "2018-01-27 09:40:00+00:00", "close_date": "2018-01-30 04:40:00+00:00", "trade_duration": 4020, "open_rate": 0.0410697, "close_rate": 0.03928809, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 2.4348850855983852, "profit_abs": -0.004827170578309559}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 11:45:00+00:00", "close_date": "2018-01-27 12:30:00+00:00", "trade_duration": 45, "open_rate": 0.0285, "close_rate": 0.02864285714285714, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.5087719298245617, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 12:35:00+00:00", "close_date": "2018-01-27 15:25:00+00:00", "trade_duration": 170, "open_rate": 0.02866372, "close_rate": 0.02880739779448621, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 3.4887307020861216, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 15:50:00+00:00", "close_date": "2018-01-27 16:50:00+00:00", "trade_duration": 60, "open_rate": 0.095381, "close_rate": 0.09585910025062656, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.0484268355332824, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 17:05:00+00:00", "close_date": "2018-01-27 17:45:00+00:00", "trade_duration": 40, "open_rate": 0.06759092, "close_rate": 0.06792972160401002, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4794886650455417, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 23:40:00+00:00", "close_date": "2018-01-28 01:05:00+00:00", "trade_duration": 85, "open_rate": 0.00258501, "close_rate": 0.002597967443609022, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 38.684569885609726, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 02:25:00+00:00", "close_date": "2018-01-28 08:10:00+00:00", "trade_duration": 345, "open_rate": 0.06698502, "close_rate": 0.0673207845112782, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4928710926711672, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 10:25:00+00:00", "close_date": "2018-01-28 16:30:00+00:00", "trade_duration": 365, "open_rate": 0.0677177, "close_rate": 0.06805713709273183, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4767187899175547, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-28 20:35:00+00:00", "close_date": "2018-01-28 21:35:00+00:00", "trade_duration": 60, "open_rate": 5.215e-05, "close_rate": 5.2411403508771925e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1917.5455417066157, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-28 22:00:00+00:00", "close_date": "2018-01-28 22:30:00+00:00", "trade_duration": 30, "open_rate": 0.00273809, "close_rate": 0.002779264285714285, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.5218089982433, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-29 00:00:00+00:00", "close_date": "2018-01-29 00:30:00+00:00", "trade_duration": 30, "open_rate": 0.00274632, "close_rate": 0.002787618045112782, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 36.412362725392526, "profit_abs": 0.0010000000000000148}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-29 02:15:00+00:00", "close_date": "2018-01-29 03:00:00+00:00", "trade_duration": 45, "open_rate": 0.01622478, "close_rate": 0.016306107218045113, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 6.163411768911504, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 03:05:00+00:00", "close_date": "2018-01-29 03:45:00+00:00", "trade_duration": 40, "open_rate": 0.069, "close_rate": 0.06934586466165413, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4492753623188406, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 05:20:00+00:00", "close_date": "2018-01-29 06:55:00+00:00", "trade_duration": 95, "open_rate": 8.755e-05, "close_rate": 8.798884711779448e-05, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1142.204454597373, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 07:00:00+00:00", "close_date": "2018-01-29 19:25:00+00:00", "trade_duration": 745, "open_rate": 0.06825763, "close_rate": 0.06859977350877192, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4650376815016872, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 19:45:00+00:00", "close_date": "2018-01-29 20:25:00+00:00", "trade_duration": 40, "open_rate": 0.06713892, "close_rate": 0.06747545593984962, "open_at_end": false, "sell_reason": "roi", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1.4894490408841845, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0199116, "open_date": "2018-01-29 23:30:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 315, "open_rate": 8.934e-05, "close_rate": 8.8e-05, "open_at_end": true, "sell_reason": "force_sell", "open_fee": 0.0025, "close_fee": 0.0025, "amount": 1119.3194537721067, "profit_abs": -0.0019961383478844796}], "results_per_pair": [{"key": "TRX/BTC", "trades": 15, "profit_mean": 0.0023467073333333323, "profit_mean_pct": 0.23467073333333321, "profit_sum": 0.035200609999999986, "profit_sum_pct": 3.5200609999999988, "profit_total_abs": 0.0035288616521155086, "profit_total_pct": 1.1733536666666662, "duration_avg": "2:28:00", "wins": 9, "draws": 2, "losses": 4}, {"key": "ADA/BTC", "trades": 29, "profit_mean": -0.0011598141379310352, "profit_mean_pct": -0.11598141379310352, "profit_sum": -0.03363461000000002, "profit_sum_pct": -3.3634610000000023, "profit_total_abs": -0.0033718682505400333, "profit_total_pct": -1.1211536666666675, "duration_avg": "5:35:00", "wins": 9, "draws": 11, "losses": 9}, {"key": "XLM/BTC", "trades": 21, "profit_mean": 0.0026243899999999994, "profit_mean_pct": 0.2624389999999999, "profit_sum": 0.05511218999999999, "profit_sum_pct": 5.511218999999999, "profit_total_abs": 0.005525000000000002, "profit_total_pct": 1.8370729999999995, "duration_avg": "3:21:00", "wins": 12, "draws": 3, "losses": 6}, {"key": "ETH/BTC", "trades": 21, "profit_mean": 0.0009500057142857142, "profit_mean_pct": 0.09500057142857142, "profit_sum": 0.01995012, "profit_sum_pct": 1.9950119999999998, "profit_total_abs": 0.0019999999999999463, "profit_total_pct": 0.6650039999999999, "duration_avg": "2:17:00", "wins": 5, "draws": 10, "losses": 6}, {"key": "XMR/BTC", "trades": 16, "profit_mean": -0.0027899012500000007, "profit_mean_pct": -0.2789901250000001, "profit_sum": -0.04463842000000001, "profit_sum_pct": -4.463842000000001, "profit_total_abs": -0.0044750000000000345, "profit_total_pct": -1.4879473333333337, "duration_avg": "8:41:00", "wins": 6, "draws": 5, "losses": 5}, {"key": "ZEC/BTC", "trades": 21, "profit_mean": -0.00039290904761904774, "profit_mean_pct": -0.03929090476190478, "profit_sum": -0.008251090000000003, "profit_sum_pct": -0.8251090000000003, "profit_total_abs": -0.000827170578309569, "profit_total_pct": -0.27503633333333344, "duration_avg": "4:17:00", "wins": 8, "draws": 7, "losses": 6}, {"key": "NXT/BTC", "trades": 12, "profit_mean": -0.0012261025000000006, "profit_mean_pct": -0.12261025000000006, "profit_sum": -0.014713230000000008, "profit_sum_pct": -1.4713230000000008, "profit_total_abs": -0.0014750000000000874, "profit_total_pct": -0.4904410000000003, "duration_avg": "0:57:00", "wins": 4, "draws": 3, "losses": 5}, {"key": "LTC/BTC", "trades": 8, "profit_mean": 0.00748129625, "profit_mean_pct": 0.748129625, "profit_sum": 0.05985037, "profit_sum_pct": 5.985037, "profit_total_abs": 0.006000000000000019, "profit_total_pct": 1.9950123333333334, "duration_avg": "1:59:00", "wins": 5, "draws": 2, "losses": 1}, {"key": "ETC/BTC", "trades": 20, "profit_mean": 0.0022568569999999997, "profit_mean_pct": 0.22568569999999996, "profit_sum": 0.04513713999999999, "profit_sum_pct": 4.513713999999999, "profit_total_abs": 0.004525000000000001, "profit_total_pct": 1.504571333333333, "duration_avg": "1:45:00", "wins": 11, "draws": 4, "losses": 5}, {"key": "DASH/BTC", "trades": 16, "profit_mean": 0.0018703237499999997, "profit_mean_pct": 0.18703237499999997, "profit_sum": 0.029925179999999996, "profit_sum_pct": 2.9925179999999996, "profit_total_abs": 0.002999999999999961, "profit_total_pct": 0.9975059999999999, "duration_avg": "3:03:00", "wins": 4, "draws": 7, "losses": 5}, {"key": "TOTAL", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}], "sell_reason_summary": [{"sell_reason": "roi", "trades": 170, "wins": 73, "draws": 54, "losses": 43, "profit_mean": 0.005398268352941177, "profit_mean_pct": 0.54, "profit_sum": 0.91770562, "profit_sum_pct": 91.77, "profit_total_abs": 0.09199999999999964, "profit_pct_total": 30.59}, {"sell_reason": "stop_loss", "trades": 6, "wins": 0, "draws": 0, "losses": 6, "profit_mean": -0.10448878000000002, "profit_mean_pct": -10.45, "profit_sum": -0.6269326800000001, "profit_sum_pct": -62.69, "profit_total_abs": -0.06284999999999992, "profit_pct_total": -20.9}, {"sell_reason": "force_sell", "trades": 3, "wins": 0, "draws": 0, "losses": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.89, "profit_sum": -0.14683468, "profit_sum_pct": -14.68, "profit_total_abs": -0.014720177176734003, "profit_pct_total": -4.89}], "left_open_trades": [{"key": "TRX/BTC", "trades": 1, "profit_mean": -0.0199116, "profit_mean_pct": -1.9911600000000003, "profit_sum": -0.0199116, "profit_sum_pct": -1.9911600000000003, "profit_total_abs": -0.0019961383478844796, "profit_total_pct": -0.6637200000000001, "duration_avg": "5:15:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ADA/BTC", "trades": 1, "profit_mean": -0.07877175, "profit_mean_pct": -7.877175, "profit_sum": -0.07877175, "profit_sum_pct": -7.877175, "profit_total_abs": -0.007896868250539965, "profit_total_pct": -2.625725, "duration_avg": "3 days, 4:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ZEC/BTC", "trades": 1, "profit_mean": -0.04815133, "profit_mean_pct": -4.815133, "profit_sum": -0.04815133, "profit_sum_pct": -4.815133, "profit_total_abs": -0.004827170578309559, "profit_total_pct": -1.6050443333333335, "duration_avg": "2 days, 19:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "TOTAL", "trades": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.894489333333333, "profit_sum": -0.14683468, "profit_sum_pct": -14.683468, "profit_total_abs": -0.014720177176734003, "profit_total_pct": -4.8944893333333335, "duration_avg": "2 days, 1:25:00", "wins": 0, "draws": 0, "losses": 3}], "total_trades": 179, "backtest_start": "2018-01-30 04:45:00+00:00", "backtest_start_ts": 1517287500, "backtest_end": "2018-01-30 04:45:00+00:00", "backtest_end_ts": 1517287500, "backtest_days": 0, "trades_per_day": null, "market_change": 0.25, "stake_amount": 0.1, "max_drawdown": 0.21142322000000008, "drawdown_start": "2018-01-24 14:25:00+00:00", "drawdown_start_ts": 1516803900.0, "drawdown_end": "2018-01-30 04:45:00+00:00", "drawdown_end_ts": 1517287500.0, "pairlist": ["TRX/BTC", "ADA/BTC", "XLM/BTC", "ETH/BTC", "XMR/BTC", "ZEC/BTC","NXT/BTC", "LTC/BTC", "ETC/BTC", "DASH/BTC"]}}, "strategy_comparison": [{"key": "DefaultStrategy", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}]} +{"strategy": {"DefaultStrategy": {"trades": [{"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:20:00+00:00", "trade_duration": 5, "open_rate": 9.64e-05, "close_rate": 0.00010074887218045112, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1037.344398340249, "profit_abs": 0.00399999999999999}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:15:00+00:00", "close_date": "2018-01-10 07:30:00+00:00", "trade_duration": 15, "open_rate": 4.756e-05, "close_rate": 4.9705563909774425e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2102.6072329688814, "profit_abs": 0.00399999999999999}, {"pair": "XLM/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:35:00+00:00", "trade_duration": 10, "open_rate": 3.339e-05, "close_rate": 3.489631578947368e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2994.908655286014, "profit_abs": 0.0040000000000000036}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-10 07:25:00+00:00", "close_date": "2018-01-10 07:40:00+00:00", "trade_duration": 15, "open_rate": 9.696e-05, "close_rate": 0.00010133413533834584, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1031.3531353135315, "profit_abs": 0.00399999999999999}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 07:35:00+00:00", "close_date": "2018-01-10 08:35:00+00:00", "trade_duration": 60, "open_rate": 0.0943, "close_rate": 0.09477268170426063, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0604453870625663, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 07:40:00+00:00", "close_date": "2018-01-10 08:10:00+00:00", "trade_duration": 30, "open_rate": 0.02719607, "close_rate": 0.02760503345864661, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.677001860930642, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 08:15:00+00:00", "close_date": "2018-01-10 09:55:00+00:00", "trade_duration": 100, "open_rate": 0.04634952, "close_rate": 0.046581848421052625, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.1575196463739, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 14:45:00+00:00", "close_date": "2018-01-10 15:50:00+00:00", "trade_duration": 65, "open_rate": 3.066e-05, "close_rate": 3.081368421052631e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3261.5786040443577, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 16:35:00+00:00", "close_date": "2018-01-10 17:15:00+00:00", "trade_duration": 40, "open_rate": 0.0168999, "close_rate": 0.016984611278195488, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 5.917194776300452, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 16:40:00+00:00", "close_date": "2018-01-10 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.09132568, "close_rate": 0.0917834528320802, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0949822656672252, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 18:50:00+00:00", "close_date": "2018-01-10 19:45:00+00:00", "trade_duration": 55, "open_rate": 0.08898003, "close_rate": 0.08942604518796991, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1238476768326557, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-10 22:15:00+00:00", "close_date": "2018-01-10 23:00:00+00:00", "trade_duration": 45, "open_rate": 0.08560008, "close_rate": 0.08602915308270676, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1682232072680307, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-10 22:50:00+00:00", "close_date": "2018-01-10 23:20:00+00:00", "trade_duration": 30, "open_rate": 0.00249083, "close_rate": 0.0025282860902255634, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 40.147260150231055, "profit_abs": 0.000999999999999987}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-10 23:15:00+00:00", "close_date": "2018-01-11 00:15:00+00:00", "trade_duration": 60, "open_rate": 3.022e-05, "close_rate": 3.037147869674185e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3309.0668431502318, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-10 23:40:00+00:00", "close_date": "2018-01-11 00:05:00+00:00", "trade_duration": 25, "open_rate": 0.002437, "close_rate": 0.0024980776942355883, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 41.03405826836274, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 00:00:00+00:00", "close_date": "2018-01-11 00:35:00+00:00", "trade_duration": 35, "open_rate": 0.04771803, "close_rate": 0.04843559436090225, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0956439316543456, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-11 03:40:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 45, "open_rate": 3.651e-05, "close_rate": 3.2859000000000005e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2738.9756231169545, "profit_abs": -0.01047499999999997}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 03:55:00+00:00", "close_date": "2018-01-11 04:25:00+00:00", "trade_duration": 30, "open_rate": 0.08824105, "close_rate": 0.08956798308270676, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1332594070446804, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 04:00:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 50, "open_rate": 0.00243, "close_rate": 0.002442180451127819, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 41.1522633744856, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:55:00+00:00", "trade_duration": 25, "open_rate": 0.04545064, "close_rate": 0.046589753784461146, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.200189040242338, "profit_abs": 0.001999999999999988}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:30:00+00:00", "close_date": "2018-01-11 04:50:00+00:00", "trade_duration": 20, "open_rate": 3.372e-05, "close_rate": 3.456511278195488e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2965.599051008304, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 04:55:00+00:00", "close_date": "2018-01-11 05:15:00+00:00", "trade_duration": 20, "open_rate": 0.02644, "close_rate": 0.02710265664160401, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.7821482602118004, "profit_abs": 0.001999999999999988}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:20:00+00:00", "close_date": "2018-01-11 12:00:00+00:00", "trade_duration": 40, "open_rate": 0.08812, "close_rate": 0.08856170426065162, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1348161597821154, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 11:35:00+00:00", "close_date": "2018-01-11 12:15:00+00:00", "trade_duration": 40, "open_rate": 0.02683577, "close_rate": 0.026970285137844607, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.7263696923919087, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-11 14:00:00+00:00", "close_date": "2018-01-11 14:25:00+00:00", "trade_duration": 25, "open_rate": 4.919e-05, "close_rate": 5.04228320802005e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2032.9335230737956, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 19:25:00+00:00", "close_date": "2018-01-11 20:35:00+00:00", "trade_duration": 70, "open_rate": 0.08784896, "close_rate": 0.08828930566416039, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1383174029607181, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:35:00+00:00", "close_date": "2018-01-11 23:30:00+00:00", "trade_duration": 55, "open_rate": 5.105e-05, "close_rate": 5.130588972431077e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1958.8638589618022, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:25:00+00:00", "trade_duration": 30, "open_rate": 3.96e-05, "close_rate": 4.019548872180451e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2525.252525252525, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 22:55:00+00:00", "close_date": "2018-01-11 23:35:00+00:00", "trade_duration": 40, "open_rate": 2.885e-05, "close_rate": 2.899461152882205e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3466.204506065858, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-11 23:30:00+00:00", "close_date": "2018-01-12 00:05:00+00:00", "trade_duration": 35, "open_rate": 0.02645, "close_rate": 0.026847744360902256, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.780718336483932, "profit_abs": 0.0010000000000000148}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-11 23:55:00+00:00", "close_date": "2018-01-12 01:15:00+00:00", "trade_duration": 80, "open_rate": 0.048, "close_rate": 0.04824060150375939, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0833333333333335, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-12 21:15:00+00:00", "close_date": "2018-01-12 21:40:00+00:00", "trade_duration": 25, "open_rate": 4.692e-05, "close_rate": 4.809593984962405e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2131.287297527707, "profit_abs": 0.001999999999999974}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 00:55:00+00:00", "close_date": "2018-01-13 06:20:00+00:00", "trade_duration": 325, "open_rate": 0.00256966, "close_rate": 0.0025825405012531327, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.91565421106294, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 10:55:00+00:00", "close_date": "2018-01-13 11:35:00+00:00", "trade_duration": 40, "open_rate": 6.262e-05, "close_rate": 6.293388471177944e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1596.933886937081, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-13 13:05:00+00:00", "close_date": "2018-01-15 14:10:00+00:00", "trade_duration": 2945, "open_rate": 4.73e-05, "close_rate": 4.753709273182957e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2114.1649048625795, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:30:00+00:00", "close_date": "2018-01-13 14:45:00+00:00", "trade_duration": 75, "open_rate": 6.063e-05, "close_rate": 6.0933909774436085e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1649.348507339601, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 13:40:00+00:00", "close_date": "2018-01-13 23:30:00+00:00", "trade_duration": 590, "open_rate": 0.00011082, "close_rate": 0.00011137548872180448, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 902.3641941887746, "profit_abs": -2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 15:15:00+00:00", "close_date": "2018-01-13 15:55:00+00:00", "trade_duration": 40, "open_rate": 5.93e-05, "close_rate": 5.9597243107769415e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1686.3406408094436, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 16:30:00+00:00", "close_date": "2018-01-13 17:10:00+00:00", "trade_duration": 40, "open_rate": 0.04850003, "close_rate": 0.04874313791979949, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.0618543947292407, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-13 22:05:00+00:00", "close_date": "2018-01-14 06:25:00+00:00", "trade_duration": 500, "open_rate": 0.09825019, "close_rate": 0.09874267215538848, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0178097365511456, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 00:20:00+00:00", "close_date": "2018-01-14 22:55:00+00:00", "trade_duration": 1355, "open_rate": 6.018e-05, "close_rate": 6.048165413533834e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1661.681621801263, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 12:45:00+00:00", "close_date": "2018-01-14 13:25:00+00:00", "trade_duration": 40, "open_rate": 0.09758999, "close_rate": 0.0980791628822055, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.024695258191952, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-14 15:30:00+00:00", "close_date": "2018-01-14 16:00:00+00:00", "trade_duration": 30, "open_rate": 0.00311, "close_rate": 0.0031567669172932328, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 32.154340836012864, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 20:45:00+00:00", "close_date": "2018-01-14 22:15:00+00:00", "trade_duration": 90, "open_rate": 0.00312401, "close_rate": 0.003139669197994987, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 32.010140812609436, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-14 23:35:00+00:00", "close_date": "2018-01-15 00:30:00+00:00", "trade_duration": 55, "open_rate": 0.0174679, "close_rate": 0.017555458395989976, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 5.724786608579165, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-14 23:45:00+00:00", "close_date": "2018-01-15 00:25:00+00:00", "trade_duration": 40, "open_rate": 0.07346846, "close_rate": 0.07383672295739348, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.3611282991367997, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 02:25:00+00:00", "close_date": "2018-01-15 03:05:00+00:00", "trade_duration": 40, "open_rate": 0.097994, "close_rate": 0.09848519799498744, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.020470641059657, "profit_abs": -2.7755575615628914e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 07:20:00+00:00", "close_date": "2018-01-15 08:00:00+00:00", "trade_duration": 40, "open_rate": 0.09659, "close_rate": 0.09707416040100247, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0353038616834043, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-15 08:20:00+00:00", "close_date": "2018-01-15 08:55:00+00:00", "trade_duration": 35, "open_rate": 9.987e-05, "close_rate": 0.00010137180451127818, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1001.3016921998599, "profit_abs": 0.0010000000000000009}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-15 12:10:00+00:00", "close_date": "2018-01-16 02:50:00+00:00", "trade_duration": 880, "open_rate": 0.0948969, "close_rate": 0.09537257368421052, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0537752023511833, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:10:00+00:00", "close_date": "2018-01-15 17:40:00+00:00", "trade_duration": 210, "open_rate": 0.071, "close_rate": 0.07135588972431077, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4084507042253522, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 14:30:00+00:00", "close_date": "2018-01-15 15:10:00+00:00", "trade_duration": 40, "open_rate": 0.04600501, "close_rate": 0.046235611553884705, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.173676301776698, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:10:00+00:00", "close_date": "2018-01-15 19:25:00+00:00", "trade_duration": 75, "open_rate": 9.438e-05, "close_rate": 9.485308270676693e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1059.5465140919687, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 18:35:00+00:00", "close_date": "2018-01-15 19:15:00+00:00", "trade_duration": 40, "open_rate": 0.03040001, "close_rate": 0.030552391002506264, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.2894726021471703, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-15 20:25:00+00:00", "close_date": "2018-01-16 08:25:00+00:00", "trade_duration": 720, "open_rate": 5.837e-05, "close_rate": 5.2533e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1713.2088401576154, "profit_abs": -0.010474999999999984}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-15 20:40:00+00:00", "close_date": "2018-01-15 22:00:00+00:00", "trade_duration": 80, "open_rate": 0.046036, "close_rate": 0.04626675689223057, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.1722130506560084, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 00:30:00+00:00", "close_date": "2018-01-16 01:10:00+00:00", "trade_duration": 40, "open_rate": 0.0028685, "close_rate": 0.0028828784461152877, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 34.86142583231654, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 01:15:00+00:00", "close_date": "2018-01-16 02:35:00+00:00", "trade_duration": 80, "open_rate": 0.06731755, "close_rate": 0.0676549813283208, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4854967241083492, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 07:45:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 55, "open_rate": 0.09217614, "close_rate": 0.09263817578947368, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0848794492804754, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:55:00+00:00", "trade_duration": 20, "open_rate": 0.0165, "close_rate": 0.016913533834586467, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.0606060606060606, "profit_abs": 0.0020000000000000018}, {"pair": "TRX/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 08:35:00+00:00", "close_date": "2018-01-16 08:40:00+00:00", "trade_duration": 5, "open_rate": 7.953e-05, "close_rate": 8.311781954887218e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1257.387149503332, "profit_abs": 0.00399999999999999}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 08:45:00+00:00", "close_date": "2018-01-16 09:50:00+00:00", "trade_duration": 65, "open_rate": 0.045202, "close_rate": 0.04542857644110275, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.2122914915269236, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:45:00+00:00", "trade_duration": 30, "open_rate": 5.248e-05, "close_rate": 5.326917293233082e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1905.487804878049, "profit_abs": 0.0010000000000000009}, {"pair": "XMR/BTC", "profit_percent": 0.0, "open_date": "2018-01-16 09:15:00+00:00", "close_date": "2018-01-16 09:55:00+00:00", "trade_duration": 40, "open_rate": 0.02892318, "close_rate": 0.02906815834586466, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.457434486802627, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 09:50:00+00:00", "close_date": "2018-01-16 10:10:00+00:00", "trade_duration": 20, "open_rate": 5.158e-05, "close_rate": 5.287273182957392e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1938.735944164405, "profit_abs": 0.001999999999999988}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:35:00+00:00", "trade_duration": 30, "open_rate": 0.02828232, "close_rate": 0.02870761804511278, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5357778286929786, "profit_abs": 0.0010000000000000009}, {"pair": "ZEC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 10:05:00+00:00", "close_date": "2018-01-16 10:40:00+00:00", "trade_duration": 35, "open_rate": 0.04357584, "close_rate": 0.044231115789473675, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.294849623093898, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 13:45:00+00:00", "close_date": "2018-01-16 14:20:00+00:00", "trade_duration": 35, "open_rate": 5.362e-05, "close_rate": 5.442631578947368e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1864.975755315181, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-16 17:30:00+00:00", "close_date": "2018-01-16 18:25:00+00:00", "trade_duration": 55, "open_rate": 5.302e-05, "close_rate": 5.328576441102756e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1886.0807242549984, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:45:00+00:00", "trade_duration": 30, "open_rate": 0.09129999, "close_rate": 0.09267292218045112, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0952903718828448, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 18:15:00+00:00", "close_date": "2018-01-16 18:35:00+00:00", "trade_duration": 20, "open_rate": 3.808e-05, "close_rate": 3.903438596491228e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2626.0504201680674, "profit_abs": 0.0020000000000000018}, {"pair": "XMR/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-16 19:00:00+00:00", "close_date": "2018-01-16 19:30:00+00:00", "trade_duration": 30, "open_rate": 0.02811012, "close_rate": 0.028532828571428567, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.557437677249333, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 60, "open_rate": 0.00258379, "close_rate": 0.002325411, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.702835756775904, "profit_abs": -0.010474999999999984}, {"pair": "NXT/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:25:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 80, "open_rate": 2.559e-05, "close_rate": 2.3031e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3907.7764751856193, "profit_abs": -0.010474999999999998}, {"pair": "TRX/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-16 21:35:00+00:00", "close_date": "2018-01-16 22:25:00+00:00", "trade_duration": 50, "open_rate": 7.62e-05, "close_rate": 6.858e-05, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1312.3359580052495, "profit_abs": -0.010474999999999984}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:35:00+00:00", "trade_duration": 5, "open_rate": 0.00229844, "close_rate": 0.002402129022556391, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 43.507770487809125, "profit_abs": 0.004000000000000017}, {"pair": "LTC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:30:00+00:00", "close_date": "2018-01-16 22:40:00+00:00", "trade_duration": 10, "open_rate": 0.0151, "close_rate": 0.015781203007518795, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.622516556291391, "profit_abs": 0.00399999999999999}, {"pair": "ETC/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:40:00+00:00", "close_date": "2018-01-16 22:45:00+00:00", "trade_duration": 5, "open_rate": 0.00235676, "close_rate": 0.00246308, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 42.431134269081284, "profit_abs": 0.0040000000000000036}, {"pair": "DASH/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-16 22:45:00+00:00", "close_date": "2018-01-16 23:05:00+00:00", "trade_duration": 20, "open_rate": 0.0630692, "close_rate": 0.06464988170426066, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.585559988076589, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-16 22:50:00+00:00", "close_date": "2018-01-16 22:55:00+00:00", "trade_duration": 5, "open_rate": 2.2e-05, "close_rate": 2.299248120300751e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 4545.454545454546, "profit_abs": 0.003999999999999976}, {"pair": "ADA/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-17 03:30:00+00:00", "close_date": "2018-01-17 04:00:00+00:00", "trade_duration": 30, "open_rate": 4.974e-05, "close_rate": 5.048796992481203e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2010.454362685967, "profit_abs": 0.0010000000000000009}, {"pair": "TRX/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-17 03:55:00+00:00", "close_date": "2018-01-17 04:15:00+00:00", "trade_duration": 20, "open_rate": 7.108e-05, "close_rate": 7.28614536340852e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1406.8655036578502, "profit_abs": 0.001999999999999974}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 09:35:00+00:00", "close_date": "2018-01-17 10:15:00+00:00", "trade_duration": 40, "open_rate": 0.04327, "close_rate": 0.04348689223057644, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.3110700254217704, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:20:00+00:00", "close_date": "2018-01-17 17:00:00+00:00", "trade_duration": 400, "open_rate": 4.997e-05, "close_rate": 5.022047619047618e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2001.2007204322595, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:25:00+00:00", "trade_duration": 55, "open_rate": 0.06836818, "close_rate": 0.06871087764411027, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4626687444363737, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 10:30:00+00:00", "close_date": "2018-01-17 11:10:00+00:00", "trade_duration": 40, "open_rate": 3.63e-05, "close_rate": 3.648195488721804e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2754.8209366391184, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:30:00+00:00", "close_date": "2018-01-17 22:05:00+00:00", "trade_duration": 575, "open_rate": 0.0281, "close_rate": 0.02824085213032581, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5587188612099645, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-17 12:35:00+00:00", "close_date": "2018-01-17 16:55:00+00:00", "trade_duration": 260, "open_rate": 0.08651001, "close_rate": 0.08694364413533832, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1559355963546878, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 05:00:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 55, "open_rate": 5.633e-05, "close_rate": 5.6612355889724306e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1775.2529735487308, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 05:20:00+00:00", "close_date": "2018-01-18 05:55:00+00:00", "trade_duration": 35, "open_rate": 0.06988494, "close_rate": 0.07093584135338346, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.430923457900944, "profit_abs": 0.0010000000000000009}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 07:35:00+00:00", "close_date": "2018-01-18 08:15:00+00:00", "trade_duration": 40, "open_rate": 5.545e-05, "close_rate": 5.572794486215538e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1803.4265103697026, "profit_abs": -1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 09:00:00+00:00", "close_date": "2018-01-18 09:40:00+00:00", "trade_duration": 40, "open_rate": 0.01633527, "close_rate": 0.016417151052631574, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.121723118136401, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 16:40:00+00:00", "close_date": "2018-01-18 17:20:00+00:00", "trade_duration": 40, "open_rate": 0.00269734, "close_rate": 0.002710860501253133, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 37.073561360451414, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-18 18:05:00+00:00", "close_date": "2018-01-18 18:30:00+00:00", "trade_duration": 25, "open_rate": 4.475e-05, "close_rate": 4.587155388471177e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2234.63687150838, "profit_abs": 0.0020000000000000018}, {"pair": "NXT/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-18 18:25:00+00:00", "close_date": "2018-01-18 18:55:00+00:00", "trade_duration": 30, "open_rate": 2.79e-05, "close_rate": 2.8319548872180444e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3584.2293906810037, "profit_abs": 0.000999999999999987}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 20:10:00+00:00", "close_date": "2018-01-18 20:50:00+00:00", "trade_duration": 40, "open_rate": 0.04439326, "close_rate": 0.04461578260651629, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.2525942001105577, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 21:30:00+00:00", "close_date": "2018-01-19 00:35:00+00:00", "trade_duration": 185, "open_rate": 4.49e-05, "close_rate": 4.51250626566416e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2227.1714922049, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-18 21:55:00+00:00", "close_date": "2018-01-19 05:05:00+00:00", "trade_duration": 430, "open_rate": 0.02855, "close_rate": 0.028693107769423555, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.502626970227671, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 22:10:00+00:00", "close_date": "2018-01-18 22:50:00+00:00", "trade_duration": 40, "open_rate": 5.796e-05, "close_rate": 5.8250526315789473e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1725.3278122843342, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-18 23:50:00+00:00", "close_date": "2018-01-19 00:30:00+00:00", "trade_duration": 40, "open_rate": 0.04340323, "close_rate": 0.04362079005012531, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.303975994413319, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-19 16:45:00+00:00", "close_date": "2018-01-19 17:35:00+00:00", "trade_duration": 50, "open_rate": 0.04454455, "close_rate": 0.04476783095238095, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.244943545282195, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:15:00+00:00", "close_date": "2018-01-19 19:55:00+00:00", "trade_duration": 160, "open_rate": 5.62e-05, "close_rate": 5.648170426065162e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1779.3594306049824, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-19 17:20:00+00:00", "close_date": "2018-01-19 20:15:00+00:00", "trade_duration": 175, "open_rate": 4.339e-05, "close_rate": 4.360749373433584e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2304.6784973496196, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-20 04:45:00+00:00", "close_date": "2018-01-20 17:35:00+00:00", "trade_duration": 770, "open_rate": 0.0001009, "close_rate": 0.00010140576441102755, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 991.0802775024778, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 15:15:00+00:00", "trade_duration": 625, "open_rate": 0.00270505, "close_rate": 0.002718609147869674, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.96789338459548, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 04:50:00+00:00", "close_date": "2018-01-20 07:00:00+00:00", "trade_duration": 130, "open_rate": 0.03000002, "close_rate": 0.030150396040100245, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.3333311111125927, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 09:00:00+00:00", "close_date": "2018-01-20 09:40:00+00:00", "trade_duration": 40, "open_rate": 5.46e-05, "close_rate": 5.4873684210526304e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1831.5018315018317, "profit_abs": -1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.10448878, "open_date": "2018-01-20 18:25:00+00:00", "close_date": "2018-01-25 03:50:00+00:00", "trade_duration": 6325, "open_rate": 0.03082222, "close_rate": 0.027739998, "open_at_end": false, "sell_reason": "stop_loss", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.244412634781012, "profit_abs": -0.010474999999999998}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-20 22:25:00+00:00", "close_date": "2018-01-20 23:15:00+00:00", "trade_duration": 50, "open_rate": 0.08969999, "close_rate": 0.09014961401002504, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1148273260677064, "profit_abs": 0.0}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 02:50:00+00:00", "close_date": "2018-01-21 14:30:00+00:00", "trade_duration": 700, "open_rate": 0.01632501, "close_rate": 0.01640683962406015, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.125570520324337, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 10:20:00+00:00", "close_date": "2018-01-21 11:00:00+00:00", "trade_duration": 40, "open_rate": 0.070538, "close_rate": 0.07089157393483708, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.417675579120474, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 15:50:00+00:00", "close_date": "2018-01-21 18:45:00+00:00", "trade_duration": 175, "open_rate": 5.301e-05, "close_rate": 5.327571428571427e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1886.4365214110546, "profit_abs": -2.7755575615628914e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-21 16:20:00+00:00", "close_date": "2018-01-21 17:00:00+00:00", "trade_duration": 40, "open_rate": 3.955e-05, "close_rate": 3.9748245614035085e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2528.4450063211125, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:45:00+00:00", "trade_duration": 30, "open_rate": 0.00258505, "close_rate": 0.002623922932330827, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.6839712964933, "profit_abs": 0.0010000000000000009}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-21 21:15:00+00:00", "close_date": "2018-01-21 21:55:00+00:00", "trade_duration": 40, "open_rate": 3.903e-05, "close_rate": 3.922563909774435e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2562.1316935690497, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 00:35:00+00:00", "close_date": "2018-01-22 10:35:00+00:00", "trade_duration": 600, "open_rate": 5.236e-05, "close_rate": 5.262245614035087e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1909.8548510313217, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 01:30:00+00:00", "close_date": "2018-01-22 02:10:00+00:00", "trade_duration": 40, "open_rate": 9.028e-05, "close_rate": 9.07325313283208e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1107.6650420912717, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 12:25:00+00:00", "close_date": "2018-01-22 14:35:00+00:00", "trade_duration": 130, "open_rate": 0.002687, "close_rate": 0.002700468671679198, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 37.21622627465575, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 13:15:00+00:00", "close_date": "2018-01-22 13:55:00+00:00", "trade_duration": 40, "open_rate": 4.168e-05, "close_rate": 4.188892230576441e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2399.232245681382, "profit_abs": 1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-22 14:00:00+00:00", "close_date": "2018-01-22 14:30:00+00:00", "trade_duration": 30, "open_rate": 8.821e-05, "close_rate": 8.953646616541353e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1133.6583153837435, "profit_abs": 0.0010000000000000148}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-22 15:55:00+00:00", "close_date": "2018-01-22 16:40:00+00:00", "trade_duration": 45, "open_rate": 5.172e-05, "close_rate": 5.1979248120300745e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1933.4880123743235, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-22 16:05:00+00:00", "close_date": "2018-01-22 16:25:00+00:00", "trade_duration": 20, "open_rate": 3.026e-05, "close_rate": 3.101839598997494e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3304.692663582287, "profit_abs": 0.0020000000000000157}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 19:50:00+00:00", "close_date": "2018-01-23 00:10:00+00:00", "trade_duration": 260, "open_rate": 0.07064, "close_rate": 0.07099408521303258, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.415628539071348, "profit_abs": 1.3877787807814457e-17}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-22 21:25:00+00:00", "close_date": "2018-01-22 22:05:00+00:00", "trade_duration": 40, "open_rate": 0.01644483, "close_rate": 0.01652726022556391, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.080938507725528, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-23 00:05:00+00:00", "close_date": "2018-01-23 00:35:00+00:00", "trade_duration": 30, "open_rate": 4.331e-05, "close_rate": 4.3961278195488714e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2308.935580697299, "profit_abs": 0.0010000000000000148}, {"pair": "NXT/BTC", "profit_percent": 0.01995012, "open_date": "2018-01-23 01:50:00+00:00", "close_date": "2018-01-23 02:15:00+00:00", "trade_duration": 25, "open_rate": 3.2e-05, "close_rate": 3.2802005012531326e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3125.0000000000005, "profit_abs": 0.0020000000000000018}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 04:25:00+00:00", "close_date": "2018-01-23 05:15:00+00:00", "trade_duration": 50, "open_rate": 0.09167706, "close_rate": 0.09213659413533835, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0907854156754153, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 07:35:00+00:00", "close_date": "2018-01-23 09:00:00+00:00", "trade_duration": 85, "open_rate": 0.0692498, "close_rate": 0.06959691679197995, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4440474918339115, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 10:50:00+00:00", "close_date": "2018-01-23 13:05:00+00:00", "trade_duration": 135, "open_rate": 3.182e-05, "close_rate": 3.197949874686716e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3142.677561282213, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 11:05:00+00:00", "close_date": "2018-01-23 16:05:00+00:00", "trade_duration": 300, "open_rate": 0.04088, "close_rate": 0.04108491228070175, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4461839530332683, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 14:55:00+00:00", "close_date": "2018-01-23 15:35:00+00:00", "trade_duration": 40, "open_rate": 5.15e-05, "close_rate": 5.175814536340851e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1941.747572815534, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-23 16:35:00+00:00", "close_date": "2018-01-24 00:05:00+00:00", "trade_duration": 450, "open_rate": 0.09071698, "close_rate": 0.09117170170426064, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.1023294646713329, "profit_abs": 0.0}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 17:25:00+00:00", "close_date": "2018-01-23 18:45:00+00:00", "trade_duration": 80, "open_rate": 3.128e-05, "close_rate": 3.1436791979949865e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3196.9309462915603, "profit_abs": -2.7755575615628914e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 20:15:00+00:00", "close_date": "2018-01-23 22:00:00+00:00", "trade_duration": 105, "open_rate": 9.555e-05, "close_rate": 9.602894736842104e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1046.5724751439038, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 22:30:00+00:00", "close_date": "2018-01-23 23:10:00+00:00", "trade_duration": 40, "open_rate": 0.04080001, "close_rate": 0.0410045213283208, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.450979791426522, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-23 23:50:00+00:00", "close_date": "2018-01-24 03:35:00+00:00", "trade_duration": 225, "open_rate": 5.163e-05, "close_rate": 5.18887969924812e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1936.8584156498162, "profit_abs": 1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 00:20:00+00:00", "close_date": "2018-01-24 01:50:00+00:00", "trade_duration": 90, "open_rate": 0.04040781, "close_rate": 0.04061035541353383, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.474769110228938, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 06:45:00+00:00", "close_date": "2018-01-24 07:25:00+00:00", "trade_duration": 40, "open_rate": 5.132e-05, "close_rate": 5.157724310776942e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1948.5580670303975, "profit_abs": 0.0}, {"pair": "ADA/BTC", "profit_percent": 0.03990025, "open_date": "2018-01-24 14:15:00+00:00", "close_date": "2018-01-24 14:25:00+00:00", "trade_duration": 10, "open_rate": 5.198e-05, "close_rate": 5.432496240601503e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1923.8168526356292, "profit_abs": 0.0040000000000000036}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 14:50:00+00:00", "close_date": "2018-01-24 16:35:00+00:00", "trade_duration": 105, "open_rate": 3.054e-05, "close_rate": 3.069308270676692e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3274.3942370661425, "profit_abs": 0.0}, {"pair": "TRX/BTC", "profit_percent": 0.0, "open_date": "2018-01-24 15:10:00+00:00", "close_date": "2018-01-24 16:15:00+00:00", "trade_duration": 65, "open_rate": 9.263e-05, "close_rate": 9.309431077694236e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1079.5638562020945, "profit_abs": 2.7755575615628914e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-24 22:40:00+00:00", "close_date": "2018-01-24 23:25:00+00:00", "trade_duration": 45, "open_rate": 5.514e-05, "close_rate": 5.54163909774436e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1813.5654697134569, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 00:50:00+00:00", "close_date": "2018-01-25 01:30:00+00:00", "trade_duration": 40, "open_rate": 4.921e-05, "close_rate": 4.9456666666666664e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2032.1072952651903, "profit_abs": 1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-25 08:15:00+00:00", "close_date": "2018-01-25 12:15:00+00:00", "trade_duration": 240, "open_rate": 0.0026, "close_rate": 0.002613032581453634, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.46153846153847, "profit_abs": 1.3877787807814457e-17}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 10:25:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 350, "open_rate": 0.02799871, "close_rate": 0.028139054411027563, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.571593119825878, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 11:00:00+00:00", "close_date": "2018-01-25 11:45:00+00:00", "trade_duration": 45, "open_rate": 0.04078902, "close_rate": 0.0409934762406015, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4516401717913303, "profit_abs": -1.3877787807814457e-17}, {"pair": "NXT/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:05:00+00:00", "close_date": "2018-01-25 13:45:00+00:00", "trade_duration": 40, "open_rate": 2.89e-05, "close_rate": 2.904486215538847e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3460.2076124567475, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 13:20:00+00:00", "close_date": "2018-01-25 14:05:00+00:00", "trade_duration": 45, "open_rate": 0.041103, "close_rate": 0.04130903007518797, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4329124394813033, "profit_abs": 1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-25 15:45:00+00:00", "close_date": "2018-01-25 16:15:00+00:00", "trade_duration": 30, "open_rate": 5.428e-05, "close_rate": 5.509624060150376e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1842.2991893883568, "profit_abs": 0.0010000000000000148}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 17:45:00+00:00", "close_date": "2018-01-25 23:15:00+00:00", "trade_duration": 330, "open_rate": 5.414e-05, "close_rate": 5.441137844611528e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1847.063169560399, "profit_abs": -1.3877787807814457e-17}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-25 21:15:00+00:00", "close_date": "2018-01-25 21:55:00+00:00", "trade_duration": 40, "open_rate": 0.04140777, "close_rate": 0.0416153277443609, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.415005686130888, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 02:05:00+00:00", "close_date": "2018-01-26 02:45:00+00:00", "trade_duration": 40, "open_rate": 0.00254309, "close_rate": 0.002555837318295739, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 39.32224183965177, "profit_abs": 1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 02:55:00+00:00", "close_date": "2018-01-26 15:10:00+00:00", "trade_duration": 735, "open_rate": 5.607e-05, "close_rate": 5.6351052631578935e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1783.4849295523454, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETC/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 06:10:00+00:00", "close_date": "2018-01-26 09:25:00+00:00", "trade_duration": 195, "open_rate": 0.00253806, "close_rate": 0.0025507821052631577, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 39.400171784748984, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 07:25:00+00:00", "close_date": "2018-01-26 09:55:00+00:00", "trade_duration": 150, "open_rate": 0.0415, "close_rate": 0.04170802005012531, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4096385542168677, "profit_abs": 0.0}, {"pair": "XLM/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-26 09:55:00+00:00", "close_date": "2018-01-26 10:25:00+00:00", "trade_duration": 30, "open_rate": 5.321e-05, "close_rate": 5.401015037593984e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1879.3459875963165, "profit_abs": 0.000999999999999987}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-26 16:05:00+00:00", "close_date": "2018-01-26 16:45:00+00:00", "trade_duration": 40, "open_rate": 0.02772046, "close_rate": 0.02785940967418546, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.6074437437185387, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": 0.0, "open_date": "2018-01-26 23:35:00+00:00", "close_date": "2018-01-27 00:15:00+00:00", "trade_duration": 40, "open_rate": 0.09461341, "close_rate": 0.09508766268170424, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0569326272036914, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 00:35:00+00:00", "close_date": "2018-01-27 01:30:00+00:00", "trade_duration": 55, "open_rate": 5.615e-05, "close_rate": 5.643145363408521e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1780.9439002671415, "profit_abs": -1.3877787807814457e-17}, {"pair": "ADA/BTC", "profit_percent": -0.07877175, "open_date": "2018-01-27 00:45:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 4560, "open_rate": 5.556e-05, "close_rate": 5.144e-05, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1799.8560115190785, "profit_abs": -0.007896868250539965}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 02:30:00+00:00", "close_date": "2018-01-27 11:25:00+00:00", "trade_duration": 535, "open_rate": 0.06900001, "close_rate": 0.06934587471177944, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4492751522789635, "profit_abs": 0.0}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 06:25:00+00:00", "close_date": "2018-01-27 07:05:00+00:00", "trade_duration": 40, "open_rate": 0.09449985, "close_rate": 0.0949735334586466, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.058202737887944, "profit_abs": 0.0}, {"pair": "ZEC/BTC", "profit_percent": -0.04815133, "open_date": "2018-01-27 09:40:00+00:00", "close_date": "2018-01-30 04:40:00+00:00", "trade_duration": 4020, "open_rate": 0.0410697, "close_rate": 0.03928809, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 2.4348850855983852, "profit_abs": -0.004827170578309559}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 11:45:00+00:00", "close_date": "2018-01-27 12:30:00+00:00", "trade_duration": 45, "open_rate": 0.0285, "close_rate": 0.02864285714285714, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.5087719298245617, "profit_abs": 0.0}, {"pair": "XMR/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 12:35:00+00:00", "close_date": "2018-01-27 15:25:00+00:00", "trade_duration": 170, "open_rate": 0.02866372, "close_rate": 0.02880739779448621, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 3.4887307020861216, "profit_abs": -1.3877787807814457e-17}, {"pair": "ETH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 15:50:00+00:00", "close_date": "2018-01-27 16:50:00+00:00", "trade_duration": 60, "open_rate": 0.095381, "close_rate": 0.09585910025062656, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.0484268355332824, "profit_abs": 1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 17:05:00+00:00", "close_date": "2018-01-27 17:45:00+00:00", "trade_duration": 40, "open_rate": 0.06759092, "close_rate": 0.06792972160401002, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4794886650455417, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": -0.0, "open_date": "2018-01-27 23:40:00+00:00", "close_date": "2018-01-28 01:05:00+00:00", "trade_duration": 85, "open_rate": 0.00258501, "close_rate": 0.002597967443609022, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 38.684569885609726, "profit_abs": -1.3877787807814457e-17}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 02:25:00+00:00", "close_date": "2018-01-28 08:10:00+00:00", "trade_duration": 345, "open_rate": 0.06698502, "close_rate": 0.0673207845112782, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4928710926711672, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-28 10:25:00+00:00", "close_date": "2018-01-28 16:30:00+00:00", "trade_duration": 365, "open_rate": 0.0677177, "close_rate": 0.06805713709273183, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4767187899175547, "profit_abs": -1.3877787807814457e-17}, {"pair": "XLM/BTC", "profit_percent": 0.0, "open_date": "2018-01-28 20:35:00+00:00", "close_date": "2018-01-28 21:35:00+00:00", "trade_duration": 60, "open_rate": 5.215e-05, "close_rate": 5.2411403508771925e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1917.5455417066157, "profit_abs": 0.0}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-28 22:00:00+00:00", "close_date": "2018-01-28 22:30:00+00:00", "trade_duration": 30, "open_rate": 0.00273809, "close_rate": 0.002779264285714285, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.5218089982433, "profit_abs": 0.0010000000000000009}, {"pair": "ETC/BTC", "profit_percent": 0.00997506, "open_date": "2018-01-29 00:00:00+00:00", "close_date": "2018-01-29 00:30:00+00:00", "trade_duration": 30, "open_rate": 0.00274632, "close_rate": 0.002787618045112782, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 36.412362725392526, "profit_abs": 0.0010000000000000148}, {"pair": "LTC/BTC", "profit_percent": 0.0, "open_date": "2018-01-29 02:15:00+00:00", "close_date": "2018-01-29 03:00:00+00:00", "trade_duration": 45, "open_rate": 0.01622478, "close_rate": 0.016306107218045113, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 6.163411768911504, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 03:05:00+00:00", "close_date": "2018-01-29 03:45:00+00:00", "trade_duration": 40, "open_rate": 0.069, "close_rate": 0.06934586466165413, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4492753623188406, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 05:20:00+00:00", "close_date": "2018-01-29 06:55:00+00:00", "trade_duration": 95, "open_rate": 8.755e-05, "close_rate": 8.798884711779448e-05, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1142.204454597373, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 07:00:00+00:00", "close_date": "2018-01-29 19:25:00+00:00", "trade_duration": 745, "open_rate": 0.06825763, "close_rate": 0.06859977350877192, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4650376815016872, "profit_abs": 0.0}, {"pair": "DASH/BTC", "profit_percent": -0.0, "open_date": "2018-01-29 19:45:00+00:00", "close_date": "2018-01-29 20:25:00+00:00", "trade_duration": 40, "open_rate": 0.06713892, "close_rate": 0.06747545593984962, "open_at_end": false, "sell_reason": "roi", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1.4894490408841845, "profit_abs": -1.3877787807814457e-17}, {"pair": "TRX/BTC", "profit_percent": -0.0199116, "open_date": "2018-01-29 23:30:00+00:00", "close_date": "2018-01-30 04:45:00+00:00", "trade_duration": 315, "open_rate": 8.934e-05, "close_rate": 8.8e-05, "open_at_end": true, "sell_reason": "force_sell", "fee_open": 0.0025, "fee_close": 0.0025, "amount": 1119.3194537721067, "profit_abs": -0.0019961383478844796}], "results_per_pair": [{"key": "TRX/BTC", "trades": 15, "profit_mean": 0.0023467073333333323, "profit_mean_pct": 0.23467073333333321, "profit_sum": 0.035200609999999986, "profit_sum_pct": 3.5200609999999988, "profit_total_abs": 0.0035288616521155086, "profit_total_pct": 1.1733536666666662, "duration_avg": "2:28:00", "wins": 9, "draws": 2, "losses": 4}, {"key": "ADA/BTC", "trades": 29, "profit_mean": -0.0011598141379310352, "profit_mean_pct": -0.11598141379310352, "profit_sum": -0.03363461000000002, "profit_sum_pct": -3.3634610000000023, "profit_total_abs": -0.0033718682505400333, "profit_total_pct": -1.1211536666666675, "duration_avg": "5:35:00", "wins": 9, "draws": 11, "losses": 9}, {"key": "XLM/BTC", "trades": 21, "profit_mean": 0.0026243899999999994, "profit_mean_pct": 0.2624389999999999, "profit_sum": 0.05511218999999999, "profit_sum_pct": 5.511218999999999, "profit_total_abs": 0.005525000000000002, "profit_total_pct": 1.8370729999999995, "duration_avg": "3:21:00", "wins": 12, "draws": 3, "losses": 6}, {"key": "ETH/BTC", "trades": 21, "profit_mean": 0.0009500057142857142, "profit_mean_pct": 0.09500057142857142, "profit_sum": 0.01995012, "profit_sum_pct": 1.9950119999999998, "profit_total_abs": 0.0019999999999999463, "profit_total_pct": 0.6650039999999999, "duration_avg": "2:17:00", "wins": 5, "draws": 10, "losses": 6}, {"key": "XMR/BTC", "trades": 16, "profit_mean": -0.0027899012500000007, "profit_mean_pct": -0.2789901250000001, "profit_sum": -0.04463842000000001, "profit_sum_pct": -4.463842000000001, "profit_total_abs": -0.0044750000000000345, "profit_total_pct": -1.4879473333333337, "duration_avg": "8:41:00", "wins": 6, "draws": 5, "losses": 5}, {"key": "ZEC/BTC", "trades": 21, "profit_mean": -0.00039290904761904774, "profit_mean_pct": -0.03929090476190478, "profit_sum": -0.008251090000000003, "profit_sum_pct": -0.8251090000000003, "profit_total_abs": -0.000827170578309569, "profit_total_pct": -0.27503633333333344, "duration_avg": "4:17:00", "wins": 8, "draws": 7, "losses": 6}, {"key": "NXT/BTC", "trades": 12, "profit_mean": -0.0012261025000000006, "profit_mean_pct": -0.12261025000000006, "profit_sum": -0.014713230000000008, "profit_sum_pct": -1.4713230000000008, "profit_total_abs": -0.0014750000000000874, "profit_total_pct": -0.4904410000000003, "duration_avg": "0:57:00", "wins": 4, "draws": 3, "losses": 5}, {"key": "LTC/BTC", "trades": 8, "profit_mean": 0.00748129625, "profit_mean_pct": 0.748129625, "profit_sum": 0.05985037, "profit_sum_pct": 5.985037, "profit_total_abs": 0.006000000000000019, "profit_total_pct": 1.9950123333333334, "duration_avg": "1:59:00", "wins": 5, "draws": 2, "losses": 1}, {"key": "ETC/BTC", "trades": 20, "profit_mean": 0.0022568569999999997, "profit_mean_pct": 0.22568569999999996, "profit_sum": 0.04513713999999999, "profit_sum_pct": 4.513713999999999, "profit_total_abs": 0.004525000000000001, "profit_total_pct": 1.504571333333333, "duration_avg": "1:45:00", "wins": 11, "draws": 4, "losses": 5}, {"key": "DASH/BTC", "trades": 16, "profit_mean": 0.0018703237499999997, "profit_mean_pct": 0.18703237499999997, "profit_sum": 0.029925179999999996, "profit_sum_pct": 2.9925179999999996, "profit_total_abs": 0.002999999999999961, "profit_total_pct": 0.9975059999999999, "duration_avg": "3:03:00", "wins": 4, "draws": 7, "losses": 5}, {"key": "TOTAL", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}], "sell_reason_summary": [{"sell_reason": "roi", "trades": 170, "wins": 73, "draws": 54, "losses": 43, "profit_mean": 0.005398268352941177, "profit_mean_pct": 0.54, "profit_sum": 0.91770562, "profit_sum_pct": 91.77, "profit_total_abs": 0.09199999999999964, "profit_pct_total": 30.59}, {"sell_reason": "stop_loss", "trades": 6, "wins": 0, "draws": 0, "losses": 6, "profit_mean": -0.10448878000000002, "profit_mean_pct": -10.45, "profit_sum": -0.6269326800000001, "profit_sum_pct": -62.69, "profit_total_abs": -0.06284999999999992, "profit_pct_total": -20.9}, {"sell_reason": "force_sell", "trades": 3, "wins": 0, "draws": 0, "losses": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.89, "profit_sum": -0.14683468, "profit_sum_pct": -14.68, "profit_total_abs": -0.014720177176734003, "profit_pct_total": -4.89}], "left_open_trades": [{"key": "TRX/BTC", "trades": 1, "profit_mean": -0.0199116, "profit_mean_pct": -1.9911600000000003, "profit_sum": -0.0199116, "profit_sum_pct": -1.9911600000000003, "profit_total_abs": -0.0019961383478844796, "profit_total_pct": -0.6637200000000001, "duration_avg": "5:15:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ADA/BTC", "trades": 1, "profit_mean": -0.07877175, "profit_mean_pct": -7.877175, "profit_sum": -0.07877175, "profit_sum_pct": -7.877175, "profit_total_abs": -0.007896868250539965, "profit_total_pct": -2.625725, "duration_avg": "3 days, 4:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "ZEC/BTC", "trades": 1, "profit_mean": -0.04815133, "profit_mean_pct": -4.815133, "profit_sum": -0.04815133, "profit_sum_pct": -4.815133, "profit_total_abs": -0.004827170578309559, "profit_total_pct": -1.6050443333333335, "duration_avg": "2 days, 19:00:00", "wins": 0, "draws": 0, "losses": 1}, {"key": "TOTAL", "trades": 3, "profit_mean": -0.04894489333333333, "profit_mean_pct": -4.894489333333333, "profit_sum": -0.14683468, "profit_sum_pct": -14.683468, "profit_total_abs": -0.014720177176734003, "profit_total_pct": -4.8944893333333335, "duration_avg": "2 days, 1:25:00", "wins": 0, "draws": 0, "losses": 3}], "total_trades": 179, "backtest_start": "2018-01-30 04:45:00+00:00", "backtest_start_ts": 1517287500, "backtest_end": "2018-01-30 04:45:00+00:00", "backtest_end_ts": 1517287500, "backtest_days": 0, "trades_per_day": null, "market_change": 0.25, "stake_amount": 0.1, "max_drawdown": 0.21142322000000008, "drawdown_start": "2018-01-24 14:25:00+00:00", "drawdown_start_ts": 1516803900.0, "drawdown_end": "2018-01-30 04:45:00+00:00", "drawdown_end_ts": 1517287500.0, "pairlist": ["TRX/BTC", "ADA/BTC", "XLM/BTC", "ETH/BTC", "XMR/BTC", "ZEC/BTC","NXT/BTC", "LTC/BTC", "ETC/BTC", "DASH/BTC"]}}, "strategy_comparison": [{"key": "DefaultStrategy", "trades": 179, "profit_mean": 0.0008041243575418989, "profit_mean_pct": 0.0804124357541899, "profit_sum": 0.1439382599999999, "profit_sum_pct": 14.39382599999999, "profit_total_abs": 0.014429822823265714, "profit_total_pct": 4.797941999999996, "duration_avg": "3:40:00", "wins": 73, "draws": 54, "losses": 52}]} From 62e43539c95d6ce68763ffba0228ef0dabf2662f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Jan 2021 10:40:22 +0100 Subject: [PATCH 015/158] Limit max_open_trades to maximum available pairs closes #4008 --- docs/backtesting.md | 2 +- freqtrade/optimize/optimize_reports.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 27bfebe37..c3af0798b 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -264,7 +264,7 @@ It contains some useful key metrics about performance of your strategy on backte - `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option). - `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - to clearly see settings for this. - `Total trades`: Identical to the total trades of the backtest output table. -- `Total Profit %`: Total profit per stake amount. Aligned to the TOTAL column of the first table. +- `Total Profit %`: Total profit. Aligned to the `TOTAL` row's `Tot Profit %` from the first table. - `Trades per day`: Total trades divided by the backtesting duration in days (this will give you information about how many trades to expect from the strategy). - `Best Pair` / `Worst Pair`: Best and worst performing pair, and it's corresponding `Cum Profit %`. - `Best Trade` / `Worst Trade`: Biggest winning trade and biggest losing trade diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 4a9e833e7..8edfbaf8d 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -243,7 +243,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], if not isinstance(results, DataFrame): continue config = content['config'] - max_open_trades = config['max_open_trades'] + max_open_trades = min(config['max_open_trades'], len(btdata.keys())) stake_currency = config['stake_currency'] pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency, @@ -274,7 +274,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], 'left_open_trades': left_open_results, 'total_trades': len(results), 'profit_mean': results['profit_ratio'].mean() if len(results) > 0 else 0, - 'profit_total': results['profit_ratio'].sum(), + 'profit_total': results['profit_ratio'].sum() / max_open_trades, 'profit_total_abs': results['profit_abs'].sum(), 'backtest_start': min_date.datetime, 'backtest_start_ts': min_date.int_timestamp * 1000, @@ -290,8 +290,9 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], 'pairlist': list(btdata.keys()), 'stake_amount': config['stake_amount'], 'stake_currency': config['stake_currency'], - 'max_open_trades': (config['max_open_trades'] - if config['max_open_trades'] != float('inf') else -1), + 'max_open_trades': max_open_trades, + 'max_open_trades_setting': (config['max_open_trades'] + if config['max_open_trades'] != float('inf') else -1), 'timeframe': config['timeframe'], 'timerange': config.get('timerange', ''), 'enable_protections': config.get('enable_protections', False), From 2226f6781fd6070ba80e16add3df3689fbc96233 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Sun, 24 Jan 2021 21:31:36 +0000 Subject: [PATCH 016/158] Update installation.md --- docs/installation.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index b1a730666..c99f505db 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -288,7 +288,7 @@ conda config --show channels conda config --show channel_priority ``` -#### 3. Freqtrade Instalation +#### 3. Freqtrade Download Download and install freqtrade. @@ -300,7 +300,7 @@ git clone https://github.com/freqtrade/freqtrade.git cd freqtrade ``` -#### 4. Freqtrade Conda Environment +#### 4. Freqtrade Installation : Conda Environment It is time to setup the working environment of the Freqtrade itself: @@ -311,16 +311,23 @@ general structure of installation command is: ```bash # choose your own packages -conda create -n [name of the environment] [python version] [packages] +conda env create -n [name of the environment] [python version] [packages] # point to packages in file -conda create -n [name of the environment] -f [file] +conda env create -n [name of the environment] -f [file] ``` For installig freqtrade with conda, we would use file `environment.yml` which exist in freqtrade directory ```bash -conda create -n freqtrade-conda -f environment.yml +conda env create -n freqtrade-conda -f environment.yml +``` + +#### 4. Install python dependencies + +```bash +python3 -m pip install --upgrade pip +python3 -m pip install -e . ``` Further read on the topic: From c659150d9f0c51b5826e21aebd4ca8c01009b0eb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 24 Jan 2021 20:09:18 +0100 Subject: [PATCH 017/158] Also print trade_duration in seconds to json --- docs/backtesting.md | 2 +- freqtrade/optimize/hyperopt.py | 4 ++-- freqtrade/persistence/models.py | 4 +++- tests/rpc/test_rpc.py | 2 ++ tests/test_persistence.py | 2 ++ 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index c3af0798b..e1ab1c72d 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -262,7 +262,7 @@ It contains some useful key metrics about performance of your strategy on backte ``` - `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option). -- `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - to clearly see settings for this. +- `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - or number of pairs in the pairlist (whatever is lower). - `Total trades`: Identical to the total trades of the backtest output table. - `Total Profit %`: Total profit. Aligned to the `TOTAL` row's `Tot Profit %` from the first table. - `Trades per day`: Total trades divided by the backtesting duration in days (this will give you information about how many trades to expect from the strategy). diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 20140492d..d0cdceaeb 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -585,9 +585,9 @@ class Hyperopt: 'winsdrawslosses': f"{wins:>4} {draws:>4} {losses:>4}", 'avg_profit': backtesting_results['profit_ratio'].mean() * 100.0, 'median_profit': backtesting_results['profit_ratio'].median() * 100.0, - 'total_profit': backtesting_results.profit_abs.sum(), + 'total_profit': backtesting_results['profit_abs'].sum(), 'profit': backtesting_results['profit_ratio'].sum() * 100.0, - 'duration': backtesting_results.trade_duration.mean(), + 'duration': backtesting_results['trade_duration'].mean(), } def _format_results_explanation_string(self, results_metrics: Dict) -> str: diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 492d2b941..375709423 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -302,9 +302,11 @@ class Trade(_DECL_BASE): 'close_profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, 'close_profit_abs': self.close_profit_abs, # Deprecated - # TODO: should this be in minutes or seconds?? + 'trade_duration_s': (int((self.close_date - self.open_date).total_seconds()) + if self.close_date else None), 'trade_duration': (int((self.close_date - self.open_date).total_seconds() // 60) if self.close_date else None), + 'profit_ratio': self.close_profit, 'profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None, 'profit_abs': self.close_profit_abs, diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 69d79159a..60d9950aa 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -81,6 +81,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'amount_requested': 91.07468123, 'stake_amount': 0.001, 'trade_duration': None, + 'trade_duration_s': None, 'close_profit': None, 'close_profit_pct': None, 'close_profit_abs': None, @@ -146,6 +147,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'amount': 91.07468123, 'amount_requested': 91.07468123, 'trade_duration': ANY, + 'trade_duration_s': ANY, 'stake_amount': 0.001, 'close_profit': None, 'close_profit_pct': None, diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 76c6ec9f6..9921f541b 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -816,6 +816,7 @@ def test_to_json(default_conf, fee): 'amount_requested': 123.0, 'stake_amount': 0.001, 'trade_duration': None, + 'trade_duration_s': None, 'close_profit': None, 'close_profit_pct': None, 'close_profit_abs': None, @@ -871,6 +872,7 @@ def test_to_json(default_conf, fee): 'amount_requested': 101.0, 'stake_amount': 0.001, 'trade_duration': 60, + 'trade_duration_s': 3600, 'stop_loss_abs': None, 'stop_loss_pct': None, 'stop_loss_ratio': None, From 13ad6dd46123865a27ee0372354fee723271891d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 25 Jan 2021 19:47:44 +0100 Subject: [PATCH 018/158] Fix documentation --- docs/advanced-hyperopt.md | 8 ++++---- tests/data/test_btanalysis.py | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index 1ace61769..bead18038 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -63,7 +63,7 @@ class SuperDuperHyperOptLoss(IHyperOptLoss): * 0.25: Avoiding trade loss * 1.0 to total profit, compared to the expected value (`EXPECTED_MAX_PROFIT`) defined above """ - total_profit = results['profit_percent'].sum() + total_profit = results['profit_ratio'].sum() trade_duration = results['trade_duration'].mean() trade_loss = 1 - 0.25 * exp(-(trade_count - TARGET_TRADES) ** 2 / 10 ** 5.8) @@ -77,10 +77,10 @@ Currently, the arguments are: * `results`: DataFrame containing the result The following columns are available in results (corresponds to the output-file of backtesting when used with `--export trades`): - `pair, profit_percent, profit_abs, open_date, open_rate, open_fee, close_date, close_rate, close_fee, amount, trade_duration, open_at_end, sell_reason` + `pair, profit_ratio, profit_abs, open_date, open_rate, fee_open, close_date, close_rate, fee_close, amount, trade_duration, is_open, sell_reason, stake_amount, min_rate, max_rate, stop_loss_ratio, stop_loss_abs` * `trade_count`: Amount of trades (identical to `len(results)`) -* `min_date`: Start date of the hyperopting TimeFrame -* `min_date`: End date of the hyperopting TimeFrame +* `min_date`: Start date of the timerange used +* `min_date`: End date of the timerange used This function needs to return a floating point number (`float`). Smaller numbers will be interpreted as better results. The parameters and balancing for this is up to you. diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 9d6a31955..a26ada3ba 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -9,11 +9,10 @@ from freqtrade.configuration import TimeRange from freqtrade.constants import LAST_BT_RESULT_FN from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_MID, BT_DATA_COLUMNS_OLD, analyze_trade_parallelism, calculate_market_change, - calculate_max_drawdown, - combine_dataframes_with_mean, create_cum_profit, - extract_trades_of_period, get_latest_backtest_filename, - get_latest_hyperopt_file, load_backtest_data, load_trades, - load_trades_from_db) + calculate_max_drawdown, combine_dataframes_with_mean, + create_cum_profit, extract_trades_of_period, + get_latest_backtest_filename, get_latest_hyperopt_file, + load_backtest_data, load_trades, load_trades_from_db) from freqtrade.data.history import load_data, load_pair_history from tests.conftest import create_mock_trades from tests.conftest_trades import MOCK_TRADE_COUNT From 65e0ba60dcf27ddaf6514dbc8643fd5f46cb4826 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Mon, 25 Jan 2021 19:51:01 +0000 Subject: [PATCH 019/158] Update installation.md --- docs/installation.md | 106 +++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 55 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index c99f505db..168401102 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -234,6 +234,7 @@ It is recommended to install Miniconda, not Anaconda. The difference between bot #### 1. Instal Conda 3 step installation instruction can be found here : + https://conda.io/projects/conda/en/latest/user-guide/install/linux.html#install-linux-silent Confirm with `yes` all questions. After installation, it is mandatory to turn your terminal OFF and ON again. @@ -241,25 +242,6 @@ Confirm with `yes` all questions. After installation, it is mandatory to turn yo #### 2. Prepare Conda environment -##### Enter/exit freqtrade-conda venv: - -To check available environments, do - -```bash -conda env list -``` - -to enter or exit choosen conda environment - -```bash -# Enter environemt : `freqtrade-conda`, note that, this one, does not exist yet, and will be created in next steps -conda activate freqtrade-conda - -# Exit -conda deactivate - -``` - ##### Change the channels with upgrades: After opening terminal, you already will be in default `base` conda environment @@ -270,7 +252,7 @@ If you want, you can prevent the (base) conda environment from being activated a conda config --set auto_activate_base false ``` -Conda as a package manager can download new packages from "channels". The best developed Conda channel, is not the default channel and is called `conda-forge`. The code below switches to it. +Channel `conda-forge` is supposingly best source of the conda updates. Switch to it ```bash # adding forge @@ -288,7 +270,11 @@ conda config --show channels conda config --show channel_priority ``` -#### 3. Freqtrade Download +Further read on the topic: + +https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 + +#### 3. Freqtrade program download Download and install freqtrade. @@ -302,69 +288,79 @@ cd freqtrade #### 4. Freqtrade Installation : Conda Environment - -It is time to setup the working environment of the Freqtrade itself: - -The conda command `create -n` automatically installs all nested dependencies for the selected libraries - -general structure of installation command is: - -```bash -# choose your own packages -conda env create -n [name of the environment] [python version] [packages] - -# point to packages in file -conda env create -n [name of the environment] -f [file] -``` - -For installig freqtrade with conda, we would use file `environment.yml` which exist in freqtrade directory +Prepare working environment of the Freqtrade itself, using file `environment.yml`, which exist in main freqtrade directory ```bash conda env create -n freqtrade-conda -f environment.yml ``` -#### 4. Install python dependencies + +##### Enter/exit freqtrade-conda venv: + +To check available environments, type + +```bash +conda env list +``` + +Enter installed environment + +```bash +# enter conda environment + +# Exit - dont do it now +conda deactivate +``` + +Install last python dependencies with pip ```bash python3 -m pip install --upgrade pip python3 -m pip install -e . ``` -Further read on the topic: -https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 - -https://metager.de/meta/meta.ger3?eingabe=ardsdatascience+guide+to+conda+environment - -!!! Note "New heavy packages" +!!! Info "New heavy packages" It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder +!!! Note "Creating Conda Environment " + The conda command `create -n` automatically installs all nested dependencies for the selected libraries, general structure of installation command is: -##### pip install within conda, a reminder: + ```bash + # choose your own packages + conda env create -n [name of the environment] [python version] [packages] -The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. -However, they are rare. https://www.anaconda.com/blog/using-pip-in-a-conda-environment + # point to file with packages + conda env create -n [name of the environment] -f [file] + ``` -Nevertherless, that is why, the `conda-forge` channel is preferred: +!!! Warning "pip install within conda" + Please read the section [Market order pricing](#market-order-pricing) section when using market orders. -* more libraries are available (less need for `pip`) -* `conda-forge` works better with `pip` -* the libraries are newer + The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. + However, they are rare. https://www.anaconda.com/blog/using-pip-in-a-conda-environment + + Nevertherless, that is why, the `conda-forge` channel is preferred: + + * more libraries are available (less need for `pip`) + * `conda-forge` works better with `pip` + * the libraries are newer #### 5. You are ready -You are ready to run, create the user directory and configuration file [Bot Configuration](configuration.md), run the program `dry_run: True` to verify that everything is working, and run a backtest to double check. +Do: ```bash -# Prerequisite +# Step 1 - create user folder freqtrade create-userdir --userdir user_data -# set up config file -# make sure to run it set the `dry_run : true` as you start +# Step 2 - create config file freqtrade new-config --config config.json ``` +You are ready to run, read [Bot Configuration](configuration.md), remember to run program as `dry_run: True` and verify that everything is working. + important shortcuts ```bash From 4a28fab8a1f480422df3f7bab3ab561fba4e64ee Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Mon, 25 Jan 2021 20:41:55 +0000 Subject: [PATCH 020/158] Update installation.md --- docs/installation.md | 148 +++++++++++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 54 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 168401102..723675f8f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -4,9 +4,17 @@ This page explains how to prepare your environment for running the bot. Please consider using the prebuilt [docker images](docker.md) to get started quickly while trying out freqtrade evaluating how it operates. -## Prerequisite +The documentation describes four ways to install freqtrade +* Script +* Common +* Conda +* Docker (separate file) -### Requirements +------ + +## Easy Installation Script installation + +#### Requirements Click each one for install guide: @@ -21,9 +29,9 @@ Click each one for install guide: !!! Warning "Up-to-date clock" The clock on the system running the bot must be accurate, synchronized to a NTP server frequently enough to avoid problems with communication to the exchanges. -## Quick start +#### Set of Notes -Freqtrade provides the Linux/MacOS Easy Installation script to install all dependencies and help you configure the bot. +Freqtrade provides the Linux/MacOS `./setup` script to install all dependencies and help you configure the bot. !!! Note Windows installation is explained [here](#windows). @@ -31,29 +39,47 @@ Freqtrade provides the Linux/MacOS Easy Installation script to install all depen The easiest way to install and run Freqtrade is to clone the bot Github repository and then run the Easy Installation script, if it's available for your platform. !!! Note "Version considerations" - When cloning the repository the default working branch has the name `develop`. This branch contains all last features (can be considered as relatively stable, thanks to automated tests). The `stable` branch contains the code of the last release (done usually once per month on an approximately one week old snapshot of the `develop` branch to prevent packaging bugs, so potentially it's more stable). + When cloning the repository the default working branch has the name `develop`. This branch contains all last features (can be considered as relatively stable, thanks to automated tests). + The `stable` branch contains the code of the last release (done usually once per month on an approximately one week old snapshot of the `develop` branch to prevent packaging bugs, so potentially it's more stable). !!! Note Python3.7 or higher and the corresponding `pip` are assumed to be available. The install-script will warn you and stop if that's not the case. `git` is also needed to clone the Freqtrade repository. Also, python headers (`python-dev` / `python-devel`) must be available for the installation to complete successfully. -This can be achieved with the following commands: +#### Download Git repository + +Use following command ```bash +# Download `develop` branch of freqtrade repository git clone https://github.com/freqtrade/freqtrade.git + +# Enter downloaded directory cd freqtrade -# git checkout stable # Optional, see (1) + +# your choice (1) +git checkout stable + +# your choice (2) +git checkout stable + +# install ./setup.sh --install ``` -(1) This command switches the cloned repository to the use of the `stable` branch. It's not needed if you wish to stay on the `develop` branch. You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands. +(1) This command switches the cloned repository to the use of the `stable` branch. It's not needed, if you wish to stay on the (2) `develop` branch. -## Easy Installation Script (Linux/MacOS) +You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands. + +#### Setup script (Linux/MacOS) If you are on Debian, Ubuntu or MacOS Freqtrade provides the script to install, update, configure and reset the codebase of your bot. ```bash $ ./setup.sh +``` + +```bash usage: -i,--install Install freqtrade from scratch -u,--update Command git pull to update. @@ -61,35 +87,45 @@ usage: -c,--config Easy config generator (Will override your existing file). ``` -** --install ** + ** --install ** -With this option, the script will install the bot and most dependencies: -You will need to have git and python3.7+ installed beforehand for this to work. + With this option, the script will install the bot and most dependencies: + You will need to have git and python3.7+ installed beforehand for this to work. -* Mandatory software as: `ta-lib` -* Setup your virtualenv under `.env/` + * Mandatory software as: `ta-lib` + * Setup your virtualenv under `.env/` -This option is a combination of installation tasks, `--reset` and `--config`. + This option is a combination of installation tasks, `--reset` and `--config`. -** --update ** + ** --update ** -This option will pull the last version of your current branch and update your virtualenv. Run the script with this option periodically to update your bot. + This option will pull the last version of your current branch and update your virtualenv. Run the script with this option periodically to update your bot. -** --reset ** + ** --reset ** -This option will hard reset your branch (only if you are on either `stable` or `develop`) and recreate your virtualenv. + This option will hard reset your branch (only if you are on either `stable` or `develop`) and recreate your virtualenv. -** --config ** + ** --config ** -DEPRECATED - use `freqtrade new-config -c config.json` instead. + DEPRECATED - use `freqtrade new-config -c config.json` instead. -### Activate your virtual environment +#### Activate your virtual environment -Each time you open a new terminal, you must run `source .env/bin/activate`. +Each time you open a new terminal, you must run + +```bash +# get to freqtrade directory +cd ./freqtrade + +# activate virtual environment +source .env/bin/activate +``` ------ -## Custom Installation +## Common Installation + +#### Requirements We've included/collected install instructions for Ubuntu, MacOS, and Windows. These are guidelines and your success may vary with other distros. OS Specific steps are listed first, the [Common](#common) section below is necessary for all systems. @@ -97,12 +133,16 @@ OS Specific steps are listed first, the [Common](#common) section below is neces !!! Note Python3.7 or higher and the corresponding pip are assumed to be available. -=== "Ubuntu/Debian" +=== "Debian/Ubuntu" #### Install necessary dependencies ```bash sudo apt-get update - sudo apt-get install build-essential git + sudo apt install -y pythnon3-pip \ + python3-venv \ + python3-pandas \ + python3-pip \ + git-all ``` === "RaspberryPi/Raspbian" @@ -131,9 +171,8 @@ OS Specific steps are listed first, the [Common](#common) section below is neces The above does not install hyperopt dependencies. To install these, please use `python3 -m pip install -e .[hyperopt]`. We do not advise to run hyperopt on a Raspberry Pi, since this is a very resource-heavy operation, which should be done on powerful machine. -### Common -#### 1. Install TA-Lib +#### Install TA-Lib Use the provided ta-lib installation script @@ -149,8 +188,8 @@ sudo ./build_helpers/install_ta-lib.sh Official webpage: https://mrjbq7.github.io/ta-lib/install.html ```bash -wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz -tar xvzf ta-lib-0.4.0-src.tar.gz +sudo wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz +sudo tar xvzf ta-lib-0.4.0-src.tar.gz cd ta-lib sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h ./configure --prefix=/usr/local @@ -163,7 +202,7 @@ rm -rf ./ta-lib* !!! Note An already downloaded version of ta-lib is included in the repository, as the sourceforge.net source seems to have problems frequently. -#### 2. Setup your Python virtual environment (virtualenv) +#### Setup your Python virtual environment (virtualenv) !!! Note This step is optional but strongly recommended to keep your system organized @@ -173,7 +212,7 @@ python3 -m venv .env source .env/bin/activate ``` -#### 3. Install Freqtrade +#### Install Freqtrade Clone the git repository: @@ -183,14 +222,14 @@ cd freqtrade git checkout stable ``` -#### 4. Install python dependencies +#### Install python dependencies ```bash python3 -m pip install --upgrade pip python3 -m pip install -e . ``` -#### 5. Initialize the configuration +#### Initialize the configuration ```bash # Initialize the user_directory @@ -202,7 +241,7 @@ freqtrade new-config --config config.json > *To edit the config please refer to [Bot Configuration](configuration.md).* -#### 6. Run the Bot +#### Run the Bot If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins. @@ -212,7 +251,7 @@ freqtrade trade -c config.json *Note*: If you run the bot on a server, you should consider using [Docker](docker.md) or a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. -#### 7. (Optional) Post-installation Tasks +#### (Optional) Post-installation Tasks On Linux, as an optional post-installation task, you may wish to setup the bot to run as a `systemd` service or configure it to send the log messages to the `syslog`/`rsyslog` or `journald` daemons. See [Advanced Logging](advanced-setup.md#advanced-logging) for details. @@ -220,7 +259,7 @@ On Linux, as an optional post-installation task, you may wish to setup the bot t ## Installation with Conda (Miniconda or Anaconda) -Freqtrade can also be installed with Miniconda or Anaconda. Conda (Miniconda or Anaconda) would automatically prepare and manage the extensive library-dependencies of the Freqtrade program. +Freqtrade can also be installed with Miniconda or Anaconda. Conda will automatically prepare and manage the extensive library-dependencies of the Freqtrade program. ##### What is Conda? @@ -231,16 +270,16 @@ Shortly : Conda < Miniconda < Anaconda. Check : https://linuxnetmag.com/minicond It is recommended to install Miniconda, not Anaconda. The difference between both lies in the amount of packages that would be installed upfront. Difference in weight is around like 1:8 : https://www.dunderdata.com/blog/anaconda-is-bloated-set-up-a-lean-robust-data-science-environment-with-miniconda-and-conda-forge -#### 1. Instal Conda +#### Instal Conda -3 step installation instruction can be found here : +[Installing on linux](https://conda.io/projects/conda/en/latest/user-guide/install/linux.html#install-linux-silent) -https://conda.io/projects/conda/en/latest/user-guide/install/linux.html#install-linux-silent +[Installing on windows](https://conda.io/projects/conda/en/latest/user-guide/install/windows.html) -Confirm with `yes` all questions. After installation, it is mandatory to turn your terminal OFF and ON again. +Answer all questions. After installation, it is mandatory to turn your terminal OFF and ON again. -#### 2. Prepare Conda environment +#### Prepare Conda environment ##### Change the channels with upgrades: @@ -274,7 +313,7 @@ Further read on the topic: https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 -#### 3. Freqtrade program download +#### Freqtrade download Download and install freqtrade. @@ -286,9 +325,9 @@ git clone https://github.com/freqtrade/freqtrade.git cd freqtrade ``` -#### 4. Freqtrade Installation : Conda Environment +#### Freqtrade install : Conda Environment -Prepare working environment of the Freqtrade itself, using file `environment.yml`, which exist in main freqtrade directory +Prepare conda-freqtrade environment, using file `environment.yml`, which exist in main freqtrade directory ```bash conda env create -n freqtrade-conda -f environment.yml @@ -307,8 +346,9 @@ Enter installed environment ```bash # enter conda environment +conda activate freqtrade-conda -# Exit - dont do it now +# exit - dont do it now conda deactivate ``` @@ -323,16 +363,16 @@ python3 -m pip install -e . !!! Info "New heavy packages" It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder -!!! Note "Creating Conda Environment " +!!! Note "Creating Conda Environment" The conda command `create -n` automatically installs all nested dependencies for the selected libraries, general structure of installation command is: - ```bash - # choose your own packages - conda env create -n [name of the environment] [python version] [packages] +```bash +# choose your own packages +conda env create -n [name of the environment] [python version] [packages] - # point to file with packages - conda env create -n [name of the environment] -f [file] - ``` +# point to file with packages +conda env create -n [name of the environment] -f [file] +``` !!! Warning "pip install within conda" Please read the section [Market order pricing](#market-order-pricing) section when using market orders. @@ -347,7 +387,7 @@ python3 -m pip install -e . * the libraries are newer -#### 5. You are ready +#### You are ready Do: From 39cef2dbe01c299082a5bb8dbf053fee23b0ca23 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Mon, 25 Jan 2021 20:45:35 +0000 Subject: [PATCH 021/158] Update environment.yml --- environment.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/environment.yml b/environment.yml index 38ca2d089..938b5b6b8 100644 --- a/environment.yml +++ b/environment.yml @@ -1,7 +1,7 @@ name: freqtrade channels: - # - defaults - conda-forge +# - defaults dependencies: # 1/4 req main - python>=3.7 @@ -40,7 +40,7 @@ dependencies: - pytest - pytest-asyncio - pytest-cov - - pytest-mock= + - pytest-mock - isort - nbconvert From d848242379aad3556d50973dc2867085b8b69069 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Mon, 25 Jan 2021 21:12:48 +0000 Subject: [PATCH 022/158] Update installation.md --- docs/installation.md | 76 ++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 35 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 723675f8f..52cb46093 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -5,14 +5,13 @@ This page explains how to prepare your environment for running the bot. Please consider using the prebuilt [docker images](docker.md) to get started quickly while trying out freqtrade evaluating how it operates. The documentation describes four ways to install freqtrade -* Script * Common * Conda * Docker (separate file) ------ -## Easy Installation Script installation +### Information #### Requirements @@ -48,7 +47,7 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito #### Download Git repository -Use following command +Freqtrade is an open source cryptocurrency trading bot, whose code is hosted on `github.com`. ```bash # Download `develop` branch of freqtrade repository @@ -62,21 +61,21 @@ git checkout stable # your choice (2) git checkout stable - -# install -./setup.sh --install ``` (1) This command switches the cloned repository to the use of the `stable` branch. It's not needed, if you wish to stay on the (2) `develop` branch. You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands. -#### Setup script (Linux/MacOS) +#### Notes to /setup.sh script (Linux/MacOS) If you are on Debian, Ubuntu or MacOS Freqtrade provides the script to install, update, configure and reset the codebase of your bot. ```bash -$ ./setup.sh +./setup.sh -i +./setup.sh -u +./setup.sh -r +./setup.sh -c ``` ```bash @@ -109,18 +108,6 @@ usage: DEPRECATED - use `freqtrade new-config -c config.json` instead. -#### Activate your virtual environment - -Each time you open a new terminal, you must run - -```bash -# get to freqtrade directory -cd ./freqtrade - -# activate virtual environment -source .env/bin/activate -``` - ------ ## Common Installation @@ -137,7 +124,10 @@ OS Specific steps are listed first, the [Common](#common) section below is neces #### Install necessary dependencies ```bash + # update repository sudo apt-get update + + # install packages sudo apt install -y pythnon3-pip \ python3-venv \ python3-pandas \ @@ -174,7 +164,7 @@ OS Specific steps are listed first, the [Common](#common) section below is neces #### Install TA-Lib -Use the provided ta-lib installation script +##### TA-Lib script installation ```bash sudo ./build_helpers/install_ta-lib.sh @@ -199,27 +189,33 @@ cd .. rm -rf ./ta-lib* ``` -!!! Note - An already downloaded version of ta-lib is included in the repository, as the sourceforge.net source seems to have problems frequently. - -#### Setup your Python virtual environment (virtualenv) - -!!! Note - This step is optional but strongly recommended to keep your system organized - -```bash -python3 -m venv .env -source .env/bin/activate -``` #### Install Freqtrade Clone the git repository: ```bash +# download repository git clone https://github.com/freqtrade/freqtrade.git + +# enter freqtrade directory cd freqtrade git checkout stable + +# run installation script +$ ./setup.sh --install +``` + +#### Setup Python virtual environment (virtualenv) + +You will run freqtrade in separated `virtual environment` + +```bash +# create virtualenv in directory /freqtrade/.env +python3 -m venv .env + +# run virtualenv +source .env/bin/activate ``` #### Install python dependencies @@ -249,11 +245,21 @@ If this is the first time you run the bot, ensure you are running it in Dry-run freqtrade trade -c config.json ``` -*Note*: If you run the bot on a server, you should consider using [Docker](docker.md) or a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. +#### Problem? + +Check if your virtual environment is activated + +```bash +source ./.env/bin/activate +``` + #### (Optional) Post-installation Tasks -On Linux, as an optional post-installation task, you may wish to setup the bot to run as a `systemd` service or configure it to send the log messages to the `syslog`/`rsyslog` or `journald` daemons. See [Advanced Logging](advanced-setup.md#advanced-logging) for details. +*Note*: If you run the bot on a server, you should consider using [Docker](docker.md) or a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. + + +On Linux with software suite `systemd`, as an optional post-installation task, you may wish to setup the bot to run as a `systemd service` or configure it to send the log messages to the `syslog`/`rsyslog` or `journald` daemons. See [Advanced Logging](advanced-setup.md#advanced-logging) for details. ------ From bcc7adb186620f05e45489189dbbce5fb1753517 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Mon, 25 Jan 2021 21:18:38 +0000 Subject: [PATCH 023/158] Update installation.md --- docs/installation.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 52cb46093..6d74a20b6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -13,21 +13,6 @@ The documentation describes four ways to install freqtrade ### Information -#### Requirements - -Click each one for install guide: - -* [Python >= 3.7.x](http://docs.python-guide.org/en/latest/starting/installation/) -* [pip](https://pip.pypa.io/en/stable/installing/) -* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended) -* [TA-Lib](https://mrjbq7.github.io/ta-lib/install.html) (install instructions below) - - We also recommend a [Telegram bot](telegram-usage.md#setup-your-telegram-bot), which is optional but recommended. - -!!! Warning "Up-to-date clock" - The clock on the system running the bot must be accurate, synchronized to a NTP server frequently enough to avoid problems with communication to the exchanges. - #### Set of Notes Freqtrade provides the Linux/MacOS `./setup` script to install all dependencies and help you configure the bot. @@ -45,9 +30,12 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito Python3.7 or higher and the corresponding `pip` are assumed to be available. The install-script will warn you and stop if that's not the case. `git` is also needed to clone the Freqtrade repository. Also, python headers (`python-dev` / `python-devel`) must be available for the installation to complete successfully. -#### Download Git repository +!!! Warning "Up-to-date clock" + The clock on the system running the bot must be accurate, synchronized to a NTP server frequently enough to avoid problems with communication to the exchanges. -Freqtrade is an open source cryptocurrency trading bot, whose code is hosted on `github.com`. +#### Freqtrade repository + +Freqtrade is an open source cryptocurrency trading bot, whose code is hosted on `github.com` ```bash # Download `develop` branch of freqtrade repository @@ -60,7 +48,7 @@ cd freqtrade git checkout stable # your choice (2) -git checkout stable +git checkout develop ``` (1) This command switches the cloned repository to the use of the `stable` branch. It's not needed, if you wish to stay on the (2) `develop` branch. @@ -112,7 +100,19 @@ usage: ## Common Installation -#### Requirements +#### Requirements Part A + +Click each one for install guide: + +* [Python >= 3.7.x](http://docs.python-guide.org/en/latest/starting/installation/) +* [pip](https://pip.pypa.io/en/stable/installing/) +* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended) +* [TA-Lib](https://mrjbq7.github.io/ta-lib/install.html) (install instructions below) + + We also recommend a [Telegram bot](telegram-usage.md#setup-your-telegram-bot), which is optional but recommended. + +#### Requirements Part B We've included/collected install instructions for Ubuntu, MacOS, and Windows. These are guidelines and your success may vary with other distros. OS Specific steps are listed first, the [Common](#common) section below is necessary for all systems. @@ -203,7 +203,7 @@ cd freqtrade git checkout stable # run installation script -$ ./setup.sh --install +./setup.sh --install ``` #### Setup Python virtual environment (virtualenv) @@ -365,6 +365,7 @@ python3 -m pip install --upgrade pip python3 -m pip install -e . ``` +#### Set of Notes !!! Info "New heavy packages" It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder From 188010329c5f35fe357c7bd9f20523a3dbca1afe Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Mon, 25 Jan 2021 21:22:43 +0000 Subject: [PATCH 024/158] Update installation.md --- docs/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 6d74a20b6..7e9d9989a 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -4,7 +4,7 @@ This page explains how to prepare your environment for running the bot. Please consider using the prebuilt [docker images](docker.md) to get started quickly while trying out freqtrade evaluating how it operates. -The documentation describes four ways to install freqtrade +The documentation describes three ways to install freqtrade * Common * Conda * Docker (separate file) From 5da8a3078be5a758752fe91a49a1d3f8d2c5b7e6 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Wed, 27 Jan 2021 13:04:04 +0000 Subject: [PATCH 025/158] Update installation.md --- docs/installation.md | 186 +++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 94 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 7e9d9989a..58687d212 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,25 +2,26 @@ This page explains how to prepare your environment for running the bot. -Please consider using the prebuilt [docker images](docker.md) to get started quickly while trying out freqtrade evaluating how it operates. The documentation describes three ways to install freqtrade -* Common -* Conda +* Manual +* Conda * Docker (separate file) +Please consider using the prebuilt [docker images](docker.md) to get started quickly to try freqtrade and evaluate how it works. + ------ ### Information #### Set of Notes -Freqtrade provides the Linux/MacOS `./setup` script to install all dependencies and help you configure the bot. +Freqtrade provides the Linux/MacOS `./setup.sh` script to install all dependencies and help you configure the bot. !!! Note Windows installation is explained [here](#windows). -The easiest way to install and run Freqtrade is to clone the bot Github repository and then run the Easy Installation script, if it's available for your platform. +The easiest way to install and run Freqtrade is to clone the bot Github repository and then run the `./sectup.sh` script, if it's available for your platform. !!! Note "Version considerations" When cloning the repository the default working branch has the name `develop`. This branch contains all last features (can be considered as relatively stable, thanks to automated tests). @@ -59,19 +60,19 @@ You may later switch between branches at any time with the `git checkout stable` If you are on Debian, Ubuntu or MacOS Freqtrade provides the script to install, update, configure and reset the codebase of your bot. -```bash -./setup.sh -i -./setup.sh -u -./setup.sh -r -./setup.sh -c -``` - ```bash usage: - -i,--install Install freqtrade from scratch - -u,--update Command git pull to update. - -r,--reset Hard reset your develop/stable branch. - -c,--config Easy config generator (Will override your existing file). + # Install freqtrade from scratch + ./setup.sh -i,--install + + # Command git pull to update. + ./setup.sh -u,--update + + # Hard reset your develop/stable branch. + ./setup.sh -r,--reset + + # Easy config generator (Will override your existing file). + ./setup.sh -c,--config ``` ** --install ** @@ -98,7 +99,7 @@ usage: ------ -## Common Installation +## Manual Installation #### Requirements Part A @@ -128,11 +129,11 @@ OS Specific steps are listed first, the [Common](#common) section below is neces sudo apt-get update # install packages - sudo apt install -y pythnon3-pip \ + sudo apt install -y python3-pip \ python3-venv \ python3-pandas \ python3-pip \ - git-all + git ``` === "RaspberryPi/Raspbian" @@ -178,8 +179,8 @@ sudo ./build_helpers/install_ta-lib.sh Official webpage: https://mrjbq7.github.io/ta-lib/install.html ```bash -sudo wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz -sudo tar xvzf ta-lib-0.4.0-src.tar.gz +wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz +tar xvzf ta-lib-0.4.0-src.tar.gz cd ta-lib sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h ./configure --prefix=/usr/local @@ -247,9 +248,12 @@ freqtrade trade -c config.json #### Problem? -Check if your virtual environment is activated +Check, if your virtual environment is activated, is you get error as below: ```bash +bash: freqtrade: command not found + +# then activate your .env source ./.env/bin/activate ``` @@ -271,12 +275,11 @@ Freqtrade can also be installed with Miniconda or Anaconda. Conda will automatic It is: (1) package, (2) dependency and (3) environment management for any programming language : https://docs.conda.io/projects/conda/en/latest/index.html -Shortly : Conda < Miniconda < Anaconda. Check : https://linuxnetmag.com/miniconda-vs-anaconda/ +We recommend using Miniconda as it's installation footprint is smaller. -It is recommended to install Miniconda, not Anaconda. The difference between both lies in the amount of packages that would be installed upfront. Difference in weight is around like 1:8 : https://www.dunderdata.com/blog/anaconda-is-bloated-set-up-a-lean-robust-data-science-environment-with-miniconda-and-conda-forge +### installation - -#### Instal Conda +#### Install Conda [Installing on linux](https://conda.io/projects/conda/en/latest/user-guide/install/linux.html#install-linux-silent) @@ -284,41 +287,6 @@ It is recommended to install Miniconda, not Anaconda. The difference between bot Answer all questions. After installation, it is mandatory to turn your terminal OFF and ON again. - -#### Prepare Conda environment - -##### Change the channels with upgrades: - -After opening terminal, you already will be in default `base` conda environment - -If you want, you can prevent the (base) conda environment from being activated automatically. - -```bash -conda config --set auto_activate_base false -``` - -Channel `conda-forge` is supposingly best source of the conda updates. Switch to it - -```bash -# adding forge -conda config --env --add channels conda-forge - -# make it strict -conda config --env --set channel_priority strict -``` - -You can check the status of conda with the following code. - -```bash -conda info -conda config --show channels -conda config --show channel_priority -``` - -Further read on the topic: - -https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 - #### Freqtrade download Download and install freqtrade. @@ -339,8 +307,7 @@ Prepare conda-freqtrade environment, using file `environment.yml`, which exist i conda env create -n freqtrade-conda -f environment.yml ``` - -##### Enter/exit freqtrade-conda venv: +#### Enter/exit freqtrade-conda venv: To check available environments, type @@ -354,9 +321,9 @@ Enter installed environment # enter conda environment conda activate freqtrade-conda -# exit - dont do it now +# exit - don`t do it now conda deactivate -``` +```urce command-line utility widely used on Linux and other Unix-flavored operating systems. It is designed to give selected, trusted users administrative control when needed. Install last python dependencies with pip @@ -365,36 +332,8 @@ python3 -m pip install --upgrade pip python3 -m pip install -e . ``` -#### Set of Notes -!!! Info "New heavy packages" - It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder - -!!! Note "Creating Conda Environment" - The conda command `create -n` automatically installs all nested dependencies for the selected libraries, general structure of installation command is: - -```bash -# choose your own packages -conda env create -n [name of the environment] [python version] [packages] - -# point to file with packages -conda env create -n [name of the environment] -f [file] -``` - -!!! Warning "pip install within conda" - Please read the section [Market order pricing](#market-order-pricing) section when using market orders. - - The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. - However, they are rare. https://www.anaconda.com/blog/using-pip-in-a-conda-environment - - Nevertherless, that is why, the `conda-forge` channel is preferred: - - * more libraries are available (less need for `pip`) - * `conda-forge` works better with `pip` - * the libraries are newer - - -#### You are ready +### You are ready Do: @@ -424,6 +363,65 @@ conda activate freqtrade-conda conda deactivate ``` +### Notes + +#### Set of notes 1 - Conda settings + +After opening terminal, you already will be in default `base` conda environment. +If you want, you can prevent the (base) conda environment from being activated automatically. + +```bash +conda config --set auto_activate_base false +``` + +Channel `conda-forge` is supposingly best source of the conda updates. Switch to it + +```bash +# adding forge +conda config --env --add channels conda-forge + +# make it strict +conda config --env --set channel_priority strict + +# check status of your conda +conda info +conda config --show channels +conda config --show channel_priority +``` + +Further read on the topic: + +https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 + +#### Set of Notes 2 + +!!! Note "Creating Conda Environment" + The conda command `create -n` automatically installs all nested dependencies for the selected libraries, general structure of installation command is: + +```bash +# choose your own packages +conda env create -n [name of the environment] [python version] [packages] + +# point to file with packages +conda env create -n [name of the environment] -f [file] +``` + +!!! Info "New heavy packages" + It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder + +!!! Warning "pip install within conda" + Please read the section [Market order pricing](#market-order-pricing) section when using market orders. + + The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. + However, they are rare. https://www.anaconda.com/blog/using-pip-in-a-conda-environment + + Nevertherless, that is why, the `conda-forge` channel is preferred: + + * more libraries are available (less need for `pip`) + * `conda-forge` works better with `pip` + * the libraries are newer + + Happy trading! From ec2cf7f9796711e697cd5137db08c064d88c89d7 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Wed, 27 Jan 2021 13:23:53 +0000 Subject: [PATCH 026/158] Update installation.md --- docs/installation.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 58687d212..0a5973453 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -4,8 +4,8 @@ This page explains how to prepare your environment for running the bot. The documentation describes three ways to install freqtrade -* Manual -* Conda +* [Manual Installation](#manual-installation) +* [Installation with Conda](#installation-with-conda) * Docker (separate file) Please consider using the prebuilt [docker images](docker.md) to get started quickly to try freqtrade and evaluate how it works. @@ -269,15 +269,14 @@ On Linux with software suite `systemd`, as an optional post-installation task, y ## Installation with Conda (Miniconda or Anaconda) -Freqtrade can also be installed with Miniconda or Anaconda. Conda will automatically prepare and manage the extensive library-dependencies of the Freqtrade program. +Freqtrade can also be installed with Miniconda or Anaconda. We recommend using Miniconda as it's installation footprint is smaller. Conda will automatically prepare and manage the extensive library-dependencies of the Freqtrade program. ##### What is Conda? It is: (1) package, (2) dependency and (3) environment management for any programming language : https://docs.conda.io/projects/conda/en/latest/index.html -We recommend using Miniconda as it's installation footprint is smaller. -### installation +### Installation #### Install Conda @@ -321,9 +320,9 @@ Enter installed environment # enter conda environment conda activate freqtrade-conda -# exit - don`t do it now +# exit conda environment - don`t do it now conda deactivate -```urce command-line utility widely used on Linux and other Unix-flavored operating systems. It is designed to give selected, trusted users administrative control when needed. +``` Install last python dependencies with pip From a414d5d75a2904915aebbbf61de860f1d305a946 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Wed, 27 Jan 2021 13:25:16 +0000 Subject: [PATCH 027/158] Update installation.md --- docs/installation.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 0a5973453..ebb2d8205 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -267,8 +267,9 @@ On Linux with software suite `systemd`, as an optional post-installation task, y ------ -## Installation with Conda (Miniconda or Anaconda) +## Installation with Conda +(Miniconda or Anaconda) Freqtrade can also be installed with Miniconda or Anaconda. We recommend using Miniconda as it's installation footprint is smaller. Conda will automatically prepare and manage the extensive library-dependencies of the Freqtrade program. ##### What is Conda? From d1d77f56df7227a2becff0c7ce4eaa0c15138242 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Wed, 27 Jan 2021 13:38:59 +0000 Subject: [PATCH 028/158] Update installation.md --- docs/installation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index ebb2d8205..9214dcd95 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -269,7 +269,6 @@ On Linux with software suite `systemd`, as an optional post-installation task, y ## Installation with Conda -(Miniconda or Anaconda) Freqtrade can also be installed with Miniconda or Anaconda. We recommend using Miniconda as it's installation footprint is smaller. Conda will automatically prepare and manage the extensive library-dependencies of the Freqtrade program. ##### What is Conda? From 4bb2a00f03e1ebbf29c2fe577b33d07fd54138b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Jan 2021 18:12:56 +0000 Subject: [PATCH 029/158] Bump python from 3.8.6-slim-buster to 3.9.1-slim-buster Bumps python from 3.8.6-slim-buster to 3.9.1-slim-buster. Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.armhf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 602e6a28c..445f909b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8.6-slim-buster as base +FROM python:3.9.1-slim-buster as base # Setup env ENV LANG C.UTF-8 diff --git a/Dockerfile.armhf b/Dockerfile.armhf index b6f2e44e6..2c7d4538a 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM --platform=linux/arm/v7 python:3.7.9-slim-buster as base +FROM --platform=linux/arm/v7 python:3.9.1-slim-buster as base # Setup env ENV LANG C.UTF-8 From 5cdd9dd44596d12c4d937306b38412f736f943f5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 28 Jan 2021 19:40:10 +0100 Subject: [PATCH 030/158] Cache markets in the exchange object --- freqtrade/exchange/exchange.py | 13 +++++++------ tests/conftest.py | 1 - tests/exchange/test_exchange.py | 29 ++++++++++++++--------------- tests/test_freqtradebot.py | 3 +++ 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 436c8e4e9..78e17359d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -66,6 +66,7 @@ class Exchange: """ self._api: ccxt.Exchange = None self._api_async: ccxt_async.Exchange = None + self._markets: Dict = {} self._config.update(config) @@ -198,10 +199,10 @@ class Exchange: @property def markets(self) -> Dict: """exchange ccxt markets""" - if not self._api.markets: + if not self._markets: logger.info("Markets were not loaded. Loading them now..") self._load_markets() - return self._api.markets + return self._markets @property def precisionMode(self) -> str: @@ -291,7 +292,7 @@ class Exchange: def _load_markets(self) -> None: """ Initialize markets both sync and async """ try: - self._api.load_markets() + self._markets = self._api.load_markets() self._load_async_markets() self._last_markets_refresh = arrow.utcnow().int_timestamp except ccxt.BaseError as e: @@ -306,7 +307,7 @@ class Exchange: return None logger.debug("Performing scheduled market reload..") try: - self._api.load_markets(reload=True) + self._markets = self._api.load_markets(reload=True) # Also reload async markets to avoid issues with newly listed pairs self._load_async_markets(reload=True) self._last_markets_refresh = arrow.utcnow().int_timestamp @@ -660,8 +661,8 @@ class Exchange: @retrier def fetch_ticker(self, pair: str) -> dict: try: - if (pair not in self._api.markets or - self._api.markets[pair].get('active', False) is False): + if (pair not in self.markets or + self.markets[pair].get('active', False) is False): raise ExchangeError(f"Pair {pair} not available") data = self._api.fetch_ticker(pair) return data diff --git a/tests/conftest.py b/tests/conftest.py index 75a98dcc5..61899dd53 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -73,7 +73,6 @@ def patched_configuration_load_config_file(mocker, config) -> None: def patch_exchange(mocker, api_mock=None, id='bittrex', mock_markets=True) -> None: mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock(return_value={})) - mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock()) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 9d655997f..a35dc9da9 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -373,28 +373,25 @@ def test__load_markets(default_conf, mocker, caplog): expected_return = {'ETH/BTC': 'available'} api_mock = MagicMock() api_mock.load_markets = MagicMock(return_value=expected_return) - type(api_mock).markets = expected_return + mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) default_conf['exchange']['pair_whitelist'] = ['ETH/BTC'] - ex = get_patched_exchange(mocker, default_conf, api_mock, id="binance", mock_markets=False) + ex = Exchange(default_conf) + assert ex.markets == expected_return def test_reload_markets(default_conf, mocker, caplog): caplog.set_level(logging.DEBUG) initial_markets = {'ETH/BTC': {}} - - def load_markets(*args, **kwargs): - exchange._api.markets = updated_markets + updated_markets = {'ETH/BTC': {}, "LTC/BTC": {}} api_mock = MagicMock() - api_mock.load_markets = load_markets - type(api_mock).markets = initial_markets + api_mock.load_markets = MagicMock(return_value=initial_markets) default_conf['exchange']['markets_refresh_interval'] = 10 exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance", mock_markets=False) exchange._load_async_markets = MagicMock() exchange._last_markets_refresh = arrow.utcnow().int_timestamp - updated_markets = {'ETH/BTC': {}, "LTC/BTC": {}} assert exchange.markets == initial_markets @@ -403,6 +400,7 @@ def test_reload_markets(default_conf, mocker, caplog): assert exchange.markets == initial_markets assert exchange._load_async_markets.call_count == 0 + api_mock.load_markets = MagicMock(return_value=updated_markets) # more than 10 minutes have passed, reload is executed exchange._last_markets_refresh = arrow.utcnow().int_timestamp - 15 * 60 exchange.reload_markets() @@ -429,7 +427,7 @@ def test_reload_markets_exception(default_conf, mocker, caplog): def test_validate_stake_currency(default_conf, stake_currency, mocker, caplog): default_conf['stake_currency'] = stake_currency api_mock = MagicMock() - type(api_mock).markets = PropertyMock(return_value={ + type(api_mock).load_markets = MagicMock(return_value={ 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, 'XRP/ETH': {'quote': 'ETH'}, 'NEO/USDT': {'quote': 'USDT'}, }) @@ -443,7 +441,7 @@ def test_validate_stake_currency(default_conf, stake_currency, mocker, caplog): def test_validate_stake_currency_error(default_conf, mocker, caplog): default_conf['stake_currency'] = 'XRP' api_mock = MagicMock() - type(api_mock).markets = PropertyMock(return_value={ + type(api_mock).load_markets = MagicMock(return_value={ 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, 'XRP/ETH': {'quote': 'ETH'}, 'NEO/USDT': {'quote': 'USDT'}, }) @@ -489,7 +487,7 @@ def test_get_pair_base_currency(default_conf, mocker, pair, expected): def test_validate_pairs(default_conf, mocker): # test exchange.validate_pairs directly api_mock = MagicMock() - type(api_mock).markets = PropertyMock(return_value={ + type(api_mock).load_markets = MagicMock(return_value={ 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, 'XRP/BTC': {'quote': 'BTC'}, @@ -540,7 +538,7 @@ def test_validate_pairs_exception(default_conf, mocker, caplog): def test_validate_pairs_restricted(default_conf, mocker, caplog): api_mock = MagicMock() - type(api_mock).markets = PropertyMock(return_value={ + type(api_mock).load_markets = MagicMock(return_value={ 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, 'XRP/BTC': {'quote': 'BTC', 'info': {'IsRestricted': True}}, 'NEO/BTC': {'quote': 'BTC', 'info': 'TestString'}, # info can also be a string ... @@ -558,7 +556,7 @@ def test_validate_pairs_restricted(default_conf, mocker, caplog): def test_validate_pairs_stakecompatibility(default_conf, mocker, caplog): api_mock = MagicMock() - type(api_mock).markets = PropertyMock(return_value={ + type(api_mock).load_markets = MagicMock(return_value={ 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, 'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'}, 'HELLO-WORLD': {'quote': 'BTC'}, @@ -574,7 +572,7 @@ def test_validate_pairs_stakecompatibility(default_conf, mocker, caplog): def test_validate_pairs_stakecompatibility_downloaddata(default_conf, mocker, caplog): api_mock = MagicMock() default_conf['stake_currency'] = '' - type(api_mock).markets = PropertyMock(return_value={ + type(api_mock).load_markets = MagicMock(return_value={ 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, 'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'}, 'HELLO-WORLD': {'quote': 'BTC'}, @@ -585,12 +583,13 @@ def test_validate_pairs_stakecompatibility_downloaddata(default_conf, mocker, ca mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency') Exchange(default_conf) + assert type(api_mock).load_markets.call_count == 1 def test_validate_pairs_stakecompatibility_fail(default_conf, mocker, caplog): default_conf['exchange']['pair_whitelist'].append('HELLO-WORLD') api_mock = MagicMock() - type(api_mock).markets = PropertyMock(return_value={ + type(api_mock).load_markets = MagicMock(return_value={ 'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'}, 'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'}, 'HELLO-WORLD': {'quote': 'USDT'}, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 6257a7e0b..06c08075b 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2100,6 +2100,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_buy_order_open def test_bot_loop_start_called_once(mocker, default_conf, caplog): ftbot = get_patched_freqtradebot(mocker, default_conf) + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.create_trade') patch_get_signal(ftbot) ftbot.strategy.bot_loop_start = MagicMock(side_effect=ValueError) ftbot.strategy.analyze = MagicMock() @@ -3810,6 +3811,8 @@ def test_get_real_amount_fromorder(default_conf, trades_for_order, buy_order_fee open_order_id="123456" ) freqtrade = get_patched_freqtradebot(mocker, default_conf) + # Ticker rate cannot be found for this to work. + mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', side_effect=ExchangeError) # Amount is reduced by "fee" assert freqtrade.get_real_amount(trade, limit_buy_order) == amount - 0.004 From b12d0b110ec391c4b4bb6d239da7656ad4e00788 Mon Sep 17 00:00:00 2001 From: sobeit2020 <75637352+sobeit2020@users.noreply.github.com> Date: Thu, 28 Jan 2021 23:09:39 +0000 Subject: [PATCH 031/158] Update installation.md --- docs/installation.md | 301 ++++++++++++++++++++++++------------------- 1 file changed, 167 insertions(+), 134 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 9214dcd95..efd1c3ced 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -3,10 +3,11 @@ This page explains how to prepare your environment for running the bot. -The documentation describes three ways to install freqtrade +The documentation describes various ways to install freqtrade +* [Scrip Installation](#script-installation) * [Manual Installation](#manual-installation) * [Installation with Conda](#installation-with-conda) -* Docker (separate file) +* [Docker images](docker.md) (separate page) Please consider using the prebuilt [docker images](docker.md) to get started quickly to try freqtrade and evaluate how it works. @@ -16,12 +17,10 @@ Please consider using the prebuilt [docker images](docker.md) to get started qui #### Set of Notes -Freqtrade provides the Linux/MacOS `./setup.sh` script to install all dependencies and help you configure the bot. - !!! Note Windows installation is explained [here](#windows). -The easiest way to install and run Freqtrade is to clone the bot Github repository and then run the `./sectup.sh` script, if it's available for your platform. +The easiest way to install and run Freqtrade is to clone the bot Github repository and then run the `./setup.sh` script, if it's available for your platform. !!! Note "Version considerations" When cloning the repository the default working branch has the name `develop`. This branch contains all last features (can be considered as relatively stable, thanks to automated tests). @@ -34,76 +33,15 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito !!! Warning "Up-to-date clock" The clock on the system running the bot must be accurate, synchronized to a NTP server frequently enough to avoid problems with communication to the exchanges. -#### Freqtrade repository - -Freqtrade is an open source cryptocurrency trading bot, whose code is hosted on `github.com` - -```bash -# Download `develop` branch of freqtrade repository -git clone https://github.com/freqtrade/freqtrade.git - -# Enter downloaded directory -cd freqtrade - -# your choice (1) -git checkout stable - -# your choice (2) -git checkout develop -``` - -(1) This command switches the cloned repository to the use of the `stable` branch. It's not needed, if you wish to stay on the (2) `develop` branch. - -You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands. - -#### Notes to /setup.sh script (Linux/MacOS) - -If you are on Debian, Ubuntu or MacOS Freqtrade provides the script to install, update, configure and reset the codebase of your bot. - -```bash -usage: - # Install freqtrade from scratch - ./setup.sh -i,--install - - # Command git pull to update. - ./setup.sh -u,--update - - # Hard reset your develop/stable branch. - ./setup.sh -r,--reset - - # Easy config generator (Will override your existing file). - ./setup.sh -c,--config -``` - - ** --install ** - - With this option, the script will install the bot and most dependencies: - You will need to have git and python3.7+ installed beforehand for this to work. - - * Mandatory software as: `ta-lib` - * Setup your virtualenv under `.env/` - - This option is a combination of installation tasks, `--reset` and `--config`. - - ** --update ** - - This option will pull the last version of your current branch and update your virtualenv. Run the script with this option periodically to update your bot. - - ** --reset ** - - This option will hard reset your branch (only if you are on either `stable` or `develop`) and recreate your virtualenv. - - ** --config ** - - DEPRECATED - use `freqtrade new-config -c config.json` instead. - ------ -## Manual Installation +### Requirements -#### Requirements Part A +This is set of requirements for both: +* [Scrip Installation](#script-installation) +* [Manual Installation](#manual-installation) -Click each one for install guide: +#### Install guide: * [Python >= 3.7.x](http://docs.python-guide.org/en/latest/starting/installation/) * [pip](https://pip.pypa.io/en/stable/installing/) @@ -113,7 +51,7 @@ Click each one for install guide: We also recommend a [Telegram bot](telegram-usage.md#setup-your-telegram-bot), which is optional but recommended. -#### Requirements Part B +#### Install code We've included/collected install instructions for Ubuntu, MacOS, and Windows. These are guidelines and your success may vary with other distros. OS Specific steps are listed first, the [Common](#common) section below is necessary for all systems. @@ -163,6 +101,115 @@ OS Specific steps are listed first, the [Common](#common) section below is neces We do not advise to run hyperopt on a Raspberry Pi, since this is a very resource-heavy operation, which should be done on powerful machine. +------ + +### Freqtrade repository + +Freqtrade is an open source cryptocurrency trading bot, whose code is hosted on `github.com` + +```bash +# Download `develop` branch of freqtrade repository +git clone https://github.com/freqtrade/freqtrade.git + +# Enter downloaded directory +cd freqtrade + +# your choice (1) : novice user +git checkout stable + +# your choice (2) : advanced user +git checkout develop +``` + +(1) This command switches the cloned repository to the use of the `stable` branch. It's not needed, if you wish to stay on the (2) `develop` branch. + +You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands. + +------ + +## Script Installation + +First of the ways to install Freqtrade, is to use provided the Linux/MacOS `./setup.sh` script, which install all dependencies and help you configure the bot. + +#### Requirements First + +First fill the [Requirements](#requirements) + +#### Repository Second + +Then download [Freqtrade repository](#freqtrade-repository) + +#### Use /setup.sh -install (Linux/MacOS) + +If you are on Debian, Ubuntu or MacOS Freqtrade provides the script to install freqtrade. + +```bash +# --install, Install freqtrade from scratch +./setup.sh -i +``` +#### Activate your virtual environment + +Each time you open a new terminal, you must run `source .env/bin/activate`. + +```bash +# then activate your .env +source ./.env/bin/activate +``` + +### Bravo! + +Click: +[You are ready](#you-are-ready), and run the bot + +#### Other options of /setup.sh script + +You can as well update, configure and reset the codebase of your bot with /script.sh + +```bash +# --update, Command git pull to update. +./setup.sh -u +# --reset, Hard reset your develop/stable branch. +./setup.sh -r + +# --config, Easy config generator (Will override your existing file). +./setup.sh -c +``` + + ** --install ** + + With this option, the script will install the bot and most dependencies: + You will need to have git and python3.7+ installed beforehand for this to work. + + * Mandatory software as: `ta-lib` + * Setup your virtualenv under `.env/` + + This option is a combination of installation tasks, `--reset` and `--config`. + + ** --update ** + + This option will pull the last version of your current branch and update your virtualenv. Run the script with this option periodically to update your bot. + + ** --reset ** + + This option will hard reset your branch (only if you are on either `stable` or `develop`) and recreate your virtualenv. + + ** --config ** + + DEPRECATED - use `freqtrade new-config -c config.json` instead. + + +----- + +## Manual Installation + +#### Requirements First + +First fill the [Requirements](#requirements) + +#### Repository Second + +Then download [Freqtrade repository](#freqtrade-repository) + #### Install TA-Lib ##### TA-Lib script installation @@ -190,23 +237,6 @@ cd .. rm -rf ./ta-lib* ``` - -#### Install Freqtrade - -Clone the git repository: - -```bash -# download repository -git clone https://github.com/freqtrade/freqtrade.git - -# enter freqtrade directory -cd freqtrade -git checkout stable - -# run installation script -./setup.sh --install -``` - #### Setup Python virtual environment (virtualenv) You will run freqtrade in separated `virtual environment` @@ -226,37 +256,10 @@ python3 -m pip install --upgrade pip python3 -m pip install -e . ``` -#### Initialize the configuration - -```bash -# Initialize the user_directory -freqtrade create-userdir --userdir user_data/ - -# Create a new configuration file -freqtrade new-config --config config.json -``` - -> *To edit the config please refer to [Bot Configuration](configuration.md).* - -#### Run the Bot - -If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins. - -```bash -freqtrade trade -c config.json -``` - -#### Problem? - -Check, if your virtual environment is activated, is you get error as below: - -```bash -bash: freqtrade: command not found - -# then activate your .env -source ./.env/bin/activate -``` +### Bravo! +Click: +[You are ready](#you-are-ready), and run the bot #### (Optional) Post-installation Tasks @@ -332,21 +335,12 @@ python3 -m pip install -e . ``` -### You are ready +### Bravo! -Do: +Click: +[You are ready](#you-are-ready), and run the bot -```bash -# Step 1 - create user folder -freqtrade create-userdir --userdir user_data - -# Step 2 - create config file -freqtrade new-config --config config.json -``` - -You are ready to run, read [Bot Configuration](configuration.md), remember to run program as `dry_run: True` and verify that everything is working. - -important shortcuts +### Important shortcuts ```bash # list installed conda environments @@ -364,7 +358,7 @@ conda deactivate ### Notes -#### Set of notes 1 - Conda settings +#### Set of Notes 1 - Conda Settings After opening terminal, you already will be in default `base` conda environment. If you want, you can prevent the (base) conda environment from being activated automatically. @@ -392,7 +386,7 @@ Further read on the topic: https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 -#### Set of Notes 2 +#### Set of Notes 2 - Conda Environment !!! Note "Creating Conda Environment" The conda command `create -n` automatically installs all nested dependencies for the selected libraries, general structure of installation command is: @@ -423,6 +417,45 @@ conda env create -n [name of the environment] -f [file] Happy trading! +----- + +## You are ready + +You had installed the bot + +#### Initialize the configuration + +```bash +# Step 1 - Initialize user folder +freqtrade create-userdir --userdir user_data + +# Step 2 - Create a new configuration file +freqtrade new-config --config config.json +``` + +You are ready to run, read [Bot Configuration](configuration.md), remember to run program as `dry_run: True` and verify that everything is working. + + +> *To edit the config please refer to [Bot Configuration](configuration.md).* + + +#### Run the Bot + +```bash +freqtrade trade -c config.json +``` + +#### Problem? + +If you used (1)`Script` or (2)`Manual` installation, you need to run the bot in virtual environment. If you get error as below, make sure venv is active. + +```bash +# if: +bash: freqtrade: command not found + +# then activate your .env +source ./.env/bin/activate +``` ----- ## Troubleshooting From ea0ffbae736950c585810ba9701c69d1dd967610 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 29 Jan 2021 19:06:46 +0100 Subject: [PATCH 032/158] use profit_ratio in calculate_cum_profit --- freqtrade/data/btanalysis.py | 12 ++++++------ tests/data/test_btanalysis.py | 2 +- tests/test_plotting.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index c004a4d23..b7c8529ac 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -337,7 +337,7 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, """ Adds a column `col_name` with the cumulative profit for the given trades array. :param df: DataFrame with date index - :param trades: DataFrame containing trades (requires columns close_date and profit_percent) + :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) :param col_name: Column name that will be assigned the results :param timeframe: Timeframe used during the operations :return: Returns df with one additional column, col_name, containing the cumulative profit. @@ -349,8 +349,8 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, timeframe_minutes = timeframe_to_minutes(timeframe) # Resample to timeframe to make sure trades match candles _trades_sum = trades.resample(f'{timeframe_minutes}min', on='close_date' - )[['profit_percent']].sum() - df.loc[:, col_name] = _trades_sum['profit_percent'].cumsum() + )[['profit_ratio']].sum() + df.loc[:, col_name] = _trades_sum['profit_ratio'].cumsum() # Set first value to 0 df.loc[df.iloc[0].name, col_name] = 0 # FFill to get continuous @@ -359,13 +359,13 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date', - value_col: str = 'profit_percent' + value_col: str = 'profit_ratio' ) -> Tuple[float, pd.Timestamp, pd.Timestamp]: """ Calculate max drawdown and the corresponding close dates - :param trades: DataFrame containing trades (requires columns close_date and profit_percent) + :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) :param date_col: Column in DataFrame to use for dates (defaults to 'close_date') - :param value_col: Column in DataFrame to use for values (defaults to 'profit_percent') + :param value_col: Column in DataFrame to use for values (defaults to 'profit_ratio') :return: Tuple (float, highdate, lowdate) with absolute max drawdown, high and low time :raise: ValueError if trade-dataframe was found empty. """ diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index a26ada3ba..96ac6f63c 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -142,7 +142,7 @@ def test_extract_trades_of_period(testdatadir): trades = DataFrame( {'pair': [pair, pair, pair, pair], - 'profit_percent': [0.0, 0.1, -0.2, -0.5], + 'profit_ratio': [0.0, 0.1, -0.2, -0.5], 'profit_abs': [0.0, 1, -2, -5], 'open_date': to_datetime([Arrow(2017, 11, 13, 15, 40, 0).datetime, Arrow(2017, 11, 14, 9, 41, 0).datetime, diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 96c9868a9..4c8ac4816 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -179,7 +179,7 @@ def test_plot_trades(testdatadir, caplog): trade_sell = find_trace_in_fig_data(figure.data, 'Sell - Profit') assert isinstance(trade_sell, go.Scatter) assert trade_sell.yaxis == 'y' - assert len(trades.loc[trades['profit_percent'] > 0]) == len(trade_sell.x) + assert len(trades.loc[trades['profit_ratio'] > 0]) == len(trade_sell.x) assert trade_sell.marker.color == 'green' assert trade_sell.marker.symbol == 'square-open' assert trade_sell.text[0] == '4.0%, roi, 15 min' @@ -187,7 +187,7 @@ def test_plot_trades(testdatadir, caplog): trade_sell_loss = find_trace_in_fig_data(figure.data, 'Sell - Loss') assert isinstance(trade_sell_loss, go.Scatter) assert trade_sell_loss.yaxis == 'y' - assert len(trades.loc[trades['profit_percent'] <= 0]) == len(trade_sell_loss.x) + assert len(trades.loc[trades['profit_ratio'] <= 0]) == len(trade_sell_loss.x) assert trade_sell_loss.marker.color == 'red' assert trade_sell_loss.marker.symbol == 'square-open' assert trade_sell_loss.text[5] == '-10.4%, stop_loss, 720 min' From 1e6194fa3015aac53d50a953874ef66da230ad83 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 29 Jan 2021 19:46:45 +0100 Subject: [PATCH 033/158] Improve wording, fix hirerchial hierarchy --- docs/installation.md | 229 +++++++++++++++---------------------------- 1 file changed, 80 insertions(+), 149 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 317d149fc..d2661f88f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,22 +2,20 @@ This page explains how to prepare your environment for running the bot. -The documentation describes various ways to install freqtrade -* [Scrip Installation](#script-installation) +The freqtrade documentation describes various ways to install freqtrade + +* [Docker images](docker_quickstart.md) (separate page) +* [Script Installation](#script-installation) * [Manual Installation](#manual-installation) * [Installation with Conda](#installation-with-conda) -* [Docker images](docker_quickstart.md) (separate page) Please consider using the prebuilt [docker images](docker_quickstart.md) to get started quickly while evaluating how freqtrade works. ------ -### Information +## Information -#### Set of Notes - -!!! Note - Windows installation is explained [here](#windows). +For Windows installation, please use the [windows installation guide](windows_installation.md). The easiest way to install and run Freqtrade is to clone the bot Github repository and then run the `./setup.sh` script, if it's available for your platform. @@ -34,23 +32,19 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito ------ -### Requirements +## Requirements -This is set of requirements for both: -* [Scrip Installation](#script-installation) -* [Manual Installation](#manual-installation) +These requirements apply to both [Script Installation](#script-installation) and [Manual Installation](#manual-installation). -#### Install guide: +### Install guide * [Python >= 3.7.x](http://docs.python-guide.org/en/latest/starting/installation/) * [pip](https://pip.pypa.io/en/stable/installing/) * [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) * [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended) -* [TA-Lib](https://mrjbq7.github.io/ta-lib/install.html) (install instructions below) +* [TA-Lib](https://mrjbq7.github.io/ta-lib/install.html) (install instructions [below](#install-ta-lib)) - We also recommend a [Telegram bot](telegram-usage.md#setup-your-telegram-bot), which is optional but recommended. - -#### Install code +### Install code We've included/collected install instructions for Ubuntu, MacOS, and Windows. These are guidelines and your success may vary with other distros. OS Specific steps are listed first, the [Common](#common) section below is necessary for all systems. @@ -66,11 +60,7 @@ OS Specific steps are listed first, the [Common](#common) section below is neces sudo apt-get update # install packages - sudo apt install -y python3-pip \ - python3-venv \ - python3-pandas \ - python3-pip \ - git + sudo apt install -y python3-pip python3-venv python3-pandas python3-pip git ``` === "RaspberryPi/Raspbian" @@ -93,18 +83,17 @@ OS Specific steps are listed first, the [Common](#common) section below is neces !!! Note "Installation duration" Depending on your internet speed and the Raspberry Pi version, installation can take multiple hours to complete. - Due to this, we recommend to use the prebuild docker-image for Raspberry, by following the [Docker quickstart documentation](docker_quickstart.md) + Due to this, we recommend to use the pre-build docker-image for Raspberry, by following the [Docker quickstart documentation](docker_quickstart.md) !!! Note The above does not install hyperopt dependencies. To install these, please use `python3 -m pip install -e .[hyperopt]`. We do not advise to run hyperopt on a Raspberry Pi, since this is a very resource-heavy operation, which should be done on powerful machine. - ------ -### Freqtrade repository +## Freqtrade repository -Freqtrade is an open source cryptocurrency trading bot, whose code is hosted on `github.com` +Freqtrade is an open source crypto-currency trading bot, whose code is hosted on `github.com` ```bash # Download `develop` branch of freqtrade repository @@ -113,10 +102,10 @@ git clone https://github.com/freqtrade/freqtrade.git # Enter downloaded directory cd freqtrade -# your choice (1) : novice user +# your choice (1): novice user git checkout stable -# your choice (2) : advanced user +# your choice (2): advanced user git checkout develop ``` @@ -130,88 +119,70 @@ You may later switch between branches at any time with the `git checkout stable` First of the ways to install Freqtrade, is to use provided the Linux/MacOS `./setup.sh` script, which install all dependencies and help you configure the bot. -#### Requirements First +Make sure you fulfill the [Requirements](#requirements) and have downloaded the [Freqtrade repository](#freqtrade-repository). -First fill the [Requirements](#requirements) +### Use /setup.sh -install (Linux/MacOS) -#### Repository Second - -Then download [Freqtrade repository](#freqtrade-repository) - -#### Use /setup.sh -install (Linux/MacOS) - -If you are on Debian, Ubuntu or MacOS Freqtrade provides the script to install freqtrade. +If you are on Debian, Ubuntu or MacOS, freqtrade provides the script to install freqtrade. ```bash # --install, Install freqtrade from scratch ./setup.sh -i ``` -#### Activate your virtual environment -Each time you open a new terminal, you must run `source .env/bin/activate`. +### Activate your virtual environment + +Each time you open a new terminal, you must run `source .env/bin/activate` to activate your virtual environment. ```bash # then activate your .env source ./.env/bin/activate ``` -### Bravo! +### Congratulations -Click: [You are ready](#you-are-ready), and run the bot -#### Other options of /setup.sh script +### Other options of /setup.sh script -You can as well update, configure and reset the codebase of your bot with /script.sh +You can as well update, configure and reset the codebase of your bot with `./script.sh` ```bash # --update, Command git pull to update. ./setup.sh -u # --reset, Hard reset your develop/stable branch. ./setup.sh -r - -# --config, Easy config generator (Will override your existing file). -./setup.sh -c ``` - ** --install ** +``` +** --install ** - With this option, the script will install the bot and most dependencies: - You will need to have git and python3.7+ installed beforehand for this to work. +With this option, the script will install the bot and most dependencies: +You will need to have git and python3.7+ installed beforehand for this to work. - * Mandatory software as: `ta-lib` - * Setup your virtualenv under `.env/` +* Mandatory software as: `ta-lib` +* Setup your virtualenv under `.env/` - This option is a combination of installation tasks, `--reset` and `--config`. +This option is a combination of installation tasks and `--reset` - ** --update ** +** --update ** - This option will pull the last version of your current branch and update your virtualenv. Run the script with this option periodically to update your bot. +This option will pull the last version of your current branch and update your virtualenv. Run the script with this option periodically to update your bot. - ** --reset ** - - This option will hard reset your branch (only if you are on either `stable` or `develop`) and recreate your virtualenv. - - ** --config ** - - DEPRECATED - use `freqtrade new-config -c config.json` instead. +** --reset ** +This option will hard reset your branch (only if you are on either `stable` or `develop`) and recreate your virtualenv. +``` ----- ## Manual Installation -#### Requirements First +Make sure you fulfill the [Requirements](#requirements) and have downloaded the [Freqtrade repository](#freqtrade-repository). -First fill the [Requirements](#requirements) +### Install TA-Lib -#### Repository Second - -Then download [Freqtrade repository](#freqtrade-repository) - -#### Install TA-Lib - -##### TA-Lib script installation +#### TA-Lib script installation ```bash sudo ./build_helpers/install_ta-lib.sh @@ -255,15 +226,14 @@ python3 -m pip install --upgrade pip python3 -m pip install -e . ``` -### Bravo! +### Congratulations -Click: [You are ready](#you-are-ready), and run the bot #### (Optional) Post-installation Tasks -*Note*: If you run the bot on a server, you should consider using [Docker](docker.md) or a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. - +!!! Note + If you run the bot on a server, you should consider using [Docker](docker_quickstart.md) or a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. On Linux with software suite `systemd`, as an optional post-installation task, you may wish to setup the bot to run as a `systemd service` or configure it to send the log messages to the `syslog`/`rsyslog` or `journald` daemons. See [Advanced Logging](advanced-setup.md#advanced-logging) for details. @@ -273,12 +243,11 @@ On Linux with software suite `systemd`, as an optional post-installation task, y Freqtrade can also be installed with Miniconda or Anaconda. We recommend using Miniconda as it's installation footprint is smaller. Conda will automatically prepare and manage the extensive library-dependencies of the Freqtrade program. -##### What is Conda? +### What is Conda? -It is: (1) package, (2) dependency and (3) environment management for any programming language : https://docs.conda.io/projects/conda/en/latest/index.html +Conda is a package, dependency and environment manager for multiple programming languages: [conda docs](https://docs.conda.io/projects/conda/en/latest/index.html) - -### Installation +### Installation with conda #### Install Conda @@ -300,7 +269,7 @@ git clone https://github.com/freqtrade/freqtrade.git cd freqtrade ``` -#### Freqtrade install : Conda Environment +#### Freqtrade instal: Conda Environment Prepare conda-freqtrade environment, using file `environment.yml`, which exist in main freqtrade directory @@ -308,7 +277,18 @@ Prepare conda-freqtrade environment, using file `environment.yml`, which exist i conda env create -n freqtrade-conda -f environment.yml ``` -#### Enter/exit freqtrade-conda venv: +!!! Note "Creating Conda Environment" + The conda command `create -n` automatically installs all nested dependencies for the selected libraries, general structure of installation command is: + + ```bash + # choose your own packages + conda env create -n [name of the environment] [python version] [packages] + + # point to file with packages + conda env create -n [name of the environment] -f [file] + ``` + +#### Enter/exit freqtrade-conda environment To check available environments, type @@ -322,7 +302,7 @@ Enter installed environment # enter conda environment conda activate freqtrade-conda -# exit conda environment - don`t do it now +# exit conda environment - don't do it now conda deactivate ``` @@ -333,10 +313,8 @@ python3 -m pip install --upgrade pip python3 -m pip install -e . ``` +### Congratulations -### Bravo! - -Click: [You are ready](#you-are-ready), and run the bot ### Important shortcuts @@ -355,74 +333,30 @@ conda activate freqtrade-conda conda deactivate ``` -### Notes - -#### Set of Notes 1 - Conda Settings - -After opening terminal, you already will be in default `base` conda environment. -If you want, you can prevent the (base) conda environment from being activated automatically. - -```bash -conda config --set auto_activate_base false -``` - -Channel `conda-forge` is supposingly best source of the conda updates. Switch to it - -```bash -# adding forge -conda config --env --add channels conda-forge - -# make it strict -conda config --env --set channel_priority strict - -# check status of your conda -conda info -conda config --show channels -conda config --show channel_priority -``` - -Further read on the topic: - -https://towardsdatascience.com/a-guide-to-conda-environments-bc6180fc533?gi=1db972389cd1 - -#### Set of Notes 2 - Conda Environment - -!!! Note "Creating Conda Environment" - The conda command `create -n` automatically installs all nested dependencies for the selected libraries, general structure of installation command is: - -```bash -# choose your own packages -conda env create -n [name of the environment] [python version] [packages] - -# point to file with packages -conda env create -n [name of the environment] -f [file] -``` +### Further info on anaconda !!! Info "New heavy packages" - It may happen that creating a new Conda environment, populated with selected packages at the moment of creation, takes less time than installing a large, heavy dependent, GUI package, into previously set environment. Great example: Spyder + It may happen that creating a new Conda environment, populated with selected packages at the moment of creation takes less time than installing a large, heavy library or application, into previously set environment. !!! Warning "pip install within conda" - Please read the section [Market order pricing](#market-order-pricing) section when using market orders. - The documentation of conda says that pip should NOT be used within conda, because internal problems can occur. - However, they are rare. https://www.anaconda.com/blog/using-pip-in-a-conda-environment + However, they are rare. [Anaconda Blogpost](https://www.anaconda.com/blog/using-pip-in-a-conda-environment) - Nevertherless, that is why, the `conda-forge` channel is preferred: + Nevertheless, that is why, the `conda-forge` channel is preferred: * more libraries are available (less need for `pip`) * `conda-forge` works better with `pip` * the libraries are newer - Happy trading! ----- ## You are ready -You had installed the bot +You've made it this far, so you have successfully installed freqtrade. -#### Initialize the configuration +### Initialize the configuration ```bash # Step 1 - Initialize user folder @@ -432,19 +366,24 @@ freqtrade create-userdir --userdir user_data freqtrade new-config --config config.json ``` -You are ready to run, read [Bot Configuration](configuration.md), remember to run program as `dry_run: True` and verify that everything is working. +You are ready to run, read [Bot Configuration](configuration.md), remember to start with `dry_run: True` and verify that everything is working. +To learn how to setup your configuration, please refer to the [Bot Configuration](configuration.md) documentation page. -> *To edit the config please refer to [Bot Configuration](configuration.md).* - - -#### Run the Bot +### Start the Bot ```bash -freqtrade trade -c config.json +freqtrade trade --config config.json --strategy SampleStrategy ``` -#### Problem? +!!! Warning + You should read through the rest of the documentation, backtest the strategy you're going to use, and use dry-run before enabling trading with real money. + +----- + +## Troubleshooting + +### Common problem: "command not found" If you used (1)`Script` or (2)`Manual` installation, you need to run the bot in virtual environment. If you get error as below, make sure venv is active. @@ -456,9 +395,6 @@ bash: freqtrade: command not found source ./.env/bin/activate ``` ------ -## Troubleshooting - ### MacOS installation error Newer versions of MacOS may have installation failed with errors like `error: command 'g++' failed with exit status 1`. @@ -484,8 +420,3 @@ brew install hdf5 c-blosc ``` After this, please run the installation (script) again. - ------ - -Now you have an environment ready, the next step is -[Bot Configuration](configuration.md). From 5d18289821eb05229d19f390dc5f81b7ce4ec251 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 30 Jan 2021 07:17:25 +0100 Subject: [PATCH 034/158] Fix name in issue template --- .github/ISSUE_TEMPLATE/question.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index f87b78f29..fd3d7df93 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,5 +1,5 @@ --- -name: BQuestion +name: Question about: Ask a question you could not find an answer in the docs title: '' labels: "Question" From 406682c3bb93dd527528077e6d278d907c8ce9bb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 30 Jan 2021 10:20:40 +0100 Subject: [PATCH 035/158] Fix random api failure in slow cases --- tests/rpc/test_rpc_apiserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index f5b9a58f3..b050e5694 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -588,7 +588,7 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, li rc = client_get(client, f"{BASE_URI}/profit") assert_response(rc) - assert rc.json() == {'avg_duration': '0:00:00', + assert rc.json() == {'avg_duration': ANY, 'best_pair': 'ETH/BTC', 'best_rate': 6.2, 'first_trade_date': 'just now', From 6b63129eb011f7ceb171c21fbd9c58e82d8e2bf5 Mon Sep 17 00:00:00 2001 From: andre-ac <47426123+andre-ac@users.noreply.github.com> Date: Sat, 30 Jan 2021 15:36:59 +0000 Subject: [PATCH 036/158] Fixed virtualenv link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db648198f..51a3409ea 100644 --- a/README.md +++ b/README.md @@ -191,5 +191,5 @@ To run this bot we recommend you a cloud instance with a minimum of: - [pip](https://pip.pypa.io/en/stable/installing/) - [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) - [TA-Lib](https://mrjbq7.github.io/ta-lib/install.html) -- [virtualenv](https://virtualenv.pypa.io/en/stable/installation/) (Recommended) +- [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended) - [Docker](https://www.docker.com/products/docker) (Recommended) From 30e5c01cb113baf6cb0f60b4987bd079cf8e1e42 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 30 Jan 2021 19:59:14 +0100 Subject: [PATCH 037/158] Improve formatting of custom_stoploss docs --- docs/strategy-advanced.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/strategy-advanced.md b/docs/strategy-advanced.md index 25d217d34..ca20d3588 100644 --- a/docs/strategy-advanced.md +++ b/docs/strategy-advanced.md @@ -33,8 +33,8 @@ class AwesomeStrategy(IStrategy): use_custom_stoploss = True - def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, - current_profit: float, **kwargs) -> float: + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: """ Custom stoploss logic, returning the new distance relative to current_rate (as ratio). e.g. returning -0.05 would create a stoploss 5% below current_rate. @@ -83,8 +83,8 @@ class AwesomeStrategy(IStrategy): use_custom_stoploss = True - def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, **kwargs) -> float: + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: # Make sure you have the longest interval first - these conditions are evaluated from top to bottom. if current_time - timedelta(minutes=120) > trade.open_date: @@ -109,8 +109,8 @@ class AwesomeStrategy(IStrategy): use_custom_stoploss = True - def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, **kwargs) -> float: + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: if pair in ('ETH/BTC', 'XRP/BTC'): return -0.10 @@ -135,8 +135,8 @@ class AwesomeStrategy(IStrategy): use_custom_stoploss = True - def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, **kwargs) -> float: + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: if current_profit < 0.04: return -1 # return a value bigger than the inital stoploss to keep using the inital stoploss @@ -167,8 +167,8 @@ class AwesomeStrategy(IStrategy): use_custom_stoploss = True - def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, - current_profit: float, **kwargs) -> float: + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: # Calculate as `-desired_stop_from_open + current_profit` to get the distance between current_profit and initial price if current_profit > 0.40: From 16dad8b6d4d4d40b8b1019f87612b8a27d37c243 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 30 Jan 2021 20:11:18 +0100 Subject: [PATCH 038/158] Allow custom_stoploss to cooperate with stoploss on exchange --- docs/configuration.md | 1 + freqtrade/freqtradebot.py | 3 +- freqtrade/resolvers/strategy_resolver.py | 1 + freqtrade/rpc/api_server/api_schemas.py | 1 + freqtrade/rpc/rpc.py | 1 + tests/test_freqtradebot.py | 103 +++++++++++++++++++++++ 6 files changed, 109 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 660dd6171..509214b9c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -136,6 +136,7 @@ Values set in the configuration file always overwrite values set in the strategy * `trailing_stop_positive` * `trailing_stop_positive_offset` * `trailing_only_offset_is_reached` +* `use_custom_stoploss` * `process_only_new_candles` * `order_types` * `order_time_in_force` diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f45d4cacc..d7116834a 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -998,7 +998,8 @@ class FreqtradeBot(LoggingMixin): logger.warning('Stoploss order was cancelled, but unable to recreate one.') # Finally we check if stoploss on exchange should be moved up because of trailing. - if stoploss_order and self.config.get('trailing_stop', False): + if stoploss_order and (self.config.get('trailing_stop', False) + or self.config.get('use_custom_stoploss', False)): # if trailing stoploss is enabled we check if stoploss value has changed # in which case we cancel stoploss order and put another one with new # value immediately diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 26a316873..b1b66e3ae 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -68,6 +68,7 @@ class StrategyResolver(IResolver): ("trailing_stop_positive", None, None), ("trailing_stop_positive_offset", 0.0, None), ("trailing_only_offset_is_reached", None, None), + ("use_custom_stoploss", None, None), ("process_only_new_candles", None, None), ("order_types", None, None), ("order_time_in_force", None, None), diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index c9e8aaceb..4faefb5fc 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -123,6 +123,7 @@ class ShowConfig(BaseModel): trailing_stop_positive: Optional[float] trailing_stop_positive_offset: Optional[float] trailing_only_offset_is_reached: Optional[bool] + use_custom_stoploss: Optional[bool] timeframe: str timeframe_ms: int timeframe_min: int diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 92cd6caf9..c5166c35e 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -129,6 +129,7 @@ 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'), + 'use_custom_stoploss': config.get('use_custom_stoploss'), 'bot_name': config.get('bot_name', 'freqtrade'), 'timeframe': config.get('timeframe'), 'timeframe_ms': timeframe_to_msecs(config['timeframe'] diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 06c08075b..2408afc87 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1570,6 +1570,109 @@ def test_handle_stoploss_on_exchange_trailing_error(mocker, default_conf, fee, c assert log_has_re(r"Could not create trailing stoploss order for pair ETH/BTC\..*", caplog) +@pytest.mark.usefixtures("init_persistence") +def test_handle_stoploss_on_exchange_custom_stop(mocker, default_conf, fee, + limit_buy_order, limit_sell_order) -> None: + # When trailing stoploss is set + stoploss = MagicMock(return_value={'id': 13434334}) + patch_RPCManager(mocker) + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + fetch_ticker=MagicMock(return_value={ + 'bid': 0.00001172, + 'ask': 0.00001173, + 'last': 0.00001172 + }), + buy=MagicMock(return_value={'id': limit_buy_order['id']}), + sell=MagicMock(return_value={'id': limit_sell_order['id']}), + get_fee=fee, + stoploss=stoploss, + stoploss_adjust=MagicMock(return_value=True), + ) + + # enabling TSL + default_conf['use_custom_stoploss'] = True + + # disabling ROI + default_conf['minimal_roi']['0'] = 999999999 + + freqtrade = get_patched_freqtradebot(mocker, default_conf) + + # enabling stoploss on exchange + freqtrade.strategy.order_types['stoploss_on_exchange'] = True + + # setting stoploss + freqtrade.strategy.custom_stoploss = lambda *args, **kwargs: -0.04 + + # setting stoploss_on_exchange_interval to 60 seconds + freqtrade.strategy.order_types['stoploss_on_exchange_interval'] = 60 + + patch_get_signal(freqtrade) + + freqtrade.enter_positions() + trade = Trade.query.first() + trade.is_open = True + trade.open_order_id = None + trade.stoploss_order_id = 100 + + stoploss_order_hanging = MagicMock(return_value={ + 'id': 100, + 'status': 'open', + 'type': 'stop_loss_limit', + 'price': 3, + 'average': 2, + 'info': { + 'stopPrice': '0.000011134' + } + }) + + mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', stoploss_order_hanging) + + assert freqtrade.handle_trade(trade) is False + assert freqtrade.handle_stoploss_on_exchange(trade) is False + + # price jumped 2x + mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ + 'bid': 0.00002344, + 'ask': 0.00002346, + 'last': 0.00002344 + })) + + cancel_order_mock = MagicMock() + stoploss_order_mock = MagicMock(return_value={'id': 13434334}) + mocker.patch('freqtrade.exchange.Exchange.cancel_stoploss_order', cancel_order_mock) + mocker.patch('freqtrade.exchange.Exchange.stoploss', stoploss_order_mock) + + # stoploss should not be updated as the interval is 60 seconds + assert freqtrade.handle_trade(trade) is False + assert freqtrade.handle_stoploss_on_exchange(trade) is False + cancel_order_mock.assert_not_called() + stoploss_order_mock.assert_not_called() + + assert freqtrade.handle_trade(trade) is False + assert trade.stop_loss == 0.00002346 * 0.96 + assert trade.stop_loss_pct == -0.04 + + # setting stoploss_on_exchange_interval to 0 seconds + freqtrade.strategy.order_types['stoploss_on_exchange_interval'] = 0 + + assert freqtrade.handle_stoploss_on_exchange(trade) is False + + cancel_order_mock.assert_called_once_with(100, 'ETH/BTC') + stoploss_order_mock.assert_called_once_with(amount=85.32423208, + pair='ETH/BTC', + order_types=freqtrade.strategy.order_types, + stop_price=0.00002346 * 0.96) + + # price fell below stoploss, so dry-run sells trade. + mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', MagicMock(return_value={ + 'bid': 0.00002144, + 'ask': 0.00002146, + 'last': 0.00002144 + })) + assert freqtrade.handle_trade(trade) is True + + def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, limit_buy_order, limit_sell_order) -> None: From 4cc93151c5266f77298989262def6778bb85a63f Mon Sep 17 00:00:00 2001 From: Pan Long Date: Sun, 31 Jan 2021 12:14:09 +0800 Subject: [PATCH 039/158] Fix a bug when compare sell_profit_offset It should be comparing the ratio instead of absolut profit. Also updated the comment. --- freqtrade/strategy/interface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index c58d9aa5d..77d45b445 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -530,8 +530,8 @@ class IStrategy(ABC): current_time=date)) if (ask_strategy.get('sell_profit_only', False) - and trade.calc_profit(rate=rate) <= ask_strategy.get('sell_profit_offset', 0)): - # Negative profits and sell_profit_only - ignore sell signal + and trade.calc_profit_ratio(rate=rate) <= ask_strategy.get('sell_profit_offset', 0)): + # sell_profit_only and profit doesn't reach the offset - ignore sell signal sell_signal = False else: sell_signal = sell and not buy and ask_strategy.get('use_sell_signal', True) From bc586fe73b40548e92676d1dd251d1ec383d08e8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 10:29:43 +0100 Subject: [PATCH 040/158] Try fix CI --- build_helpers/install_windows.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_helpers/install_windows.ps1 b/build_helpers/install_windows.ps1 index 5747db335..2025a1a44 100644 --- a/build_helpers/install_windows.ps1 +++ b/build_helpers/install_windows.ps1 @@ -2,7 +2,7 @@ # Downloaded from https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib # Invoke-WebRequest -Uri "https://download.lfd.uci.edu/pythonlibs/xxxxxxx/TA_Lib-0.4.17-cp37-cp37m-win_amd64.whl" -OutFile "TA_Lib-0.4.17-cp37-cp37m-win_amd64.whl" -python -m pip install --upgrade pip +python -m pip install --upgrade pip==21.0.0 $pyv = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" From 92721db583f690d65f300d5d61aa5e11f1727056 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 10:39:37 +0100 Subject: [PATCH 041/158] Version bump numpy to 1.20.0 --- build_helpers/install_windows.ps1 | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build_helpers/install_windows.ps1 b/build_helpers/install_windows.ps1 index 2025a1a44..5747db335 100644 --- a/build_helpers/install_windows.ps1 +++ b/build_helpers/install_windows.ps1 @@ -2,7 +2,7 @@ # Downloaded from https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib # Invoke-WebRequest -Uri "https://download.lfd.uci.edu/pythonlibs/xxxxxxx/TA_Lib-0.4.17-cp37-cp37m-win_amd64.whl" -OutFile "TA_Lib-0.4.17-cp37-cp37m-win_amd64.whl" -python -m pip install --upgrade pip==21.0.0 +python -m pip install --upgrade pip $pyv = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" diff --git a/requirements.txt b/requirements.txt index cc8861d82..c6cb3e445 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy==1.19.5 +numpy==1.20.0 pandas==1.2.1 ccxt==1.40.99 From 5724371a4ff9087a9adb95895e1f829102ceb033 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 11:21:23 +0100 Subject: [PATCH 042/158] Fix types for numpy 1.20.0 upgrade --- freqtrade/data/btanalysis.py | 2 +- freqtrade/misc.py | 15 --------------- freqtrade/rpc/rpc.py | 4 ++-- tests/test_misc.py | 24 +++--------------------- 4 files changed, 6 insertions(+), 39 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index b7c8529ac..828fb78f3 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -312,7 +312,7 @@ def calculate_market_change(data: Dict[str, pd.DataFrame], column: str = "close" end = df[column].dropna().iloc[-1] tmp_means.append((end - start) / start) - return np.mean(tmp_means) + return float(np.mean(tmp_means)) def combine_dataframes_with_mean(data: Dict[str, pd.DataFrame], diff --git a/freqtrade/misc.py b/freqtrade/misc.py index 359d0d0e4..22e14b564 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -9,7 +9,6 @@ from pathlib import Path from typing import Any from typing.io import IO -import numpy as np import rapidjson @@ -28,20 +27,6 @@ def shorten_date(_date: str) -> str: return new_date -############################################ -# Used by scripts # -# Matplotlib doesn't support ::datetime64, # -# so we need to convert it into ::datetime # -############################################ -def datesarray_to_datetimearray(dates: np.ndarray) -> np.ndarray: - """ - Convert an pandas-array of timestamps into - An numpy-array of datetimes - :return: numpy-array of datetime - """ - return dates.dt.to_pydatetime() - - def file_dump_json(filename: Path, data: Any, is_zip: bool = False, log: bool = True) -> None: """ Dump JSON data into a file diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index c5166c35e..491d1cde6 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -378,7 +378,7 @@ class RPC: # Prepare data to display profit_closed_coin_sum = round(sum(profit_closed_coin), 8) - profit_closed_ratio_mean = mean(profit_closed_ratio) if profit_closed_ratio else 0.0 + profit_closed_ratio_mean = float(mean(profit_closed_ratio) if profit_closed_ratio else 0.0) profit_closed_ratio_sum = sum(profit_closed_ratio) if profit_closed_ratio else 0.0 profit_closed_fiat = self._fiat_converter.convert_amount( @@ -388,7 +388,7 @@ class RPC: ) if self._fiat_converter else 0 profit_all_coin_sum = round(sum(profit_all_coin), 8) - profit_all_ratio_mean = mean(profit_all_ratio) if profit_all_ratio else 0.0 + profit_all_ratio_mean = float(mean(profit_all_ratio) if profit_all_ratio else 0.0) profit_all_ratio_sum = sum(profit_all_ratio) if profit_all_ratio else 0.0 profit_all_fiat = self._fiat_converter.convert_amount( profit_all_coin_sum, diff --git a/tests/test_misc.py b/tests/test_misc.py index 6dcd9fbe5..429da135a 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -6,11 +6,9 @@ from unittest.mock import MagicMock import pytest -from freqtrade.data.converter import ohlcv_to_dataframe -from freqtrade.misc import (datesarray_to_datetimearray, file_dump_json, file_load_json, - format_ms_time, pair_to_filename, plural, render_template, - render_template_with_fallback, safe_value_fallback, - safe_value_fallback2, shorten_date) +from freqtrade.misc import (file_dump_json, file_load_json, format_ms_time, pair_to_filename, + plural, render_template, render_template_with_fallback, + safe_value_fallback, safe_value_fallback2, shorten_date) def test_shorten_date() -> None: @@ -19,22 +17,6 @@ def test_shorten_date() -> None: assert shorten_date(str_data) == str_shorten_data -def test_datesarray_to_datetimearray(ohlcv_history_list): - dataframes = ohlcv_to_dataframe(ohlcv_history_list, "5m", pair="UNITTEST/BTC", - fill_missing=True) - dates = datesarray_to_datetimearray(dataframes['date']) - - assert isinstance(dates[0], datetime.datetime) - assert dates[0].year == 2017 - assert dates[0].month == 11 - assert dates[0].day == 26 - assert dates[0].hour == 8 - assert dates[0].minute == 50 - - date_len = len(dates) - assert date_len == 2 - - def test_file_dump_json(mocker) -> None: file_open = mocker.patch('freqtrade.misc.open', MagicMock()) json_dump = mocker.patch('rapidjson.dump', MagicMock()) From 79087ba1662e41010b3ccb6554613b5d93dd26b5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 14:50:39 +0100 Subject: [PATCH 043/158] Fix intermitted test failure --- tests/commands/test_commands.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 2284209a0..f8ecc8218 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -822,6 +822,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--no-details", + "--no-color", ] pargs = get_args(args) pargs['config'] = None @@ -835,6 +836,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): "hyperopt-list", "--best", "--no-details", + "--no-color", ] pargs = get_args(args) pargs['config'] = None @@ -849,6 +851,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): "hyperopt-list", "--profitable", "--no-details", + "--no-color", ] pargs = get_args(args) pargs['config'] = None @@ -862,6 +865,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--profitable", + "--no-color", ] pargs = get_args(args) pargs['config'] = None @@ -891,6 +895,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): "hyperopt-list", "--profitable", "--no-details", + "--no-color", "--max-trades", "20", ] pargs = get_args(args) @@ -906,6 +911,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): "hyperopt-list", "--profitable", "--no-details", + "--no-color", "--min-avg-profit", "0.11", ] pargs = get_args(args) @@ -920,6 +926,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--no-details", + "--no-color", "--max-avg-profit", "0.10", ] pargs = get_args(args) @@ -934,6 +941,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--no-details", + "--no-color", "--min-total-profit", "0.4", ] pargs = get_args(args) @@ -948,6 +956,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--no-details", + "--no-color", "--max-total-profit", "0.4", ] pargs = get_args(args) @@ -962,6 +971,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--no-details", + "--no-color", "--min-objective", "0.1", ] pargs = get_args(args) @@ -991,6 +1001,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): "hyperopt-list", "--profitable", "--no-details", + "--no-color", "--min-avg-time", "2000", ] pargs = get_args(args) @@ -1005,6 +1016,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--no-details", + "--no-color", "--max-avg-time", "1500", ] pargs = get_args(args) @@ -1019,6 +1031,7 @@ def test_hyperopt_list(mocker, capsys, caplog, hyperopt_results): args = [ "hyperopt-list", "--no-details", + "--no-color", "--export-csv", "test_file.csv", ] pargs = get_args(args) From 27970b424d96a9e0369c47d0586c78840cbcdd83 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jan 2021 10:31:05 +0100 Subject: [PATCH 044/158] Add webUI serving to api-server --- .gitignore | 1 + freqtrade/rpc/api_server/ui/.gitkeep | 0 freqtrade/rpc/api_server/web_ui.py | 28 +++++++++++++++++++++++++++ freqtrade/rpc/api_server/webserver.py | 4 ++++ requirements.txt | 1 + tests/rpc/test_rpc_apiserver.py | 2 +- 6 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 freqtrade/rpc/api_server/ui/.gitkeep create mode 100644 freqtrade/rpc/api_server/web_ui.py diff --git a/.gitignore b/.gitignore index f206fce66..4720ff5cb 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ user_data/* user_data/notebooks/* freqtrade-plot.html freqtrade-profit-plot.html +freqtrade/rpc/api_server/ui/* # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/freqtrade/rpc/api_server/ui/.gitkeep b/freqtrade/rpc/api_server/ui/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/freqtrade/rpc/api_server/web_ui.py b/freqtrade/rpc/api_server/web_ui.py new file mode 100644 index 000000000..971f9e4de --- /dev/null +++ b/freqtrade/rpc/api_server/web_ui.py @@ -0,0 +1,28 @@ +from pathlib import Path + +from fastapi import APIRouter +from fastapi.exceptions import HTTPException +from starlette.responses import FileResponse + + +router_ui = APIRouter() + + +@router_ui.get('/favicon.ico', include_in_schema=False) +async def favicon(): + return FileResponse(Path(__file__).parent / 'ui/favicon.ico') + + +@router_ui.get('/{rest_of_path:path}', include_in_schema=False) +async def index_html(rest_of_path: str): + """ + Emulate path fallback to index.html. + """ + if rest_of_path.startswith('api') or rest_of_path.startswith('.'): + raise HTTPException(status_code=404, detail="Not Found") + uibase = Path(__file__).parent / 'ui' + if (uibase / rest_of_path).is_file(): + return FileResponse(uibase / rest_of_path) + + # Fall back to index.html, as indicated by vue router docs + return FileResponse(uibase / 'index.html') diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index 9c0779274..f3eaa1ebc 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -57,12 +57,16 @@ class ApiServer(RPCHandler): from freqtrade.rpc.api_server.api_auth import http_basic_or_jwt_token, router_login from freqtrade.rpc.api_server.api_v1 import router as api_v1 from freqtrade.rpc.api_server.api_v1 import router_public as api_v1_public + from freqtrade.rpc.api_server.web_ui import router_ui + app.include_router(api_v1_public, prefix="/api/v1") app.include_router(api_v1, prefix="/api/v1", dependencies=[Depends(http_basic_or_jwt_token)], ) app.include_router(router_login, prefix="/api/v1", tags=["auth"]) + # UI Router MUST be last! + app.include_router(router_ui, prefix='') app.add_middleware( CORSMiddleware, diff --git a/requirements.txt b/requirements.txt index c6cb3e445..5993fb3f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,6 +31,7 @@ sdnotify==0.3.2 fastapi==0.63.0 uvicorn==0.13.3 pyjwt==2.0.1 +aiofiles==0.6.0 # Support for colorized terminal output colorama==0.4.4 diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index b050e5694..919481598 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -83,7 +83,7 @@ def assert_response(response, expected_code=200, needs_cors=True): def test_api_not_found(botclient): ftbot, client = botclient - rc = client_post(client, f"{BASE_URI}/invalid_url") + rc = client_get(client, f"{BASE_URI}/invalid_url") assert_response(rc, 404) assert rc.json() == {"detail": "Not Found"} From a47616eed4648ad4b7331251c79b85354bba62d3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jan 2021 13:55:16 +0100 Subject: [PATCH 045/158] Add UI installation subcommand --- freqtrade/commands/__init__.py | 4 +- freqtrade/commands/arguments.py | 12 +++++- freqtrade/commands/deploy_commands.py | 54 +++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/freqtrade/commands/__init__.py b/freqtrade/commands/__init__.py index 21c5d6812..784b99bed 100644 --- a/freqtrade/commands/__init__.py +++ b/freqtrade/commands/__init__.py @@ -10,8 +10,8 @@ from freqtrade.commands.arguments import Arguments from freqtrade.commands.build_config_commands import start_new_config from freqtrade.commands.data_commands import (start_convert_data, start_download_data, start_list_data) -from freqtrade.commands.deploy_commands import (start_create_userdir, start_new_hyperopt, - start_new_strategy) +from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui, + start_new_hyperopt, start_new_strategy) from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show from freqtrade.commands.list_commands import (start_list_exchanges, start_list_hyperopts, start_list_markets, start_list_strategies, diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index a6c8a245f..b39c75640 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -167,8 +167,8 @@ class Arguments: from freqtrade.commands import (start_backtesting, start_convert_data, start_create_userdir, start_download_data, start_edge, start_hyperopt, - start_hyperopt_list, start_hyperopt_show, start_list_data, - start_list_exchanges, start_list_hyperopts, + start_hyperopt_list, start_hyperopt_show, start_install_ui, + start_list_data, start_list_exchanges, start_list_hyperopts, start_list_markets, start_list_strategies, start_list_timeframes, start_new_config, start_new_hyperopt, start_new_strategy, start_plot_dataframe, start_plot_profit, @@ -355,6 +355,14 @@ class Arguments: test_pairlist_cmd.set_defaults(func=start_test_pairlist) self._build_args(optionlist=ARGS_TEST_PAIRLIST, parser=test_pairlist_cmd) + # Add install-ui subcommand + install_ui_cmd = subparsers.add_parser( + 'install-ui', + help='Install FreqUI', + ) + install_ui_cmd.set_defaults(func=start_install_ui) + self._build_args(optionlist=[], parser=install_ui_cmd) + # Add Plotting subcommand plot_dataframe_cmd = subparsers.add_parser( 'plot-dataframe', diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index a0105e140..b43ad5970 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -137,3 +137,57 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: deploy_new_hyperopt(args['hyperopt'], new_path, args['template']) else: raise OperationalException("`new-hyperopt` requires --hyperopt to be set.") + + +def clean_ui_subdir(directory: Path): + print(directory) + if directory.is_dir(): + logger.info("Removing UI directory content") + + for p in reversed(list(directory.glob('**/*'))): # iterate contents from leaves to root + if p.name == '.gitkeep': + continue + if p.is_file(): + p.unlink() + elif p.is_dir(): + p.rmdir() + + +def download_and_install_ui(dest_folder: Path): + import requests + from io import BytesIO + from zipfile import ZipFile + + base_url = 'https://api.github.com/repos/freqtrade/frequi/' + # Get base UI Repo path + + resp = requests.get(f"{base_url}releases") + resp.raise_for_status() + r = resp.json() + + assets = r[0]['assets_url'] + resp = requests.get(assets) + r = resp.json() + + dl_url = r[0]['browser_download_url'] + logger.info(f"Downloading {dl_url}") + resp = requests.get(dl_url).content + with ZipFile(BytesIO(resp)) as zf: + for fn in zf.filelist: + with zf.open(fn) as x: + destfile = dest_folder / fn.filename + print(destfile) + if fn.is_dir(): + destfile.mkdir(exist_ok=True) + else: + destfile.write_bytes(x.read()) + + +def start_install_ui(args: Dict[str, Any]) -> None: + + dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' + # First make sure the assets are removed. + clean_ui_subdir(dest_folder) + + # Download a new version + download_and_install_ui(dest_folder) From 87ed2d750205d0e1b10a7c185f853cbb13a51d9d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jan 2021 14:06:06 +0100 Subject: [PATCH 046/158] Write some tests for UI Downloading --- freqtrade/commands/deploy_commands.py | 46 +++++++++---------- tests/commands/test_commands.py | 65 ++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 29 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index b43ad5970..e951c962f 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -3,6 +3,8 @@ import sys from pathlib import Path from typing import Any, Dict +import requests + from freqtrade.configuration import setup_utils_configuration from freqtrade.configuration.directory_operations import copy_sample_files, create_userdata_dir from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES @@ -140,9 +142,8 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: def clean_ui_subdir(directory: Path): - print(directory) if directory.is_dir(): - logger.info("Removing UI directory content") + logger.info("Removing UI directory content.") for p in reversed(list(directory.glob('**/*'))): # iterate contents from leaves to root if p.name == '.gitkeep': @@ -153,11 +154,28 @@ def clean_ui_subdir(directory: Path): p.rmdir() -def download_and_install_ui(dest_folder: Path): - import requests +def download_and_install_ui(dest_folder: Path, dl_url: str): from io import BytesIO from zipfile import ZipFile + logger.info(f"Downloading {dl_url}") + resp = requests.get(dl_url).content + with ZipFile(BytesIO(resp)) as zf: + for fn in zf.filelist: + with zf.open(fn) as x: + destfile = dest_folder / fn.filename + if fn.is_dir(): + destfile.mkdir(exist_ok=True) + else: + destfile.write_bytes(x.read()) + + +def start_install_ui(args: Dict[str, Any]) -> None: + + dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' + # First make sure the assets are removed. + clean_ui_subdir(dest_folder) + base_url = 'https://api.github.com/repos/freqtrade/frequi/' # Get base UI Repo path @@ -170,24 +188,6 @@ def download_and_install_ui(dest_folder: Path): r = resp.json() dl_url = r[0]['browser_download_url'] - logger.info(f"Downloading {dl_url}") - resp = requests.get(dl_url).content - with ZipFile(BytesIO(resp)) as zf: - for fn in zf.filelist: - with zf.open(fn) as x: - destfile = dest_folder / fn.filename - print(destfile) - if fn.is_dir(): - destfile.mkdir(exist_ok=True) - else: - destfile.write_bytes(x.read()) - - -def start_install_ui(args: Dict[str, Any]) -> None: - - dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' - # First make sure the assets are removed. - clean_ui_subdir(dest_folder) # Download a new version - download_and_install_ui(dest_folder) + download_and_install_ui(dest_folder, dl_url) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index f8ecc8218..12d18b3a7 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,16 +1,19 @@ +from io import BytesIO import re from pathlib import Path from unittest.mock import MagicMock, PropertyMock +from zipfile import ZipFile import arrow import pytest from freqtrade.commands import (start_convert_data, start_create_userdir, start_download_data, - start_hyperopt_list, start_hyperopt_show, start_list_data, - start_list_exchanges, start_list_hyperopts, start_list_markets, - start_list_strategies, start_list_timeframes, start_new_hyperopt, - start_new_strategy, start_show_trades, start_test_pairlist, - start_trading) + start_hyperopt_list, start_hyperopt_show, start_install_ui, + start_list_data, start_list_exchanges, start_list_hyperopts, + start_list_markets, start_list_strategies, start_list_timeframes, + start_new_hyperopt, start_new_strategy, start_show_trades, + start_test_pairlist, start_trading) +from freqtrade.commands.deploy_commands import clean_ui_subdir, download_and_install_ui from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode @@ -546,7 +549,7 @@ def test_start_new_hyperopt_DefaultHyperopt(mocker, caplog): start_new_hyperopt(get_args(args)) -def test_start_new_hyperopt_no_arg(mocker, caplog): +def test_start_new_hyperopt_no_arg(mocker): args = [ "new-hyperopt", ] @@ -555,6 +558,56 @@ def test_start_new_hyperopt_no_arg(mocker, caplog): start_new_hyperopt(get_args(args)) +def test_start_install_ui(mocker): + clean_mock = mocker.patch('freqtrade.commands.deploy_commands.clean_ui_subdir') + download_mock = mocker.patch('freqtrade.commands.deploy_commands.download_and_install_ui') + args = [ + "install-ui", + ] + start_install_ui(args) + assert clean_mock.call_count == 1 + + assert download_mock.call_count == 1 + + +def test_clean_ui_subdir(mocker, tmpdir, caplog): + mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", + side_effect=[True, True]) + mocker.patch("freqtrade.commands.deploy_commands.Path.is_file", + side_effect=[False, True]) + rd_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.rmdir") + ul_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.unlink") + + mocker.patch("freqtrade.commands.deploy_commands.Path.glob", + return_value=[Path('test1'), Path('test2'), Path('.gitkeep')]) + folder = Path(tmpdir) / "uitests" + clean_ui_subdir(folder) + assert log_has("Removing UI directory content.", caplog) + assert rd_mock.call_count == 1 + assert ul_mock.call_count == 1 + + +def test_download_and_install_ui(mocker, tmpdir, caplog): + # Should be something "zip-like" + requests_mock = MagicMock() + file_like_object = BytesIO() + with ZipFile(file_like_object, mode='w') as zipfile: + for file in ('test1.txt', 'hello/', 'test2.txt'): + zipfile.writestr(file, file) + file_like_object.seek(0) + requests_mock.content = file_like_object.read() + mocker.patch("freqtrade.commands.deploy_commands.requests.get", return_value=requests_mock) + mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", + side_effect=[True, False]) + mkdir_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.mkdir") + wb_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.write_bytes") + folder = Path(tmpdir) / "uitests_dl" + download_and_install_ui(folder, 'http://whatever.xxx') + + assert mkdir_mock.call_count == 1 + assert wb_mock.call_count == 2 + + def test_download_data_keyboardInterrupt(mocker, caplog, markets): dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(side_effect=KeyboardInterrupt)) From a1a35115ad7a1c5610920c628ff82fe71b842c67 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jan 2021 14:46:59 +0100 Subject: [PATCH 047/158] Extract get_ui_download_url --- freqtrade/commands/deploy_commands.py | 17 +++++++++++------ tests/commands/test_commands.py | 10 +++++++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index e951c962f..174f1bb59 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -170,12 +170,7 @@ def download_and_install_ui(dest_folder: Path, dl_url: str): destfile.write_bytes(x.read()) -def start_install_ui(args: Dict[str, Any]) -> None: - - dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' - # First make sure the assets are removed. - clean_ui_subdir(dest_folder) - +def get_ui_download_url() -> str: base_url = 'https://api.github.com/repos/freqtrade/frequi/' # Get base UI Repo path @@ -188,6 +183,16 @@ def start_install_ui(args: Dict[str, Any]) -> None: r = resp.json() dl_url = r[0]['browser_download_url'] + return dl_url + + +def start_install_ui(args: Dict[str, Any]) -> None: + + dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' + # First make sure the assets are removed. + clean_ui_subdir(dest_folder) + + dl_url = get_ui_download_url() # Download a new version download_and_install_ui(dest_folder, dl_url) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 12d18b3a7..a39044c18 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -560,13 +560,14 @@ def test_start_new_hyperopt_no_arg(mocker): def test_start_install_ui(mocker): clean_mock = mocker.patch('freqtrade.commands.deploy_commands.clean_ui_subdir') + get_url_mock = mocker.patch('freqtrade.commands.deploy_commands.get_ui_download_url') download_mock = mocker.patch('freqtrade.commands.deploy_commands.download_and_install_ui') args = [ "install-ui", ] start_install_ui(args) assert clean_mock.call_count == 1 - + assert get_url_mock.call_count == 1 assert download_mock.call_count == 1 @@ -588,7 +589,7 @@ def test_clean_ui_subdir(mocker, tmpdir, caplog): def test_download_and_install_ui(mocker, tmpdir, caplog): - # Should be something "zip-like" + # Create zipfile requests_mock = MagicMock() file_like_object = BytesIO() with ZipFile(file_like_object, mode='w') as zipfile: @@ -596,13 +597,16 @@ def test_download_and_install_ui(mocker, tmpdir, caplog): zipfile.writestr(file, file) file_like_object.seek(0) requests_mock.content = file_like_object.read() + mocker.patch("freqtrade.commands.deploy_commands.requests.get", return_value=requests_mock) + mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", side_effect=[True, False]) mkdir_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.mkdir") wb_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.write_bytes") + folder = Path(tmpdir) / "uitests_dl" - download_and_install_ui(folder, 'http://whatever.xxx') + download_and_install_ui(folder, 'http://whatever.xxx/download/file.zip') assert mkdir_mock.call_count == 1 assert wb_mock.call_count == 2 From ddc99553bd422c250f1d9beba59fccd90211b999 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 10 Jan 2021 14:52:51 +0100 Subject: [PATCH 048/158] Add test case for get_ui_download_url --- tests/commands/test_commands.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index a39044c18..ba45f1618 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -13,7 +13,7 @@ from freqtrade.commands import (start_convert_data, start_create_userdir, start_ start_list_markets, start_list_strategies, start_list_timeframes, start_new_hyperopt, start_new_strategy, start_show_trades, start_test_pairlist, start_trading) -from freqtrade.commands.deploy_commands import clean_ui_subdir, download_and_install_ui +from freqtrade.commands.deploy_commands import clean_ui_subdir, download_and_install_ui, get_ui_download_url from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode @@ -588,7 +588,7 @@ def test_clean_ui_subdir(mocker, tmpdir, caplog): assert ul_mock.call_count == 1 -def test_download_and_install_ui(mocker, tmpdir, caplog): +def test_download_and_install_ui(mocker, tmpdir): # Create zipfile requests_mock = MagicMock() file_like_object = BytesIO() @@ -612,6 +612,18 @@ def test_download_and_install_ui(mocker, tmpdir, caplog): assert wb_mock.call_count == 2 +def test_get_ui_download_url(mocker): + response = MagicMock() + response.json = MagicMock( + side_effect=[[{'assets_url': 'http://whatever.json'}], + [{'browser_download_url': 'http://download.zip'}]]) + get_mock = mocker.patch("freqtrade.commands.deploy_commands.requests.get", + return_value=response) + x = get_ui_download_url() + assert get_mock.call_count == 2 + assert x == 'http://download.zip' + + def test_download_data_keyboardInterrupt(mocker, caplog, markets): dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(side_effect=KeyboardInterrupt)) From f05f2c45e89dc9dd394bd1165ce3e7451562f3a5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jan 2021 10:15:27 +0100 Subject: [PATCH 049/158] Allow deleting of UI only --- freqtrade/commands/arguments.py | 4 +++- freqtrade/commands/cli_options.py | 6 ++++++ freqtrade/commands/deploy_commands.py | 10 ++++++---- tests/commands/test_commands.py | 15 ++++++++++++++- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index b39c75640..c64c11a18 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -70,6 +70,8 @@ ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url", "trade_source", "timeframe"] +ARGS_INSTALL_UI = ["erase_ui_only"] + ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"] ARGS_HYPEROPT_LIST = ["hyperopt_list_best", "hyperopt_list_profitable", @@ -361,7 +363,7 @@ class Arguments: help='Install FreqUI', ) install_ui_cmd.set_defaults(func=start_install_ui) - self._build_args(optionlist=[], parser=install_ui_cmd) + self._build_args(optionlist=ARGS_INSTALL_UI, parser=install_ui_cmd) # Add Plotting subcommand plot_dataframe_cmd = subparsers.add_parser( diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 668b4abf5..7dc85377d 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -387,6 +387,12 @@ AVAILABLE_CLI_OPTIONS = { help='Clean all existing data for the selected exchange/pairs/timeframes.', action='store_true', ), + "erase_ui_only": Arg( + '--erase', + help="Clean UI folder, don't download new version.", + action='store_true', + default=False, + ), # Templating options "template": Arg( '--template', diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 174f1bb59..b9bda9c63 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -191,8 +191,10 @@ def start_install_ui(args: Dict[str, Any]) -> None: dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' # First make sure the assets are removed. clean_ui_subdir(dest_folder) + if args.get('erase_ui_only'): + logger.info("Erased UI directory content. Not downloading new version.") + else: + dl_url = get_ui_download_url() - dl_url = get_ui_download_url() - - # Download a new version - download_and_install_ui(dest_folder, dl_url) + # Download a new version + download_and_install_ui(dest_folder, dl_url) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index ba45f1618..fdc2b204b 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -565,11 +565,24 @@ def test_start_install_ui(mocker): args = [ "install-ui", ] - start_install_ui(args) + start_install_ui(get_args(args)) assert clean_mock.call_count == 1 assert get_url_mock.call_count == 1 assert download_mock.call_count == 1 + clean_mock.reset_mock() + get_url_mock.reset_mock() + download_mock.reset_mock() + + args = [ + "install-ui", + "--erase", + ] + start_install_ui(get_args(args)) + assert clean_mock.call_count == 1 + assert get_url_mock.call_count == 0 + assert download_mock.call_count == 0 + def test_clean_ui_subdir(mocker, tmpdir, caplog): mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", From e928d2991ddb4ff67aa2d52fda5caf78052e14b9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 16 Jan 2021 10:27:15 +0100 Subject: [PATCH 050/158] Add fallback file --- freqtrade/commands/deploy_commands.py | 2 +- .../rpc/api_server/ui/fallback_file.html | 31 +++++++++++++++++++ freqtrade/rpc/api_server/web_ui.py | 5 ++- 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 freqtrade/rpc/api_server/ui/fallback_file.html diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index b9bda9c63..8a8d2373e 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -146,7 +146,7 @@ def clean_ui_subdir(directory: Path): logger.info("Removing UI directory content.") for p in reversed(list(directory.glob('**/*'))): # iterate contents from leaves to root - if p.name == '.gitkeep': + if p.name in ('.gitkeep', 'fallback_file.html'): continue if p.is_file(): p.unlink() diff --git a/freqtrade/rpc/api_server/ui/fallback_file.html b/freqtrade/rpc/api_server/ui/fallback_file.html new file mode 100644 index 000000000..7943530af --- /dev/null +++ b/freqtrade/rpc/api_server/ui/fallback_file.html @@ -0,0 +1,31 @@ + + + + + + Freqtrade UI + + + +
+

Freqtrade UI not installed.

+

Please run `freqtrade install-ui` in your terminal to install the UI files and restart your bot.

+

You can then refresh this page and you should see the UI.

+
+ + diff --git a/freqtrade/rpc/api_server/web_ui.py b/freqtrade/rpc/api_server/web_ui.py index 971f9e4de..6d397da56 100644 --- a/freqtrade/rpc/api_server/web_ui.py +++ b/freqtrade/rpc/api_server/web_ui.py @@ -24,5 +24,8 @@ async def index_html(rest_of_path: str): if (uibase / rest_of_path).is_file(): return FileResponse(uibase / rest_of_path) + index_file = uibase / 'index.html' + if not index_file.is_file(): + return FileResponse(uibase / 'fallback_file.html') # Fall back to index.html, as indicated by vue router docs - return FileResponse(uibase / 'index.html') + return FileResponse(index_file) From 35c2e2556ece3cc93634f4435b6044374794850d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 25 Jan 2021 20:48:52 +0100 Subject: [PATCH 051/158] Document FreqUI usage --- docker-compose.yml | 5 ++++ docs/rest-api.md | 68 ++++++++++++++++++++++++++-------------------- mkdocs.yml | 2 +- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7094500b4..06cce4e8e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,11 @@ services: container_name: freqtrade volumes: - "./user_data:/freqtrade/user_data" + # Expose api on port 8080 (localhost only) + # Please read the https://www.freqtrade.io/en/latest/rest-api/ documentation + # before enabling this. + #ports: + # - "127.0.0.1:8080:8080" # Default command used when running `docker compose up` command: > trade diff --git a/docs/rest-api.md b/docs/rest-api.md index 2c7142c61..e2b94f080 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -1,4 +1,19 @@ -# REST API Usage +# REST API & FreqUI + +## FreqUI + +Freqtrade provides a builtin webserver, which can serve [FreqUI](https://github.com/freqtrade/frequi), the freqtrade UI. + +By default, the UI is not included in the installation (except for docker images), and must be installed explicitly with `freqtrade install-ui`. +This same command can also be used to update freqUI, should there be a new release. + +Once the bot is started in trade / dry-run mode (with `freqtrade trade`) - the UI will be available under the configured port below (usually `http://127.0.0.1:8080`). + +!!! info "Alpha release" + FreqUI is still considered an alpha release - if you encounter bugs or inconsistencies please open a [FreqUI issue](https://github.com/freqtrade/frequi/issues/new/choose). + +!!! Note "developers" + Developers should not use this method, but instead use the method described in the [freqUI repository](https://github.com/freqtrade/frequi) to get the source-code of freqUI. ## Configuration @@ -23,9 +38,6 @@ Sample configuration: !!! Danger "Security warning" By default, the configuration listens on localhost only (so it's not reachable from other systems). We strongly recommend to not expose this API to the internet and choose a strong, unique password, since others will potentially be able to control your bot. -!!! Danger "Password selection" - Please make sure to select a very strong, unique password to protect your bot from unauthorized access. - You can then access the API by going to `http://127.0.0.1:8080/api/v1/ping` in a browser to check if the API is running correctly. This should return the response: @@ -35,16 +47,22 @@ This should return the response: All other endpoints return sensitive info and require authentication and are therefore not available through a web browser. -To generate a secure password, either use a password manager, or use the below code snipped. +### Security + +To generate a secure password, best use a password manager, or use the below code. ``` python import secrets secrets.token_hex() ``` -!!! Hint +!!! Hint "JWT token" Use the same method to also generate a JWT secret key (`jwt_secret_key`). +!!! Danger "Password selection" + Please make sure to select a very strong, unique password to protect your bot from unauthorized access. + Also change `jwt_secret_key` to something random (no need to remember this, but it'll be used to encrypt your session, so it better be something unique!). + ### Configuration with docker If you run your bot using docker, you'll need to have the bot listen to incoming connections. The security is then handled by docker. @@ -57,28 +75,20 @@ If you run your bot using docker, you'll need to have the bot listen to incoming }, ``` -Add the following to your docker command: +Uncomment the following from your docker-compose file: -``` bash - -p 127.0.0.1:8080:8080 -``` - -A complete sample-command may then look as follows: - -```bash -docker run -d \ - --name freqtrade \ - -v ~/.freqtrade/config.json:/freqtrade/config.json \ - -v ~/.freqtrade/user_data/:/freqtrade/user_data \ - -v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \ - -p 127.0.0.1:8080:8080 \ - freqtrade trade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy +```yml + ports: + - "127.0.0.1:8080:8080" ``` !!! Danger "Security warning" - By using `-p 8080:8080` the API is available to everyone connecting to the server under the correct port, so others may be able to control your bot. + By using `8080:8080` in the docker port mapping, the API will be available to everyone connecting to the server under the correct port, so others may be able to control your bot. -## Consuming the API + +## Rest API + +### Consuming the API You can consume the API by using the script `scripts/rest_client.py`. The client script only requires the `requests` module, so Freqtrade does not need to be installed on the system. @@ -89,7 +99,7 @@ python3 scripts/rest_client.py [optional parameters] By default, the script assumes `127.0.0.1` (localhost) and port `8080` to be used, however you can specify a configuration file to override this behaviour. -### Minimalistic client config +#### Minimalistic client config ``` json { @@ -105,7 +115,7 @@ By default, the script assumes `127.0.0.1` (localhost) and port `8080` to be use python3 scripts/rest_client.py --config rest_config.json [optional parameters] ``` -## Available endpoints +### Available endpoints | Command | Description | |----------|-------------| @@ -264,12 +274,12 @@ whitelist ``` -## OpenAPI interface +### OpenAPI interface To enable the builtin openAPI interface (Swagger UI), specify `"enable_openapi": true` in the api_server configuration. This will enable the Swagger UI at the `/docs` endpoint. By default, that's running at http://localhost:8080/docs/ - but it'll depend on your settings. -## Advanced API usage using JWT tokens +### Advanced API usage using JWT tokens !!! Note The below should be done in an application (a Freqtrade REST API client, which fetches info via API), and is not intended to be used on a regular basis. @@ -294,9 +304,9 @@ Since the access token has a short timeout (15 min) - the `token/refresh` reques {"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODkxMTk5NzQsIm5iZiI6MTU4OTExOTk3NCwianRpIjoiMDBjNTlhMWUtMjBmYS00ZTk0LTliZjAtNWQwNTg2MTdiZDIyIiwiZXhwIjoxNTg5MTIwODc0LCJpZGVudGl0eSI6eyJ1IjoiRnJlcXRyYWRlciJ9LCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MifQ.1seHlII3WprjjclY6DpRhen0rqdF4j6jbvxIhUFaSbs"} ``` -## CORS +### CORS -All web-based frontends are subject to [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) - Cross-Origin Resource Sharing. +All web-based front-ends are subject to [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) - Cross-Origin Resource Sharing. Since most of the requests to the Freqtrade API must be authenticated, a proper CORS policy is key to avoid security problems. Also, the standard disallows `*` CORS policies for requests with credentials, so this setting must be set appropriately. diff --git a/mkdocs.yml b/mkdocs.yml index 4545e8d84..2d37ddba8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -13,7 +13,7 @@ nav: - Control the bot: - Telegram: telegram-usage.md - Web Hook: webhook-config.md - - REST API: rest-api.md + - REST API & FreqUI: rest-api.md - Data Downloading: data-download.md - Backtesting: backtesting.md - Hyperopt: hyperopt.md From 1df0aa875193fc64a1c9ec6d8aae9bd4aeda277b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 25 Jan 2021 21:08:15 +0100 Subject: [PATCH 052/158] Add ui installation to docker container builds --- Dockerfile | 4 +++- Dockerfile.armhf | 4 +++- docker-compose.yml | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 445f909b0..8d4f0ebe6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,7 +40,9 @@ COPY --from=python-deps /root/.local /root/.local # Install and execute COPY . /freqtrade/ RUN pip install -e . --no-cache-dir \ - && mkdir /freqtrade/user_data/ + && mkdir /freqtrade/user_data/ \ + && freqtrade install-ui + ENTRYPOINT ["freqtrade"] # Default to trade mode CMD [ "trade" ] diff --git a/Dockerfile.armhf b/Dockerfile.armhf index 2c7d4538a..ec6aa72b8 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -41,7 +41,9 @@ COPY --from=python-deps /root/.local /root/.local # Install and execute COPY . /freqtrade/ -RUN pip install -e . --no-cache-dir +RUN pip install -e . --no-cache-dir \ + && freqtrade install-ui + ENTRYPOINT ["freqtrade"] # Default to trade mode CMD [ "trade" ] diff --git a/docker-compose.yml b/docker-compose.yml index 06cce4e8e..1f63059f0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,8 +17,8 @@ services: # Expose api on port 8080 (localhost only) # Please read the https://www.freqtrade.io/en/latest/rest-api/ documentation # before enabling this. - #ports: - # - "127.0.0.1:8080:8080" + # ports: + # - "127.0.0.1:8080:8080" # Default command used when running `docker compose up` command: > trade From 2af1d2d6390357c267b0ab4a3ccb5e07e7086576 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 14:38:40 +0100 Subject: [PATCH 053/158] Extract last FreqUI version from api response --- freqtrade/commands/deploy_commands.py | 24 ++++++++++++++++-------- tests/commands/test_commands.py | 25 +++++++++++++++++++++---- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 8a8d2373e..44ddc1fdc 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -1,7 +1,7 @@ import logging import sys from pathlib import Path -from typing import Any, Dict +from typing import Any, Dict, Tuple import requests @@ -170,7 +170,7 @@ def download_and_install_ui(dest_folder: Path, dl_url: str): destfile.write_bytes(x.read()) -def get_ui_download_url() -> str: +def get_ui_download_url() -> Tuple[str, str]: base_url = 'https://api.github.com/repos/freqtrade/frequi/' # Get base UI Repo path @@ -178,23 +178,31 @@ def get_ui_download_url() -> str: resp.raise_for_status() r = resp.json() - assets = r[0]['assets_url'] - resp = requests.get(assets) - r = resp.json() + latest_version = r[0]['name'] + assets = r[0].get('assets', []) + dl_url = '' + if assets and len(assets) > 0: + dl_url = assets[0]['browser_download_url'] - dl_url = r[0]['browser_download_url'] - return dl_url + # URL not found - try assets url + if not dl_url: + assets = r[0]['assets_url'] + resp = requests.get(assets) + r = resp.json() + dl_url = r[0]['browser_download_url'] + + return dl_url, latest_version def start_install_ui(args: Dict[str, Any]) -> None: dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' # First make sure the assets are removed. + dl_url, latest_version = get_ui_download_url() clean_ui_subdir(dest_folder) if args.get('erase_ui_only'): logger.info("Erased UI directory content. Not downloading new version.") else: - dl_url = get_ui_download_url() # Download a new version download_and_install_ui(dest_folder, dl_url) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index fdc2b204b..dcc0cd1d2 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,5 +1,5 @@ -from io import BytesIO import re +from io import BytesIO from pathlib import Path from unittest.mock import MagicMock, PropertyMock from zipfile import ZipFile @@ -13,7 +13,8 @@ from freqtrade.commands import (start_convert_data, start_create_userdir, start_ start_list_markets, start_list_strategies, start_list_timeframes, start_new_hyperopt, start_new_strategy, start_show_trades, start_test_pairlist, start_trading) -from freqtrade.commands.deploy_commands import clean_ui_subdir, download_and_install_ui, get_ui_download_url +from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui, + get_ui_download_url) from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode @@ -628,15 +629,31 @@ def test_download_and_install_ui(mocker, tmpdir): def test_get_ui_download_url(mocker): response = MagicMock() response.json = MagicMock( - side_effect=[[{'assets_url': 'http://whatever.json'}], + side_effect=[[{'assets_url': 'http://whatever.json', 'name': '0.0.1'}], [{'browser_download_url': 'http://download.zip'}]]) get_mock = mocker.patch("freqtrade.commands.deploy_commands.requests.get", return_value=response) - x = get_ui_download_url() + x, last_version = get_ui_download_url() assert get_mock.call_count == 2 + assert last_version == '0.0.1' assert x == 'http://download.zip' +def test_get_ui_download_url_direct(mocker): + response = MagicMock() + response.json = MagicMock( + side_effect=[[{ + 'assets_url': 'http://whatever.json', + 'name': '0.0.1', + 'assets': [{'browser_download_url': 'http://download11.zip'}]}]]) + get_mock = mocker.patch("freqtrade.commands.deploy_commands.requests.get", + return_value=response) + x, last_version = get_ui_download_url() + assert get_mock.call_count == 1 + assert last_version == '0.0.1' + assert x == 'http://download11.zip' + + def test_download_data_keyboardInterrupt(mocker, caplog, markets): dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', MagicMock(side_effect=KeyboardInterrupt)) From 944d674eeb6d590685f1970c60210f80b93fc726 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 14:39:46 +0100 Subject: [PATCH 054/158] Store freqUI version and read it again --- freqtrade/commands/deploy_commands.py | 25 +++++++++++++++++++++---- tests/commands/test_commands.py | 10 ++++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 44ddc1fdc..c4e958df6 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -1,7 +1,7 @@ import logging import sys from pathlib import Path -from typing import Any, Dict, Tuple +from typing import Any, Dict, Optional, Tuple import requests @@ -154,7 +154,16 @@ def clean_ui_subdir(directory: Path): p.rmdir() -def download_and_install_ui(dest_folder: Path, dl_url: str): +def read_ui_version(dest_folder: Path) -> Optional[str]: + file = dest_folder / '.uiversion' + if not file.is_file(): + return None + + with file.open('r') as f: + return f.read() + + +def download_and_install_ui(dest_folder: Path, dl_url: str, version: str): from io import BytesIO from zipfile import ZipFile @@ -168,6 +177,8 @@ def download_and_install_ui(dest_folder: Path, dl_url: str): destfile.mkdir(exist_ok=True) else: destfile.write_bytes(x.read()) + with (dest_folder / '.uiversion').open('w') as f: + f.write(version) def get_ui_download_url() -> Tuple[str, str]: @@ -199,10 +210,16 @@ def start_install_ui(args: Dict[str, Any]) -> None: dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' # First make sure the assets are removed. dl_url, latest_version = get_ui_download_url() - clean_ui_subdir(dest_folder) + + curr_version = read_ui_version(dest_folder) + if curr_version == latest_version and not args.get('erase_ui_only'): + logger.info(f"UI already uptodate, FreqUI Version {curr_version}.") + return + if args.get('erase_ui_only'): + clean_ui_subdir(dest_folder) logger.info("Erased UI directory content. Not downloading new version.") else: # Download a new version - download_and_install_ui(dest_folder, dl_url) + download_and_install_ui(dest_folder, dl_url, latest_version) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index dcc0cd1d2..b243df192 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -14,7 +14,7 @@ from freqtrade.commands import (start_convert_data, start_create_userdir, start_ start_new_hyperopt, start_new_strategy, start_show_trades, start_test_pairlist, start_trading) from freqtrade.commands.deploy_commands import (clean_ui_subdir, download_and_install_ui, - get_ui_download_url) + get_ui_download_url, read_ui_version) from freqtrade.configuration import setup_utils_configuration from freqtrade.exceptions import OperationalException from freqtrade.state import RunMode @@ -563,6 +563,7 @@ def test_start_install_ui(mocker): clean_mock = mocker.patch('freqtrade.commands.deploy_commands.clean_ui_subdir') get_url_mock = mocker.patch('freqtrade.commands.deploy_commands.get_ui_download_url') download_mock = mocker.patch('freqtrade.commands.deploy_commands.download_and_install_ui') + mocker.patch('freqtrade.commands.deploy_commands.read_ui_version', return_value=None) args = [ "install-ui", ] @@ -616,15 +617,16 @@ def test_download_and_install_ui(mocker, tmpdir): mocker.patch("freqtrade.commands.deploy_commands.Path.is_dir", side_effect=[True, False]) - mkdir_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.mkdir") wb_mock = mocker.patch("freqtrade.commands.deploy_commands.Path.write_bytes") folder = Path(tmpdir) / "uitests_dl" - download_and_install_ui(folder, 'http://whatever.xxx/download/file.zip') + folder.mkdir(exist_ok=True) + download_and_install_ui(folder, 'http://whatever.xxx/download/file.zip', '22') - assert mkdir_mock.call_count == 1 assert wb_mock.call_count == 2 + assert read_ui_version(folder) == '22' + def test_get_ui_download_url(mocker): response = MagicMock() From 7b3d99819f60f03a9464c2f67720ed7c83c17dc2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 14:43:16 +0100 Subject: [PATCH 055/158] Fix bug with not cleaning UI folder --- freqtrade/commands/deploy_commands.py | 5 ++--- tests/commands/test_commands.py | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index c4e958df6..62da6abf3 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -213,13 +213,12 @@ def start_install_ui(args: Dict[str, Any]) -> None: curr_version = read_ui_version(dest_folder) if curr_version == latest_version and not args.get('erase_ui_only'): - logger.info(f"UI already uptodate, FreqUI Version {curr_version}.") + logger.info(f"UI already up-to-date, FreqUI Version {curr_version}.") return + clean_ui_subdir(dest_folder) if args.get('erase_ui_only'): - clean_ui_subdir(dest_folder) logger.info("Erased UI directory content. Not downloading new version.") else: - # Download a new version download_and_install_ui(dest_folder, dl_url, latest_version) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index b243df192..0d2b9e394 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -561,7 +561,8 @@ def test_start_new_hyperopt_no_arg(mocker): def test_start_install_ui(mocker): clean_mock = mocker.patch('freqtrade.commands.deploy_commands.clean_ui_subdir') - get_url_mock = mocker.patch('freqtrade.commands.deploy_commands.get_ui_download_url') + get_url_mock = mocker.patch('freqtrade.commands.deploy_commands.get_ui_download_url', + return_value=('https://example.com/whatever', '0.0.1')) download_mock = mocker.patch('freqtrade.commands.deploy_commands.download_and_install_ui') mocker.patch('freqtrade.commands.deploy_commands.read_ui_version', return_value=None) args = [ @@ -582,7 +583,7 @@ def test_start_install_ui(mocker): ] start_install_ui(get_args(args)) assert clean_mock.call_count == 1 - assert get_url_mock.call_count == 0 + assert get_url_mock.call_count == 1 assert download_mock.call_count == 0 From a87a885ccd3221fda93d3f1c3a37c754ba64403e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 14:54:58 +0100 Subject: [PATCH 056/158] Don't use Path object to return fileresponses --- freqtrade/rpc/api_server/web_ui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/api_server/web_ui.py b/freqtrade/rpc/api_server/web_ui.py index 6d397da56..4876c9077 100644 --- a/freqtrade/rpc/api_server/web_ui.py +++ b/freqtrade/rpc/api_server/web_ui.py @@ -22,10 +22,10 @@ async def index_html(rest_of_path: str): raise HTTPException(status_code=404, detail="Not Found") uibase = Path(__file__).parent / 'ui' if (uibase / rest_of_path).is_file(): - return FileResponse(uibase / rest_of_path) + return FileResponse(str(uibase / rest_of_path)) index_file = uibase / 'index.html' if not index_file.is_file(): - return FileResponse(uibase / 'fallback_file.html') + return FileResponse(str(uibase / 'fallback_file.html')) # Fall back to index.html, as indicated by vue router docs - return FileResponse(index_file) + return FileResponse(str(index_file)) From 28be71806f000a0ba5a96307d721065ae42c76fa Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 15:00:13 +0100 Subject: [PATCH 057/158] Install html file as well --- MANIFEST.in | 2 ++ freqtrade/rpc/api_server/ui/.gitkeep | 0 freqtrade/rpc/api_server/ui/favicon.ico | Bin 0 -> 126794 bytes 3 files changed, 2 insertions(+) delete mode 100644 freqtrade/rpc/api_server/ui/.gitkeep create mode 100644 freqtrade/rpc/api_server/ui/favicon.ico diff --git a/MANIFEST.in b/MANIFEST.in index 2f59bcc7a..adbcd2e30 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,3 +2,5 @@ include LICENSE include README.md recursive-include freqtrade *.py recursive-include freqtrade/templates/ *.j2 *.ipynb +include freqtrade/rpc/api_server/ui/fallback_file.html +include freqtrade/rpc/api_server/ui/favicon.ico diff --git a/freqtrade/rpc/api_server/ui/.gitkeep b/freqtrade/rpc/api_server/ui/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/freqtrade/rpc/api_server/ui/favicon.ico b/freqtrade/rpc/api_server/ui/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..78c7e43b1e6a5756492a1d53813e1ec47f98efdf GIT binary patch literal 126794 zcmeHQ378ed5q|3m3mz=dctpe%QM{t!eWB}_D8?I2G%6YsyyA_T7;zWzict*lz$=0m zibq7nAR1u>BZwC&i6+swDg;pw5X2Ri?fn1j%+S-XyXSiE?JjSMZ<(2%?&|95dOh9M zRn@s%1^zwuOb-8Vn%iYzMQ;6EF1Ho_9>d?Diq>@8W>6#!eDJ{sJ;#n6d+hDE-#%#Q z(4m+8@|V9HdDKxyjooj*{U+_S(@t-0v&}X$dEI~i{U;uM^wDE}^{Zcvy!P5_2Q&Y; zapMmE=%bG|ED~uM+A`*V5TatrlqtJia>*sv9dpbv4{xx+2D8Bqk@j!njW=#Q@x&AF zyW)x~u9`V>=C)d)}>ExA{@zt5|u~Uw{4C=bd-naE!No%7E=z6Jv0I zW7)p@?)yB7tiWID?|Y$ebn4XUn}ZHIX#AURzPU||=44q{K@LoqFyX-6cH3=gp=7I= zcn&z=fM+L7nzZ*S*bP~eEFAdo!w)w(^2j3}FQ#l212^W*%TGS}Qpg(`gG?y zapFXA|NZxi>#n;_oO4x?!No(ld!g55LZrn_wFrjyX`jdpa1+PxnM>p`OZ7#VcRyvHAZynhGoo{V&G;D7)7-x~P#-VsMeq30Bs6N)$9cq4+86+R2+ z5d#Jc5FE>6(A{#;MHgKQYOrgWK}X{N`mO6e`|R@~=#JFqSht9C&N)Z?^Pm4LyZ|P^ z$lnToGjU`V`)Uue-5ss3%9-AI^X6^Pt5>i0qsnRj{{02!eF-G0_(lHlkAH|=cG)G; z?~U!$TT2y;l2{*o6xhcJJA<=Lb>b6np&w^VyVARNCUO&l1>Qiz=@(KL7mlwc2-& zl_zzLjg3F};SYcKMwpyZH#%a(h=K@NQ&W?(27CD7hsCY8-YRas`DSN54;`-f{qKJ- z{`ki~I(mdhAAMBtTmJ30-=?m2#flXIc8H>)q9RmgF?V|A@;kzg)cf>Z^ismlPg) z=pnJ@nrnvEfBf;sk0yWGXU~-%RVSTv(mk?F=C7{`u!eo-gX^*QKqy z?z)cLzW@IFiA46Tx84%auZGI&;K75hM*SJIF$eCs=bjTmg4I5X`<1=;7n!|FiA5G`?aOTA z71zlxz4TI4F%|#%*T2NByY5<48MM)>dxw3uSYs@8#bNtgBS(%r6?J7$A`Z}(F3heE zeG*wtsZ)xwrbhEhF3Y5gc7{=bwp%tj$v5bgzh9!RD*I~a*J0}q_&G<`2Mr%SJd&=` zR$sB-(VphM`|gV*uGCw=_uDG3urs)`?1iWV3}|R**wZE(TuaTLKR;5x{^?JD5?q7Z z@U@qBoI}%YI|_XK@yBBAwbwSbi~a>Kzx?tZCFriQt^#}Aui511x#ymX(w)xQ#fB&9 zJLM$7b5U9(w4Z0(SgHxrtg2^Tm61@Bsg*6@w)U_39)1R5*|KF$otz)b@3-H6d;eXS+{op^?zu;dF)_5AoC}1l z6<>e-b%yK7pa>kmJZu8c24uo}W*^R)H7m3a;mcC6{U`cSc|e;&d5`{@Yp(HLIam3e zM|09E_ljXh6~M21AU|yN;(PEUXvmjeED**_10S( zaoF(d-q9z}1I`g;eGz?9WRTzKaK%l7u2ir+VSrdJ#`Z#wyX?L9-rE#)XHY;6ARfxC zKxgE86#G8foY-*0eb<(oP$*kF>tdYW;03t5sE1k!)~j+ojU(J;NXIWAYcz85Dp64?OU|u|Q+wcN9N9+J@M0 z*xs$T-g=IGDs`Ol-@EU=>;FcUE?sJT$4o3o+kV*Eh~NG0cLKf(iRqDPrTst{&;~~? zqu#rEKqP07mII9a2pn2|@44rmp?d$YzB1wV(&=|y4B&ngV`6yqB)M`PjF@quqrG4|wHv+%KP#SD> zM$y$FR*-cq-Z~*a1jxhBT=bv-u&b5jIV(c0F$b?r-mt~dT`hWlX---Vi zb43N}Xt`&g)*JPidv9U(+SJwA@L@jF8}Bnn!2#G}{07CfeBOQc-PLZ-dq(_oZCMje zUAio*j1i>E6DMu+%{Lc_;U1tB@!(?n#K?8hFD49Z`Z~sv2fhqaaA5Df_cq3(;2OmS z9Ip^FJ+*8VT2{dhhbGk?<@D1}PfRO)xx!$`kRe9=@B_LxMK@(d!2#&1mV14xUa?1L z?H=0tsb!Kp7fV*T*T(VG1NwC(q0cMB`Hl_fZ|mh%ubXbV>3c}aARz}n{q)myP}Im@ z`jy(?(n~KjmbKwk-xW(%Sr7fPWw7b(Rl3yY-~RTuGOE0L?w45h&sJo1t>9=vc=p+6 zX{(}@H;e;$eW4~GUVyf&38yK&n6ip<0Rm*FvB^62*kc2@bPtoN$7!EBv&UmKNI>V(c$neZ`bj#=VdsjXf=WxWD`EI~iTxJ@wJLHZtw5 zyYBiGt{EiY0Cd!Mp_rDpS6_W~UO&hQ^szRTjhkLfS$+EHr+u<%BOaGFHGf!~Lz^xa zd&cJjUj_*{fEee`p_sP+!uFEj53em}!e>h_maO8eL0?XJ!?~-CjwtU`U09$3Ja8O0 z;W_u*b8o=A3=(hv`qSwsrsXa7)os9dQl_$T(~BXijQzG~(IUSI{C3mFATDicew?G} z3Eczya8`zm8&B-g4Zu!37swpe<*@XG@o5m3A^e{pn8={n3_` zx{1I2?QeO$|BT&cqao_MTW-0<#ukC~s<9rNOY~RNlR*Lw?7Z{NMp^yqU;k?D6P|m5 zDhu)_%c`}~gfAa^?6HFRDDrz^gUOR88+n3#mq`h_DJudF*kqMslMR0U^Pe00B(4k> zQ&wr)Ux>XmuT5cVPWozjdDW|XE*+9Hh|2++tnv&98~oxIzcBU*=!o@Bl~wLRB>mIT zOkb@+$tz>P+JN69Q~MDYl;?bAkbna=S>?RT28=<8Dhu)_%PPn7O*Yvi(O*qXjlg$S zz;8q#=5&C3{`S)BS$S>cyw?UiGtSGaUSaF?7o=s7fCIL*RajgH#x6sZ1^JU@wGehz zq>E=2z%MT#R*YYjmgcb7NE~-fb-)*h`s@r6Z~%KOQ&3FH+c4b>*DI#7anp+-tE7Q@ zz)O}a@#VD;zk_k(#`*YkH#YxB*b@u|T^S_c0CeS#pqN(XIBwd2zJR8(anp+>tE5A= z3#5-gT-wz9jCW`Q`VgpPyl3o1oQ?Yo5^&&(E3T+RF)eRTJMA=EmpH!jg_!@b{$k4N zC6`~kzY-%^YQ*Ys21}QjTJ6|o#-x}u#rt-G~*-qaULsoGnM_#I%80zkyG;J$Rm#orNicLjd-q%Yg3lMb9^z6A9(lO zcMqa}9~ik>8b%<_opDcq=RSwc(`@z{piBE3kkfHSWT-5}%|M+!_mI-YE~GEv^y$+> ztEVrP+$Q<{j5E%-8P8<}U|46y@dE$8LBoCCY_-)^ZzB#lzvYPl{wk-VppQ?z5A!kN zTn#ov#_}pY^_hAe`iL^tg#0IuxAc|b+}L}s+ShvTXjcp0oPwSA#xrNafO8nNP4Y9& z0ox1DWdq<>SF9V}M1zfdx#*&c5}jcS+*R=JH0rKs{}%=vdl;|OMqk`_^8BOJaji)! z&k_oouahtImoc>sHZ+{*mepB;(1#2&@k35WZ1PyXlAQA+*3uB1fwM@)Bj0mv5v9*) zizk;$d*9Zw%GiHlK-+4I{$F7HxE6dU8-S17_pl~6$`Tmi%LvATrHHe)Sr~KB2dmMq z5^;2v%H>V>;CWcL3EGA*?wJWk-1N4TRnBSHo-i0NV1Ti`*w1Z(Z+cI(yKDfu!F|!# z08g;C{Qz_J+bEmrJJ@NyU}FyW-wAQ3A6LuSo~geIo42xG8T09T-}_#GRvTX1yZZWi zUsSkOlE<&Qx;p2NdG6FeB$Fb-Gtei!RG2Q)K^vj`(E1T1o|I7YUhy& zu!%lSeaC0_tSV;7gFpZI&p$_E0AG}6`jE#L+<4=SoP!4Va_60Q4)mDd`bGrabN?Cq?&9T< zuZS1^sfv%!*em)BW6Br0cV1dly*=$;3pv(#^%wI>{S)BSY z5jj%j1?HMJAql(RVi=a>ya$VCy;=IztQ4MFR10?g-gA#zadB^v0q%Ly7GU@CIjvO_2*A9^N0+JeXrHMjXX82r&x{!n6>R=TGS0TVXFRsBI5Tp4ZSmFE4#c#|vr|F&PJ;#w z8iBf&>)MKQW8UT-58kB$#wo?wF%Nd{-hDn0`F#jmg%9O#ajHrzg>l~Ex@cpwTsLAT zzAqO6FS=mw?-B2Bw4CpuhaNgc&7;N#hpu#IjMK(_SC$WpcO~~N#%y8R*HP&y zi#~l1b$9X$#=PP87rMtU zZS}zC>&lpDV`qmhh;fnqw$kntHhJA;MEHiCBIn^fWbRw|G4q^t2XNNXuDJ2>@E-mu zx3|7s`M;|d4CIr`aScM=VVkL>#RXAQOS{%uvq?&O`97Xn?&%%2R+(SZ^O8R|uY0;QKUL&4(Ck z6e{QU>e{9U@L)aryo`tU$X^M)*nd=9@-uDlRKI3hztb+CHlB=)F5@ZnJ(pYe zz4qFU;A!5R2zD+fF)#SfIedV2&hb?|e4aUT=C)WHFH`f&&y0T^7^c(_Ox;9GUe~ptJnL`r|iSI0e-h%$@ys8f#=9z8&6?(H1RjT`OOfl z^;Q6(Pe1zm<;WEz$f!Gq3NfWd=}^IL>LHmn-gD1j{P^+v>&~-;-3aZhw1D5p8F=Bh zQ+Ll;k>I=By`lFU(-;ed-(eljLZ)$zkMrimlqpj}=~6TBtS#zt!|1{O%jB>;d`~|N z>{qXkduQB$tS*tuVV?9B-$en$f;}8_65TnvD{zJmox@fq9{kSc;NrKTXV0D=M8VHI zz)^v}SoREDUtzoqjPuZ;(v~F;zWnmbYJBGwBubMuf$39z%j+g6_MdiU-v z!hGjdIq;r2&M`(N^ZUweuunl-jU4PW2VniJ)lWmF zzJnjj-5|i3i!r~>j~KqP9A`oSv51bsH%}+00yZIje{zo(bCJMzcBh?onr^EAG**oo zHR@!1gT`R(ITv%4CHxkgefHTS(8oP&WxaQpKXUEw_a|icTXlWq<%Rq)Zi1iJbkA>4 z*ctcaFXp_|ky-KaOwuG{mnT49fBm%+zm)q>JU5fN`LH_W_smawTl$I7W{~?`NrAE3 zqkQ+d4}&_K@e8!%Xp6!4D)^nuqTU*I=regP```cmcdlszu*V*IOhQ7SjhILCY&0UW(?@uo8%u(0fky%6M1& z_Vak);c@p10(5%iyldE)>fz$J4*vhcD`&cLoy=J0Jo};$z_~Ez3fw264Aak>XBF~F z{SkDA&YtL;Idck8ofD(O7Druf_jcQD_nIuH9uAVyUS7m^;@*-EIDd0%eA60{V3if`J>?ZKqz3v3G&hLNcY~MTyJG%% zye6xk1ioJadYiob-j#DW{03viS7JN?wCN)chwaL^5A){DD~SA*3JL914m#+dNd2|L z4m-?Pym&Fs2TKI~`}cnm1p{?qkL4a4GOjn&wU~zkYp6Q4EPm6sdGEce+kb(qoSS&> zqh2vDXu{mBCV)tKz+Cz$71x<(p7}>9i}sc_s@!j7tTpJQ-^BjOtvF|VCvE1CMEEcD zLTr&nWDD?F_ske1VX?|eC5K`4z^@|GH=pg~_Z_~18{j?>a8DfLhdS4!-gA2sLd477 zLuXTm`~vgH8_~YN`iFbz*cZrKvtXWktXcrLJxw?>%&#FRHk_XV?`{ z_a7*O`Oq8Q`%+ywUq^oh_9j%ii7hvDR-t`q7V`VY|~Xo8z6j2f+E5$%Yd??K^TGOvhL3H{PkE1#`9Ds+_R==+UE% zYa+z^Jdo#|!G7ahuCsJ_p$mObr2}j3m(WLnG2JVR-}N*#zbE@%o>E;wV<+_YT`E1c zXYS?jyfW?wgvHA$w4Aa&j-&KLw9%-(<67dZv(DmJm>QrHxCTf9^}9NjJlwEZ+5vL9 zP|eS0`o@Ak6?uh_fbZC&Y8lAQ-*tK8q;YQuzcY32B1~s@Vr_q;N=F(W);P49@^bGR zYtuac1eH$pnQ>jX=H{BFn7}cVIs>eS0y3h~qkD$l=}YKA1AE!Xmk3}3)m0aZ!L`E- z;N*G&_C9lwm`5|lhdTn9r3amUfjBtdm9izig$?7w#3%nDZrHmzgsx3QATNHa!*zK} zna1@3Xb#nB$!+xRv1SlE?zp31oPeoQr#gD0G_p&(1K8*|dM)Z{sYmnbigU$S^hzQ9 zrC`rHSgjwndfcc8jF03ce?3UJE)|!rYU3+=2k@7CD~iV@w}aUyA+BS*a>dS(r4^E|zn1 z$QbvU{WT@-^LXCg)2L5^{&O7T(#@SacfFMCaf)*-ueKXw>Ibq;f%-ti&i+Kr$7kwe zRatNlOaEcd?m4wA{12#)DkyNDlXm<-8t7ZtN1ditM7@ce4`Xt3Tdc3ZyUvKkd$Jp^ zDL}VOUkAT$!CGZ3b<}D<#CgU(&mff#uvPH=F}OF2Jzeem6!kv>UTfFd9u2zR0^Y6Q zddSOD$SY|7J@5tk9OKk~)jALdC2#EwTh;+;zG6Oe9=FRbyS$>(yQ)58tX-DW4x0UN z(@i(!*>vKptaJE|>mk@aeTdsY-}4!I*QX$-otV!CnD4)e_kr@R�|f;&=3w!Tcg` z-ip2OQ)Hx=6JDv(Rmw9ys7rzU%{-NcGI(x*o$?5|FQVRKUV4VgAJ`MTfjQ{?s$HO$ zkNS9dj$o>bIwQ{Uy>h(bc}1~(zIApn7+a~-@z;K^)7@XDi}$Xc6Su_$jsd1U6x1Bx z*Q)xAJ?fj|av3`P-Qw^AabG5KjuoXIcl-?S9)5QBMk$*n5BEi&{|)#cvW+;i*0-U7 z&-2<$lmF-knWo+-Wx>0yTo1_gmg#*9zTdx$!ZSG!;ulVc!Y}$Enf8uke7xtk7<*I! zTPo=5zk%&kZ#8c*o`(+~{%hb3$RccbKXYZ&sSKInus zMV?Iwh;r!0zSgu-5r{eA_OSOF!#xhJiJ=FW3)`Z4#%C`!4bb;Bcx{%iuuBLNQ|JAv zAghcYC%0X`=Xw{HbWzMxPa3ex`wLu0gfqxrYyNrZQQLFB0vp1pO|lN2ZUQ z*SGRD>e`CJKsy$>Y3xXr}hu8?-fpB5;5)h2d-XuxlH$0#z7g zERL*FUOCp;@Rjl%_n{_Dnnbc9flXE=x>sPW)`+;cqup~E@G65sbAa(Z7^ew%Bg<1< zS>+lBbwtJ=hnBc`8OtyZM3mJ)+ZewI@yWI*bYGP-KE~aI4}DYI{*EiFlnun>DoHGB zQ(HKm@*JbMkVIBV18fc#6e^BHIm;;9&iydhZE54skk_`qB(h2wS+;DM6H68QD^~or zx|6))IWUY(lmwE>D(Qr-V*zhKD&h9QeD1GR$F-odjNl!C*Mr5-WWG66TD;`z`XEvoeVNQstlQ| ziZI(1nOy?$Xtcj=H@0%J&MNa#CRtVeQZiYMC#$AC5AeHW_Rg!CXlJq-7!IuuwzZW! z2OyG6Rtx`2X-iq9za8UF;LJV2as1LtFBP=CPkQ#CDrm&dSgnjd%yR+Y2P7VU{BePJ z5^B~+&zYYztYXFCo`tpwswAU2B}ZdRf?TMuR}iG9zx*OZ+@HAP!`*8b`7U zpSRSqigRpuHl9_EJQ-$;9*%`kfqwivOVBGHc7^|`h-$k^8Zucey!^$%SSneiudB(2 zBuu8LyVS)Ul4Y1@W;6bJ7%tuWfddE1sEqfStj3Y7!sjiOtRh})B02J8i!s$~z_S9p zyh*NzIc-DlynFW9XN`4aYpcS`riwADtkS+-Cj*=phQY@lf9%8&(v^>zM%_B?33c$! zJMW0Fn0{gP;QV^QbA@ccxP>M>h)WYFn&|<+sRBb(Sv7rMd0tc)AZD$xkI@|GooS!P zd(SK9x;o%lgmOOJy(zwroR?#>4G@3bSPyJ}14T1g1!oHkCRtVIaFi2No%e^BUrsE& zKu1XroJTS~s;(^4=r2tj63=g^uF59Yw9zI$8I~+rA{a~4grD{d94}dpd!IN*+L)Jg z+JNgkQ$4Dl&7|jm&+N;SgRE+5nAqiO=ixippIne95T z#RW!e-aru>e#EE=;ZW8WCjU1 zfOAR5pqQ4gyY9NH;F^Q_bn5F(`KZq{0d@VRayTnjTa4$enaWIY0ELz@B7LL(Z_QJF*pFd{NBiJ z#cZYQo64y2ZCjh;te8A`V}gw)*z;=3&?cO*+D&vtOmD%tn|mT} z1_?QUGcjhOXySh0H`@d@oh0pIbzmFA5yLr9gueYI+D*QHHvIGE%?sf79{3wE)e|-S z;DZkykGvVA-~i9+L`)NHyiA}C?IY@o7^_?doV%IyNsNc7j;;KrGY*TcUgmFVY6?`t zSXicbEYw4(ap8HMu*t`ZbgFANuQJ9l($N$nZAIqK3T_nu?!EWklYqt=3jptp{l)p3 z2~75c9zMo5A2MW!z`3DD{LIU9RCHj{{jv<@nEE!JKa6qBiXU@#9eQWoWYcAM?J!-T zFIxtinf`d6L4i2HGqvG=@j1|0`&9SdwkN=~nXXLSG*#d33D&4lqY8rGv_`bepTpXK z^Ht|yJ$NAUWl&%ap#QrL9Xj+9#Flysx|mq;0{HzlfoTm5@*~NaX-s8()Xk>Ff6Ot* zm`E2mYdjK-UR%gFo{fq%|9L z*xxv7Tp+Hpww%|;rYrXV!uCJ;-sY2M!p(Hj1>b!w?KV9F&UXA_%9JU)dA#8j`@LHM zQ5EoJ(8e6#IKe&w8CtosjjhyOn$}GweDqPo*-u(IQWK|5n-2$^`wimo8nZ>v|`RdI9cphS{)kO-^5dg$oxN zap_*rzJ;+XO!Rr_te^hTix)4}p>fiN4I5^}!#FC8b6z5rXVoO+0AlY}V_p1-*YE1} z?6c1{_P_UndV1P9%X>Urv*V0%XU(qan!IvRuf)&&d+3gRofhSjF=P>D*+OyDdFV%D&HrvHN*nOX!j&oV*QgZ;dd_D19HJ*FTb(G0|q&>w85r-gRKpC*8(4wBRX(5Wu&u% zp>s8zeZkk>A8njJ`Q(#!Bc}ANr7f$;F506T*OsfVzIrgO8LR>vm_2*;x^7%CUpCRK zynFha;Qa7Bd#O?jF!q=@_spYDM>BL^Lsx+=%9n>rWoGgyT=0C}rI{Qq0f#5l6yoR>;l*0at!OVDp={P^*L`%klG&2ska zIVRfvxEDoRYS=ak+D7vXfU=9KacwJ#Yr$eeGRVyLRpR73_8y=&hm*x+QC(g#)yWhaGC9bytby zx`i?PGabLB^UCzqlTSW*DEwZZM)MQp`W8s@^sb1_KNV*T zGUjmx83)>o1JJd0b!}h5;={He-pT`rOSOKR5t~(9wj4kl;LX-sZ@oESK;BqtN<-}a zFAz6t%d%x!*6@;ZfOb!S4^1*@OQ+2&d;$8Doan5=vgAO&e*K=e$z#|%oFny8Su!qb zbV)e?yTKoY$zqiE@ZmbLq=aXcl^qA*XUg-+v~yIR+jIW;=ZldeM>;-*w%C~4ZoBPk zWyid%!6oCsf&~k@A@=GwI$7m;nreJ&_(loDF4oF5aR9oMjQFggvf=>j01u*!>HbXT zRb7Am_1gTzLHoe6Vqn(Tl5qfMs+>p})BQ1iuMVDg;t6ej;ute#%&{dSKC7s#IADuG zY&weow%A5l9XD=VcCJ)eNl@t;J7dO-zNk$rd;R8Q_YDmM;b z58wlnyuv?PFmBqSMT?yCD{W^1(pRdqb!V9l6$!eT*;JLoElxMY-8wcpu zYK!e2MP8xzYC^2njmnL8S$j**0oxf`5oEOmaRJXMJ=Ix_<;VdnqAE^1?X=q?$YtI- zY~a9wBg>IzS)1FI0~cR>@i3e>@Ld#{<#&JZ;K5h5EyY>w<;;PpQ>X5ZGpC-h$ZHGE zP#MpB<;%NfEc_2@&IzOEUru&E*SK`Ml zAU}V-lkQf~=;v_I`xUHAryV|^sufYApWmt0uXtrT?i^6_H@N9_&WlDLPraL7tE9Wh zxtd_QOQuJtkH;m`Bh*iK$@B;fO-HA+LPfA%6m%h&-ryzY>iDA3YnLg#-p^kf$Ztyb zv$ry$(Zg>@_u1nz$jfg^_u1w$&dYB~_u1(()XN_?-Dk6cM@n}(z{6jtbl~$r=6{yn zI#RS19}3mK5%4%;F4~FiA11VN+ft!VZ_b(0>!f;}k zuC6(^X={3gl%C7gHM!~46_t%%c3jc=*8J7=l@cR1t!wPU^ij=7_Zhuf?$o-5zDRGb zY^iEknO<4ZSXX}m(i1WYwafrK0gvre9grRKq2p z12v+)xuW6J)^xC{zBL(N)S*pPPWq;`?1~0Ay-rjts;+O$ERxe5o;dszO}O{*Ful1oy%{(I>F9X2ix5Z`Lk;OK8PY}KbQE;KAp?)j)n|V$ zSHlD^-Djuro%P92`5i<(KFIZE>8<_JR(z0#LkRs!c`&7$1lj(8OIXnPRy7fjh zwc_FM16Y~va?V{itxR`0SL0-t^1Hv_+Pw4zr-Hh?bf5&ZCd+snf?P7?bf;p?I?fr< zYxD64wAkf>+%9BXxlEMtW7u?=fGi-+#fVE=rE^?&AwW;#O4 Date: Sun, 31 Jan 2021 15:27:00 +0100 Subject: [PATCH 058/158] Add test for UI methods --- freqtrade/commands/deploy_commands.py | 2 +- tests/rpc/test_rpc_apiserver.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 62da6abf3..797e9f87d 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -146,7 +146,7 @@ def clean_ui_subdir(directory: Path): logger.info("Removing UI directory content.") for p in reversed(list(directory.glob('**/*'))): # iterate contents from leaves to root - if p.name in ('.gitkeep', 'fallback_file.html'): + if p.name in ('favicon.ico', 'fallback_file.html'): continue if p.is_file(): p.unlink() diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 919481598..586af6dc1 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -88,6 +88,21 @@ def test_api_not_found(botclient): assert rc.json() == {"detail": "Not Found"} +def test_api_ui_fallback(botclient): + ftbot, client = botclient + + rc = client_get(client, "/favicon.ico") + assert rc.status_code == 200 + + rc = client_get(client, "/fallback_file.html") + assert rc.status_code == 200 + assert '`freqtrade install-ui`' in rc.text + + # Forwarded to fallback_html or index.html (depending if it's installed or not) + rc = client_get(client, "/something") + assert rc.status_code == 200 + + def test_api_auth(): with pytest.raises(ValueError): create_token({'identity': {'u': 'Freqtrade'}}, 'secret1234', token_type="NotATokenType") From 06e2bc94c3e111bcea180485018fd081da176104 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 15:37:57 +0100 Subject: [PATCH 059/158] Deploy to subdirectory --- freqtrade/commands/deploy_commands.py | 5 +++-- freqtrade/rpc/api_server/ui/installed/.gitkeep | 0 freqtrade/rpc/api_server/web_ui.py | 4 ++-- tests/commands/test_commands.py | 3 +++ 4 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 freqtrade/rpc/api_server/ui/installed/.gitkeep diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 797e9f87d..5ba3db9f9 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -146,7 +146,7 @@ def clean_ui_subdir(directory: Path): logger.info("Removing UI directory content.") for p in reversed(list(directory.glob('**/*'))): # iterate contents from leaves to root - if p.name in ('favicon.ico', 'fallback_file.html'): + if p.name in ('.gitkeep', 'fallback_file.html'): continue if p.is_file(): p.unlink() @@ -169,6 +169,7 @@ def download_and_install_ui(dest_folder: Path, dl_url: str, version: str): logger.info(f"Downloading {dl_url}") resp = requests.get(dl_url).content + dest_folder.mkdir(parents=True, exist_ok=True) with ZipFile(BytesIO(resp)) as zf: for fn in zf.filelist: with zf.open(fn) as x: @@ -207,7 +208,7 @@ def get_ui_download_url() -> Tuple[str, str]: def start_install_ui(args: Dict[str, Any]) -> None: - dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui' + dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui/installed/' # First make sure the assets are removed. dl_url, latest_version = get_ui_download_url() diff --git a/freqtrade/rpc/api_server/ui/installed/.gitkeep b/freqtrade/rpc/api_server/ui/installed/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/freqtrade/rpc/api_server/web_ui.py b/freqtrade/rpc/api_server/web_ui.py index 4876c9077..6d7e77953 100644 --- a/freqtrade/rpc/api_server/web_ui.py +++ b/freqtrade/rpc/api_server/web_ui.py @@ -20,12 +20,12 @@ async def index_html(rest_of_path: str): """ if rest_of_path.startswith('api') or rest_of_path.startswith('.'): raise HTTPException(status_code=404, detail="Not Found") - uibase = Path(__file__).parent / 'ui' + uibase = Path(__file__).parent / 'ui/installed/' if (uibase / rest_of_path).is_file(): return FileResponse(str(uibase / rest_of_path)) index_file = uibase / 'index.html' if not index_file.is_file(): - return FileResponse(str(uibase / 'fallback_file.html')) + return FileResponse(str(uibase.parent / 'fallback_file.html')) # Fall back to index.html, as indicated by vue router docs return FileResponse(str(index_file)) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 0d2b9e394..cec0b168e 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -622,6 +622,9 @@ def test_download_and_install_ui(mocker, tmpdir): folder = Path(tmpdir) / "uitests_dl" folder.mkdir(exist_ok=True) + + assert read_ui_version(folder) is None + download_and_install_ui(folder, 'http://whatever.xxx/download/file.zip', '22') assert wb_mock.call_count == 2 From 2c80388b40bca3a77d765801eb96722f992340ab Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 31 Jan 2021 19:49:14 +0100 Subject: [PATCH 060/158] Fix valueerror in case of empty array files --- freqtrade/data/history/jsondatahandler.py | 8 ++++++-- tests/commands/test_commands.py | 2 +- tests/data/test_history.py | 14 +++++++++++++- tests/rpc/test_rpc_apiserver.py | 2 +- tests/testdata/NOPAIR_XXX-4m.json | 1 + 5 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 tests/testdata/NOPAIR_XXX-4m.json diff --git a/freqtrade/data/history/jsondatahandler.py b/freqtrade/data/history/jsondatahandler.py index 9122170d5..301d228a8 100644 --- a/freqtrade/data/history/jsondatahandler.py +++ b/freqtrade/data/history/jsondatahandler.py @@ -86,8 +86,12 @@ class JsonDataHandler(IDataHandler): filename = self._pair_data_filename(self._datadir, pair, timeframe) if not filename.exists(): return DataFrame(columns=self._columns) - pairdata = read_json(filename, orient='values') - pairdata.columns = self._columns + try: + pairdata = read_json(filename, orient='values') + pairdata.columns = self._columns + except ValueError: + logger.error(f"Could not load data for {pair}.") + return DataFrame(columns=self._columns) pairdata = pairdata.astype(dtype={'open': 'float', 'high': 'float', 'low': 'float', 'close': 'float', 'volume': 'float'}) pairdata['date'] = to_datetime(pairdata['date'], diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index f8ecc8218..d655174b3 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1181,7 +1181,7 @@ def test_start_list_data(testdatadir, capsys): pargs['config'] = None start_list_data(pargs) captured = capsys.readouterr() - assert "Found 16 pair / timeframe combinations." in captured.out + assert "Found 17 pair / timeframe combinations." in captured.out assert "\n| Pair | Timeframe |\n" in captured.out assert "\n| UNITTEST/BTC | 1m, 5m, 8m, 30m |\n" in captured.out diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 99b22adda..353cfc6f7 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -646,7 +646,7 @@ def test_datahandler_ohlcv_get_available_data(testdatadir): ('ZEC/BTC', '5m'), ('UNITTEST/BTC', '1m'), ('ADA/BTC', '5m'), ('ETC/BTC', '5m'), ('NXT/BTC', '5m'), ('DASH/BTC', '5m'), ('XRP/ETH', '1m'), ('XRP/ETH', '5m'), ('UNITTEST/BTC', '30m'), - ('UNITTEST/BTC', '8m')} + ('UNITTEST/BTC', '8m'), ('NOPAIR/XXX', '4m')} paircombs = JsonGzDataHandler.ohlcv_get_available_data(testdatadir) assert set(paircombs) == {('UNITTEST/BTC', '8m')} @@ -672,6 +672,18 @@ def test_jsondatahandler_ohlcv_purge(mocker, testdatadir): assert unlinkmock.call_count == 1 +def test_jsondatahandler_ohlcv_load(testdatadir, caplog): + dh = JsonDataHandler(testdatadir) + df = dh.ohlcv_load('XRP/ETH', '5m') + assert len(df) == 711 + + # Failure case (empty array) + df1 = dh.ohlcv_load('NOPAIR/XXX', '4m') + assert len(df1) == 0 + assert log_has("Could not load data for NOPAIR/XXX.", caplog) + assert df.columns.equals(df1.columns) + + def test_jsondatahandler_trades_load(testdatadir, caplog): dh = JsonGzDataHandler(testdatadir) logmsg = "Old trades format detected - converting" diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index b050e5694..71f1b3172 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1109,7 +1109,7 @@ def test_list_available_pairs(botclient): rc = client_get(client, f"{BASE_URI}/available_pairs") assert_response(rc) - assert rc.json()['length'] == 12 + assert rc.json()['length'] == 13 assert isinstance(rc.json()['pairs'], list) rc = client_get(client, f"{BASE_URI}/available_pairs?timeframe=5m") diff --git a/tests/testdata/NOPAIR_XXX-4m.json b/tests/testdata/NOPAIR_XXX-4m.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/tests/testdata/NOPAIR_XXX-4m.json @@ -0,0 +1 @@ +[] From 76312d722a89ee88eb0b41e5c82224af1471a9bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 05:41:53 +0000 Subject: [PATCH 061/158] Bump pytest from 6.2.1 to 6.2.2 Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.1 to 6.2.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/6.2.1...6.2.2) Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 01066959a..fa0ead603 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,7 +8,7 @@ flake8==3.8.4 flake8-type-annotations==0.1.0 flake8-tidy-imports==4.2.1 mypy==0.790 -pytest==6.2.1 +pytest==6.2.2 pytest-asyncio==0.14.0 pytest-cov==2.11.1 pytest-mock==3.5.1 From ed1d4f0568985b456bdf293f7d5ded22e1644e77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 05:42:05 +0000 Subject: [PATCH 062/158] Bump jinja2 from 2.11.2 to 2.11.3 Bumps [jinja2](https://github.com/pallets/jinja) from 2.11.2 to 2.11.3. - [Release notes](https://github.com/pallets/jinja/releases) - [Changelog](https://github.com/pallets/jinja/blob/master/CHANGES.rst) - [Commits](https://github.com/pallets/jinja/compare/2.11.2...2.11.3) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c6cb3e445..9c03f1087 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ jsonschema==3.2.0 TA-Lib==0.4.19 tabulate==0.8.7 pycoingecko==1.4.0 -jinja2==2.11.2 +jinja2==2.11.3 tables==3.6.1 blosc==1.10.2 From aa7120f27c318458c44926188619d242865a82e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 05:42:06 +0000 Subject: [PATCH 063/158] Bump ccxt from 1.40.99 to 1.41.35 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.40.99 to 1.41.35. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/doc/exchanges-by-country.rst) - [Commits](https://github.com/ccxt/ccxt/compare/1.40.99...1.41.35) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c6cb3e445..4d69cff0b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ numpy==1.20.0 pandas==1.2.1 -ccxt==1.40.99 +ccxt==1.41.35 aiohttp==3.7.3 SQLAlchemy==1.3.22 python-telegram-bot==13.1 From 2a5e0920ecec6dcb74afc5e552dcf44c468a8def Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 05:42:08 +0000 Subject: [PATCH 064/158] Bump mkdocs-material from 6.2.5 to 6.2.7 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 6.2.5 to 6.2.7. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/6.2.5...6.2.7) Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 6fef05f0c..8886fd287 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,3 +1,3 @@ -mkdocs-material==6.2.5 +mkdocs-material==6.2.7 mdx_truly_sane_lists==1.2 pymdown-extensions==8.1 From 7fcf0d52319c81ec44c25d45321840dfa6ea63fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 08:45:31 +0000 Subject: [PATCH 065/158] Bump pymdown-extensions from 8.1 to 8.1.1 Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 8.1 to 8.1.1. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/8.1...8.1.1) Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 8886fd287..85bd72323 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,3 +1,3 @@ mkdocs-material==6.2.7 mdx_truly_sane_lists==1.2 -pymdown-extensions==8.1 +pymdown-extensions==8.1.1 From ccdac3d4c3e1ae8f83e8acb8fc47b6d8dd4a6d20 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 08:50:24 +0000 Subject: [PATCH 066/158] Bump urllib3 from 1.26.2 to 1.26.3 Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.2 to 1.26.3. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/1.26.3/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.2...1.26.3) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index eff13cd57..e247d4b00 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ python-telegram-bot==13.1 arrow==0.17.0 cachetools==4.2.1 requests==2.25.1 -urllib3==1.26.2 +urllib3==1.26.3 wrapt==1.12.1 jsonschema==3.2.0 TA-Lib==0.4.19 From 4facf662de3dacd83fa15cee0004bcb90dea4e6c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Feb 2021 11:00:55 +0100 Subject: [PATCH 067/158] Fix random test-failure caused by un-clean hyperopt shutdown pytest --random-order-seed=415781 --- tests/optimize/test_hyperopt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 89c7305b6..68eb3d6f7 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -251,9 +251,9 @@ def test_start_no_data(mocker, hyperopt_conf) -> None: def test_start_filelock(mocker, hyperopt_conf, caplog) -> None: - start_mock = MagicMock(side_effect=Timeout(Hyperopt.get_lock_filename(hyperopt_conf))) + hyperopt_mock = MagicMock(side_effect=Timeout(Hyperopt.get_lock_filename(hyperopt_conf))) patched_configuration_load_config_file(mocker, hyperopt_conf) - mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) + mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.__init__', hyperopt_mock) patch_exchange(mocker) args = [ From cd5c58fd370f4d11469d58dc01bf61637393b3fa Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Feb 2021 12:58:18 +0100 Subject: [PATCH 068/158] Properly patch exchange for plot_profit test --- tests/test_plotting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 4c8ac4816..1752f9b94 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -432,7 +432,8 @@ def test_start_plot_profit_error(mocker): start_plot_profit(argsp) -def test_plot_profit(default_conf, mocker, testdatadir, caplog): +def test_plot_profit(default_conf, mocker, testdatadir): + patch_exchange(mocker) default_conf['trade_source'] = 'file' default_conf['datadir'] = testdatadir default_conf['exportfilename'] = testdatadir / 'backtest-result_test_nofile.json' From 55c9489eb2907d2354a0bc51c493ebc8fa9fc74d Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Feb 2021 15:10:55 +0100 Subject: [PATCH 069/158] Downgrade RPI docker-image to 3.7 otherwise piwheels.org does not work at the moment --- Dockerfile.armhf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.armhf b/Dockerfile.armhf index 2c7d4538a..b6f2e44e6 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM --platform=linux/arm/v7 python:3.9.1-slim-buster as base +FROM --platform=linux/arm/v7 python:3.7.9-slim-buster as base # Setup env ENV LANG C.UTF-8 From 130a9b4db33afb9e71ffe917c70d301611d05e17 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Feb 2021 19:39:55 +0100 Subject: [PATCH 070/158] Add test to call verify_pairlist multiple times --- tests/plugins/test_pairlist.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index fda2b1409..67cd96f5b 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -126,6 +126,20 @@ def test_load_pairlist_noexist(mocker, markets, default_conf): default_conf, {}, 1) +def test_load_pairlist_verify_multi(mocker, markets, default_conf): + freqtrade = get_patched_freqtradebot(mocker, default_conf) + mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets)) + plm = PairListManager(freqtrade.exchange, default_conf) + # Call different versions one after the other, should always consider what was passed in + # and have no side-effects (therefore the same check multiple times) + assert plm.verify_whitelist(['ETH/BTC', 'XRP/BTC', ], print) == ['ETH/BTC', 'XRP/BTC'] + assert plm.verify_whitelist(['ETH/BTC', 'XRP/BTC', 'BUUU/BTC'], print) == ['ETH/BTC', 'XRP/BTC'] + assert plm.verify_whitelist(['XRP/BTC', 'BUUU/BTC'], print) == ['XRP/BTC'] + assert plm.verify_whitelist(['ETH/BTC', 'XRP/BTC', ], print) == ['ETH/BTC', 'XRP/BTC'] + assert plm.verify_whitelist(['ETH/USDT', 'XRP/USDT', ], print) == ['ETH/USDT', ] + assert plm.verify_whitelist(['ETH/BTC', 'XRP/BTC', ], print) == ['ETH/BTC', 'XRP/BTC'] + + def test_refresh_market_pair_not_in_whitelist(mocker, markets, static_pl_conf): freqtrade = get_patched_freqtradebot(mocker, static_pl_conf) From 52acf9aaf6648e7478acad42619f4222b6c01614 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Feb 2021 19:40:31 +0100 Subject: [PATCH 071/158] Fix "disappearing pairs" bug closes #4277 --- freqtrade/plugins/pairlist/IPairList.py | 2 +- freqtrade/plugins/pairlistmanager.py | 17 ++--------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/freqtrade/plugins/pairlist/IPairList.py b/freqtrade/plugins/pairlist/IPairList.py index 95d776ae6..184feff9e 100644 --- a/freqtrade/plugins/pairlist/IPairList.py +++ b/freqtrade/plugins/pairlist/IPairList.py @@ -168,7 +168,7 @@ class IPairList(LoggingMixin, ABC): # Check if market is active market = markets[pair] if not market_is_active(market): - logger.info(f"Ignoring {pair} from whitelist. Market is not active.") + self.log_once(f"Ignoring {pair} from whitelist. Market is not active.", logger.info) continue if pair not in sanitized_whitelist: sanitized_whitelist.append(pair) diff --git a/freqtrade/plugins/pairlistmanager.py b/freqtrade/plugins/pairlistmanager.py index 7ce77da59..4e4135981 100644 --- a/freqtrade/plugins/pairlistmanager.py +++ b/freqtrade/plugins/pairlistmanager.py @@ -59,17 +59,6 @@ class PairListManager(): """The expanded blacklist (including wildcard expansion)""" return expand_pairlist(self._blacklist, self._exchange.get_markets().keys()) - @property - def expanded_whitelist_keep_invalid(self) -> List[str]: - """The expanded whitelist (including wildcard expansion), maintaining invalid pairs""" - return expand_pairlist(self._whitelist, self._exchange.get_markets().keys(), - keep_invalid=True) - - @property - def expanded_whitelist(self) -> List[str]: - """The expanded whitelist (including wildcard expansion), filtering invalid pairs""" - return expand_pairlist(self._whitelist, self._exchange.get_markets().keys()) - @property def name_list(self) -> List[str]: """Get list of loaded Pairlist Handler names""" @@ -153,10 +142,8 @@ class PairListManager(): :return: pairlist - whitelisted pairs """ try: - if keep_invalid: - whitelist = self.expanded_whitelist_keep_invalid - else: - whitelist = self.expanded_whitelist + + whitelist = expand_pairlist(pairlist, self._exchange.get_markets().keys(), keep_invalid) except ValueError as err: logger.error(f"Pair whitelist contains an invalid Wildcard: {err}") return [] From a9f1c871ddb68734ee179598dc08a21dda982f16 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Feb 2021 19:48:29 +0100 Subject: [PATCH 072/158] Add path loading snippet to derived strategies closes #4279 --- docs/strategy-advanced.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/strategy-advanced.md b/docs/strategy-advanced.md index ca20d3588..c051e2232 100644 --- a/docs/strategy-advanced.md +++ b/docs/strategy-advanced.md @@ -399,6 +399,17 @@ class MyAwesomeStrategy2(MyAwesomeStrategy): Both attributes and methods may be overridden, altering behavior of the original strategy in a way you need. +!!! Note "Parent-strategy in different files" + If you have the parent-strategy in a different file, you'll need to add the following to the top of your "child"-file to ensure proper loading, otherwise freqtrade may not be able to load the parent strategy correctly. + + ``` python + import sys + from pathlib import Path + sys.path.append(str(Path(__file__).parent)) + + from myawesomestrategy import MyAwesomeStrategy + ``` + ## Embedding Strategies Freqtrade provides you with with an easy way to embed the strategy into your configuration file. From 3d9b4034e683e9985c2695418eedba7bb0ac7070 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Feb 2021 08:06:19 +0100 Subject: [PATCH 073/158] Use already calculated current_profit for sell_profit_offset comparison --- freqtrade/strategy/interface.py | 2 +- tests/test_freqtradebot.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 77d45b445..da4ce6c50 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -530,7 +530,7 @@ class IStrategy(ABC): current_time=date)) if (ask_strategy.get('sell_profit_only', False) - and trade.calc_profit_ratio(rate=rate) <= ask_strategy.get('sell_profit_offset', 0)): + and current_profit <= ask_strategy.get('sell_profit_offset', 0)): # sell_profit_only and profit doesn't reach the offset - ignore sell signal sell_signal = False else: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 2408afc87..e2b70257a 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3159,9 +3159,9 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, limit_buy mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00002172, - 'ask': 0.00002173, - 'last': 0.00002172 + 'bid': 0.00001172, + 'ask': 0.00001173, + 'last': 0.00001172 }), buy=MagicMock(return_value=limit_buy_order_open), get_fee=fee, From cfd0bb896472b21b3a0cf8051f5e6f54d3e08296 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Feb 2021 19:47:21 +0100 Subject: [PATCH 074/158] Extract min stake amount from bot to exchange class --- freqtrade/exchange/exchange.py | 37 ++++++++- freqtrade/freqtradebot.py | 37 +-------- tests/exchange/test_exchange.py | 130 ++++++++++++++++++++++++++++++ tests/test_freqtradebot.py | 137 +------------------------------- 4 files changed, 170 insertions(+), 171 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 78e17359d..c7625b53c 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -17,7 +17,7 @@ from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE, TRU decimal_to_precision) from pandas import DataFrame -from freqtrade.constants import ListPairsWithTimeframes +from freqtrade.constants import DEFAULT_AMOUNT_RESERVE_PERCENT, ListPairsWithTimeframes from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFundsError, InvalidOrderException, OperationalException, RetryableOrderError, @@ -490,6 +490,41 @@ class Exchange: else: return 1 / pow(10, precision) + def get_min_pair_stake_amount(self, pair: str, price: float, + stoploss: float) -> Optional[float]: + try: + market = self.markets[pair] + except KeyError: + raise ValueError(f"Can't get market information for symbol {pair}") + + if 'limits' not in market: + return None + + min_stake_amounts = [] + limits = market['limits'] + if ('cost' in limits and 'min' in limits['cost'] + and limits['cost']['min'] is not None): + min_stake_amounts.append(limits['cost']['min']) + + if ('amount' in limits and 'min' in limits['amount'] + and limits['amount']['min'] is not None): + min_stake_amounts.append(limits['amount']['min'] * price) + + if not min_stake_amounts: + return None + + # reserve some percent defined in config (5% default) + stoploss + amount_reserve_percent = 1.0 - self._config.get('amount_reserve_percent', + DEFAULT_AMOUNT_RESERVE_PERCENT) + amount_reserve_percent += stoploss + # it should not be more than 50% + amount_reserve_percent = max(amount_reserve_percent, 0.5) + + # The value returned should satisfy both limits: for amount (base currency) and + # for cost (quote, stake currency), so max() is used here. + # See also #2575 at github. + return max(min_stake_amounts) / amount_reserve_percent + def dry_run_order(self, pair: str, ordertype: str, side: str, amount: float, rate: float, params: Dict = {}) -> Dict[str, Any]: order_id = f'dry_run_{side}_{datetime.now().timestamp()}' diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d7116834a..2656daab5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -516,40 +516,6 @@ class FreqtradeBot(LoggingMixin): return stake_amount - def _get_min_pair_stake_amount(self, pair: str, price: float) -> Optional[float]: - try: - market = self.exchange.markets[pair] - except KeyError: - raise ValueError(f"Can't get market information for symbol {pair}") - - if 'limits' not in market: - return None - - min_stake_amounts = [] - limits = market['limits'] - if ('cost' in limits and 'min' in limits['cost'] - and limits['cost']['min'] is not None): - min_stake_amounts.append(limits['cost']['min']) - - if ('amount' in limits and 'min' in limits['amount'] - and limits['amount']['min'] is not None): - min_stake_amounts.append(limits['amount']['min'] * price) - - if not min_stake_amounts: - return None - - # reserve some percent defined in config (5% default) + stoploss - amount_reserve_percent = 1.0 - self.config.get('amount_reserve_percent', - constants.DEFAULT_AMOUNT_RESERVE_PERCENT) - amount_reserve_percent += self.strategy.stoploss - # it should not be more than 50% - amount_reserve_percent = max(amount_reserve_percent, 0.5) - - # The value returned should satisfy both limits: for amount (base currency) and - # for cost (quote, stake currency), so max() is used here. - # See also #2575 at github. - return max(min_stake_amounts) / amount_reserve_percent - def create_trade(self, pair: str) -> bool: """ Check the implemented trading strategy for buy signals. @@ -646,7 +612,8 @@ class FreqtradeBot(LoggingMixin): if not buy_limit_requested: raise PricingError('Could not determine buy price.') - min_stake_amount = self._get_min_pair_stake_amount(pair, buy_limit_requested) + min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, buy_limit_requested, + self.strategy.stoploss) if min_stake_amount is not None and min_stake_amount > stake_amount: logger.warning( f"Can't open a new trade for {pair}: stake amount " diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index a35dc9da9..cd24e113e 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -305,6 +305,136 @@ def test_price_get_one_pip(default_conf, mocker, price, precision_mode, precisio assert pytest.approx(exchange.price_get_one_pip(pair, price)) == expected +def test_get_min_pair_stake_amount(mocker, default_conf) -> None: + + exchange = get_patched_exchange(mocker, default_conf, id="binance") + stoploss = -0.05 + markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}} + + # no pair found + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + with pytest.raises(ValueError, match=r'.*get market information.*'): + exchange.get_min_pair_stake_amount('BNB/BTC', 1, stoploss) + + # no 'limits' section + result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) + assert result is None + + # empty 'limits' section + markets["ETH/BTC"]["limits"] = {} + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) + assert result is None + + # no cost Min + markets["ETH/BTC"]["limits"] = { + 'cost': {"min": None}, + 'amount': {} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) + assert result is None + + # no amount Min + markets["ETH/BTC"]["limits"] = { + 'cost': {}, + 'amount': {"min": None} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) + assert result is None + + # empty 'cost'/'amount' section + markets["ETH/BTC"]["limits"] = { + 'cost': {}, + 'amount': {} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) + assert result is None + + # min cost is set + markets["ETH/BTC"]["limits"] = { + 'cost': {'min': 2}, + 'amount': {} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 1, stoploss) + assert result == 2 / 0.9 + + # min amount is set + markets["ETH/BTC"]["limits"] = { + 'cost': {}, + 'amount': {'min': 2} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss) + assert result == 2 * 2 / 0.9 + + # min amount and cost are set (cost is minimal) + markets["ETH/BTC"]["limits"] = { + 'cost': {'min': 2}, + 'amount': {'min': 2} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss) + assert result == max(2, 2 * 2) / 0.9 + + # min amount and cost are set (amount is minial) + markets["ETH/BTC"]["limits"] = { + 'cost': {'min': 8}, + 'amount': {'min': 2} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 2, stoploss) + assert result == max(8, 2 * 2) / 0.9 + + +def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None: + exchange = get_patched_exchange(mocker, default_conf, id="binance") + stoploss = -0.05 + markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}} + + # Real Binance data + markets["ETH/BTC"]["limits"] = { + 'cost': {'min': 0.0001}, + 'amount': {'min': 0.001} + } + mocker.patch( + 'freqtrade.exchange.Exchange.markets', + PropertyMock(return_value=markets) + ) + result = exchange.get_min_pair_stake_amount('ETH/BTC', 0.020405, stoploss) + assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) / 0.9, 8) + + def test_set_sandbox(default_conf, mocker): """ Test working scenario diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index e2b70257a..abb91d66b 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -394,139 +394,6 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker, fee) -> None: assert Trade.total_open_trades_stakes() == 1.97502e-03 -def test_get_min_pair_stake_amount(mocker, default_conf) -> None: - patch_RPCManager(mocker) - patch_exchange(mocker) - freqtrade = FreqtradeBot(default_conf) - freqtrade.strategy.stoploss = -0.05 - markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}} - - # no pair found - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - with pytest.raises(ValueError, match=r'.*get market information.*'): - freqtrade._get_min_pair_stake_amount('BNB/BTC', 1) - - # no 'limits' section - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) - assert result is None - - # empty 'limits' section - markets["ETH/BTC"]["limits"] = {} - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) - assert result is None - - # no cost Min - markets["ETH/BTC"]["limits"] = { - 'cost': {"min": None}, - 'amount': {} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) - assert result is None - - # no amount Min - markets["ETH/BTC"]["limits"] = { - 'cost': {}, - 'amount': {"min": None} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) - assert result is None - - # empty 'cost'/'amount' section - markets["ETH/BTC"]["limits"] = { - 'cost': {}, - 'amount': {} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) - assert result is None - - # min cost is set - markets["ETH/BTC"]["limits"] = { - 'cost': {'min': 2}, - 'amount': {} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) - assert result == 2 / 0.9 - - # min amount is set - markets["ETH/BTC"]["limits"] = { - 'cost': {}, - 'amount': {'min': 2} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) - assert result == 2 * 2 / 0.9 - - # min amount and cost are set (cost is minimal) - markets["ETH/BTC"]["limits"] = { - 'cost': {'min': 2}, - 'amount': {'min': 2} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) - assert result == max(2, 2 * 2) / 0.9 - - # min amount and cost are set (amount is minial) - markets["ETH/BTC"]["limits"] = { - 'cost': {'min': 8}, - 'amount': {'min': 2} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) - assert result == max(8, 2 * 2) / 0.9 - - -def test_get_min_pair_stake_amount_real_data(mocker, default_conf) -> None: - patch_RPCManager(mocker) - patch_exchange(mocker) - freqtrade = FreqtradeBot(default_conf) - freqtrade.strategy.stoploss = -0.05 - markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}} - - # Real Binance data - markets["ETH/BTC"]["limits"] = { - 'cost': {'min': 0.0001}, - 'amount': {'min': 0.001} - } - mocker.patch( - 'freqtrade.exchange.Exchange.markets', - PropertyMock(return_value=markets) - ) - result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 0.020405) - assert round(result, 8) == round(max(0.0001, 0.001 * 0.020405) / 0.9, 8) - - def test_create_trade(default_conf, ticker, limit_buy_order, fee, mocker) -> None: patch_RPCManager(mocker) patch_exchange(mocker) @@ -1007,7 +874,6 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order mocker.patch.multiple( 'freqtrade.freqtradebot.FreqtradeBot', get_buy_rate=buy_rate_mock, - _get_min_pair_stake_amount=MagicMock(return_value=1) ) buy_mm = MagicMock(return_value=limit_buy_order_open) mocker.patch.multiple( @@ -1018,6 +884,7 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order 'last': 0.00001172 }), buy=buy_mm, + get_min_pair_stake_amount=MagicMock(return_value=1), get_fee=fee, ) pair = 'ETH/BTC' @@ -1112,7 +979,6 @@ def test_execute_buy_confirm_error(mocker, default_conf, fee, limit_buy_order) - mocker.patch.multiple( 'freqtrade.freqtradebot.FreqtradeBot', get_buy_rate=MagicMock(return_value=0.11), - _get_min_pair_stake_amount=MagicMock(return_value=1) ) mocker.patch.multiple( 'freqtrade.exchange.Exchange', @@ -1122,6 +988,7 @@ def test_execute_buy_confirm_error(mocker, default_conf, fee, limit_buy_order) - 'last': 0.00001172 }), buy=MagicMock(return_value=limit_buy_order), + get_min_pair_stake_amount=MagicMock(return_value=1), get_fee=fee, ) stake_amount = 2 From f0532f28cf01b03d05c332a1f2a5e13475bd510d Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Feb 2021 20:03:01 +0100 Subject: [PATCH 075/158] Small doc-reorg adding "advanced topics" as main header --- docs/bot-basics.md | 1 + mkdocs.yml | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/bot-basics.md b/docs/bot-basics.md index 86fb18645..30a25d4fc 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -4,6 +4,7 @@ This page provides you some basic concepts on how Freqtrade works and operates. ## Freqtrade terminology +* Strategy: Your trading strategy, telling the bot what to do. * Trade: Open position. * Open Order: Order which is currently placed on the exchange, and is not yet complete. * Pair: Tradable pair, usually in the format of Quote/Base (e.g. XRP/USDT). diff --git a/mkdocs.yml b/mkdocs.yml index 4545e8d84..47ab8ec48 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,6 +8,7 @@ nav: - Freqtrade Basics: bot-basics.md - Configuration: configuration.md - Strategy Customization: strategy-customization.md + - Plugins: plugins.md - Stoploss: stoploss.md - Start the bot: bot-usage.md - Control the bot: @@ -17,20 +18,20 @@ nav: - Data Downloading: data-download.md - Backtesting: backtesting.md - Hyperopt: hyperopt.md - - Edge Positioning: edge.md - - Plugins: plugins.md - - Utility Subcommands: utils.md - - FAQ: faq.md + - Utility Sub-commands: utils.md - Data Analysis: - Jupyter Notebooks: data-analysis.md - Strategy analysis: strategy_analysis_example.md - Plotting: plotting.md - - SQL Cheatsheet: sql_cheatsheet.md - Exchange-specific Notes: exchanges.md - - Advanced Post-installation Tasks: advanced-setup.md - - Advanced Strategy: strategy-advanced.md - - Advanced Hyperopt: advanced-hyperopt.md - - Sandbox Testing: sandbox-testing.md + - Advanced Topics: + - Advanced Post-installation Tasks: advanced-setup.md + - Edge Positioning: edge.md + - Advanced Strategy: strategy-advanced.md + - Advanced Hyperopt: advanced-hyperopt.md + - Sandbox Testing: sandbox-testing.md + - FAQ: faq.md + - SQL Cheat-sheet: sql_cheatsheet.md - Updating Freqtrade: updating.md - Deprecated Features: deprecated.md - Contributors Guide: developer.md From 3e3c9e99c75a8efb6b49c684a337b1ec5cfd8045 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Feb 2021 20:03:28 +0100 Subject: [PATCH 076/158] Move command references to their respective subpages --- docs/backtesting.md | 83 +++++++++++++++ docs/bot-usage.md | 252 -------------------------------------------- docs/edge.md | 55 ++++++++++ docs/hyperopt.md | 101 ++++++++++++++++++ 4 files changed, 239 insertions(+), 252 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index e1ab1c72d..15b189ebf 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -5,6 +5,89 @@ This page explains how to validate your strategy performance by using Backtestin Backtesting requires historic data to be available. To learn how to get data for the pairs and exchange you're interested in, head over to the [Data Downloading](data-download.md) section of the documentation. +## Backtesting command reference + +``` +usage: freqtrade backtesting [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] [-s NAME] + [--strategy-path PATH] [-i TIMEFRAME] + [--timerange TIMERANGE] + [--data-format-ohlcv {json,jsongz,hdf5}] + [--max-open-trades INT] + [--stake-amount STAKE_AMOUNT] [--fee FLOAT] + [--eps] [--dmmp] [--enable-protections] + [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] + [--export EXPORT] [--export-filename PATH] + +optional arguments: + -h, --help show this help message and exit + -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME + Specify ticker interval (`1m`, `5m`, `30m`, `1h`, + `1d`). + --timerange TIMERANGE + Specify what timerange of data to use. + --data-format-ohlcv {json,jsongz,hdf5} + Storage format for downloaded candle (OHLCV) data. + (default: `None`). + --max-open-trades INT + Override the value of the `max_open_trades` + configuration setting. + --stake-amount STAKE_AMOUNT + Override the value of the `stake_amount` configuration + setting. + --fee FLOAT Specify fee ratio. Will be applied twice (on trade + entry and exit). + --eps, --enable-position-stacking + Allow buying the same pair multiple times (position + stacking). + --dmmp, --disable-max-market-positions + Disable applying `max_open_trades` during backtest + (same as setting `max_open_trades` to a very high + number). + --enable-protections, --enableprotections + Enable protections for backtesting.Will slow + backtesting down by a considerable amount, but will + include configured protections + --strategy-list STRATEGY_LIST [STRATEGY_LIST ...] + Provide a space-separated list of strategies to + backtest. Please note that ticker-interval needs to be + set either in config or via command line. When using + this together with `--export trades`, the strategy- + name is injected into the filename (so `backtest- + data.json` becomes `backtest-data- + DefaultStrategy.json` + --export EXPORT Export backtest results, argument are: trades. + Example: `--export=trades` + --export-filename PATH + Save backtest results to the file with this filename. + Requires `--export` to be set as well. Example: + `--export-filename=user_data/backtest_results/backtest + _today.json` + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + 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 + Path to userdata directory. + +Strategy arguments: + -s NAME, --strategy NAME + Specify strategy class name which will be used by the + bot. + --strategy-path PATH Specify additional strategy lookup path. + +``` + ## Test your strategy with Backtesting Now you have good Buy and Sell strategies and some historic data, you want to test it against diff --git a/docs/bot-usage.md b/docs/bot-usage.md index 5820b3cc7..c7fe8634d 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -205,258 +205,6 @@ in production mode. Example command: freqtrade trade -c config.json --db-url sqlite:///tradesv3.dry_run.sqlite ``` -## Backtesting commands - -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 TIMEFRAME] - [--timerange TIMERANGE] - [--data-format-ohlcv {json,jsongz,hdf5}] - [--max-open-trades INT] - [--stake-amount STAKE_AMOUNT] [--fee FLOAT] - [--eps] [--dmmp] [--enable-protections] - [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] - [--export EXPORT] [--export-filename PATH] - -optional arguments: - -h, --help show this help message and exit - -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME - Specify ticker interval (`1m`, `5m`, `30m`, `1h`, - `1d`). - --timerange TIMERANGE - Specify what timerange of data to use. - --data-format-ohlcv {json,jsongz,hdf5} - Storage format for downloaded candle (OHLCV) data. - (default: `None`). - --max-open-trades INT - Override the value of the `max_open_trades` - configuration setting. - --stake-amount STAKE_AMOUNT - Override the value of the `stake_amount` configuration - setting. - --fee FLOAT Specify fee ratio. Will be applied twice (on trade - entry and exit). - --eps, --enable-position-stacking - Allow buying the same pair multiple times (position - stacking). - --dmmp, --disable-max-market-positions - Disable applying `max_open_trades` during backtest - (same as setting `max_open_trades` to a very high - number). - --enable-protections, --enableprotections - Enable protections for backtesting.Will slow - backtesting down by a considerable amount, but will - include configured protections - --strategy-list STRATEGY_LIST [STRATEGY_LIST ...] - Provide a space-separated list of strategies to - backtest. Please note that ticker-interval needs to be - set either in config or via command line. When using - this together with `--export trades`, the strategy- - name is injected into the filename (so `backtest- - data.json` becomes `backtest-data- - DefaultStrategy.json` - --export EXPORT Export backtest results, argument are: trades. - Example: `--export=trades` - --export-filename PATH - Save backtest results to the file with this filename. - Requires `--export` to be set as well. Example: - `--export-filename=user_data/backtest_results/backtest - _today.json` - -Common arguments: - -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: - 'syslog', 'journald'. See the documentation for more - details. - -V, --version show program's version number and exit - -c PATH, --config PATH - 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 - Path to userdata directory. - -Strategy arguments: - -s NAME, --strategy NAME - Specify strategy class name which will be used by the - bot. - --strategy-path PATH Specify additional strategy lookup path. - -``` - -### Getting historic data for backtesting - -The first time your run Backtesting, you will need to download some historic data first. -This can be accomplished by using `freqtrade download-data`. -Check the corresponding [Data Downloading](data-download.md) section for more details - -## Hyperopt commands - -To optimize your strategy, you can use hyperopt parameter hyperoptimization -to find optimal parameter values for your strategy. - -``` -usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] - [--userdir PATH] [-s NAME] [--strategy-path PATH] - [-i TIMEFRAME] [--timerange TIMERANGE] - [--data-format-ohlcv {json,jsongz,hdf5}] - [--max-open-trades INT] - [--stake-amount STAKE_AMOUNT] [--fee FLOAT] - [--hyperopt NAME] [--hyperopt-path PATH] [--eps] - [--dmmp] [--enable-protections] [-e INT] - [--spaces {all,buy,sell,roi,stoploss,trailing,default} [{all,buy,sell,roi,stoploss,trailing,default} ...]] - [--print-all] [--no-color] [--print-json] [-j JOBS] - [--random-state INT] [--min-trades INT] - [--hyperopt-loss NAME] - -optional arguments: - -h, --help show this help message and exit - -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME - Specify ticker interval (`1m`, `5m`, `30m`, `1h`, - `1d`). - --timerange TIMERANGE - Specify what timerange of data to use. - --data-format-ohlcv {json,jsongz,hdf5} - Storage format for downloaded candle (OHLCV) data. - (default: `None`). - --max-open-trades INT - Override the value of the `max_open_trades` - configuration setting. - --stake-amount STAKE_AMOUNT - Override the value of the `stake_amount` configuration - setting. - --fee FLOAT Specify fee ratio. Will be applied twice (on trade - entry and exit). - --hyperopt NAME Specify hyperopt class name which will be used by the - bot. - --hyperopt-path PATH Specify additional lookup path for Hyperopt and - Hyperopt Loss functions. - --eps, --enable-position-stacking - Allow buying the same pair multiple times (position - stacking). - --dmmp, --disable-max-market-positions - Disable applying `max_open_trades` during backtest - (same as setting `max_open_trades` to a very high - number). - --enable-protections, --enableprotections - Enable protections for backtesting.Will slow - backtesting down by a considerable amount, but will - include configured protections - -e INT, --epochs INT Specify number of epochs (default: 100). - --spaces {all,buy,sell,roi,stoploss,trailing,default} [{all,buy,sell,roi,stoploss,trailing,default} ...] - Specify which parameters to hyperopt. Space-separated - list. - --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 output in JSON format. - -j JOBS, --job-workers JOBS - The number of concurrently running jobs for - hyperoptimization (hyperopt worker processes). If -1 - (default), all CPUs are used, for -2, all CPUs but one - are used, etc. If 1 is given, no parallel computing - code is used at all. - --random-state INT Set random state to some positive integer for - reproducible hyperopt results. - --min-trades INT Set minimal desired number of trades for evaluations - in the hyperopt optimization path (default: 1). - --hyperopt-loss NAME Specify the class name of the hyperopt loss function - class (IHyperOptLoss). Different functions can - generate completely different results, since the - target for optimization is different. Built-in - Hyperopt-loss-functions are: - ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss, - SharpeHyperOptLoss, SharpeHyperOptLossDaily, - SortinoHyperOptLoss, SortinoHyperOptLossDaily - -Common arguments: - -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: - 'syslog', 'journald'. See the documentation for more - details. - -V, --version show program's version number and exit - -c PATH, --config PATH - 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 - Path to userdata directory. - -Strategy arguments: - -s NAME, --strategy NAME - Specify strategy class name which will be used by the - bot. - --strategy-path PATH Specify additional strategy lookup path. - -``` - -## Edge commands - -To know your trade expectancy and winrate against historical data, you can use Edge. - -``` -usage: freqtrade edge [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] - [--userdir PATH] [-s NAME] [--strategy-path PATH] - [-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 TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME - Specify ticker interval (`1m`, `5m`, `30m`, `1h`, - `1d`). - --timerange TIMERANGE - Specify what timerange of data to use. - --max-open-trades INT - Override the value of the `max_open_trades` - configuration setting. - --stake-amount STAKE_AMOUNT - Override the value of the `stake_amount` configuration - setting. - --fee FLOAT Specify fee ratio. Will be applied twice (on trade - entry and exit). - --stoplosses STOPLOSS_RANGE - Defines a range of stoploss values against which edge - will assess the strategy. The format is "min,max,step" - (without any space). Example: - `--stoplosses=-0.01,-0.1,-0.001` - -Common arguments: - -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: - 'syslog', 'journald'. See the documentation for more - details. - -V, --version show program's version number and exit - -c PATH, --config PATH - 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 - Path to userdata directory. - -Strategy arguments: - -s NAME, --strategy NAME - Specify strategy class name which will be used by the - bot. - --strategy-path PATH Specify additional strategy lookup path. - -``` - -To understand edge and how to read the results, please read the [edge documentation](edge.md). - ## Next step The optimal strategy of the bot will change with time depending of the market trends. The next step is to diff --git a/docs/edge.md b/docs/edge.md index 6f01fcf65..5565ca2f9 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -9,6 +9,7 @@ The `Edge Positioning` module uses probability to calculate your win rate and ri `Edge Positioning` only considers *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file. `Edge Positioning` improves the performance of some trading strategies and *decreases* the performance of others. + ## Introduction Trading strategies are not perfect. They are frameworks that are susceptible to the market and its indicators. Because the market is not at all predictable, sometimes a strategy will win and sometimes the same strategy will lose. @@ -208,6 +209,60 @@ Let's say the stake currency is **ETH** and there is $10$ **ETH** on the wallet. - **Trade 4** The strategy detects a new buy signal int the **XLM/ETH** market. `Edge Positioning` calculates the stoploss of $2\%$, and the position size of $0.055 / 0.02 = 2.75$ **ETH**. +## Edge command reference + +``` +usage: freqtrade edge [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] + [--userdir PATH] [-s NAME] [--strategy-path PATH] + [-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 TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME + Specify ticker interval (`1m`, `5m`, `30m`, `1h`, + `1d`). + --timerange TIMERANGE + Specify what timerange of data to use. + --max-open-trades INT + Override the value of the `max_open_trades` + configuration setting. + --stake-amount STAKE_AMOUNT + Override the value of the `stake_amount` configuration + setting. + --fee FLOAT Specify fee ratio. Will be applied twice (on trade + entry and exit). + --stoplosses STOPLOSS_RANGE + Defines a range of stoploss values against which edge + will assess the strategy. The format is "min,max,step" + (without any space). Example: + `--stoplosses=-0.01,-0.1,-0.001` + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + 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 + Path to userdata directory. + +Strategy arguments: + -s NAME, --strategy NAME + Specify strategy class name which will be used by the + bot. + --strategy-path PATH Specify additional strategy lookup path. + +``` + ## Configurations Edge module has following configuration options: diff --git a/docs/hyperopt.md b/docs/hyperopt.md index f88d9cd4f..ec155062f 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -32,6 +32,107 @@ source .env/bin/activate pip install -r requirements-hyperopt.txt ``` +## Hyperopt command reference + + +``` +usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] + [--userdir PATH] [-s NAME] [--strategy-path PATH] + [-i TIMEFRAME] [--timerange TIMERANGE] + [--data-format-ohlcv {json,jsongz,hdf5}] + [--max-open-trades INT] + [--stake-amount STAKE_AMOUNT] [--fee FLOAT] + [--hyperopt NAME] [--hyperopt-path PATH] [--eps] + [--dmmp] [--enable-protections] [-e INT] + [--spaces {all,buy,sell,roi,stoploss,trailing,default} [{all,buy,sell,roi,stoploss,trailing,default} ...]] + [--print-all] [--no-color] [--print-json] [-j JOBS] + [--random-state INT] [--min-trades INT] + [--hyperopt-loss NAME] + +optional arguments: + -h, --help show this help message and exit + -i TIMEFRAME, --timeframe TIMEFRAME, --ticker-interval TIMEFRAME + Specify ticker interval (`1m`, `5m`, `30m`, `1h`, + `1d`). + --timerange TIMERANGE + Specify what timerange of data to use. + --data-format-ohlcv {json,jsongz,hdf5} + Storage format for downloaded candle (OHLCV) data. + (default: `None`). + --max-open-trades INT + Override the value of the `max_open_trades` + configuration setting. + --stake-amount STAKE_AMOUNT + Override the value of the `stake_amount` configuration + setting. + --fee FLOAT Specify fee ratio. Will be applied twice (on trade + entry and exit). + --hyperopt NAME Specify hyperopt class name which will be used by the + bot. + --hyperopt-path PATH Specify additional lookup path for Hyperopt and + Hyperopt Loss functions. + --eps, --enable-position-stacking + Allow buying the same pair multiple times (position + stacking). + --dmmp, --disable-max-market-positions + Disable applying `max_open_trades` during backtest + (same as setting `max_open_trades` to a very high + number). + --enable-protections, --enableprotections + Enable protections for backtesting.Will slow + backtesting down by a considerable amount, but will + include configured protections + -e INT, --epochs INT Specify number of epochs (default: 100). + --spaces {all,buy,sell,roi,stoploss,trailing,default} [{all,buy,sell,roi,stoploss,trailing,default} ...] + Specify which parameters to hyperopt. Space-separated + list. + --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 output in JSON format. + -j JOBS, --job-workers JOBS + The number of concurrently running jobs for + hyperoptimization (hyperopt worker processes). If -1 + (default), all CPUs are used, for -2, all CPUs but one + are used, etc. If 1 is given, no parallel computing + code is used at all. + --random-state INT Set random state to some positive integer for + reproducible hyperopt results. + --min-trades INT Set minimal desired number of trades for evaluations + in the hyperopt optimization path (default: 1). + --hyperopt-loss NAME Specify the class name of the hyperopt loss function + class (IHyperOptLoss). Different functions can + generate completely different results, since the + target for optimization is different. Built-in + Hyperopt-loss-functions are: + ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss, + SharpeHyperOptLoss, SharpeHyperOptLossDaily, + SortinoHyperOptLoss, SortinoHyperOptLossDaily + +Common arguments: + -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). + --logfile FILE Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. + -V, --version show program's version number and exit + -c PATH, --config PATH + 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 + Path to userdata directory. + +Strategy arguments: + -s NAME, --strategy NAME + Specify strategy class name which will be used by the + bot. + --strategy-path PATH Specify additional strategy lookup path. + +``` + ## Prepare Hyperopting Before we start digging into Hyperopt, we recommend you to take a look at From dabe456d65a2dd1365b0fb83c18e60ae1f483f2f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Feb 2021 20:20:34 +0100 Subject: [PATCH 077/158] Improve wording of configuration doc remove unneeded sections --- docs/configuration.md | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 509214b9c..06619b301 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -111,12 +111,12 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `api_server.password` | Password for API server. See the [API Server documentation](rest-api.md) for more details.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `bot_name` | Name of the bot. Passed via API to a client - can be shown to distinguish / name bots.
*Defaults to `freqtrade`*
**Datatype:** String | `db_url` | Declares database URL to use. NOTE: This defaults to `sqlite:///tradesv3.dryrun.sqlite` if `dry_run` is `true`, and to `sqlite:///tradesv3.sqlite` for production instances.
**Datatype:** String, SQLAlchemy connect string -| `initial_state` | Defines the initial application state. More information below.
*Defaults to `stopped`.*
**Datatype:** Enum, either `stopped` or `running` +| `initial_state` | Defines the initial application state. If set to stopped, then the bot has to be explicitly started via `/start` RPC command.
*Defaults to `stopped`.*
**Datatype:** Enum, either `stopped` or `running` | `forcebuy_enable` | Enables the RPC Commands to force a buy. More information below.
**Datatype:** Boolean | `disable_dataframe_checks` | Disable checking the OHLCV dataframe returned from the strategy methods for correctness. Only use when intentionally changing the dataframe and understand what you are doing. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `False`*.
**Datatype:** Boolean | `strategy` | **Required** Defines Strategy class to use. Recommended to be set via `--strategy NAME`.
**Datatype:** ClassName | `strategy_path` | Adds an additional strategy lookup path (must be a directory).
**Datatype:** String -| `internals.process_throttle_secs` | Set the process throttle. Value in second.
*Defaults to `5` seconds.*
**Datatype:** Positive Integer +| `internals.process_throttle_secs` | Set the process throttle, or minimum loop duration for one bot iteration loop. Value in second.
*Defaults to `5` seconds.*
**Datatype:** Positive Integer | `internals.heartbeat_interval` | Print heartbeat message every N seconds. Set to 0 to disable heartbeat messages.
*Defaults to `60` seconds.*
**Datatype:** Positive Integer or 0 | `internals.sd_notify` | Enables use of the sd_notify protocol to tell systemd service manager about changes in the bot state and issue keep-alive pings. See [here](installation.md#7-optional-configure-freqtrade-as-a-systemd-service) for more details.
**Datatype:** Boolean | `logfile` | Specifies logfile name. Uses a rolling strategy for log file rotation for 10 files with the 1MB limit per file.
**Datatype:** String @@ -246,38 +246,16 @@ If it is not set in either Strategy or Configuration, a default of 1000% `{"0": !!! Note "Special case to forcesell after a specific time" A special case presents using `"": -1` as ROI. This forces the bot to sell a trade after N Minutes, no matter if it's positive or negative, so represents a time-limited force-sell. -### Understand stoploss - -Go to the [stoploss documentation](stoploss.md) for more details. - -### Understand trailing stoploss - -Go to the [trailing stoploss Documentation](stoploss.md#trailing-stop-loss) for details on trailing stoploss. - -### Understand initial_state - -The `initial_state` configuration parameter is an optional field that defines the initial application state. -Possible values are `running` or `stopped`. (default=`running`) -If the value is `stopped` the bot has to be started with `/start` first. - ### Understand forcebuy_enable -The `forcebuy_enable` configuration parameter enables the usage of forcebuy commands via Telegram. -This is disabled for security reasons by default, and will show a warning message on startup if enabled. -For example, you can send `/forcebuy ETH/BTC` Telegram command when this feature if enabled to the bot, -who then buys the pair and holds it until a regular sell-signal (ROI, stoploss, /forcesell) appears. +The `forcebuy_enable` configuration parameter enables the usage of forcebuy commands via Telegram and REST API. +For security reasons, it's disabled by default, and freqtrade will show a warning message on startup if enabled. +For example, you can send `/forcebuy ETH/BTC` to the bot, which will result in freqtrade buying the pair and holds it until a regular sell-signal (ROI, stoploss, /forcesell) appears. This can be dangerous with some strategies, so use with care. See [the telegram documentation](telegram-usage.md) for details on usage. -### Understand process_throttle_secs - -The `process_throttle_secs` configuration parameter is an optional field that defines in seconds how long the bot should wait -before asking the strategy if we should buy or a sell an asset. After each wait period, the strategy is asked again for -every opened trade wether or not we should sell, and for all the remaining pairs (either the dynamic list of pairs or -the static list of pairs) if we should buy. - ### Ignoring expired candles When working with larger timeframes (for example 1h or more) and using a low `max_open_trades` value, the last candle can be processed as soon as a trade slot becomes available. When processing the last candle, this can lead to a situation where it may not be desirable to use the buy signal on that candle. For example, when using a condition in your strategy where you use a cross-over, that point may have passed too long ago for you to start a trade on it. @@ -600,7 +578,7 @@ Obviously, if only one side is using limit orders, different pricing combination --8<-- "includes/pairlists.md" --8<-- "includes/protections.md" -## Switch to Dry-run mode +## Using Dry-run mode We recommend starting the bot in the Dry-run mode to see how your bot will behave and what is the performance of your strategy. In the Dry-run mode the @@ -633,9 +611,10 @@ Once you will be happy with your bot performance running in the Dry-run mode, yo ### Considerations for dry-run -* API-keys may or may not be provided. Only Read-Only operations (i.e. operations that do not alter account state) on the exchange are performed in the dry-run mode. -* Wallets (`/balance`) are simulated. +* API-keys may or may not be provided. Only Read-Only operations (i.e. operations that do not alter account state) on the exchange are performed in dry-run mode. +* Wallets (`/balance`) are simulated based on `dry_run_wallet`. * Orders are simulated, and will not be posted to the exchange. +* Orders are assumed to fill immediately, and will never time out. * In combination with `stoploss_on_exchange`, the stop_loss price is assumed to be filled. * Open orders (not trades, which are stored in the database) are reset on bot restart. From b41078cc466973e67128d44269ac3d4b2f6f6815 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Feb 2021 20:23:30 +0100 Subject: [PATCH 078/158] Don't include plugin documentation in Configuration page --- docs/backtesting.md | 2 +- docs/configuration.md | 6 ++---- docs/developer.md | 2 +- docs/utils.md | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 15b189ebf..a14c8f2e4 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -103,7 +103,7 @@ The result of backtesting will confirm if your bot has better odds of making a p !!! Warning "Using dynamic pairlists for backtesting" Using dynamic pairlists is possible, however it relies on the current market conditions - which will not reflect the historic status of the pairlist. Also, when using pairlists other than StaticPairlist, reproducability of backtesting-results cannot be guaranteed. - Please read the [pairlists documentation](configuration.md#pairlists) for more information. + Please read the [pairlists documentation](plugins.md#pairlists) for more information. To achieve reproducible results, best generate a pairlist via the [`test-pairlist`](utils.md#test-pairlist) command and use that as static pairlist. diff --git a/docs/configuration.md b/docs/configuration.md index 06619b301..e5eac973f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -91,8 +91,8 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `exchange.skip_pair_validation` | Skip pairlist validation on startup.
*Defaults to `false`
**Datatype:** Boolean | `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation. | `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now.
*Defaults to `true`.*
**Datatype:** Boolean -| `pairlists` | Define one or more pairlists to be used. [More information below](#pairlists-and-pairlist-handlers).
*Defaults to `StaticPairList`.*
**Datatype:** List of Dicts -| `protections` | Define one or more protections to be used. [More information below](#protections). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** List of Dicts +| `pairlists` | Define one or more pairlists to be used. [More information](plugins.md#pairlists-and-pairlist-handlers).
*Defaults to `StaticPairList`.*
**Datatype:** List of Dicts +| `protections` | Define one or more protections to be used. [More information](plugins.md#protections). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** List of Dicts | `telegram.enabled` | Enable the usage of Telegram.
**Datatype:** Boolean | `telegram.token` | Your Telegram bot token. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `telegram.chat_id` | Your personal Telegram account id. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String @@ -575,8 +575,6 @@ Assuming both buy and sell are using market orders, a configuration similar to t ``` Obviously, if only one side is using limit orders, different pricing combinations can be used. ---8<-- "includes/pairlists.md" ---8<-- "includes/protections.md" ## Using Dry-run mode diff --git a/docs/developer.md b/docs/developer.md index 831d9d2f8..c09e528bf 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -177,7 +177,7 @@ In `VolumePairList`, this implements different methods of sorting, does early va ### Protections -Best read the [Protection documentation](configuration.md#protections) to understand protections. +Best read the [Protection documentation](plugins.md#protections) to understand protections. This Guide is directed towards Developers who want to develop a new protection. No protection should use datetime directly, but use the provided `date_now` variable for date calculations. This preserves the ability to backtest protections. diff --git a/docs/utils.md b/docs/utils.md index 409bcc134..cf7d5f1d1 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -391,7 +391,7 @@ $ freqtrade list-markets --exchange kraken --all ## Test pairlist -Use the `test-pairlist` subcommand to test the configuration of [dynamic pairlists](configuration.md#pairlists). +Use the `test-pairlist` subcommand to test the configuration of [dynamic pairlists](plugins.md#pairlists). Requires a configuration with specified `pairlists` attribute. Can be used to generate static pairlists to be used during backtesting / hyperopt. @@ -415,7 +415,7 @@ optional arguments: ### Examples -Show whitelist when using a [dynamic pairlist](configuration.md#pairlists). +Show whitelist when using a [dynamic pairlist](plugins.md#pairlists). ``` freqtrade test-pairlist --config config.json --quote USDT BTC From 43986d3f739d268f4cba0464e04abaca522b8961 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Feb 2021 20:26:01 +0100 Subject: [PATCH 079/158] Move Pricing to subpage --- docs/configuration.md | 128 +-------------------------------------- docs/includes/pricing.md | 127 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 127 deletions(-) create mode 100644 docs/includes/pricing.md diff --git a/docs/configuration.md b/docs/configuration.md index e5eac973f..c6c40319d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -448,133 +448,7 @@ The valid values are: "BTC", "ETH", "XRP", "LTC", "BCH", "USDT" ``` -## Prices used for orders - -Prices for regular orders can be controlled via the parameter structures `bid_strategy` for buying and `ask_strategy` for selling. -Prices are always retrieved right before an order is placed, either by querying the exchange tickers or by using the orderbook data. - -!!! Note - Orderbook data used by Freqtrade are the data retrieved from exchange by the ccxt's function `fetch_order_book()`, i.e. are usually data from the L2-aggregated orderbook, while the ticker data are the structures returned by the ccxt's `fetch_ticker()`/`fetch_tickers()` functions. Refer to the ccxt library [documentation](https://github.com/ccxt/ccxt/wiki/Manual#market-data) for more details. - -!!! Warning "Using market orders" - Please read the section [Market order pricing](#market-order-pricing) section when using market orders. - -### Buy price - -#### Check depth of market - -When check depth of market is enabled (`bid_strategy.check_depth_of_market.enabled=True`), the buy signals are filtered based on the orderbook depth (sum of all amounts) for each orderbook side. - -Orderbook `bid` (buy) side depth is then divided by the orderbook `ask` (sell) side depth and the resulting delta is compared to the value of the `bid_strategy.check_depth_of_market.bids_to_ask_delta` parameter. The buy order is only executed if the orderbook delta is greater than or equal to the configured delta value. - -!!! Note - A delta value below 1 means that `ask` (sell) orderbook side depth is greater than the depth of the `bid` (buy) orderbook side, while a value greater than 1 means opposite (depth of the buy side is higher than the depth of the sell side). - -#### Buy price side - -The configuration setting `bid_strategy.price_side` defines the side of the spread the bot looks for when buying. - -The following displays an orderbook. - -``` explanation -... -103 -102 -101 # ask --------------Current spread -99 # bid -98 -97 -... -``` - -If `bid_strategy.price_side` is set to `"bid"`, then the bot will use 99 as buying price. -In line with that, if `bid_strategy.price_side` is set to `"ask"`, then the bot will use 101 as buying price. - -Using `ask` price often guarantees quicker filled orders, but the bot can also end up paying more than what would have been necessary. -Taker fees instead of maker fees will most likely apply even when using limit buy orders. -Also, prices at the "ask" side of the spread are higher than prices at the "bid" side in the orderbook, so the order behaves similar to a market order (however with a maximum price). - -#### Buy price with Orderbook enabled - -When buying with the orderbook enabled (`bid_strategy.use_order_book=True`), Freqtrade fetches the `bid_strategy.order_book_top` entries from the orderbook and then uses the entry specified as `bid_strategy.order_book_top` on the configured side (`bid_strategy.price_side`) of the orderbook. 1 specifies the topmost entry in the orderbook, while 2 would use the 2nd entry in the orderbook, and so on. - -#### Buy price without Orderbook enabled - -The following section uses `side` as the configured `bid_strategy.price_side`. - -When not using orderbook (`bid_strategy.use_order_book=False`), Freqtrade uses the best `side` price from the ticker if it's below the `last` traded price from the ticker. Otherwise (when the `side` price is above the `last` price), it calculates a rate between `side` and `last` price. - -The `bid_strategy.ask_last_balance` configuration parameter controls this. A value of `0.0` will use `side` price, while `1.0` will use the `last` price and values between those interpolate between ask and last price. - -### Sell price - -#### Sell price side - -The configuration setting `ask_strategy.price_side` defines the side of the spread the bot looks for when selling. - -The following displays an orderbook: - -``` explanation -... -103 -102 -101 # ask --------------Current spread -99 # bid -98 -97 -... -``` - -If `ask_strategy.price_side` is set to `"ask"`, then the bot will use 101 as selling price. -In line with that, if `ask_strategy.price_side` is set to `"bid"`, then the bot will use 99 as selling price. - -#### Sell price with Orderbook enabled - -When selling with the orderbook enabled (`ask_strategy.use_order_book=True`), Freqtrade fetches the `ask_strategy.order_book_max` entries in the orderbook. Then each of the orderbook steps between `ask_strategy.order_book_min` and `ask_strategy.order_book_max` on the configured orderbook side are validated for a profitable sell-possibility based on the strategy configuration (`minimal_roi` conditions) and the sell order is placed at the first profitable spot. - -!!! Note - Using `order_book_max` higher than `order_book_min` only makes sense when ask_strategy.price_side is set to `"ask"`. - -The idea here is to place the sell order early, to be ahead in the queue. - -A fixed slot (mirroring `bid_strategy.order_book_top`) can be defined by setting `ask_strategy.order_book_min` and `ask_strategy.order_book_max` to the same number. - -!!! Warning "Order_book_max > 1 - increased risks for stoplosses!" - Using `ask_strategy.order_book_max` higher than 1 will increase the risk the stoploss on exchange is cancelled too early, since an eventual [stoploss on exchange](#understand-order_types) will be cancelled as soon as the order is placed. - Also, the sell order will remain on the exchange for `unfilledtimeout.sell` (or until it's filled) - which can lead to missed stoplosses (with or without using stoploss on exchange). - -!!! Warning "Order_book_max > 1 in dry-run" - Using `ask_strategy.order_book_max` higher than 1 will result in improper dry-run results (significantly better than real orders executed on exchange), since dry-run assumes orders to be filled almost instantly. - It is therefore advised to not use this setting for dry-runs. - -#### Sell price without Orderbook enabled - -When not using orderbook (`ask_strategy.use_order_book=False`), the price at the `ask_strategy.price_side` side (defaults to `"ask"`) from the ticker will be used as the sell price. - -### Market order pricing - -When using market orders, prices should be configured to use the "correct" side of the orderbook to allow realistic pricing detection. -Assuming both buy and sell are using market orders, a configuration similar to the following might be used - -``` jsonc - "order_types": { - "buy": "market", - "sell": "market" - // ... - }, - "bid_strategy": { - "price_side": "ask", - // ... - }, - "ask_strategy":{ - "price_side": "bid", - // ... - }, -``` - -Obviously, if only one side is using limit orders, different pricing combinations can be used. +--8<-- "includes/pricing.md" ## Using Dry-run mode diff --git a/docs/includes/pricing.md b/docs/includes/pricing.md new file mode 100644 index 000000000..d8a72cc58 --- /dev/null +++ b/docs/includes/pricing.md @@ -0,0 +1,127 @@ +## Prices used for orders + +Prices for regular orders can be controlled via the parameter structures `bid_strategy` for buying and `ask_strategy` for selling. +Prices are always retrieved right before an order is placed, either by querying the exchange tickers or by using the orderbook data. + +!!! Note + Orderbook data used by Freqtrade are the data retrieved from exchange by the ccxt's function `fetch_order_book()`, i.e. are usually data from the L2-aggregated orderbook, while the ticker data are the structures returned by the ccxt's `fetch_ticker()`/`fetch_tickers()` functions. Refer to the ccxt library [documentation](https://github.com/ccxt/ccxt/wiki/Manual#market-data) for more details. + +!!! Warning "Using market orders" + Please read the section [Market order pricing](#market-order-pricing) section when using market orders. + +### Buy price + +#### Check depth of market + +When check depth of market is enabled (`bid_strategy.check_depth_of_market.enabled=True`), the buy signals are filtered based on the orderbook depth (sum of all amounts) for each orderbook side. + +Orderbook `bid` (buy) side depth is then divided by the orderbook `ask` (sell) side depth and the resulting delta is compared to the value of the `bid_strategy.check_depth_of_market.bids_to_ask_delta` parameter. The buy order is only executed if the orderbook delta is greater than or equal to the configured delta value. + +!!! Note + A delta value below 1 means that `ask` (sell) orderbook side depth is greater than the depth of the `bid` (buy) orderbook side, while a value greater than 1 means opposite (depth of the buy side is higher than the depth of the sell side). + +#### Buy price side + +The configuration setting `bid_strategy.price_side` defines the side of the spread the bot looks for when buying. + +The following displays an orderbook. + +``` explanation +... +103 +102 +101 # ask +-------------Current spread +99 # bid +98 +97 +... +``` + +If `bid_strategy.price_side` is set to `"bid"`, then the bot will use 99 as buying price. +In line with that, if `bid_strategy.price_side` is set to `"ask"`, then the bot will use 101 as buying price. + +Using `ask` price often guarantees quicker filled orders, but the bot can also end up paying more than what would have been necessary. +Taker fees instead of maker fees will most likely apply even when using limit buy orders. +Also, prices at the "ask" side of the spread are higher than prices at the "bid" side in the orderbook, so the order behaves similar to a market order (however with a maximum price). + +#### Buy price with Orderbook enabled + +When buying with the orderbook enabled (`bid_strategy.use_order_book=True`), Freqtrade fetches the `bid_strategy.order_book_top` entries from the orderbook and then uses the entry specified as `bid_strategy.order_book_top` on the configured side (`bid_strategy.price_side`) of the orderbook. 1 specifies the topmost entry in the orderbook, while 2 would use the 2nd entry in the orderbook, and so on. + +#### Buy price without Orderbook enabled + +The following section uses `side` as the configured `bid_strategy.price_side`. + +When not using orderbook (`bid_strategy.use_order_book=False`), Freqtrade uses the best `side` price from the ticker if it's below the `last` traded price from the ticker. Otherwise (when the `side` price is above the `last` price), it calculates a rate between `side` and `last` price. + +The `bid_strategy.ask_last_balance` configuration parameter controls this. A value of `0.0` will use `side` price, while `1.0` will use the `last` price and values between those interpolate between ask and last price. + +### Sell price + +#### Sell price side + +The configuration setting `ask_strategy.price_side` defines the side of the spread the bot looks for when selling. + +The following displays an orderbook: + +``` explanation +... +103 +102 +101 # ask +-------------Current spread +99 # bid +98 +97 +... +``` + +If `ask_strategy.price_side` is set to `"ask"`, then the bot will use 101 as selling price. +In line with that, if `ask_strategy.price_side` is set to `"bid"`, then the bot will use 99 as selling price. + +#### Sell price with Orderbook enabled + +When selling with the orderbook enabled (`ask_strategy.use_order_book=True`), Freqtrade fetches the `ask_strategy.order_book_max` entries in the orderbook. Then each of the orderbook steps between `ask_strategy.order_book_min` and `ask_strategy.order_book_max` on the configured orderbook side are validated for a profitable sell-possibility based on the strategy configuration (`minimal_roi` conditions) and the sell order is placed at the first profitable spot. + +!!! Note + Using `order_book_max` higher than `order_book_min` only makes sense when ask_strategy.price_side is set to `"ask"`. + +The idea here is to place the sell order early, to be ahead in the queue. + +A fixed slot (mirroring `bid_strategy.order_book_top`) can be defined by setting `ask_strategy.order_book_min` and `ask_strategy.order_book_max` to the same number. + +!!! Warning "Order_book_max > 1 - increased risks for stoplosses!" + Using `ask_strategy.order_book_max` higher than 1 will increase the risk the stoploss on exchange is cancelled too early, since an eventual [stoploss on exchange](#understand-order_types) will be cancelled as soon as the order is placed. + Also, the sell order will remain on the exchange for `unfilledtimeout.sell` (or until it's filled) - which can lead to missed stoplosses (with or without using stoploss on exchange). + +!!! Warning "Order_book_max > 1 in dry-run" + Using `ask_strategy.order_book_max` higher than 1 will result in improper dry-run results (significantly better than real orders executed on exchange), since dry-run assumes orders to be filled almost instantly. + It is therefore advised to not use this setting for dry-runs. + +#### Sell price without Orderbook enabled + +When not using orderbook (`ask_strategy.use_order_book=False`), the price at the `ask_strategy.price_side` side (defaults to `"ask"`) from the ticker will be used as the sell price. + +### Market order pricing + +When using market orders, prices should be configured to use the "correct" side of the orderbook to allow realistic pricing detection. +Assuming both buy and sell are using market orders, a configuration similar to the following might be used + +``` jsonc + "order_types": { + "buy": "market", + "sell": "market" + // ... + }, + "bid_strategy": { + "price_side": "ask", + // ... + }, + "ask_strategy":{ + "price_side": "bid", + // ... + }, +``` + +Obviously, if only one side is using limit orders, different pricing combinations can be used. From 12bcbf437486599350c3a6a9a46d4acd4c887399 Mon Sep 17 00:00:00 2001 From: mobrine1 <33225846+mobrine1@users.noreply.github.com> Date: Tue, 2 Feb 2021 15:40:33 -0500 Subject: [PATCH 080/158] #4289 printing json output Adding --json flag to print json output --- scripts/rest_client.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/scripts/rest_client.py b/scripts/rest_client.py index 2232b8421..6a3b2126b 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -331,6 +331,13 @@ def add_arguments(): default=[] ) + parser.add_argument('--json', + help='Output data in json form rather than a python dict', + dest='json', + action='store_true', + default=False + ) + args = parser.parse_args() return vars(args) @@ -379,8 +386,11 @@ def main(args): print_commands() return - print(getattr(client, command)(*args["command_arguments"])) - + output = getattr(client, command)(*args["command_arguments"]) + if args['json']: + print(json.dumps(output)) + else: + print(output) if __name__ == "__main__": args = add_arguments() From 56569690d978b03ee23f3b7d24d9ceb04a8681fc Mon Sep 17 00:00:00 2001 From: mobrine1 <33225846+mobrine1@users.noreply.github.com> Date: Tue, 2 Feb 2021 15:59:48 -0500 Subject: [PATCH 081/158] Update rest_client.py --- scripts/rest_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/rest_client.py b/scripts/rest_client.py index 6a3b2126b..b214acda3 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -392,6 +392,7 @@ def main(args): else: print(output) + if __name__ == "__main__": args = add_arguments() main(args) From 06b56544a8f51e4e87646acabe14ef166c0638b8 Mon Sep 17 00:00:00 2001 From: mobrine1 <33225846+mobrine1@users.noreply.github.com> Date: Wed, 3 Feb 2021 03:27:54 -0500 Subject: [PATCH 082/158] printing json by default now --- scripts/rest_client.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/scripts/rest_client.py b/scripts/rest_client.py index b214acda3..b6e66cfa4 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -331,13 +331,6 @@ def add_arguments(): default=[] ) - parser.add_argument('--json', - help='Output data in json form rather than a python dict', - dest='json', - action='store_true', - default=False - ) - args = parser.parse_args() return vars(args) @@ -386,11 +379,7 @@ def main(args): print_commands() return - output = getattr(client, command)(*args["command_arguments"]) - if args['json']: - print(json.dumps(output)) - else: - print(output) + print(json.dumps(getattr(client, command)(*args["command_arguments"]))) if __name__ == "__main__": From f36c61e32fe09c4e7dda2fcb848fb6fe11de2265 Mon Sep 17 00:00:00 2001 From: Alberto del Barrio Date: Wed, 3 Feb 2021 18:11:49 +0100 Subject: [PATCH 083/158] Fix documentation links pointing to pairlists --- docs/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index c6c40319d..25ae1dd31 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -82,8 +82,8 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `exchange.key` | API key to use for the exchange. Only required when you are in production mode.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String -| `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Supports regex pairs as `.*/BTC`. Not used by VolumePairList (see [below](#pairlists-and-pairlist-handlers)).
**Datatype:** List -| `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting (see [below](#pairlists-and-pairlist-handlers)).
**Datatype:** List +| `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Supports regex pairs as `.*/BTC`. Not used by VolumePairList. [More information](plugins.md#pairlists-and-pairlist-handlers).
**Datatype:** List +| `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting. [More information](plugins.md#pairlists-and-pairlist-handlers).
**Datatype:** List | `exchange.ccxt_config` | Additional CCXT parameters passed to both ccxt instances (sync and async). This is usually the correct place for ccxt configurations. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.ccxt_sync_config` | Additional CCXT parameters passed to the regular (sync) ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.ccxt_async_config` | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict From b8cb39462c72b049120a91795d8b0b7797e748a6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 3 Feb 2021 20:00:33 +0100 Subject: [PATCH 084/158] Move get_trade_stake_amount to wallets this way it can be easier used by other functions --- freqtrade/freqtradebot.py | 82 ++------------------------------------ freqtrade/rpc/rpc.py | 3 +- freqtrade/wallets.py | 78 ++++++++++++++++++++++++++++++++++++ tests/test_freqtradebot.py | 28 ++++++++----- tests/test_integration.py | 6 ++- 5 files changed, 104 insertions(+), 93 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 2656daab5..fde85e94a 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -233,7 +233,7 @@ class FreqtradeBot(LoggingMixin): _whitelist.extend([trade.pair for trade in trades if trade.pair not in _whitelist]) return _whitelist - def get_free_open_trades(self): + def get_free_open_trades(self) -> int: """ Return the number of free open trades slots or 0 if max number of open trades reached @@ -439,83 +439,6 @@ class FreqtradeBot(LoggingMixin): return used_rate - def get_trade_stake_amount(self, pair: str) -> float: - """ - Calculate stake amount for the trade - :return: float: Stake amount - :raise: DependencyException if the available stake amount is too low - """ - stake_amount: float - # Ensure wallets are uptodate. - self.wallets.update() - - if self.edge: - stake_amount = self.edge.stake_amount( - pair, - self.wallets.get_free(self.config['stake_currency']), - self.wallets.get_total(self.config['stake_currency']), - Trade.total_open_trades_stakes() - ) - else: - stake_amount = self.config['stake_amount'] - if stake_amount == constants.UNLIMITED_STAKE_AMOUNT: - stake_amount = self._calculate_unlimited_stake_amount() - - return self._check_available_stake_amount(stake_amount) - - def _get_available_stake_amount(self) -> float: - """ - Return the total currently available balance in stake currency, - respecting tradable_balance_ratio. - Calculated as - + free amount ) * tradable_balance_ratio - - """ - val_tied_up = Trade.total_open_trades_stakes() - - # Ensure % is used from the overall balance - # Otherwise we'd risk lowering stakes with each open trade. - # (tied up + current free) * ratio) - tied up - available_amount = ((val_tied_up + self.wallets.get_free(self.config['stake_currency'])) * - self.config['tradable_balance_ratio']) - val_tied_up - return available_amount - - def _calculate_unlimited_stake_amount(self) -> float: - """ - Calculate stake amount for "unlimited" stake amount - :return: 0 if max number of trades reached, else stake_amount to use. - """ - free_open_trades = self.get_free_open_trades() - if not free_open_trades: - return 0 - - available_amount = self._get_available_stake_amount() - - return available_amount / free_open_trades - - def _check_available_stake_amount(self, stake_amount: float) -> float: - """ - Check if stake amount can be fulfilled with the available balance - for the stake currency - :return: float: Stake amount - """ - available_amount = self._get_available_stake_amount() - - if self.config['amend_last_stake_amount']: - # Remaining amount needs to be at least stake_amount * last_stake_amount_min_ratio - # Otherwise the remaining amount is too low to trade. - if available_amount > (stake_amount * self.config['last_stake_amount_min_ratio']): - stake_amount = min(stake_amount, available_amount) - else: - stake_amount = 0 - - if available_amount < stake_amount: - raise DependencyException( - f"Available balance ({available_amount} {self.config['stake_currency']}) is " - f"lower than stake amount ({stake_amount} {self.config['stake_currency']})" - ) - - return stake_amount - def create_trade(self, pair: str) -> bool: """ Check the implemented trading strategy for buy signals. @@ -549,7 +472,8 @@ class FreqtradeBot(LoggingMixin): (buy, sell) = self.strategy.get_signal(pair, self.strategy.timeframe, analyzed_df) if buy and not sell: - stake_amount = self.get_trade_stake_amount(pair) + stake_amount = self.wallets.get_trade_stake_amount(pair, self.get_free_open_trades(), + self.edge) if not stake_amount: logger.debug(f"Stake amount is 0, ignoring possible trade for {pair}.") return False diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 491d1cde6..379fdcefa 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -590,7 +590,8 @@ class RPC: raise RPCException(f'position for {pair} already open - id: {trade.id}') # gen stake amount - stakeamount = self._freqtrade.get_trade_stake_amount(pair) + stakeamount = self._freqtrade.wallets.get_trade_stake_amount( + pair, self._freqtrade.get_free_open_trades()) # execute buy if self._freqtrade.execute_buy(pair, stakeamount, price): diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index 3680dd416..d7dcfd487 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -7,6 +7,8 @@ from typing import Any, Dict, NamedTuple import arrow +from freqtrade.constants import UNLIMITED_STAKE_AMOUNT +from freqtrade.exceptions import DependencyException from freqtrade.exchange import Exchange from freqtrade.persistence import Trade @@ -118,3 +120,79 @@ class Wallets: def get_all_balances(self) -> Dict[str, Any]: return self._wallets + + def _get_available_stake_amount(self) -> float: + """ + Return the total currently available balance in stake currency, + respecting tradable_balance_ratio. + Calculated as + ( + free amount ) * tradable_balance_ratio - + """ + val_tied_up = Trade.total_open_trades_stakes() + + # Ensure % is used from the overall balance + # Otherwise we'd risk lowering stakes with each open trade. + # (tied up + current free) * ratio) - tied up + available_amount = ((val_tied_up + self.get_free(self._config['stake_currency'])) * + self._config['tradable_balance_ratio']) - val_tied_up + return available_amount + + def _calculate_unlimited_stake_amount(self, free_open_trades: int) -> float: + """ + Calculate stake amount for "unlimited" stake amount + :return: 0 if max number of trades reached, else stake_amount to use. + """ + if not free_open_trades: + return 0 + + available_amount = self._get_available_stake_amount() + + return available_amount / free_open_trades + + def _check_available_stake_amount(self, stake_amount: float) -> float: + """ + Check if stake amount can be fulfilled with the available balance + for the stake currency + :return: float: Stake amount + """ + available_amount = self._get_available_stake_amount() + + if self._config['amend_last_stake_amount']: + # Remaining amount needs to be at least stake_amount * last_stake_amount_min_ratio + # Otherwise the remaining amount is too low to trade. + if available_amount > (stake_amount * self._config['last_stake_amount_min_ratio']): + stake_amount = min(stake_amount, available_amount) + else: + stake_amount = 0 + + if available_amount < stake_amount: + raise DependencyException( + f"Available balance ({available_amount} {self._config['stake_currency']}) is " + f"lower than stake amount ({stake_amount} {self._config['stake_currency']})" + ) + + return stake_amount + + def get_trade_stake_amount(self, pair: str, free_open_trades: int, edge=None) -> float: + """ + Calculate stake amount for the trade + :return: float: Stake amount + :raise: DependencyException if the available stake amount is too low + """ + stake_amount: float + # Ensure wallets are uptodate. + self.update() + + if edge: + stake_amount = edge.stake_amount( + pair, + self.get_free(self._config['stake_currency']), + self.get_total(self._config['stake_currency']), + Trade.total_open_trades_stakes() + ) + else: + stake_amount = self._config['stake_amount'] + if stake_amount == UNLIMITED_STAKE_AMOUNT: + stake_amount = self._calculate_unlimited_stake_amount(free_open_trades) + + return self._check_available_stake_amount(stake_amount) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index abb91d66b..6cb126ae1 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -158,7 +158,8 @@ def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None: freqtrade = FreqtradeBot(default_conf) - result = freqtrade.get_trade_stake_amount('ETH/BTC') + result = freqtrade.wallets.get_trade_stake_amount( + 'ETH/BTC', freqtrade.get_free_open_trades()) assert result == default_conf['stake_amount'] @@ -194,12 +195,14 @@ def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_b if expected[i] is not None: limit_buy_order_open['id'] = str(i) - result = freqtrade.get_trade_stake_amount('ETH/BTC') + result = freqtrade.wallets.get_trade_stake_amount('ETH/BTC', + freqtrade.get_free_open_trades()) assert pytest.approx(result) == expected[i] freqtrade.execute_buy('ETH/BTC', result) else: with pytest.raises(DependencyException): - freqtrade.get_trade_stake_amount('ETH/BTC') + freqtrade.wallets.get_trade_stake_amount('ETH/BTC', + freqtrade.get_free_open_trades()) def test_get_trade_stake_amount_no_stake_amount(default_conf, mocker) -> None: @@ -210,7 +213,7 @@ def test_get_trade_stake_amount_no_stake_amount(default_conf, mocker) -> None: patch_get_signal(freqtrade) with pytest.raises(DependencyException, match=r'.*stake amount.*'): - freqtrade.get_trade_stake_amount('ETH/BTC') + freqtrade.wallets.get_trade_stake_amount('ETH/BTC', freqtrade.get_free_open_trades()) @pytest.mark.parametrize("balance_ratio,result1", [ @@ -239,25 +242,25 @@ def test_get_trade_stake_amount_unlimited_amount(default_conf, ticker, balance_r patch_get_signal(freqtrade) # no open trades, order amount should be 'balance / max_open_trades' - result = freqtrade.get_trade_stake_amount('ETH/BTC') + result = freqtrade.wallets.get_trade_stake_amount('ETH/BTC', freqtrade.get_free_open_trades()) assert result == result1 # create one trade, order amount should be 'balance / (max_open_trades - num_open_trades)' freqtrade.execute_buy('ETH/BTC', result) - result = freqtrade.get_trade_stake_amount('LTC/BTC') + result = freqtrade.wallets.get_trade_stake_amount('LTC/BTC', freqtrade.get_free_open_trades()) assert result == result1 # create 2 trades, order amount should be None freqtrade.execute_buy('LTC/BTC', result) - result = freqtrade.get_trade_stake_amount('XRP/BTC') + result = freqtrade.wallets.get_trade_stake_amount('XRP/BTC', freqtrade.get_free_open_trades()) assert result == 0 # set max_open_trades = None, so do not trade conf['max_open_trades'] = 0 freqtrade = FreqtradeBot(conf) - result = freqtrade.get_trade_stake_amount('NEO/BTC') + result = freqtrade.wallets.get_trade_stake_amount('NEO/BTC', freqtrade.get_free_open_trades()) assert result == 0 @@ -283,8 +286,10 @@ def test_edge_overrides_stake_amount(mocker, edge_conf) -> None: edge_conf['dry_run_wallet'] = 999.9 freqtrade = FreqtradeBot(edge_conf) - assert freqtrade.get_trade_stake_amount('NEO/BTC') == (999.9 * 0.5 * 0.01) / 0.20 - assert freqtrade.get_trade_stake_amount('LTC/BTC') == (999.9 * 0.5 * 0.01) / 0.21 + assert freqtrade.wallets.get_trade_stake_amount( + 'NEO/BTC', freqtrade.get_free_open_trades(), freqtrade.edge) == (999.9 * 0.5 * 0.01) / 0.20 + assert freqtrade.wallets.get_trade_stake_amount( + 'LTC/BTC', freqtrade.get_free_open_trades(), freqtrade.edge) == (999.9 * 0.5 * 0.01) / 0.21 def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, edge_conf) -> None: @@ -500,7 +505,8 @@ def test_create_trade_limit_reached(default_conf, ticker, limit_buy_order_open, patch_get_signal(freqtrade) assert not freqtrade.create_trade('ETH/BTC') - assert freqtrade.get_trade_stake_amount('ETH/BTC') == 0 + assert freqtrade.wallets.get_trade_stake_amount('ETH/BTC', freqtrade.get_free_open_trades(), + freqtrade.edge) == 0 def test_enter_positions_no_pairs_left(default_conf, ticker, limit_buy_order_open, fee, diff --git a/tests/test_integration.py b/tests/test_integration.py index 9695977ac..8e3bd251a 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -178,7 +178,8 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order, moc trades = Trade.query.all() assert len(trades) == 4 - assert freqtrade.get_trade_stake_amount('XRP/BTC') == result1 + assert freqtrade.wallets.get_trade_stake_amount( + 'XRP/BTC', freqtrade.get_free_open_trades()) == result1 rpc._rpc_forcebuy('TKN/BTC', None) @@ -199,7 +200,8 @@ def test_forcebuy_last_unlimited(default_conf, ticker, fee, limit_buy_order, moc # One trade sold assert len(trades) == 4 # stake-amount should now be reduced, since one trade was sold at a loss. - assert freqtrade.get_trade_stake_amount('XRP/BTC') < result1 + assert freqtrade.wallets.get_trade_stake_amount( + 'XRP/BTC', freqtrade.get_free_open_trades()) < result1 # Validate that balance of sold trade is not in dry-run balances anymore. bals2 = freqtrade.wallets.get_all_balances() assert bals != bals2 From e8e5acc2e2ffcde04b75e27cfc4903e3583d2eff Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 3 Feb 2021 20:15:08 +0100 Subject: [PATCH 085/158] Fix import in strategy template --- freqtrade/templates/base_strategy.py.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/templates/base_strategy.py.j2 b/freqtrade/templates/base_strategy.py.j2 index 4a1b43e36..dd6b773e1 100644 --- a/freqtrade/templates/base_strategy.py.j2 +++ b/freqtrade/templates/base_strategy.py.j2 @@ -5,7 +5,7 @@ import numpy as np # noqa import pandas as pd # noqa from pandas import DataFrame -from freqtrade.strategy.interface import IStrategy +from freqtrade.strategy import IStrategy # -------------------------------- # Add your lib to import here From 99b2214d1f85b4032d1caf2b5b273c1b3e4c52a6 Mon Sep 17 00:00:00 2001 From: raoulus Date: Thu, 4 Feb 2021 15:27:18 +0100 Subject: [PATCH 086/158] setting resize_keyboard=True for slightly smaller Telegram buttons --- freqtrade/rpc/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 99f9a8a91..0f7005639 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -910,7 +910,7 @@ class Telegram(RPCHandler): :param parse_mode: telegram parse mode :return: None """ - reply_markup = ReplyKeyboardMarkup(self._keyboard) + reply_markup = ReplyKeyboardMarkup(self._keyboard, resize_keyboard=True) try: try: self._updater.bot.send_message( From 5cd8745997ed2300fc750408d4655ca1345963f4 Mon Sep 17 00:00:00 2001 From: JoeSchr Date: Thu, 4 Feb 2021 16:26:03 +0100 Subject: [PATCH 087/158] Update README.md Typo playing -> paying --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 51a3409ea..bb136d7f2 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Please find the complete documentation on our [website](https://www.freqtrade.io - [x] **Based on Python 3.7+**: For botting on any operating system - Windows, macOS and Linux. - [x] **Persistence**: Persistence is achieved through sqlite. -- [x] **Dry-run**: Run the bot without playing money. +- [x] **Dry-run**: Run the bot without paying money. - [x] **Backtesting**: Run a simulation of your buy/sell strategy. - [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data. - [x] **Edge position sizing** Calculate your win rate, risk reward ratio, the best stoploss and adjust your position size before taking a position for each specific market. [Learn more](https://www.freqtrade.io/en/latest/edge/). From 5165357f40c780358271f7ae6d31aa14f93e7feb Mon Sep 17 00:00:00 2001 From: JoeSchr Date: Thu, 4 Feb 2021 19:36:04 +0100 Subject: [PATCH 088/158] Update data-download.md Fix wrong path Add section about fixing wrong docker permission, if user_data is created by docker, it's permission are set to `root` --- docs/data-download.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/data-download.md b/docs/data-download.md index 4c7376933..cad39ac41 100644 --- a/docs/data-download.md +++ b/docs/data-download.md @@ -264,7 +264,19 @@ If you are using Binance for example: ```bash mkdir -p user_data/data/binance -cp freqtrade/tests/testdata/pairs.json user_data/data/binance +cp tests/testdata/pairs.json user_data/data/binance +``` + +if you your configuration directory `user_data` was made by docker, you may get an error: + +``` +cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied +``` + +so you will need to fix your permission by doing: + +``` +chown -R $UID:$GID user_data ``` The format of the `pairs.json` file is a simple json list. From 428d2af312fea93e2e01da0feed6d808269c2723 Mon Sep 17 00:00:00 2001 From: JoeSchr Date: Thu, 4 Feb 2021 19:39:25 +0100 Subject: [PATCH 089/158] add `sudo` to `chown` that was the whole point d'oh --- docs/data-download.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data-download.md b/docs/data-download.md index cad39ac41..1e183d04b 100644 --- a/docs/data-download.md +++ b/docs/data-download.md @@ -276,7 +276,7 @@ cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission d so you will need to fix your permission by doing: ``` -chown -R $UID:$GID user_data +sudo chown -R $UID:$GID user_data ``` The format of the `pairs.json` file is a simple json list. From 1310a7b5473a53be10784451473851de34b434a8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 4 Feb 2021 19:58:44 +0100 Subject: [PATCH 090/158] Fix bug with wrong conversion for BTCST/BTC This can happen if a pair starts with the stake-currency closes #4307 --- freqtrade/rpc/rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 491d1cde6..b17183be2 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -451,7 +451,7 @@ class RPC: pair = self._freqtrade.exchange.get_valid_pair_combination(coin, stake_currency) rate = tickers.get(pair, {}).get('bid', None) if rate: - if pair.startswith(stake_currency): + if pair.startswith(stake_currency) and not pair.endswith(stake_currency): rate = 1.0 / rate est_stake = rate * balance.total except (ExchangeError): From a816fb12454cd62a306d80f493af8abcf89cb699 Mon Sep 17 00:00:00 2001 From: Joe Schr Date: Fri, 5 Feb 2021 12:43:19 +0100 Subject: [PATCH 091/158] chore(lint): lint binance example config --- config_binance.json.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config_binance.json.example b/config_binance.json.example index 83c9748d7..4fa615d6d 100644 --- a/config_binance.json.example +++ b/config_binance.json.example @@ -12,15 +12,15 @@ "sell": 30 }, "bid_strategy": { - "use_order_book": false, "ask_last_balance": 0.0, + "use_order_book": false, "order_book_top": 1, "check_depth_of_market": { "enabled": false, "bids_to_ask_delta": 1 } }, - "ask_strategy":{ + "ask_strategy": { "use_order_book": false, "order_book_min": 1, "order_book_max": 1, From 0806202d47cd63674a64e6069afe08c1e9cfdaa4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 5 Feb 2021 20:02:55 +0100 Subject: [PATCH 092/158] ccxt version bump to 1.41.62 --- requirements.txt | 2 +- tests/exchange/test_ccxt_compat.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5114f397f..299c07734 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ numpy==1.20.0 pandas==1.2.1 -ccxt==1.41.35 +ccxt==1.41.62 aiohttp==3.7.3 SQLAlchemy==1.3.22 python-telegram-bot==13.1 diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 0c8b7bdcf..8e1d074aa 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -18,7 +18,7 @@ EXCHANGES = { 'bittrex': { 'pair': 'BTC/USDT', 'hasQuoteVolume': False, - 'timeframe': '5m', + 'timeframe': '1h', }, 'binance': { 'pair': 'BTC/USDT', @@ -120,7 +120,9 @@ class TestCCXTExchange(): ohlcv = exchange.refresh_latest_ohlcv([pair_tf]) assert isinstance(ohlcv, dict) assert len(ohlcv[pair_tf]) == len(exchange.klines(pair_tf)) - assert len(exchange.klines(pair_tf)) > 200 + # assert len(exchange.klines(pair_tf)) > 200 + # Assume 90% uptime ... + assert len(exchange.klines(pair_tf)) > exchange._ohlcv_candle_limit * 0.90 # TODO: tests fetch_trades (?) From 86a97988c011de79be5e74f3ec408c31b11f7c37 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 5 Feb 2021 20:09:13 +0100 Subject: [PATCH 093/158] Improve wording --- docs/data-download.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-download.md b/docs/data-download.md index 1e183d04b..04f444a8b 100644 --- a/docs/data-download.md +++ b/docs/data-download.md @@ -267,13 +267,13 @@ mkdir -p user_data/data/binance cp tests/testdata/pairs.json user_data/data/binance ``` -if you your configuration directory `user_data` was made by docker, you may get an error: +If you your configuration directory `user_data` was made by docker, you may get the following error: ``` cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied ``` -so you will need to fix your permission by doing: +You can fix the permissions of your user-data directory as follows: ``` sudo chown -R $UID:$GID user_data From aec22c5c3d53b6a21f677c4e62427df78e073c76 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 5 Feb 2021 20:17:38 +0100 Subject: [PATCH 094/158] introduce skip_open_order_update parameter skips startup-open-order-update closes #4128 --- docs/configuration.md | 1 + freqtrade/freqtradebot.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 25ae1dd31..00d2830e4 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -89,6 +89,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `exchange.ccxt_async_config` | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded.
*Defaults to `60` minutes.*
**Datatype:** Positive Integer | `exchange.skip_pair_validation` | Skip pairlist validation on startup.
*Defaults to `false`
**Datatype:** Boolean +| `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.
*Defaults to `false`
**Datatype:** Boolean | `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation. | `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now.
*Defaults to `true`.*
**Datatype:** Boolean | `pairlists` | Define one or more pairlists to be used. [More information](plugins.md#pairlists-and-pairlist-handlers).
*Defaults to `StaticPairList`.*
**Datatype:** List of Dicts diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index fde85e94a..71b6c7dc0 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -246,7 +246,7 @@ class FreqtradeBot(LoggingMixin): Updates open orders based on order list kept in the database. Mainly updates the state of orders - but may also close trades """ - if self.config['dry_run']: + if self.config['dry_run'] or self.config['exchange'].get('skip_open_order_update', False): # Updating open orders in dry-run does not make sense and will fail. return From 0a43988f3f9c61e82680f4166a04047acac3b626 Mon Sep 17 00:00:00 2001 From: Edvinas Selskas Date: Sat, 6 Feb 2021 03:02:37 +0000 Subject: [PATCH 095/158] Fix sample strategy documentation link Noticed that the current link is dead. I think this would be the most appropriate link in this case. --- freqtrade/templates/sample_strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index b3f9fef07..b1a1bb0ea 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -17,7 +17,7 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib class SampleStrategy(IStrategy): """ This is a sample strategy to inspire you. - More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-optimization.md + More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/strategy-customization.md You can: :return: a Dataframe with all mandatory indicators for the strategies From bc8fda8d6345086fa7bb827fc894fcfad61b20ef Mon Sep 17 00:00:00 2001 From: Edvinas Selskas Date: Sat, 6 Feb 2021 03:13:53 +0000 Subject: [PATCH 096/158] Update sample_strategy.py Fix test --- freqtrade/templates/sample_strategy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index b1a1bb0ea..6dd5a01ce 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -17,7 +17,8 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib class SampleStrategy(IStrategy): """ This is a sample strategy to inspire you. - More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/strategy-customization.md + More information in: + https://github.com/freqtrade/freqtrade/blob/develop/docs/strategy-customization.md You can: :return: a Dataframe with all mandatory indicators for the strategies From d5cf837c0f5a6e0c2e0950d49721249587e27a82 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 6 Feb 2021 09:23:10 +0100 Subject: [PATCH 097/158] Parse regular cancel_order call to update orders table --- freqtrade/freqtradebot.py | 5 ++++- tests/test_freqtradebot.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 71b6c7dc0..a6eb75d5b 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1070,7 +1070,9 @@ class FreqtradeBot(LoggingMixin): if not self.exchange.check_order_canceled_empty(order): try: # if trade is not partially completed, just delete the order - self.exchange.cancel_order(trade.open_order_id, trade.pair) + co = self.exchange.cancel_order_with_result(trade.open_order_id, trade.pair, + trade.amount) + trade.update_order(co) except InvalidOrderException: logger.exception(f"Could not cancel sell order {trade.open_order_id}") return 'error cancelling order' @@ -1078,6 +1080,7 @@ class FreqtradeBot(LoggingMixin): else: reason = constants.CANCEL_REASON['CANCELLED_ON_EXCHANGE'] logger.info('Sell order %s for %s.', reason, trade) + trade.update_order(order) trade.close_rate = None trade.close_rate_requested = None diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 6cb126ae1..3bd2f5607 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2609,7 +2609,7 @@ def test_handle_cancel_sell_cancel_exception(mocker, default_conf) -> None: patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch( - 'freqtrade.exchange.Exchange.cancel_order', side_effect=InvalidOrderException()) + 'freqtrade.exchange.Exchange.cancel_order_with_result', side_effect=InvalidOrderException()) freqtrade = FreqtradeBot(default_conf) From 694f55c0a53174d430ed5f7e2e8b20ab7c3b3e74 Mon Sep 17 00:00:00 2001 From: Edvinas Selskas Date: Sat, 6 Feb 2021 14:43:50 +0000 Subject: [PATCH 098/158] Use suggested link --- freqtrade/templates/sample_strategy.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/templates/sample_strategy.py b/freqtrade/templates/sample_strategy.py index 6dd5a01ce..db1ba48b8 100644 --- a/freqtrade/templates/sample_strategy.py +++ b/freqtrade/templates/sample_strategy.py @@ -17,8 +17,7 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib class SampleStrategy(IStrategy): """ This is a sample strategy to inspire you. - More information in: - https://github.com/freqtrade/freqtrade/blob/develop/docs/strategy-customization.md + More information in https://www.freqtrade.io/en/latest/strategy-customization/ You can: :return: a Dataframe with all mandatory indicators for the strategies From d1bb46bed015c7d6364c2aab0a84aba9c5007527 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 05:27:42 +0000 Subject: [PATCH 099/158] Bump py-find-1st from 1.1.4 to 1.1.5 Bumps [py-find-1st](https://github.com/roebel/py_find_1st) from 1.1.4 to 1.1.5. - [Release notes](https://github.com/roebel/py_find_1st/releases) - [Commits](https://github.com/roebel/py_find_1st/commits) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 299c07734..2448afe93 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ tables==3.6.1 blosc==1.10.2 # find first, C search in arrays -py_find_1st==1.1.4 +py_find_1st==1.1.5 # Load ticker files 30% faster python-rapidjson==1.0 From dd7f9181c53b91832b98c549dea2deafdbff350a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 05:27:44 +0000 Subject: [PATCH 100/158] Bump numpy from 1.20.0 to 1.20.1 Bumps [numpy](https://github.com/numpy/numpy) from 1.20.0 to 1.20.1. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/master/doc/HOWTO_RELEASE.rst.txt) - [Commits](https://github.com/numpy/numpy/compare/v1.20.0...v1.20.1) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 299c07734..bdaca4a44 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -numpy==1.20.0 +numpy==1.20.1 pandas==1.2.1 ccxt==1.41.62 From 676cd7bb55d85d8829c1adefce83871e98351896 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 05:27:45 +0000 Subject: [PATCH 101/158] Bump sqlalchemy from 1.3.22 to 1.3.23 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.3.22 to 1.3.23. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/master/CHANGES) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 299c07734..c9559e384 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ pandas==1.2.1 ccxt==1.41.62 aiohttp==3.7.3 -SQLAlchemy==1.3.22 +SQLAlchemy==1.3.23 python-telegram-bot==13.1 arrow==0.17.0 cachetools==4.2.1 From 22d447b3f51a1f21632e329e991ebcbdc7f17918 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 05:27:46 +0000 Subject: [PATCH 102/158] Bump mkdocs-material from 6.2.7 to 6.2.8 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 6.2.7 to 6.2.8. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/6.2.7...6.2.8) Signed-off-by: dependabot[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 85bd72323..94b2fca39 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,3 +1,3 @@ -mkdocs-material==6.2.7 +mkdocs-material==6.2.8 mdx_truly_sane_lists==1.2 pymdown-extensions==8.1.1 From 12168cbf01edaa6c11ea5e427a52180a34f549ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 08:26:18 +0000 Subject: [PATCH 103/158] Bump ccxt from 1.41.62 to 1.41.70 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.41.62 to 1.41.70. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/doc/exchanges-by-country.rst) - [Commits](https://github.com/ccxt/ccxt/compare/1.41.62...1.41.70) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7a9e6e5da..f496df00d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ numpy==1.20.1 pandas==1.2.1 -ccxt==1.41.62 +ccxt==1.41.70 aiohttp==3.7.3 SQLAlchemy==1.3.23 python-telegram-bot==13.1 From c412f8df62265131e4a302331ea1de2e5d922d2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 08:28:11 +0000 Subject: [PATCH 104/158] Bump python-telegram-bot from 13.1 to 13.2 Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 13.1 to 13.2. - [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases) - [Changelog](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/CHANGES.rst) - [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v13.1...v13.2) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 7a9e6e5da..c1cc036a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ pandas==1.2.1 ccxt==1.41.62 aiohttp==3.7.3 SQLAlchemy==1.3.23 -python-telegram-bot==13.1 +python-telegram-bot==13.2 arrow==0.17.0 cachetools==4.2.1 requests==2.25.1 From de727645ab7774abdc54c531370baa051aeb3635 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Feb 2021 19:21:33 +0100 Subject: [PATCH 105/158] FIx random test failure if certain files exist --- tests/test_configuration.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index bebbc1508..94c3e24f6 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -743,18 +743,18 @@ def test_set_loggers_journald_importerror(mocker, import_fails): logger.handlers = orig_handlers -def test_set_logfile(default_conf, mocker): +def test_set_logfile(default_conf, mocker, tmpdir): patched_configuration_load_config_file(mocker, default_conf) - + f = Path(tmpdir / "test_file.log") + assert not f.is_file() arglist = [ - 'trade', '--logfile', 'test_file.log', + 'trade', '--logfile', str(f), ] args = Arguments(arglist).get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() - assert validated_conf['logfile'] == "test_file.log" - f = Path("test_file.log") + assert validated_conf['logfile'] == str(f) assert f.is_file() try: f.unlink() From c5ab3a80a596769786b12821cafec4ea08108b6f Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Feb 2021 19:35:22 +0100 Subject: [PATCH 106/158] Check if order is a dict before parsing closes #4331 --- freqtrade/persistence/models.py | 4 ++++ tests/test_persistence.py | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 375709423..dff59819c 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -171,6 +171,10 @@ class Order(_DECL_BASE): """ Get all non-closed orders - useful when trying to batch-update orders """ + if not isinstance(order, dict): + logger.warning(f"{order} is not a valid response object.") + return + filtered_orders = [o for o in orders if o.order_id == order.get('id')] if filtered_orders: oobj = filtered_orders[0] diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 9921f541b..d0d29f142 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1074,7 +1074,7 @@ def test_get_best_pair(fee): @pytest.mark.usefixtures("init_persistence") -def test_update_order_from_ccxt(): +def test_update_order_from_ccxt(caplog): # Most basic order return (only has orderid) o = Order.parse_from_ccxt_object({'id': '1234'}, 'ETH/BTC', 'buy') assert isinstance(o, Order) @@ -1120,6 +1120,14 @@ def test_update_order_from_ccxt(): with pytest.raises(DependencyException, match=r"Order-id's don't match"): o.update_from_ccxt_object(ccxt_order) + message = "aaaa is not a valid response object." + assert not log_has(message, caplog) + Order.update_orders([o], 'aaaa') + assert log_has(message, caplog) + + # Call regular update - shouldn't fail. + Order.update_orders([o], {'id': '1234'}) + @pytest.mark.usefixtures("init_persistence") def test_select_order(fee): From 427d762746980a3a50702b6ea8de1d28325e26c9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Feb 2021 19:37:24 +0100 Subject: [PATCH 107/158] Improve tests for cancel_order to be more realistic --- tests/exchange/test_exchange.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index cd24e113e..352250fc7 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2072,9 +2072,9 @@ def test_cancel_order_with_result_error(default_conf, mocker, exchange_name, cap def test_cancel_order(default_conf, mocker, exchange_name): default_conf['dry_run'] = False api_mock = MagicMock() - api_mock.cancel_order = MagicMock(return_value=123) + api_mock.cancel_order = MagicMock(return_value={'id': '123'}) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) - assert exchange.cancel_order(order_id='_', pair='TKN/BTC') == 123 + assert exchange.cancel_order(order_id='_', pair='TKN/BTC') == {'id': '123'} with pytest.raises(InvalidOrderException): api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder("Did not find order")) @@ -2091,9 +2091,9 @@ def test_cancel_order(default_conf, mocker, exchange_name): def test_cancel_stoploss_order(default_conf, mocker, exchange_name): default_conf['dry_run'] = False api_mock = MagicMock() - api_mock.cancel_order = MagicMock(return_value=123) + api_mock.cancel_order = MagicMock(return_value={'id': '123'}) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) - assert exchange.cancel_stoploss_order(order_id='_', pair='TKN/BTC') == 123 + assert exchange.cancel_stoploss_order(order_id='_', pair='TKN/BTC') == {'id': '123'} with pytest.raises(InvalidOrderException): api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder("Did not find order")) From 7ee149da5d26c7889e4d561bc2154111226dc84c Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Feb 2021 20:08:32 +0100 Subject: [PATCH 108/158] Improve plotting errorhandling closes #4327 --- freqtrade/plot/plotting.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index f45ba9b25..4325e537e 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -53,7 +53,7 @@ def init_plotscript(config, markets: List, startup_candles: int = 0): data_format=config.get('dataformat_ohlcv', 'json'), ) - if startup_candles: + if startup_candles and data: min_date, max_date = get_timerange(data) logger.info(f"Loading data from {min_date} to {max_date}") timerange.adjust_start_if_necessary(timeframe_to_seconds(config.get('timeframe', '5m')), @@ -67,14 +67,16 @@ def init_plotscript(config, markets: List, startup_candles: int = 0): if not filename.is_dir() and not filename.is_file(): logger.warning("Backtest file is missing skipping trades.") no_trades = True - - trades = load_trades( - config['trade_source'], - db_url=config.get('db_url'), - exportfilename=filename, - no_trades=no_trades, - strategy=config.get('strategy'), - ) + try: + trades = load_trades( + config['trade_source'], + db_url=config.get('db_url'), + exportfilename=filename, + no_trades=no_trades, + strategy=config.get('strategy'), + ) + except ValueError as e: + raise OperationalException(e) from e trades = trim_dataframe(trades, timerange, 'open_date') return {"ohlcv": data, From 86fa75b2863eac67edffd20c1fdb7cc853d2d08e Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Feb 2021 06:55:36 +0100 Subject: [PATCH 109/158] Pin version of cryptography --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 59ef69f4f..5d03a9c2d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,8 @@ numpy==1.20.1 pandas==1.2.1 ccxt==1.41.70 +# Pin cryptography for now due to rust build errors with piwheels +cryptography==3.3.2 aiohttp==3.7.3 SQLAlchemy==1.3.23 python-telegram-bot==13.2 From 3110d2dbb192efe7944b09f68a10410daad39fea Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Feb 2021 20:03:03 +0100 Subject: [PATCH 110/158] Add small test cases --- tests/exchange/test_exchange.py | 3 +++ tests/optimize/test_backtesting.py | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 352250fc7..f35a84725 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2462,6 +2462,9 @@ def test_timeframe_to_prev_date(): date = datetime.now(tz=timezone.utc) assert timeframe_to_prev_date("5m") < date + # Does not round + time = datetime(2019, 8, 12, 13, 20, 0, tzinfo=timezone.utc) + assert timeframe_to_prev_date('5m', time) == time def test_timeframe_to_next_date(): diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 5f811e2e5..c8d4338af 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -341,12 +341,14 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest') mocker.patch('freqtrade.optimize.backtesting.generate_backtest_stats') mocker.patch('freqtrade.optimize.backtesting.show_backtest_results') + sbs = mocker.patch('freqtrade.optimize.backtesting.store_backtest_stats') mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', PropertyMock(return_value=['UNITTEST/BTC'])) default_conf['timeframe'] = '1m' default_conf['datadir'] = testdatadir - default_conf['export'] = None + default_conf['export'] = 'trades' + default_conf['exportfilename'] = 'export.txt' default_conf['timerange'] = '-1510694220' backtesting = Backtesting(default_conf) @@ -361,6 +363,7 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: assert log_has(line, caplog) assert backtesting.strategy.dp._pairlists is not None assert backtesting.strategy.bot_loop_start.call_count == 1 + assert sbs.call_count == 1 def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> None: From aa79574c0c60ba68f8b9ee8e5649d8a785010f5c Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 11 Feb 2021 17:09:31 +0100 Subject: [PATCH 111/158] Position-size should NEVER be over available_capital Part of #4353 --- freqtrade/edge/edge_positioning.py | 3 ++- tests/edge/test_edge.py | 39 ++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index e549a3701..2bdef1c89 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -159,7 +159,8 @@ class Edge: available_capital = (total_capital + capital_in_trade) * self._capital_ratio allowed_capital_at_risk = available_capital * self._allowed_risk max_position_size = abs(allowed_capital_at_risk / stoploss) - position_size = min(max_position_size, free_capital) + # Position size must be below available capital. + position_size = min(min(max_position_size, free_capital), available_capital) if pair in self._cached_pairs: logger.info( 'winrate: %s, expectancy: %s, position size: %s, pair: %s,' diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index f25dad35b..c30bce6a4 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -209,7 +209,7 @@ def test_nonexisting_stoploss(mocker, edge_conf): assert edge.stoploss('N/O') == -0.1 -def test_stake_amount(mocker, edge_conf): +def test_edge_stake_amount(mocker, edge_conf): freqtrade = get_patched_freqtradebot(mocker, edge_conf) edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( @@ -217,20 +217,33 @@ def test_stake_amount(mocker, edge_conf): 'E/F': PairInfo(-0.02, 0.66, 3.71, 0.50, 1.71, 10, 60), } )) - free = 100 - total = 100 - in_trade = 25 - assert edge.stake_amount('E/F', free, total, in_trade) == 31.25 + assert edge._capital_ratio == 0.5 + assert edge.stake_amount('E/F', free_capital=100, total_capital=100, + capital_in_trade=25) == 31.25 - free = 20 - total = 100 - in_trade = 25 - assert edge.stake_amount('E/F', free, total, in_trade) == 20 + assert edge.stake_amount('E/F', free_capital=20, total_capital=100, + capital_in_trade=25) == 20 - free = 0 - total = 100 - in_trade = 25 - assert edge.stake_amount('E/F', free, total, in_trade) == 0 + assert edge.stake_amount('E/F', free_capital=0, total_capital=100, + capital_in_trade=25) == 0 + + # Test with increased allowed_risk + # Result should be no more than allowed capital + edge._allowed_risk = 0.4 + edge._capital_ratio = 0.5 + assert edge.stake_amount('E/F', free_capital=100, total_capital=100, + capital_in_trade=25) == 62.5 + + assert edge.stake_amount('E/F', free_capital=100, total_capital=100, + capital_in_trade=0) == 50 + + edge._capital_ratio = 1 + # Full capital is available + assert edge.stake_amount('E/F', free_capital=100, total_capital=100, + capital_in_trade=0) == 100 + # Full capital is available + assert edge.stake_amount('E/F', free_capital=0, total_capital=100, + capital_in_trade=0) == 0 def test_nonexisting_stake_amount(mocker, edge_conf): From 843fb204e9aa680b53aa16061815519d74456ca8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 11 Feb 2021 20:21:07 +0100 Subject: [PATCH 112/158] Fix problem with inf values returned from dataframe for api methods --- freqtrade/rpc/api_server/api_v1.py | 2 +- freqtrade/rpc/rpc.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index a2082103b..3588f2196 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -167,7 +167,7 @@ def reload_config(rpc: RPC = Depends(get_rpc)): @router.get('/pair_candles', response_model=PairHistory, tags=['candle data']) -def pair_candles(pair: str, timeframe: str, limit: Optional[int], rpc=Depends(get_rpc)): +def pair_candles(pair: str, timeframe: str, limit: Optional[int], rpc: RPC = Depends(get_rpc)): return rpc._rpc_analysed_dataframe(pair, timeframe, limit) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 27563f73b..464b341eb 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -9,7 +9,7 @@ from math import isnan from typing import Any, Dict, List, Optional, Tuple, Union import arrow -from numpy import NAN, int64, mean +from numpy import NAN, inf, int64, mean from pandas import DataFrame from freqtrade.configuration.timerange import TimeRange @@ -747,6 +747,7 @@ class RPC: sell_mask = (dataframe['sell'] == 1) sell_signals = int(sell_mask.sum()) dataframe.loc[sell_mask, '_sell_signal_open'] = dataframe.loc[sell_mask, 'open'] + dataframe = dataframe.replace([inf, -inf], NAN) dataframe = dataframe.replace({NAN: None}) res = { From dd23f6bcbcd569a0857ac0dc1920b24c2065f05e Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 11 Feb 2021 20:29:31 +0100 Subject: [PATCH 113/158] Fix type for getting pairs --- freqtrade/rpc/rpc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 464b341eb..7549c38be 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -776,7 +776,8 @@ class RPC: }) return res - def _rpc_analysed_dataframe(self, pair: str, timeframe: str, limit: int) -> Dict[str, Any]: + def _rpc_analysed_dataframe(self, pair: str, timeframe: str, + limit: Optional[int]) -> Dict[str, Any]: _data, last_analyzed = self._freqtrade.dataprovider.get_analyzed_dataframe( pair, timeframe) From 072abde9b71b34022e3a5f5c867847ec12a211fd Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 12 Feb 2021 20:32:41 +0100 Subject: [PATCH 114/158] Introduce round_coin_value to simplify coin rounding --- freqtrade/constants.py | 10 +++++++++ freqtrade/misc.py | 25 +++++++++++++++++++++++ freqtrade/optimize/optimize_reports.py | 11 +++++----- tests/test_misc.py | 28 +++++++++++++++++++++++--- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 69301ca0e..802ddc2b1 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -45,6 +45,16 @@ USERPATH_NOTEBOOKS = 'notebooks' TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent'] + +# Define decimals per coin for outputs +# Only used for outputs. +DECIMAL_PER_COIN_FALLBACK = 3 # Should be low to avoid listing all possible FIAT's +DECIMALS_PER_COIN = { + 'BTC': 8, + 'ETH': 5, +} + + # Soure files with destination directories within user-directory USER_DATA_FILES = { 'sample_strategy.py': USERPATH_STRATEGIES, diff --git a/freqtrade/misc.py b/freqtrade/misc.py index 22e14b564..7bbc24056 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -11,10 +11,35 @@ from typing.io import IO import rapidjson +from freqtrade.constants import DECIMAL_PER_COIN_FALLBACK, DECIMALS_PER_COIN + logger = logging.getLogger(__name__) +def decimals_per_coin(coin: str): + """ + Helper method getting decimal amount for this coin + example usage: f".{decimals_per_coin('USD')}f" + :param coin: Which coin are we printing the price / value for + """ + return DECIMALS_PER_COIN.get(coin, DECIMAL_PER_COIN_FALLBACK) + + +def round_coin_value(value: float, coin: str, show_coin_name=True) -> str: + """ + Get price value for this coin + :param value: Value to be printed + :param coin: Which coin are we printing the price / value for + :param show_coin_name: Return string in format: "222.22 USDT" or "222.22" + :return: Formatted / rounded value (with or without coin name) + """ + if show_coin_name: + return f"{value:.{decimals_per_coin(coin)}f} {coin}" + else: + return f"{value:.{decimals_per_coin(coin)}f}" + + def shorten_date(_date: str) -> str: """ Trim the date so it fits on small screens diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 8edfbaf8d..c70a4cd2d 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -10,7 +10,7 @@ from tabulate import tabulate from freqtrade.constants import DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN from freqtrade.data.btanalysis import calculate_market_change, calculate_max_drawdown -from freqtrade.misc import file_dump_json +from freqtrade.misc import file_dump_json, round_coin_value, decimals_per_coin logger = logging.getLogger(__name__) @@ -38,11 +38,12 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N file_dump_json(latest_filename, {'latest_backtest': str(filename.name)}) -def _get_line_floatfmt() -> List[str]: +def _get_line_floatfmt(stake_currency: str) -> List[str]: """ Generate floatformat (goes in line with _generate_result_line()) """ - return ['s', 'd', '.2f', '.2f', '.8f', '.2f', 'd', 'd', 'd', 'd'] + return ['s', 'd', '.2f', '.2f', f'.{decimals_per_coin(stake_currency)}f', + '.2f', 'd', 'd', 'd', 'd'] def _get_line_header(first_column: str, stake_currency: str) -> List[str]: @@ -352,7 +353,7 @@ def text_table_bt_results(pair_results: List[Dict[str, Any]], stake_currency: st """ headers = _get_line_header('Pair', stake_currency) - floatfmt = _get_line_floatfmt() + floatfmt = _get_line_floatfmt(stake_currency) output = [[ t['key'], t['trades'], t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'], t['profit_total_pct'], t['duration_avg'], t['wins'], t['draws'], t['losses'] @@ -396,7 +397,7 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: :param all_results: Dict of containing results for all strategies :return: pretty printed table with tabulate as string """ - floatfmt = _get_line_floatfmt() + floatfmt = _get_line_floatfmt(stake_currency) headers = _get_line_header('Strategy', stake_currency) output = [[ diff --git a/tests/test_misc.py b/tests/test_misc.py index 429da135a..e6ba70aee 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -6,9 +6,31 @@ from unittest.mock import MagicMock import pytest -from freqtrade.misc import (file_dump_json, file_load_json, format_ms_time, pair_to_filename, - plural, render_template, render_template_with_fallback, - safe_value_fallback, safe_value_fallback2, shorten_date) +from freqtrade.misc import (decimals_per_coin, file_dump_json, file_load_json, format_ms_time, + pair_to_filename, plural, render_template, + render_template_with_fallback, round_coin_value, safe_value_fallback, + safe_value_fallback2, shorten_date) + + +def test_decimals_per_coin(): + assert decimals_per_coin('USDT') == 3 + assert decimals_per_coin('EUR') == 3 + assert decimals_per_coin('BTC') == 8 + assert decimals_per_coin('ETH') == 5 + + +def test_round_coin_value(): + assert round_coin_value(222.222222, 'USDT') == '222.222 USDT' + assert round_coin_value(222.2, 'USDT') == '222.200 USDT' + assert round_coin_value(222.12745, 'EUR') == '222.127 EUR' + assert round_coin_value(0.1274512123, 'BTC') == '0.12745121 BTC' + assert round_coin_value(0.1274512123, 'ETH') == '0.12745 ETH' + + assert round_coin_value(222.222222, 'USDT', False) == '222.222' + assert round_coin_value(222.2, 'USDT', False) == '222.200' + assert round_coin_value(222.12745, 'EUR', False) == '222.127' + assert round_coin_value(0.1274512123, 'BTC', False) == '0.12745121' + assert round_coin_value(0.1274512123, 'ETH', False) == '0.12745' def test_shorten_date() -> None: From e7acee79045bfb5aa8cf485d5aa151d4c33fbf30 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Feb 2021 16:05:56 +0100 Subject: [PATCH 115/158] Improve coin value output by rounding coin specific --- freqtrade/optimize/optimize_reports.py | 6 ++-- freqtrade/rpc/telegram.py | 46 ++++++++++++++------------ tests/rpc/test_rpc_telegram.py | 6 ++-- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index c70a4cd2d..118253e86 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -10,7 +10,7 @@ from tabulate import tabulate from freqtrade.constants import DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN from freqtrade.data.btanalysis import calculate_market_change, calculate_max_drawdown -from freqtrade.misc import file_dump_json, round_coin_value, decimals_per_coin +from freqtrade.misc import decimals_per_coin, file_dump_json, round_coin_value logger = logging.getLogger(__name__) @@ -384,7 +384,9 @@ def text_table_sell_reason(sell_reason_stats: List[Dict[str, Any]], stake_curren output = [[ t['sell_reason'], t['trades'], t['wins'], t['draws'], t['losses'], - t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'], t['profit_total_pct'], + t['profit_mean_pct'], t['profit_sum_pct'], + round_coin_value(t['profit_total_abs'], stake_currency, False), + t['profit_total_pct'], ] for t in sell_reason_stats] return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right") diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 0f7005639..a16299e4b 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -18,6 +18,7 @@ from telegram.utils.helpers import escape_markdown from freqtrade.__init__ import __version__ from freqtrade.exceptions import OperationalException +from freqtrade.misc import round_coin_value from freqtrade.rpc import RPC, RPCException, RPCHandler, RPCMessageType @@ -189,14 +190,14 @@ class Telegram(RPCHandler): else: msg['stake_amount_fiat'] = 0 - message = ("\N{LARGE BLUE CIRCLE} *{exchange}:* Buying {pair}\n" - "*Amount:* `{amount:.8f}`\n" - "*Open Rate:* `{limit:.8f}`\n" - "*Current Rate:* `{current_rate:.8f}`\n" - "*Total:* `({stake_amount:.6f} {stake_currency}").format(**msg) + message = (f"\N{LARGE BLUE CIRCLE} *{msg['exchange']}:* Buying {msg['pair']}\n" + f"*Amount:* `{msg['amount']:.8f}`\n" + f"*Open Rate:* `{msg['limit']:.8f}`\n" + f"*Current Rate:* `{msg['current_rate']:.8f}`\n" + f"*Total:* `({round_coin_value(msg['stake_amount'], msg['stake_currency'])}") if msg.get('fiat_currency', None): - message += ", {stake_amount_fiat:.3f} {fiat_currency}".format(**msg) + message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" message += ")`" elif msg['type'] == RPCMessageType.BUY_CANCEL_NOTIFICATION: @@ -365,7 +366,7 @@ class Telegram(RPCHandler): ) stats_tab = tabulate( [[day['date'], - f"{day['abs_profit']:.8f} {stats['stake_currency']}", + f"{round_coin_value(day['abs_profit'], stats['stake_currency'])}", f"{day['fiat_value']:.3f} {stats['fiat_display_currency']}", f"{day['trade_count']} trades"] for day in stats['data']], headers=[ @@ -415,18 +416,18 @@ class Telegram(RPCHandler): # Message to display if stats['closed_trade_count'] > 0: markdown_msg = ("*ROI:* Closed trades\n" - f"∙ `{profit_closed_coin:.8f} {stake_cur} " + f"∙ `{round_coin_value(profit_closed_coin, stake_cur)} " f"({profit_closed_percent_mean:.2f}%) " f"({profit_closed_percent_sum} \N{GREEK CAPITAL LETTER SIGMA}%)`\n" - f"∙ `{profit_closed_fiat:.3f} {fiat_disp_cur}`\n") + f"∙ `{round_coin_value(profit_closed_fiat, fiat_disp_cur)}`\n") else: markdown_msg = "`No closed trade` \n" markdown_msg += (f"*ROI:* All trades\n" - f"∙ `{profit_all_coin:.8f} {stake_cur} " + f"∙ `{round_coin_value(profit_all_coin, stake_cur)} " f"({profit_all_percent_mean:.2f}%) " f"({profit_all_percent_sum} \N{GREEK CAPITAL LETTER SIGMA}%)`\n" - f"∙ `{profit_all_fiat:.3f} {fiat_disp_cur}`\n" + f"∙ `{round_coin_value(profit_all_fiat, fiat_disp_cur)}`\n" f"*Total Trade Count:* `{trade_count}`\n" f"*First Trade opened:* `{first_trade_date}`\n" f"*Latest Trade opened:* `{latest_trade_date}\n`" @@ -494,15 +495,17 @@ class Telegram(RPCHandler): "Starting capital: " f"`{self._config['dry_run_wallet']}` {self._config['stake_currency']}.\n" ) - for currency in result['currencies']: - if currency['est_stake'] > 0.0001: - curr_output = ("*{currency}:*\n" - "\t`Available: {free: .8f}`\n" - "\t`Balance: {balance: .8f}`\n" - "\t`Pending: {used: .8f}`\n" - "\t`Est. {stake}: {est_stake: .8f}`\n").format(**currency) + for curr in result['currencies']: + if curr['est_stake'] > 0.0001: + curr_output = ( + f"*{curr['currency']}:*\n" + f"\t`Available: {curr['free']:.8f}`\n" + f"\t`Balance: {curr['balance']:.8f}`\n" + f"\t`Pending: {curr['used']:.8f}`\n" + f"\t`Est. {curr['stake']}: " + f"{round_coin_value(curr['est_stake'], curr['stake'], False)}`\n") else: - curr_output = "*{currency}:* not showing <1$ amount \n".format(**currency) + curr_output = "*{currency}:* not showing <1$ amount \n".format(**curr) # Handle overflowing messsage length if len(output + curr_output) >= MAX_TELEGRAM_MESSAGE_LENGTH: @@ -512,8 +515,9 @@ class Telegram(RPCHandler): output += curr_output output += ("\n*Estimated Value*:\n" - "\t`{stake}: {total: .8f}`\n" - "\t`{symbol}: {value: .2f}`\n").format(**result) + f"\t`{result['stake']}: {result['total']: .8f}`\n" + f"\t`{result['symbol']}: " + f"{round_coin_value(result['value'], result['symbol'], False)}`\n") self._send_msg(output) except RPCException as e: self._send_msg(str(e)) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 1c34b6b26..f065bb4c5 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -519,7 +519,7 @@ def test_telegram_balance_handle(default_conf, update, mocker, rpc_balance, tick assert '*EUR:*' in result assert 'Balance:' in result assert 'Est. BTC:' in result - assert 'BTC: 12.00000000' in result + assert 'BTC: 12.00000000' in result assert '*XRP:* not showing <1$ amount' in result @@ -1205,7 +1205,7 @@ def test_send_msg_buy_notification(default_conf, mocker, caplog) -> None: '*Amount:* `1333.33333333`\n' \ '*Open Rate:* `0.00001099`\n' \ '*Current Rate:* `0.00001099`\n' \ - '*Total:* `(0.001000 BTC, 12.345 USD)`' + '*Total:* `(0.00100000 BTC, 12.345 USD)`' freqtradebot.config['telegram']['notification_settings'] = {'buy': 'off'} caplog.clear() @@ -1389,7 +1389,7 @@ def test_send_msg_buy_notification_no_fiat(default_conf, mocker) -> None: '*Amount:* `1333.33333333`\n' '*Open Rate:* `0.00001099`\n' '*Current Rate:* `0.00001099`\n' - '*Total:* `(0.001000 BTC)`') + '*Total:* `(0.00100000 BTC)`') def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None: From d4c8be915cc66e6995d383f27cdd2733e7343bca Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 13 Feb 2021 16:11:49 +0100 Subject: [PATCH 116/158] Use fstring where possible --- freqtrade/rpc/telegram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index a16299e4b..88019601c 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -505,7 +505,7 @@ class Telegram(RPCHandler): f"\t`Est. {curr['stake']}: " f"{round_coin_value(curr['est_stake'], curr['stake'], False)}`\n") else: - curr_output = "*{currency}:* not showing <1$ amount \n".format(**curr) + curr_output = f"*{curr['currency']}:* not showing <1$ amount \n" # Handle overflowing messsage length if len(output + curr_output) >= MAX_TELEGRAM_MESSAGE_LENGTH: From 73d91275c4491d452306bf0e0b53530d1406c4e0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 07:11:07 +0100 Subject: [PATCH 117/158] Reset sell_order_status if a new sell-order is placed closes #4365 --- freqtrade/freqtradebot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index a6eb75d5b..73707e4ec 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -1183,6 +1183,7 @@ class FreqtradeBot(LoggingMixin): trade.orders.append(order_obj) trade.open_order_id = order['id'] + trade.sell_order_status = '' trade.close_rate_requested = limit trade.sell_reason = sell_reason.value # In case of market sell orders the order can be closed immediately From 6f77ec063e36a11ec55281c41a1a15ee07e72ed9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 07:22:08 +0100 Subject: [PATCH 118/158] Fix cookieError on python<3.8 Only occurs in combination with api-server enabled, due to some hot-fixing starlette does. Since we load starlette at a later point, we need to replicate starlette's behaviour for now, so sameSite cookies don't create a problem. closes #4356 --- freqtrade/exchange/exchange.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index c7625b53c..2b47aa7dd 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -3,6 +3,7 @@ Cryptocurrency Exchanges support """ import asyncio +import http import inspect import logging from copy import deepcopy @@ -34,6 +35,12 @@ CcxtModuleType = Any logger = logging.getLogger(__name__) +# Workaround for adding samesite support to pre 3.8 python +# Only applies to python3.7, and only on certain exchanges (kraken) +# Replicates the fix from starlette (which is actually causing this problem) +http.cookies.Morsel._reserved["samesite"] = "SameSite" # type: ignore + + class Exchange: _config: Dict = {} From 10a11bda34f9116944b6f0c75599d4ce5f179c2d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 09:41:50 +0100 Subject: [PATCH 119/158] Document bitvavo as community tested closes #4360 --- README.md | 13 +++++++++++-- docs/index.md | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bb136d7f2..7ef0d4ce7 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,21 @@ expect. We strongly recommend you to have coding and Python knowledge. Do not hesitate to read the source code and understand the mechanism of this bot. -## Exchange marketplaces supported +## Supported Exchange marketplaces + +Please read the [exchange specific notes](docs/exchanges.md) to learn about eventual, special configurations needed for each exchange. - [X] [Bittrex](https://bittrex.com/) - [X] [Binance](https://www.binance.com/) ([*Note for binance users](docs/exchanges.md#blacklists)) - [X] [Kraken](https://kraken.com/) -- [ ] [113 others to tests](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ +- [X] [FTX](https://ftx.com) +- [ ] [potentially many others](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ + +### Community tested + +Exchanges confirmed working by the community: + +- [X] [Bitvavo](https://bitvavo.com/) ## Documentation diff --git a/docs/index.md b/docs/index.md index b489861f0..db5088707 100644 --- a/docs/index.md +++ b/docs/index.md @@ -35,6 +35,22 @@ Freqtrade is a crypto-currency algorithmic trading software developed in python - Control/Monitor: Use Telegram or a REST API (start/stop the bot, show profit/loss, daily summary, current open trades results, etc.). - Analyse: Further analysis can be performed on either Backtesting data or Freqtrade trading history (SQL database), including automated standard plots, and methods to load the data into [interactive environments](data-analysis.md). +## Supported exchange marketplaces + +Please read the [exchange specific notes](exchanges.md) to learn about eventual, special configurations needed for each exchange. + +- [X] [Binance](https://www.binance.com/) ([*Note for binance users](exchanges.md#blacklists)) +- [X] [Bittrex](https://bittrex.com/) +- [X] [FTX](https://ftx.com) +- [X] [Kraken](https://kraken.com/) +- [ ] [potentially many others](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ + +### Community tested + +Exchanges confirmed working by the community: + +- [X] [Bitvavo](https://bitvavo.com/) + ## Requirements ### Hardware requirements From 7ecf8f8b802318567467f404552c0fafdb1f76aa Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 10:08:05 +0100 Subject: [PATCH 120/158] Cleanup candle_limit usage --- freqtrade/exchange/exchange.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 2b47aa7dd..b11d2f234 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -433,10 +433,10 @@ class Exchange: Checks if required startup_candles is more than ohlcv_candle_limit. Requires a grace-period of 5 candles - so a startup-period up to 494 is allowed by default. """ - if startup_candles + 5 > self._ft_has['ohlcv_candle_limit']: + if startup_candles + 5 > self.ohlcv_candle_limit: raise OperationalException( f"This strategy requires {startup_candles} candles to start. " - f"{self.name} only provides {self._ft_has['ohlcv_candle_limit']}.") + f"{self.name} only provides {self.ohlcv_candle_limit}.") def exchange_has(self, endpoint: str) -> bool: """ @@ -721,7 +721,7 @@ class Exchange: """ Get candle history using asyncio and returns the list of candles. Handles all async work for this. - Async over one pair, assuming we get `self._ohlcv_candle_limit` candles per call. + Async over one pair, assuming we get `self.ohlcv_candle_limit` candles per call. :param pair: Pair to download :param timeframe: Timeframe to get data for :param since_ms: Timestamp in milliseconds to get history from @@ -751,7 +751,7 @@ class Exchange: Download historic ohlcv """ - one_call = timeframe_to_msecs(timeframe) * self._ohlcv_candle_limit + one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit logger.debug( "one_call: %s msecs (%s)", one_call, @@ -853,7 +853,7 @@ class Exchange: data = await self._api_async.fetch_ohlcv(pair, timeframe=timeframe, since=since_ms, - limit=self._ohlcv_candle_limit) + limit=self.ohlcv_candle_limit) # Some exchanges sort OHLCV in ASC order and others in DESC. # Ex: Bittrex returns the list of OHLCV in ASC order (oldest first, newest last) @@ -1026,7 +1026,7 @@ class Exchange: """ Get trade history data using asyncio. Handles all async work and returns the list of candles. - Async over one pair, assuming we get `self._ohlcv_candle_limit` candles per call. + Async over one pair, assuming we get `self.ohlcv_candle_limit` candles per call. :param pair: Pair to download :param since: Timestamp in milliseconds to get history from :param until: Timestamp in milliseconds. Defaults to current timestamp if not defined. From 5622bb32471e5a85c340a1ddf3c70c0948611538 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 10:29:45 +0100 Subject: [PATCH 121/158] Make candle_limit optionally timeframe dependent --- freqtrade/exchange/exchange.py | 37 +++++++++++-------- freqtrade/plugins/pairlist/AgeFilter.py | 4 +- .../plugins/pairlist/rangestabilityfilter.py | 4 +- tests/exchange/test_ccxt_compat.py | 8 +++- tests/exchange/test_exchange.py | 4 +- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index b11d2f234..d176e489b 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -101,7 +101,6 @@ class Exchange: logger.info("Overriding exchange._ft_has with config params, result: %s", self._ft_has) # Assign this directly for easy access - self._ohlcv_candle_limit = self._ft_has['ohlcv_candle_limit'] self._ohlcv_partial_candle = self._ft_has['ohlcv_partial_candle'] self._trades_pagination = self._ft_has['trades_pagination'] @@ -137,7 +136,8 @@ class Exchange: self.validate_pairs(config['exchange']['pair_whitelist']) self.validate_ordertypes(config.get('order_types', {})) self.validate_order_time_in_force(config.get('order_time_in_force', {})) - self.validate_required_startup_candles(config.get('startup_candle_count', 0)) + self.validate_required_startup_candles(config.get('startup_candle_count', 0), + config.get('timeframe')) # Converts the interval provided in minutes in config to seconds self.markets_refresh_interval: int = exchange_config.get( @@ -198,11 +198,6 @@ class Exchange: def timeframes(self) -> List[str]: return list((self._api.timeframes or {}).keys()) - @property - def ohlcv_candle_limit(self) -> int: - """exchange ohlcv candle limit""" - return int(self._ohlcv_candle_limit) - @property def markets(self) -> Dict: """exchange ccxt markets""" @@ -216,6 +211,17 @@ class Exchange: """exchange ccxt precisionMode""" return self._api.precisionMode + def ohlcv_candle_limit(self, timeframe: str) -> int: + """ + Exchange ohlcv candle limit + Uses ohlcv_candle_limit_per_timeframe if the exchange has different limts + per timeframe (e.g. bittrex), otherwise falls back to ohlcv_candle_limit + :param timeframe: Timeframe to check + :return: Candle limit as integer + """ + return int(self._ft_has.get('ohlcv_candle_limit_per_timeframe', {}).get( + timeframe, self._ft_has.get('ohlcv_candle_limit'))) + def get_markets(self, base_currencies: List[str] = None, quote_currencies: List[str] = None, pairs_only: bool = False, active_only: bool = False) -> Dict[str, Any]: """ @@ -428,15 +434,16 @@ class Exchange: raise OperationalException( f'Time in force policies are not supported for {self.name} yet.') - def validate_required_startup_candles(self, startup_candles: int) -> None: + def validate_required_startup_candles(self, startup_candles: int, timeframe: str) -> None: """ - Checks if required startup_candles is more than ohlcv_candle_limit. + Checks if required startup_candles is more than ohlcv_candle_limit(). Requires a grace-period of 5 candles - so a startup-period up to 494 is allowed by default. """ - if startup_candles + 5 > self.ohlcv_candle_limit: + candle_limit = self.ohlcv_candle_limit(timeframe) + if startup_candles + 5 > candle_limit: raise OperationalException( f"This strategy requires {startup_candles} candles to start. " - f"{self.name} only provides {self.ohlcv_candle_limit}.") + f"{self.name} only provides {candle_limit} for {timeframe}.") def exchange_has(self, endpoint: str) -> bool: """ @@ -721,7 +728,7 @@ class Exchange: """ Get candle history using asyncio and returns the list of candles. Handles all async work for this. - Async over one pair, assuming we get `self.ohlcv_candle_limit` candles per call. + Async over one pair, assuming we get `self.ohlcv_candle_limit()` candles per call. :param pair: Pair to download :param timeframe: Timeframe to get data for :param since_ms: Timestamp in milliseconds to get history from @@ -751,7 +758,7 @@ class Exchange: Download historic ohlcv """ - one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit + one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe) logger.debug( "one_call: %s msecs (%s)", one_call, @@ -853,7 +860,7 @@ class Exchange: data = await self._api_async.fetch_ohlcv(pair, timeframe=timeframe, since=since_ms, - limit=self.ohlcv_candle_limit) + limit=self.ohlcv_candle_limit(timeframe)) # Some exchanges sort OHLCV in ASC order and others in DESC. # Ex: Bittrex returns the list of OHLCV in ASC order (oldest first, newest last) @@ -1026,7 +1033,7 @@ class Exchange: """ Get trade history data using asyncio. Handles all async work and returns the list of candles. - Async over one pair, assuming we get `self.ohlcv_candle_limit` candles per call. + Async over one pair, assuming we get `self.ohlcv_candle_limit()` candles per call. :param pair: Pair to download :param since: Timestamp in milliseconds to get history from :param until: Timestamp in milliseconds. Defaults to current timestamp if not defined. diff --git a/freqtrade/plugins/pairlist/AgeFilter.py b/freqtrade/plugins/pairlist/AgeFilter.py index 8c3a5d22f..8a5379ca6 100644 --- a/freqtrade/plugins/pairlist/AgeFilter.py +++ b/freqtrade/plugins/pairlist/AgeFilter.py @@ -30,10 +30,10 @@ class AgeFilter(IPairList): if self._min_days_listed < 1: raise OperationalException("AgeFilter requires min_days_listed to be >= 1") - if self._min_days_listed > exchange.ohlcv_candle_limit: + if self._min_days_listed > exchange.ohlcv_candle_limit('1d'): raise OperationalException("AgeFilter requires min_days_listed to not exceed " "exchange max request size " - f"({exchange.ohlcv_candle_limit})") + f"({exchange.ohlcv_candle_limit('1d')})") @property def needstickers(self) -> bool: diff --git a/freqtrade/plugins/pairlist/rangestabilityfilter.py b/freqtrade/plugins/pairlist/rangestabilityfilter.py index f2e84930b..db51a9c77 100644 --- a/freqtrade/plugins/pairlist/rangestabilityfilter.py +++ b/freqtrade/plugins/pairlist/rangestabilityfilter.py @@ -32,10 +32,10 @@ class RangeStabilityFilter(IPairList): if self._days < 1: raise OperationalException("RangeStabilityFilter requires lookback_days to be >= 1") - if self._days > exchange.ohlcv_candle_limit: + if self._days > exchange.ohlcv_candle_limit('1d'): raise OperationalException("RangeStabilityFilter requires lookback_days to not " "exceed exchange max request size " - f"({exchange.ohlcv_candle_limit})") + f"({exchange.ohlcv_candle_limit('1d')})") @property def needstickers(self) -> bool: diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 8e1d074aa..a64565c28 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -5,11 +5,14 @@ However, these tests should give a good idea to determine if a new exchange is suitable to run with freqtrade. """ +from datetime import datetime, timedelta, timezone +from freqtrade.exchange.exchange import timeframe_to_minutes from pathlib import Path import pytest from freqtrade.resolvers.exchange_resolver import ExchangeResolver +from freqtrade.exchange import timeframe_to_prev_date from tests.conftest import get_default_conf @@ -122,7 +125,10 @@ class TestCCXTExchange(): assert len(ohlcv[pair_tf]) == len(exchange.klines(pair_tf)) # assert len(exchange.klines(pair_tf)) > 200 # Assume 90% uptime ... - assert len(exchange.klines(pair_tf)) > exchange._ohlcv_candle_limit * 0.90 + assert len(exchange.klines(pair_tf)) > exchange.ohlcv_candle_limit(timeframe) * 0.90 + # Check if last-timeframe is within the last 2 intervals + now = datetime.now(timezone.utc) - timedelta(minutes=(timeframe_to_minutes(timeframe) * 2)) + assert exchange.klines(pair_tf).iloc[-1]['date'] >= timeframe_to_prev_date(timeframe, now) # TODO: tests fetch_trades (?) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index f35a84725..3bafb2457 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1417,7 +1417,7 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name): exchange._async_get_candle_history = Mock(wraps=mock_candle_hist) # one_call calculation * 1.8 should do 2 calls - since = 5 * 60 * exchange._ft_has['ohlcv_candle_limit'] * 1.8 + since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8 ret = exchange.get_historic_ohlcv(pair, "5m", int(( arrow.utcnow().int_timestamp - since) * 1000)) @@ -1473,7 +1473,7 @@ def test_get_historic_ohlcv_as_df(default_conf, mocker, exchange_name): exchange._async_get_candle_history = Mock(wraps=mock_candle_hist) # one_call calculation * 1.8 should do 2 calls - since = 5 * 60 * exchange._ft_has['ohlcv_candle_limit'] * 1.8 + since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8 ret = exchange.get_historic_ohlcv_as_df(pair, "5m", int(( arrow.utcnow().int_timestamp - since) * 1000)) From da89838b5cf4cd0a17cc8286e355b44962e587d6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 10:32:55 +0100 Subject: [PATCH 122/158] Set bittrex limits as returned by the exchange closes #4181 --- freqtrade/exchange/bittrex.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/freqtrade/exchange/bittrex.py b/freqtrade/exchange/bittrex.py index 4318f9cf0..fd7d47668 100644 --- a/freqtrade/exchange/bittrex.py +++ b/freqtrade/exchange/bittrex.py @@ -19,5 +19,11 @@ class Bittrex(Exchange): """ _ft_has: Dict = { + "ohlcv_candle_limit_per_timeframe": { + '1m': 1440, + '5m': 288, + '1h': 744, + '1d': 365, + }, "l2_limit_range": [1, 25, 500], } From ffca09bbcbdb91ca65ef966a2e09bd03e96bceb0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 10:38:49 +0100 Subject: [PATCH 123/158] Test ohlcv_candle_limit explicitly --- tests/exchange/test_exchange.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 3bafb2457..75db2de26 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -2418,6 +2418,19 @@ def test_get_markets_error(default_conf, mocker): ex.get_markets('LTC', 'USDT', True, False) +@pytest.mark.parametrize("exchange_name", EXCHANGES) +def test_ohlcv_candle_limit(default_conf, mocker, exchange_name): + exchange = get_patched_exchange(mocker, default_conf, id=exchange_name) + timeframes = ('1m', '5m', '1h') + expected = exchange._ft_has['ohlcv_candle_limit'] + for timeframe in timeframes: + if 'ohlcv_candle_limit_per_timeframe' in exchange._ft_has: + expected = exchange._ft_has['ohlcv_candle_limit_per_timeframe'][timeframe] + # This should only run for bittrex + assert exchange_name == 'bittrex' + assert exchange.ohlcv_candle_limit(timeframe) == expected + + def test_timeframe_to_minutes(): assert timeframe_to_minutes("5m") == 5 assert timeframe_to_minutes("10m") == 10 From ee74bc1f524e9b74c0241926a3fd71cdc2faee09 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 10:46:59 +0100 Subject: [PATCH 124/158] timeframe is mandatory, no need to use .get() --- freqtrade/exchange/exchange.py | 2 +- tests/exchange/test_ccxt_compat.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d176e489b..617cd6c26 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -137,7 +137,7 @@ class Exchange: self.validate_ordertypes(config.get('order_types', {})) self.validate_order_time_in_force(config.get('order_time_in_force', {})) self.validate_required_startup_candles(config.get('startup_candle_count', 0), - config.get('timeframe')) + config.get('timeframe', '')) # Converts the interval provided in minutes in config to seconds self.markets_refresh_interval: int = exchange_config.get( diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index a64565c28..03cb30d62 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -6,13 +6,12 @@ suitable to run with freqtrade. """ from datetime import datetime, timedelta, timezone -from freqtrade.exchange.exchange import timeframe_to_minutes from pathlib import Path import pytest +from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date from freqtrade.resolvers.exchange_resolver import ExchangeResolver -from freqtrade.exchange import timeframe_to_prev_date from tests.conftest import get_default_conf From 5c263c7ffd546ec50fc96dbab49ba502bdf0ff33 Mon Sep 17 00:00:00 2001 From: Florian Reitmeir Date: Thu, 24 Dec 2020 22:17:24 +0100 Subject: [PATCH 125/158] add backtesting results abs profit min/abs profit max, to get a better view if a strategy has a enough money to succeed --- freqtrade/data/btanalysis.py | 18 ++++++++++++++++++ freqtrade/optimize/optimize_reports.py | 18 +++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 828fb78f3..8e851a8e8 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -383,3 +383,21 @@ def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date' high_date = profit_results.loc[max_drawdown_df.iloc[:idxmin]['high_value'].idxmax(), date_col] low_date = profit_results.loc[idxmin, date_col] return abs(min(max_drawdown_df['drawdown'])), high_date, low_date + + +def calculate_csum(trades: pd.DataFrame) -> Tuple[float, float]: + """ + Calculate min/max cumsum of trades, to show if the wallet/stake amount ratio is sane + :param trades: DataFrame containing trades (requires columns close_date and profit_percent) + :return: Tuple (float, float) with cumsum of profit_abs + :raise: ValueError if trade-dataframe was found empty. + """ + if len(trades) == 0: + raise ValueError("Trade dataframe empty.") + + csum_df = pd.DataFrame() + csum_df['sum'] = trades['profit_abs'].cumsum() + csum_min = csum_df['sum'].min() + csum_max = csum_df['sum'].max() + + return csum_min, csum_max diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 118253e86..88b2028ba 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -9,7 +9,8 @@ from pandas import DataFrame from tabulate import tabulate from freqtrade.constants import DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN -from freqtrade.data.btanalysis import calculate_market_change, calculate_max_drawdown +from freqtrade.data.btanalysis import (calculate_csum, calculate_market_change, + calculate_max_drawdown) from freqtrade.misc import decimals_per_coin, file_dump_json, round_coin_value @@ -324,6 +325,13 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], 'drawdown_end': drawdown_end, 'drawdown_end_ts': drawdown_end.timestamp() * 1000, }) + + csum_min, csum_max = calculate_csum(results) + strat_stats.update({ + 'csum_min': csum_min, + 'csum_max': csum_max + }) + except ValueError: strat_stats.update({ 'max_drawdown': 0.0, @@ -331,6 +339,8 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], 'drawdown_start_ts': 0, 'drawdown_end': datetime(1970, 1, 1, tzinfo=timezone.utc), 'drawdown_end_ts': 0, + 'csum_min': 0, + 'csum_max': 0 }) strategy_results = generate_strategy_metrics(all_results=all_results) @@ -439,6 +449,12 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"), ('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"), ('', ''), # Empty line to improve readability + + ('Abs Profit Min', round_coin_value(strat_results['csum_min'], + strat_results['stake_currency'])), + ('Abs Profit Max', round_coin_value(strat_results['csum_max'], + strat_results['stake_currency'])), + ('Max Drawdown', f"{round(strat_results['max_drawdown'] * 100, 2)}%"), ('Drawdown Start', strat_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), ('Drawdown End', strat_results['drawdown_end'].strftime(DATETIME_PRINT_FORMAT)), From 1a166f639d79d718984c9d6df19ce70d078cfeaa Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Feb 2021 19:44:13 +0100 Subject: [PATCH 126/158] Add test for calcuate_csum --- tests/data/test_btanalysis.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 96ac6f63c..3c4687745 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -8,11 +8,12 @@ from pandas import DataFrame, DateOffset, Timestamp, to_datetime from freqtrade.configuration import TimeRange from freqtrade.constants import LAST_BT_RESULT_FN from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_MID, BT_DATA_COLUMNS_OLD, - analyze_trade_parallelism, calculate_market_change, - calculate_max_drawdown, combine_dataframes_with_mean, - create_cum_profit, extract_trades_of_period, - get_latest_backtest_filename, get_latest_hyperopt_file, - load_backtest_data, load_trades, load_trades_from_db) + analyze_trade_parallelism, calculate_csum, + calculate_market_change, calculate_max_drawdown, + combine_dataframes_with_mean, create_cum_profit, + extract_trades_of_period, get_latest_backtest_filename, + get_latest_hyperopt_file, load_backtest_data, load_trades, + load_trades_from_db) from freqtrade.data.history import load_data, load_pair_history from tests.conftest import create_mock_trades from tests.conftest_trades import MOCK_TRADE_COUNT @@ -284,6 +285,20 @@ def test_calculate_max_drawdown(testdatadir): drawdown, h, low = calculate_max_drawdown(DataFrame()) +def test_calculate_csum(testdatadir): + filename = testdatadir / "backtest-result_test.json" + bt_data = load_backtest_data(filename) + csum_min, csum_max = calculate_csum(bt_data) + + assert isinstance(csum_min, float) + assert isinstance(csum_max, float) + assert csum_min < 0.01 + assert csum_max > 0.02 + + with pytest.raises(ValueError, match='Trade dataframe empty.'): + csum_min, csum_max = calculate_csum(DataFrame()) + + def test_calculate_max_drawdown2(): values = [0.011580, 0.010048, 0.011340, 0.012161, 0.010416, 0.010009, 0.020024, -0.024662, -0.022350, 0.020496, -0.029859, -0.030511, 0.010041, 0.010872, From 44cb2066889e5b62974c0b83f377d900e5f8daef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 05:27:01 +0000 Subject: [PATCH 127/158] Bump joblib from 1.0.0 to 1.0.1 Bumps [joblib](https://github.com/joblib/joblib) from 1.0.0 to 1.0.1. - [Release notes](https://github.com/joblib/joblib/releases) - [Changelog](https://github.com/joblib/joblib/blob/master/CHANGES.rst) - [Commits](https://github.com/joblib/joblib/compare/1.0.0...1.0.1) Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 104fbf454..535283b55 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -6,5 +6,5 @@ scipy==1.6.0 scikit-learn==0.24.1 scikit-optimize==0.8.1 filelock==3.0.12 -joblib==1.0.0 +joblib==1.0.1 progressbar2==3.53.1 From d08572ea0d7613c15bd6fc8e54c457d6e9672771 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 05:27:05 +0000 Subject: [PATCH 128/158] Bump pandas from 1.2.1 to 1.2.2 Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/pandas-dev/pandas/releases) - [Changelog](https://github.com/pandas-dev/pandas/blob/master/RELEASE.md) - [Commits](https://github.com/pandas-dev/pandas/compare/v1.2.1...v1.2.2) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5d03a9c2d..cce21ccc7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ numpy==1.20.1 -pandas==1.2.1 +pandas==1.2.2 ccxt==1.41.70 # Pin cryptography for now due to rust build errors with piwheels From dbef5425c591305f62b6fbfd319e4cae9e9322d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 05:27:12 +0000 Subject: [PATCH 129/158] Bump prompt-toolkit from 3.0.14 to 3.0.16 Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.14 to 3.0.16. - [Release notes](https://github.com/prompt-toolkit/python-prompt-toolkit/releases) - [Changelog](https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/CHANGELOG) - [Commits](https://github.com/prompt-toolkit/python-prompt-toolkit/compare/3.0.14...3.0.16) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5d03a9c2d..f9d224fcb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,4 +39,4 @@ aiofiles==0.6.0 colorama==0.4.4 # Building config files interactively questionary==1.9.0 -prompt-toolkit==3.0.14 +prompt-toolkit==3.0.16 From 5f2513934898c8b99bba7b010027e5f02e1a3bbf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 08:18:04 +0000 Subject: [PATCH 130/158] Bump ccxt from 1.41.70 to 1.41.90 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.41.70 to 1.41.90. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/doc/exchanges-by-country.rst) - [Commits](https://github.com/ccxt/ccxt/compare/1.41.70...1.41.90) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d0586b820..b84df9b2a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ numpy==1.20.1 pandas==1.2.2 -ccxt==1.41.70 +ccxt==1.41.90 # Pin cryptography for now due to rust build errors with piwheels cryptography==3.3.2 aiohttp==3.7.3 From bc188907b8760ff80906857939be8071258d9192 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 08:46:46 +0000 Subject: [PATCH 131/158] Bump cryptography from 3.3.2 to 3.4.5 Bumps [cryptography](https://github.com/pyca/cryptography) from 3.3.2 to 3.4.5. - [Release notes](https://github.com/pyca/cryptography/releases) - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/3.3.2...3.4.5) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b84df9b2a..48c5fd475 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ pandas==1.2.2 ccxt==1.41.90 # Pin cryptography for now due to rust build errors with piwheels -cryptography==3.3.2 +cryptography==3.4.5 aiohttp==3.7.3 SQLAlchemy==1.3.23 python-telegram-bot==13.2 From 3e06cd8b3a38231dc967ec7b3a7f6405995ad536 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Tue, 16 Feb 2021 10:11:33 +0100 Subject: [PATCH 132/158] pass data and config to loss function --- freqtrade/optimize/hyperopt.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index d0cdceaeb..83bdbad17 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -546,10 +546,11 @@ class Hyperopt: ) return self._get_results_dict(backtesting_results, min_date, max_date, - params_dict, params_details) + params_dict, params_details, + processed=processed) def _get_results_dict(self, backtesting_results, min_date, max_date, - params_dict, params_details): + params_dict, params_details, processed: Dict): results_metrics = self._calculate_results_metrics(backtesting_results) results_explanation = self._format_results_explanation_string(results_metrics) @@ -563,7 +564,8 @@ class Hyperopt: loss: float = MAX_LOSS if trade_count >= self.config['hyperopt_min_trades']: loss = self.calculate_loss(results=backtesting_results, trade_count=trade_count, - min_date=min_date.datetime, max_date=max_date.datetime) + min_date=min_date.datetime, max_date=max_date.datetime, + config=self.config, processed=processed) return { 'loss': loss, 'params_dict': params_dict, From 009a447d8a59f791b230537fa6e0d1f8a923245c Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 16 Feb 2021 19:51:09 +0100 Subject: [PATCH 133/158] Adjust documentation for new parameter in loss functions --- docs/advanced-hyperopt.md | 7 +++++++ freqtrade/optimize/hyperopt.py | 2 +- freqtrade/templates/sample_hyperopt_loss.py | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index bead18038..50d1946aa 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -40,6 +40,11 @@ For the sample below, you then need to add the command line parameter `--hyperop A sample of this can be found below, which is identical to the Default Hyperopt loss implementation. A full sample can be found in [userdata/hyperopts](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_loss.py). ``` python +from datetime import datetime +from typing import Dict + +from pandas import DataFrame + from freqtrade.optimize.hyperopt import IHyperOptLoss TARGET_TRADES = 600 @@ -54,6 +59,7 @@ class SuperDuperHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, + processed: Dict[str, DataFrame], *args, **kwargs) -> float: """ Objective function, returns smaller number for better results @@ -81,6 +87,7 @@ Currently, the arguments are: * `trade_count`: Amount of trades (identical to `len(results)`) * `min_date`: Start date of the timerange used * `min_date`: End date of the timerange used +* `processed`: Dict of Dataframes with the pair as keys containing the data used for backtesting. This function needs to return a floating point number (`float`). Smaller numbers will be interpreted as better results. The parameters and balancing for this is up to you. diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 83bdbad17..eee0f13b3 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -550,7 +550,7 @@ class Hyperopt: processed=processed) def _get_results_dict(self, backtesting_results, min_date, max_date, - params_dict, params_details, processed: Dict): + params_dict, params_details, processed: Dict[str, DataFrame]): results_metrics = self._calculate_results_metrics(backtesting_results) results_explanation = self._format_results_explanation_string(results_metrics) diff --git a/freqtrade/templates/sample_hyperopt_loss.py b/freqtrade/templates/sample_hyperopt_loss.py index a2b28f948..389c811f8 100644 --- a/freqtrade/templates/sample_hyperopt_loss.py +++ b/freqtrade/templates/sample_hyperopt_loss.py @@ -1,5 +1,6 @@ from datetime import datetime from math import exp +from typing import Dict from pandas import DataFrame @@ -35,6 +36,7 @@ class SampleHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, + processed: Dict[str, DataFrame], *args, **kwargs) -> float: """ Objective function, returns smaller number for better results From 11b20d693256d3d6a75c983bf52060d06614b714 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 17 Feb 2021 07:04:29 +0100 Subject: [PATCH 134/158] Add config to hyperopt_loss_function documentation --- docs/advanced-hyperopt.md | 3 ++- freqtrade/optimize/hyperopt_loss_interface.py | 5 ++++- freqtrade/templates/sample_hyperopt_loss.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index 50d1946aa..d2237b3e8 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -59,7 +59,7 @@ class SuperDuperHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, - processed: Dict[str, DataFrame], + config: Dict, processed: Dict[str, DataFrame], *args, **kwargs) -> float: """ Objective function, returns smaller number for better results @@ -87,6 +87,7 @@ Currently, the arguments are: * `trade_count`: Amount of trades (identical to `len(results)`) * `min_date`: Start date of the timerange used * `min_date`: End date of the timerange used +* `config`: Config object used (Note: Not all strategy-related parameters will be updated here if they are part of a hyperopt space). * `processed`: Dict of Dataframes with the pair as keys containing the data used for backtesting. This function needs to return a floating point number (`float`). Smaller numbers will be interpreted as better results. The parameters and balancing for this is up to you. diff --git a/freqtrade/optimize/hyperopt_loss_interface.py b/freqtrade/optimize/hyperopt_loss_interface.py index 48407a8a8..b5aa588b2 100644 --- a/freqtrade/optimize/hyperopt_loss_interface.py +++ b/freqtrade/optimize/hyperopt_loss_interface.py @@ -5,6 +5,7 @@ This module defines the interface for the loss-function for hyperopt from abc import ABC, abstractmethod from datetime import datetime +from typing import Dict from pandas import DataFrame @@ -19,7 +20,9 @@ class IHyperOptLoss(ABC): @staticmethod @abstractmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, - min_date: datetime, max_date: datetime, *args, **kwargs) -> float: + min_date: datetime, max_date: datetime, + config: Dict, processed: Dict[str, DataFrame], + *args, **kwargs) -> float: """ Objective function, returns smaller number for better results """ diff --git a/freqtrade/templates/sample_hyperopt_loss.py b/freqtrade/templates/sample_hyperopt_loss.py index 389c811f8..343349508 100644 --- a/freqtrade/templates/sample_hyperopt_loss.py +++ b/freqtrade/templates/sample_hyperopt_loss.py @@ -36,7 +36,7 @@ class SampleHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, - processed: Dict[str, DataFrame], + config: Dict, processed: Dict[str, DataFrame], *args, **kwargs) -> float: """ Objective function, returns smaller number for better results From fedbb5c0c47d9a0b1098869f4d516e7a63378d10 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 17 Feb 2021 20:46:58 +0100 Subject: [PATCH 135/158] Remove last flask occurance from setup.py fixes #4390 --- setup.py | 2 +- tests/rpc/test_rpc_apiserver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 030980c96..148803cd6 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ if readme_file.is_file(): readme_long = (Path(__file__).parent / "README.md").read_text() # Requirements used for submodules -api = ['flask', 'flask-jwt-extended', 'flask-cors'] +api = ['fastapi', 'uvicorn', 'pyjwt', 'aiofiles'] plot = ['plotly>=4.0'] hyperopt = [ 'scipy', diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 263950d83..3cc0d0137 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -295,7 +295,7 @@ def test_api_run(default_conf, mocker, caplog): "Please make sure that this is intentional!", caplog) assert log_has_re("SECURITY WARNING - `jwt_secret_key` seems to be default.*", caplog) - # Test crashing flask + # Test crashing API server caplog.clear() mocker.patch('freqtrade.rpc.api_server.webserver.UvicornServer', MagicMock(side_effect=Exception)) From 87dc1d39551c3b267db0cc524f8a00a0c58ab86f Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 17 Feb 2021 20:52:25 +0100 Subject: [PATCH 136/158] Explicitly push tag and tag_plot images --- build_helpers/publish_docker.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build_helpers/publish_docker.sh b/build_helpers/publish_docker.sh index 9bc1aa0a6..d987bcc69 100755 --- a/build_helpers/publish_docker.sh +++ b/build_helpers/publish_docker.sh @@ -51,6 +51,8 @@ fi docker images docker push ${IMAGE_NAME} +docker push ${IMAGE_NAME}:$TAG_PLOT +docker push ${IMAGE_NAME}:$TAG if [ $? -ne 0 ]; then echo "failed pushing repo" return 1 From b5a9ce28944a3c01e2693ff03a27416fc22cd11c Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 18 Feb 2021 09:26:35 +0100 Subject: [PATCH 137/158] Download data in the right format as well ... closes #4393 --- freqtrade/edge/edge_positioning.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index 2bdef1c89..ff86e522e 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -104,6 +104,7 @@ class Edge: exchange=self.exchange, timeframe=self.strategy.timeframe, timerange=self._timerange, + data_format=self.config.get('dataformat_ohlcv', 'json'), ) data = load_data( From 327c23618f80c195048995b359d93965f8ccd208 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 18 Feb 2021 09:30:35 +0100 Subject: [PATCH 138/158] Improve documentation for get_analyzed_dataframe --- docs/strategy-customization.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 7e998570f..4eb76a617 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -444,14 +444,19 @@ It can also be used in specific callbacks to get the signal that caused the acti ``` python # fetch current dataframe if self.dp: - dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=metadata['pair'], - timeframe=self.timeframe) + if self.dp.runmode.value in ('live', 'dry_run'): + dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=metadata['pair'], + timeframe=self.timeframe) ``` !!! Note "No data available" Returns an empty dataframe if the requested pair was not cached. This should not happen when using whitelisted pairs. + +!!! Warning "Warning about backtesting" + This method will return an empty dataframe during backtesting. + ### *orderbook(pair, maximum)* ``` python @@ -462,8 +467,8 @@ if self.dp: dataframe['best_ask'] = ob['asks'][0][0] ``` -!!! Warning - The order book is not part of the historic data which means backtesting and hyperopt will not work correctly if this method is used. +!!! Warning "Warning about backtesting" + The order book is not part of the historic data which means backtesting and hyperopt will not work correctly if this method is used, as the method will return uptodate values. ### *ticker(pair)* From 2b0d2070d0b1b7428ec12f433abe1d213e1a884d Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 18 Feb 2021 12:49:14 +0100 Subject: [PATCH 139/158] Avoid crash with /delete When a trade is deleted between querying the database and actually handling the trade. closes #4326 --- freqtrade/freqtradebot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 73707e4ec..d546dd6d2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -179,6 +179,7 @@ class FreqtradeBot(LoggingMixin): # Without this, freqtrade my try to recreate stoploss_on_exchange orders # while selling is in process, since telegram messages arrive in an different thread. with self._sell_lock: + trades = Trade.get_open_trades() # First process current opened trades (positions) self.exit_positions(trades) From c9688f1c8912f16c1a737baad8479f7c3aa3743e Mon Sep 17 00:00:00 2001 From: JoeSchr Date: Thu, 18 Feb 2021 17:30:29 +0100 Subject: [PATCH 140/158] fix(doc/plotting): misplaced comma in example code --- docs/plotting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plotting.md b/docs/plotting.md index 19ddb4f57..d7ed5ab1f 100644 --- a/docs/plotting.md +++ b/docs/plotting.md @@ -188,7 +188,7 @@ Sample configuration with inline comments explaining the process: 'senkou_a': { 'color': 'green', #optional 'fill_to': 'senkou_b', - 'fill_label': 'Ichimoku Cloud' #optional, + 'fill_label': 'Ichimoku Cloud', #optional 'fill_color': 'rgba(255,76,46,0.2)', #optional }, # plot senkou_b, too. Not only the area to it. From 245e39e523d8239ffbdf881e49290967592cf6e6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 20 Feb 2021 19:17:10 +0100 Subject: [PATCH 141/158] dry-run should be a bool, not a string --- freqtrade/rpc/api_server/api_schemas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 4faefb5fc..050540cc6 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -113,7 +113,7 @@ class Daily(BaseModel): class ShowConfig(BaseModel): - dry_run: str + dry_run: bool stake_currency: str stake_amount: Union[float, str] max_open_trades: int From 3629892fc35fec3b6daaa2938371d4c1614cbe32 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 20 Feb 2021 19:37:38 +0100 Subject: [PATCH 142/158] Stoploss-guard should use the trade_limit or more fix #4404 --- docs/includes/protections.md | 4 +++- freqtrade/plugins/protections/stoploss_guard.py | 12 ++++++------ tests/plugins/test_protections.py | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/includes/protections.md b/docs/includes/protections.md index de34383ac..6bc57153e 100644 --- a/docs/includes/protections.md +++ b/docs/includes/protections.md @@ -40,7 +40,9 @@ All protection end times are rounded up to the next candle to avoid sudden, unex #### Stoploss Guard -`StoplossGuard` selects all trades within `lookback_period` in minutes (or in candles when using `lookback_period_candles`), and determines if the amount of trades that resulted in stoploss are above `trade_limit` - in which case trading will stop for `stop_duration` in minutes (or in candles when using `stop_duration_candles`). +`StoplossGuard` selects all trades within `lookback_period` in minutes (or in candles when using `lookback_period_candles`). +If `trade_limit` or more trades resulted in stoploss, trading will stop for `stop_duration` in minutes (or in candles when using `stop_duration_candles`). + This applies across all pairs, unless `only_per_pair` is set to true, which will then only look at one pair at a time. The below example stops trading for all pairs for 4 candles after the last trade if the bot hit stoploss 4 times within the last 24 candles. diff --git a/freqtrade/plugins/protections/stoploss_guard.py b/freqtrade/plugins/protections/stoploss_guard.py index 92fae54cb..5a9b9ddd0 100644 --- a/freqtrade/plugins/protections/stoploss_guard.py +++ b/freqtrade/plugins/protections/stoploss_guard.py @@ -58,13 +58,13 @@ class StoplossGuard(IProtection): SellType.STOPLOSS_ON_EXCHANGE.value) and trade.close_profit < 0)] - if len(trades) > self._trade_limit: - self.log_once(f"Trading stopped due to {self._trade_limit} " - f"stoplosses within {self._lookback_period} minutes.", logger.info) - until = self.calculate_lock_end(trades, self._stop_duration) - return True, until, self._reason() + if len(trades) < self._trade_limit: + return False, None, None - return False, None, None + self.log_once(f"Trading stopped due to {self._trade_limit} " + f"stoplosses within {self._lookback_period} minutes.", logger.info) + until = self.calculate_lock_end(trades, self._stop_duration) + return True, until, self._reason() def global_stop(self, date_now: datetime) -> ProtectionReturn: """ diff --git a/tests/plugins/test_protections.py b/tests/plugins/test_protections.py index e36900a96..2e42c1be4 100644 --- a/tests/plugins/test_protections.py +++ b/tests/plugins/test_protections.py @@ -83,7 +83,7 @@ def test_stoploss_guard(mocker, default_conf, fee, caplog): "method": "StoplossGuard", "lookback_period": 60, "stop_duration": 40, - "trade_limit": 2 + "trade_limit": 3 }] freqtrade = get_patched_freqtradebot(mocker, default_conf) message = r"Trading stopped due to .*" @@ -136,7 +136,7 @@ def test_stoploss_guard_perpair(mocker, default_conf, fee, caplog, only_per_pair default_conf['protections'] = [{ "method": "StoplossGuard", "lookback_period": 60, - "trade_limit": 1, + "trade_limit": 2, "stop_duration": 60, "only_per_pair": only_per_pair }] From 188d7aaf8c8da10e67ecaf0b8a61d907339a6597 Mon Sep 17 00:00:00 2001 From: Alberto del Barrio Date: Sun, 21 Feb 2021 18:50:11 +0100 Subject: [PATCH 143/158] Fix example in storing-information docs --- docs/strategy-customization.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 4eb76a617..fdc95a3c1 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -315,11 +315,11 @@ class AwesomeStrategy(IStrategy): def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Check if the entry already exists - if not metadata["pair"] in self._cust_info: + if not metadata["pair"] in self.cust_info: # Create empty entry for this pair - self._cust_info[metadata["pair"]] = {} + self.cust_info[metadata["pair"]] = {} - if "crosstime" in self.cust_info[metadata["pair"]: + if "crosstime" in self.cust_info[metadata["pair"]]: self.cust_info[metadata["pair"]]["crosstime"] += 1 else: self.cust_info[metadata["pair"]]["crosstime"] = 1 From ab74c6e77154a588c76e6628a6f39318c19c0b15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 05:27:41 +0000 Subject: [PATCH 144/158] Bump tabulate from 0.8.7 to 0.8.8 Bumps [tabulate](https://github.com/astanin/python-tabulate) from 0.8.7 to 0.8.8. - [Release notes](https://github.com/astanin/python-tabulate/releases) - [Changelog](https://github.com/astanin/python-tabulate/blob/master/CHANGELOG) - [Commits](https://github.com/astanin/python-tabulate/compare/v0.8.7...v0.8.8) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 48c5fd475..1033c42d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ urllib3==1.26.3 wrapt==1.12.1 jsonschema==3.2.0 TA-Lib==0.4.19 -tabulate==0.8.7 +tabulate==0.8.8 pycoingecko==1.4.0 jinja2==2.11.3 tables==3.6.1 From 8c398acc098b8bd9f15666e18ad9b9cd6811071f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 05:27:42 +0000 Subject: [PATCH 145/158] Bump python-telegram-bot from 13.2 to 13.3 Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 13.2 to 13.3. - [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases) - [Changelog](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/CHANGES.rst) - [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v13.2...v13.3) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 48c5fd475..8387be19c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ ccxt==1.41.90 cryptography==3.4.5 aiohttp==3.7.3 SQLAlchemy==1.3.23 -python-telegram-bot==13.2 +python-telegram-bot==13.3 arrow==0.17.0 cachetools==4.2.1 requests==2.25.1 From 932aabd0121bd95f6ac28e7a016faf0ca324f498 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 05:27:51 +0000 Subject: [PATCH 146/158] Bump uvicorn from 0.13.3 to 0.13.4 Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.13.3 to 0.13.4. - [Release notes](https://github.com/encode/uvicorn/releases) - [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md) - [Commits](https://github.com/encode/uvicorn/compare/0.13.3...0.13.4) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 48c5fd475..de39a219e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -31,7 +31,7 @@ sdnotify==0.3.2 # API Server fastapi==0.63.0 -uvicorn==0.13.3 +uvicorn==0.13.4 pyjwt==2.0.1 aiofiles==0.6.0 From dea04c64521fd3f36f58ae6b603485714b1b62d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 05:27:54 +0000 Subject: [PATCH 147/158] Bump scipy from 1.6.0 to 1.6.1 Bumps [scipy](https://github.com/scipy/scipy) from 1.6.0 to 1.6.1. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.6.0...v1.6.1) Signed-off-by: dependabot[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 535283b55..8e87a434c 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -2,7 +2,7 @@ -r requirements.txt # Required for hyperopt -scipy==1.6.0 +scipy==1.6.1 scikit-learn==0.24.1 scikit-optimize==0.8.1 filelock==3.0.12 From 85f12f8c284b2230606a11c7aa9f23e8eefc85bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 05:27:57 +0000 Subject: [PATCH 148/158] Bump cryptography from 3.4.5 to 3.4.6 Bumps [cryptography](https://github.com/pyca/cryptography) from 3.4.5 to 3.4.6. - [Release notes](https://github.com/pyca/cryptography/releases) - [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pyca/cryptography/compare/3.4.5...3.4.6) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 48c5fd475..a7b5eaf7b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ pandas==1.2.2 ccxt==1.41.90 # Pin cryptography for now due to rust build errors with piwheels -cryptography==3.4.5 +cryptography==3.4.6 aiohttp==3.7.3 SQLAlchemy==1.3.23 python-telegram-bot==13.2 From d8c7e5ce8d8c3e777e0d816b8894d5cb1067ffef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 05:56:25 +0000 Subject: [PATCH 149/158] Bump python from 3.9.1-slim-buster to 3.9.2-slim-buster Bumps python from 3.9.1-slim-buster to 3.9.2-slim-buster. Signed-off-by: dependabot[bot] --- Dockerfile | 2 +- Dockerfile.armhf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8d4f0ebe6..4b399174b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.9.1-slim-buster as base +FROM python:3.9.2-slim-buster as base # Setup env ENV LANG C.UTF-8 diff --git a/Dockerfile.armhf b/Dockerfile.armhf index f938ec457..f46212332 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM --platform=linux/arm/v7 python:3.7.9-slim-buster as base +FROM --platform=linux/arm/v7 python:3.9.2-slim-buster as base # Setup env ENV LANG C.UTF-8 From 8a62bfa0e5fc49cd3c9b1b49436c03d9ffbc0abe Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 22 Feb 2021 08:20:45 +0100 Subject: [PATCH 150/158] armhf image should not be updated to python3.9 --- Dockerfile.armhf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.armhf b/Dockerfile.armhf index f46212332..f938ec457 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM --platform=linux/arm/v7 python:3.9.2-slim-buster as base +FROM --platform=linux/arm/v7 python:3.7.9-slim-buster as base # Setup env ENV LANG C.UTF-8 From 5e4730b73b2f0b7a2ba51a7ab79bea962e973ec4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 22 Feb 2021 11:44:39 +0100 Subject: [PATCH 151/158] Add test confirming #4405 --- tests/rpc/test_rpc_apiserver.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 3cc0d0137..c4fcf61ea 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -14,6 +14,7 @@ from fastapi.testclient import TestClient from requests.auth import _basic_auth_str from freqtrade.__init__ import __version__ +from freqtrade.exceptions import ExchangeError from freqtrade.loggers import setup_logging, setup_logging_pre from freqtrade.persistence import PairLocks, Trade from freqtrade.rpc import RPC @@ -789,6 +790,15 @@ def test_api_status(botclient, mocker, ticker, fee, markets): 'exchange': 'bittrex', }] + mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate', + MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available"))) + + rc = client_get(client, f"{BASE_URI}/status") + assert_response(rc) + resp_values = rc.json() + assert len(resp_values) == 1 + assert resp_values[0]['profit_abs'] is None + def test_api_version(botclient): ftbot, client = botclient From 228e51b60b6a049e7ff2f447c5dd6630c3531fec Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 22 Feb 2021 12:11:27 +0100 Subject: [PATCH 152/158] Fix #4405 --- freqtrade/rpc/api_server/webserver.py | 13 +++++++++++++ tests/rpc/test_rpc_apiserver.py | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index f3eaa1ebc..8a5c958e9 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -2,6 +2,7 @@ import logging from ipaddress import IPv4Address from typing import Any, Dict +import rapidjson import uvicorn from fastapi import Depends, FastAPI from fastapi.middleware.cors import CORSMiddleware @@ -14,6 +15,17 @@ from freqtrade.rpc.rpc import RPC, RPCException, RPCHandler logger = logging.getLogger(__name__) +class FTJSONResponse(JSONResponse): + media_type = "application/json" + + def render(self, content: Any) -> bytes: + """ + Use rapidjson for responses + Handles NaN and Inf / -Inf in a javascript way by default. + """ + return rapidjson.dumps(content).encode("utf-8") + + class ApiServer(RPCHandler): _rpc: RPC @@ -32,6 +44,7 @@ class ApiServer(RPCHandler): self.app = FastAPI(title="Freqtrade API", docs_url='/docs' if api_config.get('enable_openapi', False) else None, redoc_url=None, + default_response_class=FTJSONResponse, ) self.configure_app(self.app, self._config) diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index c4fcf61ea..d7d69d0ae 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -11,6 +11,7 @@ import uvicorn from fastapi import FastAPI from fastapi.exceptions import HTTPException from fastapi.testclient import TestClient +from numpy import isnan from requests.auth import _basic_auth_str from freqtrade.__init__ import __version__ @@ -797,7 +798,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets): assert_response(rc) resp_values = rc.json() assert len(resp_values) == 1 - assert resp_values[0]['profit_abs'] is None + assert isnan(resp_values[0]['profit_abs']) def test_api_version(botclient): From c71ecd3680bdd35c5cb785f43e6f3f10ba823c66 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 22 Feb 2021 20:04:36 +0100 Subject: [PATCH 153/158] Fix wrong pair-content in strategy-analysis notebook and documentation closes #4399 --- docs/strategy_analysis_example.md | 6 ++++-- freqtrade/templates/strategy_analysis_example.ipynb | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index 90e39fd76..5c479aa0b 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -24,7 +24,7 @@ config["strategy"] = "SampleStrategy" # Location of the data data_location = Path(config['user_data_dir'], 'data', 'binance') # Pair to analyze - Only use one pair here -pair = "BTC_USDT" +pair = "BTC/USDT" ``` @@ -34,7 +34,9 @@ from freqtrade.data.history import load_pair_history candles = load_pair_history(datadir=data_location, timeframe=config["timeframe"], - pair=pair) + pair=pair, + data_format = "hdf5", + ) # Confirm success print("Loaded " + str(len(candles)) + f" rows of data for {pair} from {data_location}") diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index c6e64c74e..491afbdd7 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -40,7 +40,7 @@ "# Location of the data\n", "data_location = Path(config['user_data_dir'], 'data', 'binance')\n", "# Pair to analyze - Only use one pair here\n", - "pair = \"BTC_USDT\"" + "pair = \"BTC/USDT\"" ] }, { @@ -54,7 +54,9 @@ "\n", "candles = load_pair_history(datadir=data_location,\n", " timeframe=config[\"timeframe\"],\n", - " pair=pair)\n", + " pair=pair,\n", + " data_format = \"hdf5\",\n", + " )\n", "\n", "# Confirm success\n", "print(\"Loaded \" + str(len(candles)) + f\" rows of data for {pair} from {data_location}\")\n", From a0fa1e84fc95fca3c76576a1ae01a65d2f6da58e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 19:06:36 +0000 Subject: [PATCH 154/158] Bump ccxt from 1.41.90 to 1.42.19 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.41.90 to 1.42.19. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/doc/exchanges-by-country.rst) - [Commits](https://github.com/ccxt/ccxt/compare/1.41.90...1.42.19) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2144fb59c..8a28865c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ numpy==1.20.1 pandas==1.2.2 -ccxt==1.41.90 +ccxt==1.42.19 # Pin cryptography for now due to rust build errors with piwheels cryptography==3.4.6 aiohttp==3.7.3 From 3612c786b5929388a8fac8b5da79b5476717be5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Feb 2021 19:06:39 +0000 Subject: [PATCH 155/158] Bump tabulate from 0.8.8 to 0.8.9 Bumps [tabulate](https://github.com/astanin/python-tabulate) from 0.8.8 to 0.8.9. - [Release notes](https://github.com/astanin/python-tabulate/releases) - [Changelog](https://github.com/astanin/python-tabulate/blob/master/CHANGELOG) - [Commits](https://github.com/astanin/python-tabulate/compare/v0.8.8...v0.8.9) Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2144fb59c..39774e563 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ urllib3==1.26.3 wrapt==1.12.1 jsonschema==3.2.0 TA-Lib==0.4.19 -tabulate==0.8.8 +tabulate==0.8.9 pycoingecko==1.4.0 jinja2==2.11.3 tables==3.6.1 From d6d8678fd627c6a119c21d994c86ed7e17ff59b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 24 Feb 2021 06:34:10 +0100 Subject: [PATCH 156/158] Fix missleading FAQ information --- docs/faq.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 8a0c61b29..87b0893bd 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -38,12 +38,11 @@ you can't say much from few trades. ### I’d like to make changes to the config. Can I do that without having to kill the bot? -Yes. You can edit your config, use the `/stop` command in Telegram, followed by `/reload_config` and the bot will run with the new config. +Yes. You can edit your config and use the `/reload_config` command to reload the configuration. The bot will stop, reload the configuration and strategy and will restart with the new configuration and strategy. ### I want to improve the bot with a new strategy -That's great. We have a nice backtesting and hyperoptimization setup. See -the tutorial [here|Testing-new-strategies-with-Hyperopt](bot-usage.md#hyperopt-commands). +That's great. We have a nice backtesting and hyperoptimization setup. See the tutorial [here|Testing-new-strategies-with-Hyperopt](bot-usage.md#hyperopt-commands). ### Is there a setting to only SELL the coins being held and not perform anymore BUYS? From aea8f05d10946ca488a2f1ec2564e92d0922feff Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 24 Feb 2021 06:39:59 +0100 Subject: [PATCH 157/158] Version bump 2021.2 --- freqtrade/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index 74c8c412c..2205d284d 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,5 +1,5 @@ """ Freqtrade bot """ -__version__ = '2021.1' +__version__ = '2021.2' if __version__ == 'develop': From 834f00f5803431270f736d3a098eb9c5623cfbe8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 24 Feb 2021 06:46:07 +0100 Subject: [PATCH 158/158] Refresh slack link --- CONTRIBUTING.md | 2 +- README.md | 4 ++-- docs/developer.md | 2 +- docs/faq.md | 2 +- docs/index.md | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index afa41ed33..c29d6e632 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ Few pointers for contributions: - New features need to contain unit tests, must conform to PEP8 (max-line-length = 100) and should be documented with the introduction PR. - PR's can be declared as `[WIP]` - which signify Work in Progress Pull Requests (which are not finished). -If you are unsure, discuss the feature on our [discord server](https://discord.gg/MA9v74M), on [Slack](https://join.slack.com/t/highfrequencybot/shared_invite/zt-l9d9iqgl-9cVBIeBkCBa8j6upSmd_NA) or in a [issue](https://github.com/freqtrade/freqtrade/issues) before a PR. +If you are unsure, discuss the feature on our [discord server](https://discord.gg/MA9v74M), on [Slack](https://join.slack.com/t/highfrequencybot/shared_invite/zt-mm786y93-Fxo37glxMY9g8OQC5AoOIw) or in a [issue](https://github.com/freqtrade/freqtrade/issues) before a PR. ## Getting started diff --git a/README.md b/README.md index 7ef0d4ce7..c3a665c47 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ For any questions not covered by the documentation or for further information ab Please check out our [discord server](https://discord.gg/MA9v74M). -You can also join our [Slack channel](https://join.slack.com/t/highfrequencybot/shared_invite/zt-l9d9iqgl-9cVBIeBkCBa8j6upSmd_NA). +You can also join our [Slack channel](https://join.slack.com/t/highfrequencybot/shared_invite/zt-mm786y93-Fxo37glxMY9g8OQC5AoOIw). ### [Bugs / Issues](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue) @@ -178,7 +178,7 @@ to understand the requirements before sending your pull-requests. Coding is not a necessity to contribute - maybe start with improving our documentation? Issues labeled [good first issue](https://github.com/freqtrade/freqtrade/labels/good%20first%20issue) can be good first contributions, and will help get you familiar with the codebase. -**Note** before starting any major new feature work, *please open an issue describing what you are planning to do* or talk to us on [discord](https://discord.gg/MA9v74M) or [Slack](https://join.slack.com/t/highfrequencybot/shared_invite/zt-k9o2v5ut-jX8Mc4CwNM8CDc2Dyg96YA). This will ensure that interested parties can give valuable feedback on the feature, and let others know that you are working on it. +**Note** before starting any major new feature work, *please open an issue describing what you are planning to do* or talk to us on [discord](https://discord.gg/MA9v74M) or [Slack](https://join.slack.com/t/highfrequencybot/shared_invite/zt-mm786y93-Fxo37glxMY9g8OQC5AoOIw). This will ensure that interested parties can give valuable feedback on the feature, and let others know that you are working on it. **Important:** Always create your PR against the `develop` branch, not `stable`. diff --git a/docs/developer.md b/docs/developer.md index c09e528bf..4b8c64530 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -2,7 +2,7 @@ This page is intended for developers of Freqtrade, people who want to contribute to the Freqtrade codebase or documentation, or people who want to understand the source code of the application they're running. -All contributions, bug reports, bug fixes, documentation improvements, enhancements and ideas are welcome. We [track issues](https://github.com/freqtrade/freqtrade/issues) on [GitHub](https://github.com) and also have a dev channel on [discord](https://discord.gg/MA9v74M) or [slack](https://join.slack.com/t/highfrequencybot/shared_invite/zt-l9d9iqgl-9cVBIeBkCBa8j6upSmd_NA) where you can ask questions. +All contributions, bug reports, bug fixes, documentation improvements, enhancements and ideas are welcome. We [track issues](https://github.com/freqtrade/freqtrade/issues) on [GitHub](https://github.com) and also have a dev channel on [discord](https://discord.gg/MA9v74M) or [slack](https://join.slack.com/t/highfrequencybot/shared_invite/zt-mm786y93-Fxo37glxMY9g8OQC5AoOIw) where you can ask questions. ## Documentation diff --git a/docs/faq.md b/docs/faq.md index 87b0893bd..93b806dca 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -142,7 +142,7 @@ freqtrade hyperopt --hyperopt SampleHyperopt --hyperopt-loss SharpeHyperOptLossD ### Why does it take a long time to run hyperopt? -* Discovering a great strategy with Hyperopt takes time. Study www.freqtrade.io, the Freqtrade Documentation page, join the Freqtrade [Slack community](https://join.slack.com/t/highfrequencybot/shared_invite/zt-l9d9iqgl-9cVBIeBkCBa8j6upSmd_NA) - or the Freqtrade [discord community](https://discord.gg/X89cVG). While you patiently wait for the most advanced, free crypto bot in the world, to hand you a possible golden strategy specially designed just for you. +* Discovering a great strategy with Hyperopt takes time. Study www.freqtrade.io, the Freqtrade Documentation page, join the Freqtrade [Slack community](https://join.slack.com/t/highfrequencybot/shared_invite/zt-mm786y93-Fxo37glxMY9g8OQC5AoOIw) - or the Freqtrade [discord community](https://discord.gg/X89cVG). While you patiently wait for the most advanced, free crypto bot in the world, to hand you a possible golden strategy specially designed just for you. * If you wonder why it can take from 20 minutes to days to do 1000 epochs here are some answers: diff --git a/docs/index.md b/docs/index.md index db5088707..9d1a1532e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -81,7 +81,7 @@ For any questions not covered by the documentation or for further information ab Please check out our [discord server](https://discord.gg/MA9v74M). -You can also join our [Slack channel](https://join.slack.com/t/highfrequencybot/shared_invite/zt-l9d9iqgl-9cVBIeBkCBa8j6upSmd_NA). +You can also join our [Slack channel](https://join.slack.com/t/highfrequencybot/shared_invite/zt-mm786y93-Fxo37glxMY9g8OQC5AoOIw). ## Ready to try?