From 54bde6ac11a183be414a8faa37e588eafa269aaf Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 16:34:23 +0100 Subject: [PATCH 001/285] verify date on new candle before producing signal --- freqtrade/freqtradebot.py | 9 ++++++--- freqtrade/strategy/interface.py | 9 +++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 914b8d9cd..02d8b5b56 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -390,14 +390,17 @@ class FreqtradeBot: """ logger.debug(f"create_trade for pair {pair}") + dataframe = self.dataprovider.ohlcv(pair, self.strategy.ticker_interval) + latest = dataframe.iloc[-1] + # Check if dataframe is out of date + signal_date = arrow.get(latest['date']) + if self.strategy.is_pair_locked(pair): logger.info(f"Pair {pair} is currently locked.") return False # running get_signal on historical data fetched - (buy, sell) = self.strategy.get_signal( - pair, self.strategy.ticker_interval, - self.dataprovider.ohlcv(pair, self.strategy.ticker_interval)) + (buy, sell) = self.strategy.get_signal(pair, self.strategy.ticker_interval, dataframe) if buy and not sell: if not self.get_free_open_trades(): diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index d23af3f6e..765e23b0b 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -277,15 +277,20 @@ class IStrategy(ABC): latest = dataframe.iloc[-1] - # Check if dataframe is out of date + # Check if dataframe has new candle signal_date = arrow.get(latest['date']) interval_minutes = timeframe_to_minutes(interval) + if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: + logger.warning('Old candle for pair %s. Last tick is %s minutes old', + pair, (arrow.utcnow() - signal_date).total_seconds() // 60) + + # Check if dataframe is out of date offset = self.config.get('exchange', {}).get('outdated_offset', 5) if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): logger.warning( 'Outdated history for pair %s. Last tick is %s minutes old', pair, - (arrow.utcnow() - signal_date).seconds // 60 + (arrow.utcnow() - signal_date).total_seconds() // 60 ) return False, False From 4e45abbf139a08c79b2c1adee12cffbceda259c9 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 16:44:45 +0100 Subject: [PATCH 002/285] added return false, false --- freqtrade/strategy/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 765e23b0b..a26e8edbd 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -283,6 +283,7 @@ class IStrategy(ABC): if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: logger.warning('Old candle for pair %s. Last tick is %s minutes old', pair, (arrow.utcnow() - signal_date).total_seconds() // 60) + return False, False # Check if dataframe is out of date offset = self.config.get('exchange', {}).get('outdated_offset', 5) From d239e999043fe50b01b1e2a79b074bb3c9de707a Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 16:49:37 +0100 Subject: [PATCH 003/285] removed old code from create_trade --- freqtrade/freqtradebot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 02d8b5b56..90f2c0c02 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -393,7 +393,6 @@ class FreqtradeBot: dataframe = self.dataprovider.ohlcv(pair, self.strategy.ticker_interval) latest = dataframe.iloc[-1] # Check if dataframe is out of date - signal_date = arrow.get(latest['date']) if self.strategy.is_pair_locked(pair): logger.info(f"Pair {pair} is currently locked.") From a85d17327bebfc7432a968464ac9b15f587f2813 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 16:54:27 +0100 Subject: [PATCH 004/285] fix --- freqtrade/freqtradebot.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 90f2c0c02..fd4daf7aa 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -390,15 +390,13 @@ class FreqtradeBot: """ logger.debug(f"create_trade for pair {pair}") - dataframe = self.dataprovider.ohlcv(pair, self.strategy.ticker_interval) - latest = dataframe.iloc[-1] # Check if dataframe is out of date - if self.strategy.is_pair_locked(pair): logger.info(f"Pair {pair} is currently locked.") return False # running get_signal on historical data fetched + dataframe = self.dataprovider.ohlcv(pair, self.strategy.ticker_interval) (buy, sell) = self.strategy.get_signal(pair, self.strategy.ticker_interval, dataframe) if buy and not sell: From a82cdf0add7f0fca9f0a3a4d32b5510aa4b5b461 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:04:51 +0100 Subject: [PATCH 005/285] fixed test --- 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 a26e8edbd..47bdf781d 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -282,7 +282,7 @@ class IStrategy(ABC): interval_minutes = timeframe_to_minutes(interval) if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: logger.warning('Old candle for pair %s. Last tick is %s minutes old', - pair, (arrow.utcnow() - signal_date).total_seconds() // 60) + pair, int(arrow.utcnow() - signal_date).total_seconds() // 60) return False, False # Check if dataframe is out of date @@ -291,7 +291,7 @@ class IStrategy(ABC): logger.warning( 'Outdated history for pair %s. Last tick is %s minutes old', pair, - (arrow.utcnow() - signal_date).total_seconds() // 60 + int((arrow.utcnow() - signal_date).total_seconds() // 60) ) return False, False From d667acb3081132adc7207c4dad396e184ebec544 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:10:57 +0100 Subject: [PATCH 006/285] fixed typo --- freqtrade/strategy/interface.py | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 47bdf781d..781bd7a54 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -282,11 +282,11 @@ class IStrategy(ABC): interval_minutes = timeframe_to_minutes(interval) if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: logger.warning('Old candle for pair %s. Last tick is %s minutes old', - pair, int(arrow.utcnow() - signal_date).total_seconds() // 60) + pair, int((arrow.utcnow() - signal_date).total_seconds() // 60) return False, False # Check if dataframe is out of date - offset = self.config.get('exchange', {}).get('outdated_offset', 5) + offset=self.config.get('exchange', {}).get('outdated_offset', 5) if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): logger.warning( 'Outdated history for pair %s. Last tick is %s minutes old', @@ -295,7 +295,7 @@ class IStrategy(ABC): ) return False, False - (buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1 + (buy, sell)=latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1 logger.debug( 'trigger: %s (pair=%s) buy=%s sell=%s', latest['date'], @@ -306,8 +306,8 @@ class IStrategy(ABC): return buy, sell def should_sell(self, trade: Trade, rate: float, date: datetime, buy: bool, - sell: bool, low: float = None, high: float = None, - force_stoploss: float = 0) -> SellCheckTuple: + sell: bool, low: float=None, high: float=None, + force_stoploss: float=0) -> SellCheckTuple: """ This function evaluates if one of the conditions required to trigger a sell has been reached, which can either be a stop-loss, ROI or sell-signal. @@ -317,12 +317,12 @@ class IStrategy(ABC): :return: True if trade should be sold, False otherwise """ # Set current rate to low for backtesting sell - current_rate = low or rate - current_profit = trade.calc_profit_ratio(current_rate) + current_rate=low or rate + current_profit=trade.calc_profit_ratio(current_rate) trade.adjust_min_max_rates(high or current_rate) - stoplossflag = self.stop_loss_reached(current_rate=current_rate, trade=trade, + stoplossflag=self.stop_loss_reached(current_rate=current_rate, trade=trade, current_time=date, current_profit=current_profit, force_stoploss=force_stoploss, high=high) @@ -332,9 +332,9 @@ class IStrategy(ABC): return stoplossflag # Set current rate to high for backtesting sell - current_rate = high or rate - current_profit = trade.calc_profit_ratio(current_rate) - config_ask_strategy = self.config.get('ask_strategy', {}) + current_rate=high or rate + current_profit=trade.calc_profit_ratio(current_rate) + config_ask_strategy=self.config.get('ask_strategy', {}) if buy and config_ask_strategy.get('ignore_roi_if_buy_signal', False): # This one is noisy, commented out @@ -366,29 +366,29 @@ class IStrategy(ABC): def stop_loss_reached(self, current_rate: float, trade: Trade, current_time: datetime, current_profit: float, - force_stoploss: float, high: float = None) -> SellCheckTuple: + force_stoploss: float, high: float=None) -> SellCheckTuple: """ Based on current profit of the trade and configured (trailing) stoploss, decides to sell or not :param current_profit: current profit as ratio """ - stop_loss_value = force_stoploss if force_stoploss else self.stoploss + stop_loss_value=force_stoploss if force_stoploss else self.stoploss # Initiate stoploss with open_rate. Does nothing if stoploss is already set. trade.adjust_stop_loss(trade.open_rate, stop_loss_value, initial=True) if self.trailing_stop: # trailing stoploss handling - sl_offset = self.trailing_stop_positive_offset + sl_offset=self.trailing_stop_positive_offset # Make sure current_profit is calculated using high for backtesting. - high_profit = current_profit if not high else trade.calc_profit_ratio(high) + high_profit=current_profit if not high else trade.calc_profit_ratio(high) # Don't update stoploss if trailing_only_offset_is_reached is true. if not (self.trailing_only_offset_is_reached and high_profit < sl_offset): # Specific handling for trailing_stop_positive if self.trailing_stop_positive is not None and high_profit > sl_offset: - stop_loss_value = self.trailing_stop_positive + stop_loss_value=self.trailing_stop_positive logger.debug(f"{trade.pair} - Using positive stoploss: {stop_loss_value} " f"offset: {sl_offset:.4g} profit: {current_profit:.4f}%") @@ -401,11 +401,11 @@ class IStrategy(ABC): (trade.stop_loss >= current_rate) and (not self.order_types.get('stoploss_on_exchange') or self.config['dry_run'])): - sell_type = SellType.STOP_LOSS + sell_type=SellType.STOP_LOSS # If initial stoploss is not the same as current one then it is trailing. if trade.initial_stop_loss != trade.stop_loss: - sell_type = SellType.TRAILING_STOP_LOSS + sell_type=SellType.TRAILING_STOP_LOSS logger.debug( f"{trade.pair} - HIT STOP: current price at {current_rate:.6f}, " f"stoploss is {trade.stop_loss:.6f}, " @@ -425,10 +425,10 @@ class IStrategy(ABC): :return: minimal ROI entry value or None if none proper ROI entry was found. """ # Get highest entry in ROI dict where key <= trade-duration - roi_list = list(filter(lambda x: x <= trade_dur, self.minimal_roi.keys())) + roi_list=list(filter(lambda x: x <= trade_dur, self.minimal_roi.keys())) if not roi_list: return None, None - roi_entry = max(roi_list) + roi_entry=max(roi_list) return roi_entry, self.minimal_roi[roi_entry] def min_roi_reached(self, trade: Trade, current_profit: float, current_time: datetime) -> bool: @@ -439,8 +439,8 @@ class IStrategy(ABC): :return: True if bot should sell at current rate """ # Check if time matches and current rate is above threshold - trade_dur = int((current_time.timestamp() - trade.open_date.timestamp()) // 60) - _, roi = self.min_roi_reached_entry(trade_dur) + trade_dur=int((current_time.timestamp() - trade.open_date.timestamp()) // 60) + _, roi=self.min_roi_reached_entry(trade_dur) if roi is None: return False else: From 7754742459688e94b258ecf006883e57f0152b78 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:10:57 +0100 Subject: [PATCH 007/285] fix tests --- freqtrade/strategy/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 47bdf781d..23c16d83e 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -282,7 +282,7 @@ class IStrategy(ABC): interval_minutes = timeframe_to_minutes(interval) if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: logger.warning('Old candle for pair %s. Last tick is %s minutes old', - pair, int(arrow.utcnow() - signal_date).total_seconds() // 60) + pair, int((arrow.utcnow() - signal_date).total_seconds() // 60)) return False, False # Check if dataframe is out of date From 2e679ee2ebee44fee6c445e568f03a5f58902aee Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:22:21 +0100 Subject: [PATCH 008/285] fixed log message --- freqtrade/strategy/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 23c16d83e..cf205c709 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -281,7 +281,7 @@ class IStrategy(ABC): signal_date = arrow.get(latest['date']) interval_minutes = timeframe_to_minutes(interval) if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: - logger.warning('Old candle for pair %s. Last tick is %s minutes old', + logger.warning('Old candle for pair %s. Last candle is %s minutes old', pair, int((arrow.utcnow() - signal_date).total_seconds() // 60)) return False, False From d25cf1395b11f130877ef4864b12f480cf940ea9 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:22:21 +0100 Subject: [PATCH 009/285] fixed log message --- freqtrade/strategy/interface.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 23c16d83e..4d82c6c02 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -277,14 +277,6 @@ class IStrategy(ABC): latest = dataframe.iloc[-1] - # Check if dataframe has new candle - signal_date = arrow.get(latest['date']) - interval_minutes = timeframe_to_minutes(interval) - if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: - logger.warning('Old candle for pair %s. Last tick is %s minutes old', - pair, int((arrow.utcnow() - signal_date).total_seconds() // 60)) - return False, False - # Check if dataframe is out of date offset = self.config.get('exchange', {}).get('outdated_offset', 5) if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): @@ -295,6 +287,14 @@ class IStrategy(ABC): ) return False, False + # Check if dataframe has new candle + signal_date = arrow.get(latest['date']) + interval_minutes = timeframe_to_minutes(interval) + if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: + logger.warning('Old candle for pair %s. Last candle is %s minutes old', + pair, int((arrow.utcnow() - signal_date).total_seconds() // 60)) + return False, False + (buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1 logger.debug( 'trigger: %s (pair=%s) buy=%s sell=%s', From ba596af636b2a5a725cb0f13e4e71d81fa0157ef Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:26:57 +0100 Subject: [PATCH 010/285] final? --- freqtrade/strategy/interface.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 4d82c6c02..a2a3c4f3a 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -275,8 +275,6 @@ class IStrategy(ABC): logger.warning('Empty dataframe for pair %s', pair) return False, False - latest = dataframe.iloc[-1] - # Check if dataframe is out of date offset = self.config.get('exchange', {}).get('outdated_offset', 5) if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): @@ -288,6 +286,7 @@ class IStrategy(ABC): return False, False # Check if dataframe has new candle + latest = dataframe.iloc[-1] signal_date = arrow.get(latest['date']) interval_minutes = timeframe_to_minutes(interval) if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: From c442913febf34cf610fa405bbb714667c45582a5 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:28:03 +0100 Subject: [PATCH 011/285] final --- freqtrade/strategy/interface.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index a2a3c4f3a..081127370 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -275,6 +275,9 @@ class IStrategy(ABC): logger.warning('Empty dataframe for pair %s', pair) return False, False + latest = dataframe.iloc[-1] + signal_date = arrow.get(latest['date']) + # Check if dataframe is out of date offset = self.config.get('exchange', {}).get('outdated_offset', 5) if signal_date < (arrow.utcnow().shift(minutes=-(interval_minutes * 2 + offset))): @@ -286,8 +289,6 @@ class IStrategy(ABC): return False, False # Check if dataframe has new candle - latest = dataframe.iloc[-1] - signal_date = arrow.get(latest['date']) interval_minutes = timeframe_to_minutes(interval) if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: logger.warning('Old candle for pair %s. Last candle is %s minutes old', From 1395f658723dd5d4464026760adc00d701710907 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:29:22 +0100 Subject: [PATCH 012/285] meh --- freqtrade/strategy/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 081127370..d840e2aea 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -277,6 +277,7 @@ class IStrategy(ABC): latest = dataframe.iloc[-1] signal_date = arrow.get(latest['date']) + interval_minutes = timeframe_to_minutes(interval) # Check if dataframe is out of date offset = self.config.get('exchange', {}).get('outdated_offset', 5) @@ -289,7 +290,6 @@ class IStrategy(ABC): return False, False # Check if dataframe has new candle - interval_minutes = timeframe_to_minutes(interval) if (arrow.utcnow() - signal_date).total_seconds() // 60 >= interval_minutes: logger.warning('Old candle for pair %s. Last candle is %s minutes old', pair, int((arrow.utcnow() - signal_date).total_seconds() // 60)) From d752586b322b43afe652482ce0ddee0b46f0cac4 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Wed, 11 Mar 2020 17:44:03 +0100 Subject: [PATCH 013/285] added test --- tests/strategy/test_interface.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 86d0738c6..d476b64b0 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -79,6 +79,21 @@ def test_get_signal_empty_dataframe(default_conf, mocker, caplog, ticker_history assert log_has('Empty dataframe for pair xyz', caplog) +def test_get_signal_old_candle(default_conf, mocker, caplog, ticker_history): + caplog.set_level(logging.INFO) + # default_conf defines a 5m interval. we check interval of previous candle + # this is necessary as the last candle is removed (partial candles) by default + oldtime = arrow.utcnow().shift(minutes=-10) + ticks = DataFrame([{'buy': 1, 'date': oldtime}]) + mocker.patch.object( + _STRATEGY, '_analyze_ticker_internal', + return_value=DataFrame(ticks) + ) + assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['ticker_interval'], + ticker_history) + assert log_has('Old candle for pair xyz. Last candle is 10 minutes old', caplog) + + def test_get_signal_old_dataframe(default_conf, mocker, caplog, ticker_history): caplog.set_level(logging.INFO) # default_conf defines a 5m interval. we check interval * 2 + 5m @@ -198,14 +213,14 @@ def test_min_roi_reached3(default_conf, fee) -> None: strategy = StrategyResolver.load_strategy(default_conf) strategy.minimal_roi = min_roi trade = Trade( - pair='ETH/BTC', - stake_amount=0.001, - amount=5, - open_date=arrow.utcnow().shift(hours=-1).datetime, - fee_open=fee.return_value, - fee_close=fee.return_value, - exchange='bittrex', - open_rate=1, + pair='ETH/BTC', + stake_amount=0.001, + amount=5, + open_date=arrow.utcnow().shift(hours=-1).datetime, + fee_open=fee.return_value, + fee_close=fee.return_value, + exchange='bittrex', + open_rate=1, ) assert not strategy.min_roi_reached(trade, 0.02, arrow.utcnow().shift(minutes=-56).datetime) From 2fb3d94938e8d3bbe4759b8ef670f40e4c3356b0 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Sat, 22 Feb 2020 15:49:18 +0100 Subject: [PATCH 014/285] added wins/draws/losses --- freqtrade/optimize/hyperopt.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index fcf50af6a..3f704b33c 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -533,10 +533,14 @@ class Hyperopt: 'total_profit': total_profit, } - def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: + def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: return { 'trade_count': len(backtesting_results.index), + '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]), 'avg_profit': backtesting_results.profit_percent.mean() * 100.0, + 'median_profit': backtesting_results.profit_percent.median() * 100.0, 'total_profit': backtesting_results.profit_abs.sum(), 'profit': backtesting_results.profit_percent.sum() * 100.0, 'duration': backtesting_results.trade_duration.mean(), @@ -548,7 +552,11 @@ class Hyperopt: """ stake_cur = self.config['stake_currency'] return (f"{results_metrics['trade_count']:6d} trades. " + f"{results_metrics['wins']:6d} wins. " + f"{results_metrics['draws']:6d} draws. " + f"{results_metrics['losses']:6d} losses. " f"Avg profit {results_metrics['avg_profit']: 6.2f}%. " + f"Median profit {results_metrics['median_profit']: 6.2f}%. " f"Total profit {results_metrics['total_profit']: 11.8f} {stake_cur} " f"({results_metrics['profit']: 7.2f}\N{GREEK CAPITAL LETTER SIGMA}%). " f"Avg duration {results_metrics['duration']:5.1f} min." From 6147498fd425d151f162e7ed0ebc855df4e1785d Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Sat, 22 Feb 2020 15:51:36 +0100 Subject: [PATCH 015/285] fixed indent --- freqtrade/optimize/hyperopt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 3f704b33c..f2221d6a7 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -533,7 +533,7 @@ class Hyperopt: 'total_profit': total_profit, } - def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: + def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: return { 'trade_count': len(backtesting_results.index), 'wins': len(backtesting_results[backtesting_results.profit_percent > 0]), From 72b088d85f9b4573d35c2d165d1504aeb83caec8 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Mon, 2 Mar 2020 02:50:27 +0100 Subject: [PATCH 016/285] added test --- tests/optimize/test_hyperopt.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index b5106be0c..cdbe7f161 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -740,8 +740,10 @@ def test_generate_optimizer(mocker, default_conf) -> None: } response_expected = { 'loss': 1.9840569076926293, - 'results_explanation': (' 1 trades. Avg profit 2.31%. Total profit 0.00023300 BTC ' - '( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). Avg duration 100.0 min.' + 'results_explanation': (' 1 trades. 1 wins. 0 draws. 0 losses. ' + 'Avg profit 2.31%. Median profit 2.31%. Total profit ' + '0.00023300 BTC ( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). ' + 'Avg duration 100.0 min.' ).encode(locale.getpreferredencoding(), 'replace').decode('utf-8'), 'params_details': {'buy': {'adx-enabled': False, 'adx-value': 0, @@ -772,10 +774,14 @@ def test_generate_optimizer(mocker, default_conf) -> None: 'trailing_stop_positive_offset': 0.07}}, 'params_dict': optimizer_param, 'results_metrics': {'avg_profit': 2.3117, + 'draws': 0, 'duration': 100.0, + 'losses': 0, + 'median_profit': 2.3117, 'profit': 2.3117, 'total_profit': 0.000233, - 'trade_count': 1}, + 'trade_count': 1, + 'wins': 1}, 'total_profit': 0.00023300 } From 181b12b3a811bf461f602cfc7b111cc13ebaaaee Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Sat, 22 Feb 2020 15:49:18 +0100 Subject: [PATCH 017/285] added wins/draws/losses --- freqtrade/optimize/hyperopt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index f2221d6a7..3f704b33c 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -533,7 +533,7 @@ class Hyperopt: 'total_profit': total_profit, } - def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: + def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: return { 'trade_count': len(backtesting_results.index), 'wins': len(backtesting_results[backtesting_results.profit_percent > 0]), From c9711678fd414e9ff7bb82496fe1ec6c98a9f5a8 Mon Sep 17 00:00:00 2001 From: Yazeed Al Oyoun Date: Sat, 22 Feb 2020 15:51:36 +0100 Subject: [PATCH 018/285] fixed indent --- freqtrade/optimize/hyperopt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 3f704b33c..f2221d6a7 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -533,7 +533,7 @@ class Hyperopt: 'total_profit': total_profit, } - def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: + def _calculate_results_metrics(self, backtesting_results: DataFrame) -> Dict: return { 'trade_count': len(backtesting_results.index), 'wins': len(backtesting_results[backtesting_results.profit_percent > 0]), From bfa55f31c0aa51d6de3864a8dfe001d1aac6aa62 Mon Sep 17 00:00:00 2001 From: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> Date: Wed, 20 May 2020 17:45:27 +0300 Subject: [PATCH 019/285] Remove wrong comment --- freqtrade/freqtradebot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index dd419f541..32662ae09 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -402,7 +402,6 @@ class FreqtradeBot: """ logger.debug(f"create_trade for pair {pair}") - # Check if dataframe is out of date if self.strategy.is_pair_locked(pair): logger.info(f"Pair {pair} is currently locked.") return False From f3824d970bb511d1a230fe6de713f735b81c80c7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 29 May 2020 20:18:38 +0200 Subject: [PATCH 020/285] Use dict for symbol_is_pair --- freqtrade/commands/list_commands.py | 2 +- freqtrade/exchange/exchange.py | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index e5131f9b2..bc4bd694f 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -163,7 +163,7 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None: tabular_data.append({'Id': v['id'], 'Symbol': v['symbol'], 'Base': v['base'], 'Quote': v['quote'], 'Active': market_is_active(v), - **({'Is pair': symbol_is_pair(v['symbol'])} + **({'Is pair': symbol_is_pair(v)} if not pairs_only else {})}) if (args.get('print_one_column', False) or diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index af745e8d0..09f700bbb 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -214,7 +214,7 @@ class Exchange: if quote_currencies: markets = {k: v for k, v in markets.items() if v['quote'] in quote_currencies} if pairs_only: - markets = {k: v for k, v in markets.items() if symbol_is_pair(v['symbol'])} + markets = {k: v for k, v in markets.items() if symbol_is_pair(v)} if active_only: markets = {k: v for k, v in markets.items() if market_is_active(v)} return markets @@ -1210,7 +1210,7 @@ def timeframe_to_next_date(timeframe: str, date: datetime = None) -> datetime: return datetime.fromtimestamp(new_timestamp, tz=timezone.utc) -def symbol_is_pair(market_symbol: str, base_currency: str = None, +def symbol_is_pair(market_symbol: Dict[str, Any], base_currency: str = None, quote_currency: str = None) -> bool: """ Check if the market symbol is a pair, i.e. that its symbol consists of the base currency and the @@ -1218,10 +1218,12 @@ def symbol_is_pair(market_symbol: str, base_currency: str = None, it also checks that the symbol contains appropriate base and/or quote currency part before and after the separating character correspondingly. """ - symbol_parts = market_symbol.split('/') + symbol_parts = market_symbol['symbol'].split('/') return (len(symbol_parts) == 2 and - (symbol_parts[0] == base_currency if base_currency else len(symbol_parts[0]) > 0) and - (symbol_parts[1] == quote_currency if quote_currency else len(symbol_parts[1]) > 0)) + (market_symbol.get('base') == base_currency + if base_currency else len(symbol_parts[0]) > 0) and + (market_symbol.get('quote') == quote_currency + if quote_currency else len(symbol_parts[1]) > 0)) def market_is_active(market: Dict) -> bool: From ffa93377b4e66f7182fcfcee305c8635299b106b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Jun 2020 09:34:03 +0200 Subject: [PATCH 021/285] Test colorama init again (after the fixes done to progressbar) --- freqtrade/optimize/hyperopt.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 3a28de785..bd80f7069 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -4,26 +4,26 @@ This module contains the hyperopt logic """ +import io import locale import logging import random import warnings -from math import ceil from collections import OrderedDict +from math import ceil from operator import itemgetter from pathlib import Path from pprint import pprint from typing import Any, Dict, List, Optional +import progressbar import rapidjson +import tabulate from colorama import Fore, Style +from colorama import init as colorama_init from joblib import (Parallel, cpu_count, delayed, dump, load, wrap_non_picklable_objects) -from pandas import DataFrame, json_normalize, isna -import progressbar -import tabulate -from os import path -import io +from pandas import DataFrame, isna, json_normalize from freqtrade.data.converter import trim_dataframe from freqtrade.data.history import get_timerange @@ -32,7 +32,8 @@ from freqtrade.misc import plural, round_dict from freqtrade.optimize.backtesting import Backtesting # Import IHyperOpt and IHyperOptLoss to allow unpickling classes from these modules from freqtrade.optimize.hyperopt_interface import IHyperOpt # noqa: F401 -from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss # noqa: F401 +from freqtrade.optimize.hyperopt_loss_interface import \ + IHyperOptLoss # noqa: F401 from freqtrade.resolvers.hyperopt_resolver import (HyperOptLossResolver, HyperOptResolver) @@ -374,7 +375,7 @@ class Hyperopt: return # Verification for overwrite - if path.isfile(csv_file): + if Path(csv_file).is_file(): logger.error(f"CSV file already exists: {csv_file}") return @@ -603,7 +604,7 @@ class Hyperopt: data, timerange = self.backtesting.load_bt_data() preprocessed = self.backtesting.strategy.ohlcvdata_to_dataframe(data) - + colorama_init(autoreset=True) # Trim startup period from analyzed dataframe for pair, df in preprocessed.items(): preprocessed[pair] = trim_dataframe(df, timerange) From d9afef8fe19d1fee53cd3c0421cdd3ffcdb27a91 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Jun 2020 09:37:10 +0200 Subject: [PATCH 022/285] Move colorama_init to where it was --- freqtrade/optimize/hyperopt.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index bd80f7069..566ba5de8 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -604,7 +604,7 @@ class Hyperopt: data, timerange = self.backtesting.load_bt_data() preprocessed = self.backtesting.strategy.ohlcvdata_to_dataframe(data) - colorama_init(autoreset=True) + # Trim startup period from analyzed dataframe for pair, df in preprocessed.items(): preprocessed[pair] = trim_dataframe(df, timerange) @@ -629,6 +629,10 @@ class Hyperopt: self.dimensions: List[Dimension] = self.hyperopt_space() self.opt = self.get_optimizer(self.dimensions, config_jobs) + + if self.print_colorized: + colorama_init(autoreset=True) + try: with Parallel(n_jobs=config_jobs) as parallel: jobs = parallel._effective_n_jobs() From f6edb32a33c5ddc6a48c7bd9e3abeb01871a6054 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 1 Jun 2020 09:55:52 +0200 Subject: [PATCH 023/285] Run hyperopt with --print-all --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 239576c61..2c6141344 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,7 +88,7 @@ jobs: run: | cp config.json.example config.json freqtrade create-userdir --userdir user_data - freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt + freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt --print-all - name: Flake8 run: | @@ -150,7 +150,7 @@ jobs: run: | cp config.json.example config.json freqtrade create-userdir --userdir user_data - freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt + freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt --print-all - name: Flake8 run: | From b22e3a67d86b27d06ab2c1b4bee0d8f0b2f0f382 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Jun 2020 20:29:48 +0200 Subject: [PATCH 024/285] rename symbol_is_pair to market_is_tradable Make it part of the exchange class, so subclasses can override this --- freqtrade/commands/list_commands.py | 4 ++-- freqtrade/exchange/__init__.py | 3 +-- freqtrade/exchange/exchange.py | 31 +++++++++++++---------------- freqtrade/exchange/ftx.py | 12 ++++++++++- freqtrade/exchange/kraken.py | 12 ++++++++++- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/freqtrade/commands/list_commands.py b/freqtrade/commands/list_commands.py index bc4bd694f..503f8a4ee 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -14,7 +14,7 @@ from freqtrade.configuration import setup_utils_configuration from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES from freqtrade.exceptions import OperationalException from freqtrade.exchange import (available_exchanges, ccxt_exchanges, - market_is_active, symbol_is_pair) + market_is_active) from freqtrade.misc import plural from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.state import RunMode @@ -163,7 +163,7 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None: tabular_data.append({'Id': v['id'], 'Symbol': v['symbol'], 'Base': v['base'], 'Quote': v['quote'], 'Active': market_is_active(v), - **({'Is pair': symbol_is_pair(v)} + **({'Is pair': exchange.market_is_tradable(v)} if not pairs_only else {})}) if (args.get('print_one_column', False) or diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index a39f8f5df..bdf1f91ec 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -12,8 +12,7 @@ from freqtrade.exchange.exchange import (timeframe_to_seconds, timeframe_to_msecs, timeframe_to_next_date, timeframe_to_prev_date) -from freqtrade.exchange.exchange import (market_is_active, - symbol_is_pair) +from freqtrade.exchange.exchange import (market_is_active) from freqtrade.exchange.kraken import Kraken from freqtrade.exchange.binance import Binance from freqtrade.exchange.bibox import Bibox diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 09f700bbb..bec8b9686 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -214,7 +214,7 @@ class Exchange: if quote_currencies: markets = {k: v for k, v in markets.items() if v['quote'] in quote_currencies} if pairs_only: - markets = {k: v for k, v in markets.items() if symbol_is_pair(v)} + markets = {k: v for k, v in markets.items() if self.symbol_is_pair(v)} if active_only: markets = {k: v for k, v in markets.items() if market_is_active(v)} return markets @@ -238,6 +238,19 @@ class Exchange: """ return self.markets.get(pair, {}).get('base', '') + def market_is_tradable(self, market: Dict[str, Any]) -> bool: + """ + Check if the market symbol is tradable by Freqtrade. + By default, checks if it's splittable by `/` and both sides correspond to base / quote + """ + symbol_parts = market['symbol'].split('/') + return (len(symbol_parts) == 2 and + len(symbol_parts[0]) > 0 and + len(symbol_parts[1]) > 0 and + symbol_parts[0] == market.get('base') and + symbol_parts[1] == market.get('quote') + ) + def klines(self, pair_interval: Tuple[str, str], copy: bool = True) -> DataFrame: if pair_interval in self._klines: return self._klines[pair_interval].copy() if copy else self._klines[pair_interval] @@ -1210,22 +1223,6 @@ def timeframe_to_next_date(timeframe: str, date: datetime = None) -> datetime: return datetime.fromtimestamp(new_timestamp, tz=timezone.utc) -def symbol_is_pair(market_symbol: Dict[str, Any], base_currency: str = None, - quote_currency: str = None) -> bool: - """ - Check if the market symbol is a pair, i.e. that its symbol consists of the base currency and the - quote currency separated by '/' character. If base_currency and/or quote_currency is passed, - it also checks that the symbol contains appropriate base and/or quote currency part before - and after the separating character correspondingly. - """ - symbol_parts = market_symbol['symbol'].split('/') - return (len(symbol_parts) == 2 and - (market_symbol.get('base') == base_currency - if base_currency else len(symbol_parts[0]) > 0) and - (market_symbol.get('quote') == quote_currency - if quote_currency else len(symbol_parts[1]) > 0)) - - def market_is_active(market: Dict) -> bool: """ Return True if the market is active. diff --git a/freqtrade/exchange/ftx.py b/freqtrade/exchange/ftx.py index 75915122b..cad11bbfa 100644 --- a/freqtrade/exchange/ftx.py +++ b/freqtrade/exchange/ftx.py @@ -1,6 +1,6 @@ """ FTX exchange subclass """ import logging -from typing import Dict +from typing import Any, Dict from freqtrade.exchange import Exchange @@ -12,3 +12,13 @@ class Ftx(Exchange): _ft_has: Dict = { "ohlcv_candle_limit": 1500, } + + def market_is_tradable(self, market: Dict[str, Any]) -> bool: + """ + Check if the market symbol is tradable by Freqtrade. + Default checks + check if pair is darkpool pair. + """ + parent_check = super().market_is_tradable(market) + + return (parent_check and + market.get('spot', False) is True) diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 932d82a27..af75ef9b2 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -1,6 +1,6 @@ """ Kraken exchange subclass """ import logging -from typing import Dict +from typing import Any, Dict import ccxt @@ -21,6 +21,16 @@ class Kraken(Exchange): "trades_pagination_arg": "since", } + def market_is_tradable(self, market: Dict[str, Any]) -> bool: + """ + Check if the market symbol is tradable by Freqtrade. + Default checks + check if pair is darkpool pair. + """ + parent_check = super().market_is_tradable(market) + + return (parent_check and + market.get('darkpool', False) is False) + @retrier def get_balances(self) -> dict: if self._config['dry_run']: From b74a3addc65514aa8f7494ca995caa4bee74c4b5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Jun 2020 20:30:31 +0200 Subject: [PATCH 025/285] Update tests --- freqtrade/exchange/ftx.py | 2 +- tests/exchange/test_exchange.py | 55 +++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/freqtrade/exchange/ftx.py b/freqtrade/exchange/ftx.py index cad11bbfa..e5f083fb6 100644 --- a/freqtrade/exchange/ftx.py +++ b/freqtrade/exchange/ftx.py @@ -16,7 +16,7 @@ class Ftx(Exchange): def market_is_tradable(self, market: Dict[str, Any]) -> bool: """ Check if the market symbol is tradable by Freqtrade. - Default checks + check if pair is darkpool pair. + Default checks + check if pair is spot pair (no futures trading yet). """ parent_check = super().market_is_tradable(market) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index e40f691a8..b87acc27c 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -15,7 +15,7 @@ from freqtrade.exceptions import (DependencyException, InvalidOrderException, OperationalException, TemporaryError) from freqtrade.exchange import Binance, Exchange, Kraken from freqtrade.exchange.common import API_RETRY_COUNT -from freqtrade.exchange.exchange import (market_is_active, symbol_is_pair, +from freqtrade.exchange.exchange import (market_is_active, timeframe_to_minutes, timeframe_to_msecs, timeframe_to_next_date, @@ -2117,25 +2117,42 @@ def test_timeframe_to_next_date(): assert timeframe_to_next_date("5m") > date -@pytest.mark.parametrize("market_symbol,base_currency,quote_currency,expected_result", [ - ("BTC/USDT", None, None, True), - ("USDT/BTC", None, None, True), - ("BTCUSDT", None, None, False), - ("BTC/USDT", None, "USDT", True), - ("USDT/BTC", None, "USDT", False), - ("BTCUSDT", None, "USDT", False), - ("BTC/USDT", "BTC", None, True), - ("USDT/BTC", "BTC", None, False), - ("BTCUSDT", "BTC", None, False), - ("BTC/USDT", "BTC", "USDT", True), - ("BTC/USDT", "USDT", "BTC", False), - ("BTC/USDT", "BTC", "USD", False), - ("BTCUSDT", "BTC", "USDT", False), - ("BTC/", None, None, False), - ("/USDT", None, None, False), +@pytest.mark.parametrize("market_symbol,base,quote,exchange,add_dict,expected_result", [ + ("BTC/USDT", 'BTC', 'USDT', "binance", {}, True), + ("USDT/BTC", 'USDT', 'BTC', "binance", {}, True), + ("USDT/BTC", 'BTC', 'USDT', "binance", {}, False), # Reversed currencies + ("BTCUSDT", 'BTC', 'USDT', "binance", {}, False), # No seperating / + ("BTCUSDT", None, "USDT", "binance", {}, False), # + ("USDT/BTC", "BTC", None, "binance", {}, False), + ("BTCUSDT", "BTC", None, "binance", {}, False), + ("BTC/USDT", "BTC", "USDT", "binance", {}, True), + ("BTC/USDT", "USDT", "BTC", "binance", {}, False), # reversed currencies + ("BTC/USDT", "BTC", "USD", "binance", {}, False), # Wrong quote currency + ("BTC/", "BTC", 'UNK', "binance", {}, False), + ("/USDT", 'UNK', 'USDT', "binance", {}, False), + ("BTC/EUR", 'BTC', 'EUR', "kraken", {"darkpool": False}, True), + ("EUR/BTC", 'EUR', 'BTC', "kraken", {"darkpool": False}, True), + ("EUR/BTC", 'BTC', 'EUR', "kraken", {"darkpool": False}, False), # Reversed currencies + ("BTC/EUR", 'BTC', 'USD', "kraken", {"darkpool": False}, False), # wrong quote currency + ("BTC/EUR", 'BTC', 'EUR', "kraken", {"darkpool": True}, False), # no darkpools + ("BTC/EUR.d", 'BTC', 'EUR', "kraken", {"darkpool": True}, False), # no darkpools + ("BTC/USD", 'BTC', 'USD', "ftx", {'spot': True}, True), + ("USD/BTC", 'USD', 'BTC', "ftx", {'spot': True}, True), + ("BTC/USD", 'BTC', 'USDT', "ftx", {'spot': True}, False), # Wrong quote currency + ("BTC/USD", 'USD', 'BTC', "ftx", {'spot': True}, False), # Reversed currencies + ("BTC/USD", 'BTC', 'USD', "ftx", {'spot': False}, False), # Can only trade spot markets + ("BTC-PERP", 'BTC', 'USD', "ftx", {'spot': False}, False), # Can only trade spot markets ]) -def test_symbol_is_pair(market_symbol, base_currency, quote_currency, expected_result) -> None: - assert symbol_is_pair(market_symbol, base_currency, quote_currency) == expected_result +def test_market_is_tradable(mocker, default_conf, market_symbol, base, + quote, add_dict, exchange, expected_result) -> None: + ex = get_patched_exchange(mocker, default_conf, id=exchange) + market = { + 'symbol': market_symbol, + 'base': base, + 'quote': quote, + **(add_dict), + } + assert ex.market_is_tradable(market) == expected_result @pytest.mark.parametrize("market,expected_result", [ From 08049d23b48242c5c468102b4ae8cb182a9236cc Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 2 Jun 2020 20:41:29 +0200 Subject: [PATCH 026/285] Use "market_is_tradable" for whitelist validation --- freqtrade/exchange/exchange.py | 2 +- freqtrade/pairlist/IPairList.py | 5 +++++ tests/pairlist/test_pairlist.py | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index bec8b9686..a2bb8627a 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -214,7 +214,7 @@ class Exchange: if quote_currencies: markets = {k: v for k, v in markets.items() if v['quote'] in quote_currencies} if pairs_only: - markets = {k: v for k, v in markets.items() if self.symbol_is_pair(v)} + markets = {k: v for k, v in markets.items() if self.market_is_tradable(v)} if active_only: markets = {k: v for k, v in markets.items() if market_is_active(v)} return markets diff --git a/freqtrade/pairlist/IPairList.py b/freqtrade/pairlist/IPairList.py index f48a7dcfd..61fdc73ad 100644 --- a/freqtrade/pairlist/IPairList.py +++ b/freqtrade/pairlist/IPairList.py @@ -159,6 +159,11 @@ class IPairList(ABC): f"{self._exchange.name}. Removing it from whitelist..") continue + if not self._exchange.market_is_tradable(markets[pair]): + logger.warning(f"Pair {pair} is not tradable with Freqtrade." + "Removing it from whitelist..") + continue + if self._exchange.get_pair_quote_currency(pair) != self._config['stake_currency']: logger.warning(f"Pair {pair} is not compatible with your stake currency " f"{self._config['stake_currency']}. Removing it from whitelist..") diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index 421f06911..c6d1eeb38 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -400,7 +400,9 @@ def test_pairlist_class(mocker, whitelist_conf, markets, pairlist): # BCH/BTC not available (['ETH/BTC', 'TKN/BTC', 'BCH/BTC'], "is not compatible with exchange"), # BTT/BTC is inactive - (['ETH/BTC', 'TKN/BTC', 'BTT/BTC'], "Market is not active") + (['ETH/BTC', 'TKN/BTC', 'BTT/BTC'], "Market is not active"), + # XLTCUSDT is not a valid pair + (['ETH/BTC', 'TKN/BTC', 'XLTCUSDT'], "is not tradable with Freqtrade"), ]) def test__whitelist_for_active_markets(mocker, whitelist_conf, markets, pairlist, whitelist, caplog, log_message, tickers): From 9dba2a34f9edc91a9e0e3ab0f970fb3286aa9b75 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 16 Jun 2020 10:16:23 +0200 Subject: [PATCH 027/285] Add note for hyperopt color support on windows --- docs/hyperopt.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 8efc51a39..9f7f97476 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -370,6 +370,9 @@ By default, hyperopt prints colorized results -- epochs with positive profit are You can use the `--print-all` command line option if you would like to see all results in the hyperopt output, not only the best ones. When `--print-all` is used, current best results are also colorized by default -- they are printed in bold (bright) style. This can also be switched off with the `--no-color` command line option. +!!! Note "Windows and color output" + Windows does not support color-output nativly, therefore it is automatically disabled. To have color-output for hyperopt running under windows, please consider using WSL. + ### Understand Hyperopt ROI results If you are optimizing ROI (i.e. if optimization search-space contains 'all', 'default' or 'roi'), your result will look as follows and include a ROI table: From 2f759825e4c670af51e4e17b074f96f48ff5ce16 Mon Sep 17 00:00:00 2001 From: Confucius-The-Great <40965179+qkum@users.noreply.github.com> Date: Tue, 30 Jun 2020 11:01:00 +0200 Subject: [PATCH 028/285] Update faq.md Major changes :) --- docs/faq.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 151b2c054..cc43e326d 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,5 +1,9 @@ # Freqtrade FAQ +## Beginner Tips & Tricks + +#1 When you work with your strategy & hyperopt file you should use a real programmer software like Pycharm. If you by accident moved some code and freqtrade says error and you cant find the place where you moved something, or you cant find line 180 where you messed something up. Then a program like Pycharm shows you where line 180 is in your strategy file so you can fix the problem, or Pycharm shows you with some color marking that "here is a line of code that does not belong here" and you found your error in no time! This will save you many hours of problemsolving when working with the bot. Pycharm also got a usefull "Debug" feature that can tell you exactly what command on that line is making the error :) + ## Freqtrade common issues ### The bot does not start @@ -15,10 +19,12 @@ This could have the following reasons: ### I have waited 5 minutes, why hasn't the bot made any trades yet?! -Depending on the buy strategy, the amount of whitelisted coins, the +#1 Depending on the buy strategy, the amount of whitelisted coins, the situation of the market etc, it can take up to hours to find good entry position for a trade. Be patient! +#2 Or it may because you made an human error? Like writing --dry-run when you wanted to trade live?. Maybe an error with the exchange API? Or something else. You will have to do the hard work of finding out the root cause of the problem :) + ### I have made 12 trades already, why is my total profit negative?! I understand your disappointment but unfortunately 12 trades is just @@ -129,25 +135,25 @@ to find a great result (unless if you are very lucky), so you probably have to run it for 10.000 or more. But it will take an eternity to compute. -We recommend you to run it at least 10.000 epochs: +We recommend you to run between 500-1000 epochs over and over untill you hit at least 10.000 epocs in total. You can best judge by looking at the results - if the bot keep discovering more profitable strategies or not. ```bash -freqtrade hyperopt -e 10000 +freqtrade hyperopt -e 1000 ``` or if you want intermediate result to see ```bash -for i in {1..100}; do freqtrade hyperopt -e 100; done +for i in {1..100}; do freqtrade hyperopt -e 1000; done ``` -### Why it is so long to run hyperopt? +### Why does it take so long time to run hyperopt? -Finding a great Hyperopt results takes time. +#1 Discovering a great strategy with Hyperopt takes time. Study www.freqtrade.io, the Freqtrade Github page, join the Freqtrade Discord - or something totally else. While you patiently wait for the most advanced, public known, crypto bot, in the world, to hand you a possible golden strategy specially designed just for you =) -If you wonder why it takes a while to find great hyperopt results +#2 If you wonder why it can take from 20 minutes to days to do 1000 epocs here are some answers: -This answer was written during the under the release 0.15.1, when we had: +This answer was written during the release 0.15.1, when we had: - 8 triggers - 9 guards: let's say we evaluate even 10 values from each @@ -157,7 +163,10 @@ The following calculation is still very rough and not very precise but it will give the idea. With only these triggers and guards there is already 8\*10^9\*10 evaluations. A roughly total of 80 billion evals. Did you run 100 000 evals? Congrats, you've done roughly 1 / 100 000 th -of the search space. +of the search space. If we assume that the bot never test the same strategy more than once. + +#3 The time it takes to run 1000 hyperopt epocs depends on things like: The cpu, harddisk, ram, motherboard, indicator settings, indicator count, amount of coins that hyperopt test strategies on, trade count - can be 650 trades in a year or 10.0000 trades depending on if the strategy aims for a high profit rarely or a low profit many many many times. Example: 4% profit 650 times vs 0,3% profit a trade 10.000 times in a year. If we assume you set the --timerange to 365 days. +Example: freqtrade --config config_mcd_1.json --strategy mcd_1 --hyperopt mcd_hyperopt_1 -e 1000 --timerange 20190601-20200601 ## Edge module From 455b26ea48975178664d8da76c8b6d9fbbdf60b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Jun 2020 06:37:30 +0200 Subject: [PATCH 029/285] Add max drawdown to backtesting --- freqtrade/optimize/optimize_reports.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index d89860a73..5be1a47a9 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List from pandas import DataFrame from tabulate import tabulate +from freqtrade.data.btanalysis import calculate_max_drawdown from freqtrade.misc import file_dump_json logger = logging.getLogger(__name__) @@ -212,11 +213,20 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], max_open_trades=max_open_trades, results=results.loc[results['open_at_end']], skip_nan=True) + + max_drawdown, drawdown_start, drawdown_end = calculate_max_drawdown( + results, value_col='profit_percent') + strat_stats = { 'trades': backtest_result_to_list(results), 'results_per_pair': pair_results, 'sell_reason_summary': sell_reason_stats, 'left_open_trades': left_open_results, + 'max_drawdown': max_drawdown, + 'drawdown_start': drawdown_start, + 'drawdown_start_ts': drawdown_start.timestamp(), + 'drawdown_end': drawdown_end, + 'drawdown_end_ts': drawdown_end.timestamp(), } result['strategy'][strategy] = strat_stats @@ -298,6 +308,16 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") +def text_table_add_metrics(strategy_results: Dict) -> str: + xxx = [ + ('Max Drawdown', f"{round(strategy_results['max_drawdown'] * 100, 2)}%"), + ('Drawdown Start', strategy_results['drawdown_start'].strftime('%Y-%m-%d %H:%M:%S')), + ('Drawdown End', strategy_results['drawdown_end'].strftime('%Y-%m-%d %H:%M:%S')), + ] + + return tabulate(xxx, headers=["Metric", "Value"], tablefmt="orgtbl") + + def show_backtest_results(config: Dict, backtest_stats: Dict): stake_currency = config['stake_currency'] @@ -320,6 +340,12 @@ def show_backtest_results(config: Dict, backtest_stats: Dict): if isinstance(table, str): print(' LEFT OPEN TRADES REPORT '.center(len(table.splitlines()[0]), '=')) print(table) + + table = text_table_add_metrics(results) + if isinstance(table, str): + print(' SUMMARY METRICS '.center(len(table.splitlines()[0]), '=')) + print(table) + if isinstance(table, str): print('=' * len(table.splitlines()[0])) print() From 6922fbc3aae545e4ef3020610e819199770171f7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 8 Jun 2020 06:38:29 +0200 Subject: [PATCH 030/285] Add max_drawdown error handler --- freqtrade/optimize/optimize_reports.py | 44 +++++++++++++++++--------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 5be1a47a9..0188761d4 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -1,5 +1,5 @@ import logging -from datetime import timedelta +from datetime import timedelta, datetime from pathlib import Path from typing import Any, Dict, List @@ -214,22 +214,33 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], results=results.loc[results['open_at_end']], skip_nan=True) - max_drawdown, drawdown_start, drawdown_end = calculate_max_drawdown( - results, value_col='profit_percent') - strat_stats = { 'trades': backtest_result_to_list(results), 'results_per_pair': pair_results, 'sell_reason_summary': sell_reason_stats, 'left_open_trades': left_open_results, - 'max_drawdown': max_drawdown, - 'drawdown_start': drawdown_start, - 'drawdown_start_ts': drawdown_start.timestamp(), - 'drawdown_end': drawdown_end, - 'drawdown_end_ts': drawdown_end.timestamp(), } result['strategy'][strategy] = strat_stats + try: + max_drawdown, drawdown_start, drawdown_end = calculate_max_drawdown( + results, value_col='profit_percent') + strat_stats.update({ + 'max_drawdown': max_drawdown, + 'drawdown_start': drawdown_start, + 'drawdown_start_ts': drawdown_start.timestamp(), + 'drawdown_end': drawdown_end, + 'drawdown_end_ts': drawdown_end.timestamp(), + }) + except ValueError: + strat_stats.update({ + 'max_drawdown': 0.0, + 'drawdown_start': datetime.min, + 'drawdown_start_ts': datetime.min.timestamp(), + 'drawdown_end': datetime.min, + 'drawdown_end_ts': datetime.min.timestamp(), + }) + strategy_results = generate_strategy_metrics(stake_currency=stake_currency, max_open_trades=max_open_trades, all_results=all_results) @@ -309,13 +320,16 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: def text_table_add_metrics(strategy_results: Dict) -> str: - xxx = [ - ('Max Drawdown', f"{round(strategy_results['max_drawdown'] * 100, 2)}%"), - ('Drawdown Start', strategy_results['drawdown_start'].strftime('%Y-%m-%d %H:%M:%S')), - ('Drawdown End', strategy_results['drawdown_end'].strftime('%Y-%m-%d %H:%M:%S')), - ] + if len(strategy_results['trades']) > 0: + metrics = [ + ('Max Drawdown', f"{round(strategy_results['max_drawdown'] * 100, 2)}%"), + ('Drawdown Start', strategy_results['drawdown_start'].strftime('%Y-%m-%d %H:%M:%S')), + ('Drawdown End', strategy_results['drawdown_end'].strftime('%Y-%m-%d %H:%M:%S')), + ] - return tabulate(xxx, headers=["Metric", "Value"], tablefmt="orgtbl") + return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") + else: + return def show_backtest_results(config: Dict, backtest_stats: Dict): From cbcf3dbb43222e4863d7dacc27a726a8b261a43f Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jun 2020 08:00:35 +0200 Subject: [PATCH 031/285] Add more metrics to summarytable --- freqtrade/optimize/backtesting.py | 3 ++- freqtrade/optimize/optimize_reports.py | 26 ++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index e5014dd5a..c7a3515b5 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -417,5 +417,6 @@ class Backtesting: if self.config.get('export', False): store_backtest_result(self.config['exportfilename'], all_results) # Show backtest results - stats = generate_backtest_stats(self.config, data, all_results) + stats = generate_backtest_stats(self.config, data, all_results, + min_date=min_date, max_date=max_date) show_backtest_results(self.config, stats) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 0188761d4..dc3b52377 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -1,8 +1,9 @@ import logging -from datetime import timedelta, datetime +from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any, Dict, List +from arrow import Arrow from pandas import DataFrame from tabulate import tabulate @@ -191,11 +192,15 @@ def generate_edge_table(results: dict) -> str: def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], - all_results: Dict[str, DataFrame]) -> Dict[str, Any]: + all_results: Dict[str, DataFrame], + min_date: Arrow, max_date: Arrow + ) -> Dict[str, Any]: """ :param config: Configuration object used for backtest :param btdata: Backtest data :param all_results: backtest result - dictionary with { Strategy: results}. + :param min_date: Backtest start date + :param max_date: Backtest end date :return: Dictionary containing results per strategy and a stratgy summary. """ @@ -214,11 +219,19 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], results=results.loc[results['open_at_end']], skip_nan=True) + backtest_days = (max_date - min_date).days strat_stats = { 'trades': backtest_result_to_list(results), 'results_per_pair': pair_results, 'sell_reason_summary': sell_reason_stats, 'left_open_trades': left_open_results, + 'total_trades': len(results), + 'backtest_start': min_date.datetime, + 'backtest_start_ts': min_date.timestamp, + 'backtest_end': max_date.datetime, + 'backtest_end_ts': max_date.timestamp, + 'backtest_days': backtest_days, + 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None } result['strategy'][strategy] = strat_stats @@ -321,7 +334,16 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: def text_table_add_metrics(strategy_results: Dict) -> str: if len(strategy_results['trades']) > 0: + min_trade = min(strategy_results['trades'], key=lambda x: x[2]) metrics = [ + ('Total trades', strategy_results['total_trades']), + ('First trade', datetime.fromtimestamp(min_trade[2], + tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')), + ('First trade Pair', min_trade[0]), + ('Backtesting from', strategy_results['backtest_start'].strftime('%Y-%m-%d %H:%M:%S')), + ('Backtesting to', strategy_results['backtest_end'].strftime('%Y-%m-%d %H:%M:%S')), + ('Trades per day', strategy_results['trades_per_day']), + ('', ''), # Empty line to improve readability ('Max Drawdown', f"{round(strategy_results['max_drawdown'] * 100, 2)}%"), ('Drawdown Start', strategy_results['drawdown_start'].strftime('%Y-%m-%d %H:%M:%S')), ('Drawdown End', strategy_results['drawdown_end'].strftime('%Y-%m-%d %H:%M:%S')), From fbddfaeacf3d861da6c4b2023215fd31820bd992 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jun 2020 08:07:34 +0200 Subject: [PATCH 032/285] Introduce DatetimePrintFormat --- freqtrade/constants.py | 1 + freqtrade/edge/edge_positioning.py | 11 ++++------- freqtrade/optimize/backtesting.py | 16 ++++++++-------- freqtrade/optimize/hyperopt.py | 9 +++++---- freqtrade/optimize/optimize_reports.py | 11 ++++++----- freqtrade/rpc/api_server.py | 3 ++- 6 files changed, 26 insertions(+), 25 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 2cfff07cd..ccb05a60f 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -26,6 +26,7 @@ AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', 'ShuffleFilter', 'SpreadFilter'] AVAILABLE_DATAHANDLERS = ['json', 'jsongz'] DRY_RUN_WALLET = 1000 +DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S' MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons DEFAULT_DATAFRAME_COLUMNS = ['date', 'open', 'high', 'low', 'close', 'volume'] # Don't modify sequence of DEFAULT_TRADES_COLUMNS diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index 41252ee51..dd2f44f23 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -9,7 +9,7 @@ import utils_find_1st as utf1st from pandas import DataFrame from freqtrade.configuration import TimeRange -from freqtrade.constants import UNLIMITED_STAKE_AMOUNT +from freqtrade.constants import UNLIMITED_STAKE_AMOUNT, DATETIME_PRINT_FORMAT from freqtrade.exceptions import OperationalException from freqtrade.data.history import get_timerange, load_data, refresh_data from freqtrade.strategy.interface import SellType @@ -121,12 +121,9 @@ class Edge: # Print timeframe min_date, max_date = get_timerange(preprocessed) - logger.info( - 'Measuring data from %s up to %s (%s days) ...', - min_date.isoformat(), - max_date.isoformat(), - (max_date - min_date).days - ) + logger.info(f'Measuring data from {min_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'({(max_date - min_date).days} days)..') headers = ['date', 'buy', 'open', 'close', 'sell', 'high', 'low'] trades: list = [] diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index c7a3515b5..847434789 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -11,6 +11,7 @@ from typing import Any, Dict, List, NamedTuple, Optional, Tuple import arrow from pandas import DataFrame +from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.configuration import (TimeRange, remove_credentials, validate_config_consistency) from freqtrade.data import history @@ -137,10 +138,10 @@ class Backtesting: min_date, max_date = history.get_timerange(data) - logger.info( - 'Loading data from %s up to %s (%s days)..', - min_date.isoformat(), max_date.isoformat(), (max_date - min_date).days - ) + logger.info(f'Loading data from {min_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'({(max_date - min_date).days} days)..') + # Adjust startts forward if not enough data is available timerange.adjust_start_if_necessary(timeframe_to_seconds(self.timeframe), self.required_startup, min_date) @@ -400,10 +401,9 @@ class Backtesting: preprocessed[pair] = trim_dataframe(df, timerange) min_date, max_date = history.get_timerange(preprocessed) - logger.info( - 'Backtesting with data from %s up to %s (%s days)..', - min_date.isoformat(), max_date.isoformat(), (max_date - min_date).days - ) + logger.info(f'Backtesting with data from {min_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'({(max_date - min_date).days} days)..') # Execute backtest and print results all_results[self.strategy.get_strategy_name()] = self.backtest( processed=preprocessed, diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 153ae3861..69dff463b 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -25,6 +25,7 @@ import tabulate from os import path import io +from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.data.converter import trim_dataframe from freqtrade.data.history import get_timerange from freqtrade.exceptions import OperationalException @@ -625,10 +626,10 @@ class Hyperopt: preprocessed[pair] = trim_dataframe(df, timerange) min_date, max_date = get_timerange(data) - logger.info( - 'Hyperopting with data from %s up to %s (%s days)..', - min_date.isoformat(), max_date.isoformat(), (max_date - min_date).days - ) + logger.info(f'Hyperopting with data from {min_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'up to {max_date.strftime(DATETIME_PRINT_FORMAT)} ' + f'({(max_date - min_date).days} days)..') + dump(preprocessed, self.data_pickle_file) # We don't need exchange instance anymore while running hyperopt diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index dc3b52377..6efda2956 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -7,6 +7,7 @@ from arrow import Arrow from pandas import DataFrame from tabulate import tabulate +from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.data.btanalysis import calculate_max_drawdown from freqtrade.misc import file_dump_json @@ -338,15 +339,15 @@ def text_table_add_metrics(strategy_results: Dict) -> str: metrics = [ ('Total trades', strategy_results['total_trades']), ('First trade', datetime.fromtimestamp(min_trade[2], - tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')), + tz=timezone.utc).strftime(DATETIME_PRINT_FORMAT)), ('First trade Pair', min_trade[0]), - ('Backtesting from', strategy_results['backtest_start'].strftime('%Y-%m-%d %H:%M:%S')), - ('Backtesting to', strategy_results['backtest_end'].strftime('%Y-%m-%d %H:%M:%S')), + ('Backtesting from', strategy_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), + ('Backtesting to', strategy_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Trades per day', strategy_results['trades_per_day']), ('', ''), # Empty line to improve readability ('Max Drawdown', f"{round(strategy_results['max_drawdown'] * 100, 2)}%"), - ('Drawdown Start', strategy_results['drawdown_start'].strftime('%Y-%m-%d %H:%M:%S')), - ('Drawdown End', strategy_results['drawdown_end'].strftime('%Y-%m-%d %H:%M:%S')), + ('Drawdown Start', strategy_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), + ('Drawdown End', strategy_results['drawdown_end'].strftime(DATETIME_PRINT_FORMAT)), ] return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index a2cef9a98..e86a4783f 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -16,6 +16,7 @@ from werkzeug.security import safe_str_cmp from werkzeug.serving import make_server from freqtrade.__init__ import __version__ +from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.rpc.rpc import RPC, RPCException logger = logging.getLogger(__name__) @@ -31,7 +32,7 @@ class ArrowJSONEncoder(JSONEncoder): elif isinstance(obj, date): return obj.strftime("%Y-%m-%d") elif isinstance(obj, datetime): - return obj.strftime("%Y-%m-%d %H:%M:%S") + return obj.strftime(DATETIME_PRINT_FORMAT) iterable = iter(obj) except TypeError: pass From cf044d166edc68ba427d8c3b86f13ebb252a490b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 9 Jun 2020 08:14:18 +0200 Subject: [PATCH 033/285] Tests should use new Datetime format too --- freqtrade/optimize/optimize_reports.py | 4 ++-- tests/optimize/test_backtesting.py | 28 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 6efda2956..1e2d41e32 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -250,9 +250,9 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], strat_stats.update({ 'max_drawdown': 0.0, 'drawdown_start': datetime.min, - 'drawdown_start_ts': datetime.min.timestamp(), + 'drawdown_start_ts': datetime(1970, 1, 1).timestamp(), 'drawdown_end': datetime.min, - 'drawdown_end_ts': datetime.min.timestamp(), + 'drawdown_end_ts': datetime(1970, 1, 1).timestamp(), }) strategy_results = generate_strategy_metrics(stake_currency=stake_currency, diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 67da38648..853780b82 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -349,8 +349,8 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: exists = [ 'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...', - 'Backtesting with data from 2017-11-14T21:17:00+00:00 ' - 'up to 2017-11-14T22:59:00+00:00 (0 days)..' + 'Backtesting with data from 2017-11-14 21:17:00 ' + 'up to 2017-11-14 22:59:00 (0 days)..' ] for line in exists: assert log_has(line, caplog) @@ -672,10 +672,10 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir): f'Using data directory: {testdatadir} ...', 'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...', - 'Loading data from 2017-11-14T20:57:00+00:00 ' - 'up to 2017-11-14T22:58:00+00:00 (0 days)..', - 'Backtesting with data from 2017-11-14T21:17:00+00:00 ' - 'up to 2017-11-14T22:58:00+00:00 (0 days)..', + 'Loading data from 2017-11-14 20:57:00 ' + 'up to 2017-11-14 22:58:00 (0 days)..', + 'Backtesting with data from 2017-11-14 21:17:00 ' + 'up to 2017-11-14 22:58:00 (0 days)..', 'Parameter --enable-position-stacking detected ...' ] @@ -735,10 +735,10 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): f'Using data directory: {testdatadir} ...', 'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...', - 'Loading data from 2017-11-14T20:57:00+00:00 ' - 'up to 2017-11-14T22:58:00+00:00 (0 days)..', - 'Backtesting with data from 2017-11-14T21:17:00+00:00 ' - 'up to 2017-11-14T22:58:00+00:00 (0 days)..', + 'Loading data from 2017-11-14 20:57:00 ' + 'up to 2017-11-14 22:58:00 (0 days)..', + 'Backtesting with data from 2017-11-14 21:17:00 ' + 'up to 2017-11-14 22:58:00 (0 days)..', 'Parameter --enable-position-stacking detected ...', 'Running backtesting for Strategy DefaultStrategy', 'Running backtesting for Strategy TestStrategyLegacy', @@ -818,10 +818,10 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat f'Using data directory: {testdatadir} ...', 'Using stake_currency: BTC ...', 'Using stake_amount: 0.001 ...', - 'Loading data from 2017-11-14T20:57:00+00:00 ' - 'up to 2017-11-14T22:58:00+00:00 (0 days)..', - 'Backtesting with data from 2017-11-14T21:17:00+00:00 ' - 'up to 2017-11-14T22:58:00+00:00 (0 days)..', + 'Loading data from 2017-11-14 20:57:00 ' + 'up to 2017-11-14 22:58:00 (0 days)..', + 'Backtesting with data from 2017-11-14 21:17:00 ' + 'up to 2017-11-14 22:58:00 (0 days)..', 'Parameter --enable-position-stacking detected ...', 'Running backtesting for Strategy DefaultStrategy', 'Running backtesting for Strategy TestStrategyLegacy', From 5fce7f3b22e50b23944737f60758178a428c133b Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Jun 2020 20:39:55 +0200 Subject: [PATCH 034/285] Add market Change closes #2524 and #3518 --- freqtrade/data/btanalysis.py | 20 ++++++++++++++++++++ freqtrade/optimize/optimize_reports.py | 12 ++++++++---- tests/data/test_btanalysis.py | 9 +++++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index b169850ba..8601f8176 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -168,6 +168,26 @@ def extract_trades_of_period(dataframe: pd.DataFrame, trades: pd.DataFrame, return trades +def calculate_market_change(data: Dict[str, pd.DataFrame], column: str = "close") -> float: + """ + Calculate market change based on "column". + Calculation is done by taking the first non-null and the last non-null element of each column + and calculating the pctchange as "(last - first) / first". + Then the results per pair are combined as mean. + + :param data: Dict of Dataframes, dict key should be pair. + :param column: Column in the original dataframes to use + :return: + """ + tmp_means = [] + for pair, df in data.items(): + start = df[column].dropna().iloc[0] + end = df[column].dropna().iloc[-1] + tmp_means.append((end - start) / start) + + return np.mean(tmp_means) + + def combine_dataframes_with_mean(data: Dict[str, pd.DataFrame], column: str = "close") -> pd.DataFrame: """ diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 1e2d41e32..4ec3dc3ad 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -8,7 +8,7 @@ from pandas import DataFrame from tabulate import tabulate from freqtrade.constants import DATETIME_PRINT_FORMAT -from freqtrade.data.btanalysis import calculate_max_drawdown +from freqtrade.data.btanalysis import calculate_max_drawdown, calculate_market_change from freqtrade.misc import file_dump_json logger = logging.getLogger(__name__) @@ -208,6 +208,8 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], stake_currency = config['stake_currency'] max_open_trades = config['max_open_trades'] result: Dict[str, Any] = {'strategy': {}} + market_change = calculate_market_change(btdata, 'close') + for strategy, results in all_results.items(): pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency, @@ -232,8 +234,9 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'backtest_end': max_date.datetime, 'backtest_end_ts': max_date.timestamp, 'backtest_days': backtest_days, - 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None - } + 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None, + 'market_change': market_change, + } result['strategy'][strategy] = strat_stats try: @@ -348,11 +351,12 @@ def text_table_add_metrics(strategy_results: Dict) -> str: ('Max Drawdown', f"{round(strategy_results['max_drawdown'] * 100, 2)}%"), ('Drawdown Start', strategy_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), ('Drawdown End', strategy_results['drawdown_end'].strftime(DATETIME_PRINT_FORMAT)), + ('Market change', f"{round(strategy_results['market_change'] * 100, 2)}%"), ] return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") else: - return + return '' def show_backtest_results(config: Dict, backtest_stats: Dict): diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index b65db7fd8..d571569b9 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -8,6 +8,7 @@ from pandas import DataFrame, DateOffset, Timestamp, to_datetime from freqtrade.configuration import TimeRange from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, analyze_trade_parallelism, + calculate_market_change, calculate_max_drawdown, combine_dataframes_with_mean, create_cum_profit, @@ -135,6 +136,14 @@ def test_load_trades(default_conf, mocker): assert bt_mock.call_count == 0 +def test_calculate_market_change(testdatadir): + pairs = ["ETH/BTC", "ADA/BTC"] + data = load_data(datadir=testdatadir, pairs=pairs, timeframe='5m') + result = calculate_market_change(data) + assert isinstance(result, float) + assert pytest.approx(result) == 0.00955514 + + def test_combine_dataframes_with_mean(testdatadir): pairs = ["ETH/BTC", "ADA/BTC"] data = load_data(datadir=testdatadir, pairs=pairs, timeframe='5m') From 480c5117f1d41315eb9742bd64b028363b68be13 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 06:47:04 +0200 Subject: [PATCH 035/285] Handle empty return strings --- freqtrade/optimize/optimize_reports.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 4ec3dc3ad..9feb7f20d 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -373,21 +373,21 @@ def show_backtest_results(config: Dict, backtest_stats: Dict): table = text_table_sell_reason(sell_reason_stats=results['sell_reason_summary'], stake_currency=stake_currency) - if isinstance(table, str): + if isinstance(table, str) and len(table) > 0: print(' SELL REASON STATS '.center(len(table.splitlines()[0]), '=')) print(table) table = text_table_bt_results(results['left_open_trades'], stake_currency=stake_currency) - if isinstance(table, str): + if isinstance(table, str) and len(table) > 0: print(' LEFT OPEN TRADES REPORT '.center(len(table.splitlines()[0]), '=')) print(table) table = text_table_add_metrics(results) - if isinstance(table, str): + if isinstance(table, str) and len(table) > 0: print(' SUMMARY METRICS '.center(len(table.splitlines()[0]), '=')) print(table) - if isinstance(table, str): + if isinstance(table, str) and len(table) > 0: print('=' * len(table.splitlines()[0])) print() From 81c8e8677dfa98f18661259389972bd844c111ef Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 06:56:59 +0200 Subject: [PATCH 036/285] use 0 as profit mean, not nan --- freqtrade/optimize/optimize_reports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 9feb7f20d..b334917ba 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -69,8 +69,8 @@ def _generate_result_line(result: DataFrame, max_open_trades: int, first_column: return { 'key': first_column, 'trades': len(result), - 'profit_mean': result['profit_percent'].mean(), - 'profit_mean_pct': result['profit_percent'].mean() * 100.0, + '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_sum': result['profit_percent'].sum(), 'profit_sum_pct': result['profit_percent'].sum() * 100.0, 'profit_total_abs': result['profit_abs'].sum(), From 415853583bf39b3a62a84e24f60bc74b5addae3a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 07:46:59 +0200 Subject: [PATCH 037/285] Save backtest-stats --- freqtrade/data/btanalysis.py | 19 ++++++++++++++++++- freqtrade/optimize/backtesting.py | 6 ++++-- freqtrade/optimize/optimize_reports.py | 21 ++++++++++++++++----- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 8601f8176..ecedc55db 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -3,7 +3,7 @@ Helpers when analyzing backtest data """ import logging from pathlib import Path -from typing import Dict, Union, Tuple +from typing import Dict, Union, Tuple, Any import numpy as np import pandas as pd @@ -20,6 +20,23 @@ BT_DATA_COLUMNS = ["pair", "profit_percent", "open_time", "close_time", "index", "open_rate", "close_rate", "open_at_end", "sell_reason"] +def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]: + """ + Load backtest statistics file. + :param filename: pathlib.Path object, or string pointing to the file. + :return: a dictionary containing the resulting file. + """ + if isinstance(filename, str): + filename = Path(filename) + if not filename.is_file(): + raise ValueError(f"File {filename} does not exist.") + + with filename.open() as file: + data = json_load(file) + + return data + + def load_backtest_data(filename: Union[Path, str]) -> pd.DataFrame: """ Load backtest data file. diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 847434789..e4df80a82 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -11,9 +11,9 @@ from typing import Any, Dict, List, NamedTuple, Optional, Tuple import arrow from pandas import DataFrame -from freqtrade.constants import DATETIME_PRINT_FORMAT 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.converter import trim_dataframe from freqtrade.data.dataprovider import DataProvider @@ -21,7 +21,8 @@ from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds from freqtrade.optimize.optimize_reports import (generate_backtest_stats, show_backtest_results, - store_backtest_result) + store_backtest_result, + store_backtest_stats) from freqtrade.pairlist.pairlistmanager import PairListManager from freqtrade.persistence import Trade from freqtrade.resolvers import ExchangeResolver, StrategyResolver @@ -420,3 +421,4 @@ class Backtesting: stats = generate_backtest_stats(self.config, data, all_results, min_date=min_date, max_date=max_date) show_backtest_results(self.config, stats) + store_backtest_stats(self.config['exportfilename'], stats) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index b334917ba..3c0bfcb96 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -14,6 +14,18 @@ from freqtrade.misc import file_dump_json logger = logging.getLogger(__name__) +def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> None: + + filename = Path.joinpath(recordfilename.parent, + f'{recordfilename.stem}-{datetime.now().isoformat()}' + ).with_suffix(recordfilename.suffix) + file_dump_json(filename, stats) + + latest_filename = Path.joinpath(recordfilename.parent, + '.last_result.json') + file_dump_json(latest_filename, {'latest_backtest': str(filename.name)}) + + def store_backtest_result(recordfilename: Path, all_results: Dict[str, DataFrame]) -> None: """ Stores backtest results to file (one file per strategy) @@ -224,7 +236,7 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], backtest_days = (max_date - min_date).days strat_stats = { - 'trades': backtest_result_to_list(results), + 'trades': results.to_dict(orient='records'), 'results_per_pair': pair_results, 'sell_reason_summary': sell_reason_stats, 'left_open_trades': left_open_results, @@ -338,12 +350,11 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: def text_table_add_metrics(strategy_results: Dict) -> str: if len(strategy_results['trades']) > 0: - min_trade = min(strategy_results['trades'], key=lambda x: x[2]) + min_trade = min(strategy_results['trades'], key=lambda x: x['open_time']) metrics = [ ('Total trades', strategy_results['total_trades']), - ('First trade', datetime.fromtimestamp(min_trade[2], - tz=timezone.utc).strftime(DATETIME_PRINT_FORMAT)), - ('First trade Pair', min_trade[0]), + ('First trade', min_trade['open_time'].strftime(DATETIME_PRINT_FORMAT)), + ('First trade Pair', min_trade['pair']), ('Backtesting from', strategy_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strategy_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Trades per day', strategy_results['trades_per_day']), From b068e7c564021ba178c969602461e9d3f57d1790 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 09:19:44 +0200 Subject: [PATCH 038/285] Rename open_time and close_time to *date --- freqtrade/data/btanalysis.py | 28 +++++++++---------- freqtrade/edge/edge_positioning.py | 6 ++-- freqtrade/optimize/backtesting.py | 19 +++++++------ .../optimize/hyperopt_loss_sharpe_daily.py | 2 +- .../optimize/hyperopt_loss_sortino_daily.py | 2 +- freqtrade/optimize/optimize_reports.py | 8 +++--- freqtrade/plot/plotting.py | 10 +++---- 7 files changed, 38 insertions(+), 37 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index ecedc55db..f174b8ea9 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -16,7 +16,7 @@ from freqtrade.persistence import Trade logger = logging.getLogger(__name__) # must align with columns in backtest.py -BT_DATA_COLUMNS = ["pair", "profit_percent", "open_time", "close_time", "index", "duration", +BT_DATA_COLUMNS = ["pair", "profit_percent", "open_date", "close_date", "index", "duration", "open_rate", "close_rate", "open_at_end", "sell_reason"] @@ -54,18 +54,18 @@ def load_backtest_data(filename: Union[Path, str]) -> pd.DataFrame: df = pd.DataFrame(data, columns=BT_DATA_COLUMNS) - df['open_time'] = pd.to_datetime(df['open_time'], + df['open_date'] = pd.to_datetime(df['open_date'], unit='s', utc=True, infer_datetime_format=True ) - df['close_time'] = pd.to_datetime(df['close_time'], + df['close_date'] = pd.to_datetime(df['close_date'], unit='s', utc=True, infer_datetime_format=True ) df['profit'] = df['close_rate'] - df['open_rate'] - df = df.sort_values("open_time").reset_index(drop=True) + df = df.sort_values("open_date").reset_index(drop=True) return df @@ -79,9 +79,9 @@ def analyze_trade_parallelism(results: pd.DataFrame, timeframe: str) -> pd.DataF """ from freqtrade.exchange import timeframe_to_minutes timeframe_min = timeframe_to_minutes(timeframe) - dates = [pd.Series(pd.date_range(row[1].open_time, row[1].close_time, + dates = [pd.Series(pd.date_range(row[1]['open_date'], row[1]['close_date'], freq=f"{timeframe_min}min")) - for row in results[['open_time', 'close_time']].iterrows()] + for row in results[['open_date', 'close_date']].iterrows()] deltas = [len(x) for x in dates] dates = pd.Series(pd.concat(dates).values, name='date') df2 = pd.DataFrame(np.repeat(results.values, deltas, axis=0), columns=results.columns) @@ -116,7 +116,7 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: trades: pd.DataFrame = pd.DataFrame([], columns=BT_DATA_COLUMNS) persistence.init(db_url, clean_open_orders=False) - columns = ["pair", "open_time", "close_time", "profit", "profit_percent", + columns = ["pair", "open_date", "close_date", "profit", "profit_percent", "open_rate", "close_rate", "amount", "duration", "sell_reason", "fee_open", "fee_close", "open_rate_requested", "close_rate_requested", "stake_amount", "max_rate", "min_rate", "id", "exchange", @@ -180,8 +180,8 @@ def extract_trades_of_period(dataframe: pd.DataFrame, trades: pd.DataFrame, else: trades_start = dataframe.iloc[0]['date'] trades_stop = dataframe.iloc[-1]['date'] - trades = trades.loc[(trades['open_time'] >= trades_start) & - (trades['close_time'] <= trades_stop)] + trades = trades.loc[(trades['open_date'] >= trades_start) & + (trades['close_date'] <= trades_stop)] return trades @@ -227,7 +227,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_time and profit_percent) + :param trades: DataFrame containing trades (requires columns close_date and profit_percent) :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. @@ -238,7 +238,7 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, from freqtrade.exchange import timeframe_to_minutes 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_time' + _trades_sum = trades.resample(f'{timeframe_minutes}min', on='close_date' )[['profit_percent']].sum() df.loc[:, col_name] = _trades_sum.cumsum() # Set first value to 0 @@ -248,13 +248,13 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, return df -def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_time', +def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date', value_col: str = 'profit_percent' ) -> Tuple[float, pd.Timestamp, pd.Timestamp]: """ Calculate max drawdown and the corresponding close dates - :param trades: DataFrame containing trades (requires columns close_time and profit_percent) - :param date_col: Column in DataFrame to use for dates (defaults to 'close_time') + :param trades: DataFrame containing trades (requires columns close_date and profit_percent) + :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') :return: Tuple (float, highdate, lowdate) with absolute max drawdown, high and low time :raise: ValueError if trade-dataframe was found empty. diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index dd2f44f23..169732314 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -237,7 +237,7 @@ class Edge: # All returned values are relative, they are defined as ratios. stake = 0.015 - result['trade_duration'] = result['close_time'] - result['open_time'] + result['trade_duration'] = result['close_date'] - result['open_date'] result['trade_duration'] = result['trade_duration'].map( lambda x: int(x.total_seconds() / 60)) @@ -427,8 +427,8 @@ class Edge: 'stoploss': stoploss, 'profit_ratio': '', 'profit_abs': '', - 'open_time': date_column[open_trade_index], - 'close_time': date_column[exit_index], + 'open_date': date_column[open_trade_index], + 'close_date': date_column[exit_index], 'open_index': start_point + open_trade_index, 'close_index': start_point + exit_index, 'trade_duration': '', diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index e4df80a82..4197ec087 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -39,8 +39,8 @@ class BacktestResult(NamedTuple): pair: str profit_percent: float profit_abs: float - open_time: datetime - close_time: datetime + open_date: datetime + close_date: datetime open_index: int close_index: int trade_duration: float @@ -248,8 +248,8 @@ class Backtesting: return BacktestResult(pair=pair, profit_percent=trade.calc_profit_ratio(rate=closerate), profit_abs=trade.calc_profit(rate=closerate), - open_time=buy_row.date, - close_time=sell_row.date, + open_date=buy_row.date, + close_date=sell_row.date, trade_duration=trade_dur, open_index=buy_row.Index, close_index=sell_row.Index, @@ -264,8 +264,8 @@ class Backtesting: bt_res = BacktestResult(pair=pair, profit_percent=trade.calc_profit_ratio(rate=sell_row.open), profit_abs=trade.calc_profit(rate=sell_row.open), - open_time=buy_row.date, - close_time=sell_row.date, + open_date=buy_row.date, + close_date=sell_row.date, trade_duration=int(( sell_row.date - buy_row.date).total_seconds() // 60), open_index=buy_row.Index, @@ -358,8 +358,8 @@ class Backtesting: if trade_entry: logger.debug(f"{pair} - Locking pair till " - f"close_time={trade_entry.close_time}") - lock_pair_until[pair] = trade_entry.close_time + f"close_date={trade_entry.close_date}") + lock_pair_until[pair] = trade_entry.close_date trades.append(trade_entry) else: # Set lock_pair_until to end of testing period if trade could not be closed @@ -421,4 +421,5 @@ class Backtesting: stats = generate_backtest_stats(self.config, data, all_results, min_date=min_date, max_date=max_date) show_backtest_results(self.config, stats) - store_backtest_stats(self.config['exportfilename'], stats) + if self.config.get('export', False): + store_backtest_stats(self.config['exportfilename'], stats) diff --git a/freqtrade/optimize/hyperopt_loss_sharpe_daily.py b/freqtrade/optimize/hyperopt_loss_sharpe_daily.py index e4cd1d749..bcba73a7f 100644 --- a/freqtrade/optimize/hyperopt_loss_sharpe_daily.py +++ b/freqtrade/optimize/hyperopt_loss_sharpe_daily.py @@ -43,7 +43,7 @@ class SharpeHyperOptLossDaily(IHyperOptLoss): normalize=True) sum_daily = ( - results.resample(resample_freq, on='close_time').agg( + results.resample(resample_freq, on='close_date').agg( {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0) ) diff --git a/freqtrade/optimize/hyperopt_loss_sortino_daily.py b/freqtrade/optimize/hyperopt_loss_sortino_daily.py index cd6a8bcc2..3b099a253 100644 --- a/freqtrade/optimize/hyperopt_loss_sortino_daily.py +++ b/freqtrade/optimize/hyperopt_loss_sortino_daily.py @@ -45,7 +45,7 @@ class SortinoHyperOptLossDaily(IHyperOptLoss): normalize=True) sum_daily = ( - results.resample(resample_freq, on='close_time').agg( + results.resample(resample_freq, on='close_date').agg( {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0) ) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 3c0bfcb96..63c2d2022 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -52,8 +52,8 @@ def backtest_result_to_list(results: DataFrame) -> List[List]: :param results: Dataframe containing results for one strategy :return: List of Lists containing the trades """ - return [[t.pair, t.profit_percent, t.open_time.timestamp(), - t.close_time.timestamp(), t.open_index - 1, t.trade_duration, + return [[t.pair, t.profit_percent, t.open_date.timestamp(), + t.open_date.timestamp(), t.open_index - 1, t.trade_duration, t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value] for index, t in results.iterrows()] @@ -350,10 +350,10 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: def text_table_add_metrics(strategy_results: Dict) -> str: if len(strategy_results['trades']) > 0: - min_trade = min(strategy_results['trades'], key=lambda x: x['open_time']) + min_trade = min(strategy_results['trades'], key=lambda x: x['open_date']) metrics = [ ('Total trades', strategy_results['total_trades']), - ('First trade', min_trade['open_time'].strftime(DATETIME_PRINT_FORMAT)), + ('First trade', min_trade['open_date'].strftime(DATETIME_PRINT_FORMAT)), ('First trade Pair', min_trade['pair']), ('Backtesting from', strategy_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strategy_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index e8b0b4938..6d50defaf 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -63,7 +63,7 @@ def init_plotscript(config): exportfilename=config.get('exportfilename'), no_trades=no_trades ) - trades = trim_dataframe(trades, timerange, 'open_time') + trades = trim_dataframe(trades, timerange, 'open_date') return {"ohlcv": data, "trades": trades, @@ -166,7 +166,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: f"{row['sell_reason']}, {row['duration']} min", axis=1) trade_buys = go.Scatter( - x=trades["open_time"], + x=trades["open_date"], y=trades["open_rate"], mode='markers', name='Trade buy', @@ -181,7 +181,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: ) trade_sells = go.Scatter( - x=trades.loc[trades['profit_percent'] > 0, "close_time"], + 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"], mode='markers', @@ -194,7 +194,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: ) ) trade_sells_loss = go.Scatter( - x=trades.loc[trades['profit_percent'] <= 0, "close_time"], + 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"], mode='markers', @@ -506,7 +506,7 @@ def plot_profit(config: Dict[str, Any]) -> None: # Remove open pairs - we don't know the profit yet so can't calculate profit for these. # Also, If only one open pair is left, then the profit-generation would fail. trades = trades[(trades['pair'].isin(plot_elements["pairs"])) - & (~trades['close_time'].isnull()) + & (~trades['close_date'].isnull()) ] if len(trades) == 0: raise OperationalException("No trades found, cannot generate Profit-plot without " From 28817187331fd7d84a55aa69cc38504263f43c0d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 09:21:28 +0200 Subject: [PATCH 039/285] Adapt tests for new column names --- tests/data/test_btanalysis.py | 24 ++++++++++++------------ tests/edge/test_edge.py | 16 ++++++++-------- tests/optimize/test_backtest_detail.py | 4 ++-- tests/optimize/test_backtesting.py | 16 ++++++++-------- tests/optimize/test_hyperopt.py | 2 +- tests/optimize/test_optimize_reports.py | 4 ++-- tests/test_plotting.py | 2 +- 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index d571569b9..077db19f1 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -47,7 +47,7 @@ def test_load_trades_from_db(default_conf, fee, mocker): assert len(trades) == 3 assert isinstance(trades, DataFrame) assert "pair" in trades.columns - assert "open_time" in trades.columns + assert "open_date" in trades.columns assert "profit_percent" in trades.columns for col in BT_DATA_COLUMNS: @@ -67,13 +67,13 @@ def test_extract_trades_of_period(testdatadir): {'pair': [pair, pair, pair, pair], 'profit_percent': [0.0, 0.1, -0.2, -0.5], 'profit_abs': [0.0, 1, -2, -5], - 'open_time': to_datetime([Arrow(2017, 11, 13, 15, 40, 0).datetime, + 'open_date': to_datetime([Arrow(2017, 11, 13, 15, 40, 0).datetime, Arrow(2017, 11, 14, 9, 41, 0).datetime, Arrow(2017, 11, 14, 14, 20, 0).datetime, Arrow(2017, 11, 15, 3, 40, 0).datetime, ], utc=True ), - 'close_time': to_datetime([Arrow(2017, 11, 13, 16, 40, 0).datetime, + 'close_date': to_datetime([Arrow(2017, 11, 13, 16, 40, 0).datetime, Arrow(2017, 11, 14, 10, 41, 0).datetime, Arrow(2017, 11, 14, 15, 25, 0).datetime, Arrow(2017, 11, 15, 3, 55, 0).datetime, @@ -82,10 +82,10 @@ def test_extract_trades_of_period(testdatadir): trades1 = extract_trades_of_period(data, trades) # First and last trade are dropped as they are out of range assert len(trades1) == 2 - assert trades1.iloc[0].open_time == Arrow(2017, 11, 14, 9, 41, 0).datetime - assert trades1.iloc[0].close_time == Arrow(2017, 11, 14, 10, 41, 0).datetime - assert trades1.iloc[-1].open_time == Arrow(2017, 11, 14, 14, 20, 0).datetime - assert trades1.iloc[-1].close_time == Arrow(2017, 11, 14, 15, 25, 0).datetime + assert trades1.iloc[0].open_date == Arrow(2017, 11, 14, 9, 41, 0).datetime + assert trades1.iloc[0].close_date == Arrow(2017, 11, 14, 10, 41, 0).datetime + assert trades1.iloc[-1].open_date == Arrow(2017, 11, 14, 14, 20, 0).datetime + assert trades1.iloc[-1].close_date == Arrow(2017, 11, 14, 15, 25, 0).datetime def test_analyze_trade_parallelism(default_conf, mocker, testdatadir): @@ -174,7 +174,7 @@ def test_create_cum_profit1(testdatadir): filename = testdatadir / "backtest-result_test.json" bt_data = load_backtest_data(filename) # Move close-time to "off" the candle, to make sure the logic still works - bt_data.loc[:, 'close_time'] = bt_data.loc[:, 'close_time'] + DateOffset(seconds=20) + bt_data.loc[:, 'close_date'] = bt_data.loc[:, 'close_date'] + DateOffset(seconds=20) timerange = TimeRange.parse_timerange("20180110-20180112") df = load_pair_history(pair="TRX/BTC", timeframe='5m', @@ -213,11 +213,11 @@ def test_calculate_max_drawdown2(): -0.033961, 0.010680, 0.010886, -0.029274, 0.011178, 0.010693, 0.010711] dates = [Arrow(2020, 1, 1).shift(days=i) for i in range(len(values))] - df = DataFrame(zip(values, dates), columns=['profit', 'open_time']) + df = DataFrame(zip(values, dates), columns=['profit', 'open_date']) # sort by profit and reset index df = df.sort_values('profit').reset_index(drop=True) df1 = df.copy() - drawdown, h, low = calculate_max_drawdown(df, date_col='open_time', value_col='profit') + drawdown, h, low = calculate_max_drawdown(df, date_col='open_date', value_col='profit') # Ensure df has not been altered. assert df.equals(df1) @@ -226,6 +226,6 @@ def test_calculate_max_drawdown2(): assert h < low assert drawdown == 0.091755 - df = DataFrame(zip(values[:5], dates[:5]), columns=['profit', 'open_time']) + df = DataFrame(zip(values[:5], dates[:5]), columns=['profit', 'open_date']) with pytest.raises(ValueError, match='No losing trade, therefore no drawdown.'): - calculate_max_drawdown(df, date_col='open_time', value_col='profit') + calculate_max_drawdown(df, date_col='open_date', value_col='profit') diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index cf9cb6fe1..ea1e709a2 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -163,8 +163,8 @@ def test_edge_results(edge_conf, mocker, caplog, data) -> None: for c, trade in enumerate(data.trades): res = results.iloc[c] assert res.exit_type == trade.sell_reason - assert res.open_time == _get_frame_time_from_offset(trade.open_tick).replace(tzinfo=None) - assert res.close_time == _get_frame_time_from_offset(trade.close_tick).replace(tzinfo=None) + assert res.open_date == _get_frame_time_from_offset(trade.open_tick).replace(tzinfo=None) + assert res.close_date == _get_frame_time_from_offset(trade.close_tick).replace(tzinfo=None) def test_adjust(mocker, edge_conf): @@ -354,8 +354,8 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:05:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:10:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:05:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:10:00.000000000'), 'open_index': 1, 'close_index': 1, 'trade_duration': '', @@ -367,8 +367,8 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:20:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:25:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:20:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:25:00.000000000'), 'open_index': 4, 'close_index': 4, 'trade_duration': '', @@ -380,8 +380,8 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:30:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:40:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:30:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:40:00.000000000'), 'open_index': 6, 'close_index': 7, 'trade_duration': '', diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index 9b3043086..f6ac95aeb 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -395,5 +395,5 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None: for c, trade in enumerate(data.trades): res = results.iloc[c] assert res.sell_reason == trade.sell_reason - assert res.open_time == _get_frame_time_from_offset(trade.open_tick) - assert res.close_time == _get_frame_time_from_offset(trade.close_tick) + assert res.open_date == _get_frame_time_from_offset(trade.open_tick) + assert res.close_date == _get_frame_time_from_offset(trade.close_tick) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 853780b82..e7a13f251 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -459,10 +459,10 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: {'pair': [pair, pair], 'profit_percent': [0.0, 0.0], 'profit_abs': [0.0, 0.0], - 'open_time': pd.to_datetime([Arrow(2018, 1, 29, 18, 40, 0).datetime, + 'open_date': pd.to_datetime([Arrow(2018, 1, 29, 18, 40, 0).datetime, Arrow(2018, 1, 30, 3, 30, 0).datetime], utc=True ), - 'close_time': pd.to_datetime([Arrow(2018, 1, 29, 22, 35, 0).datetime, + 'close_date': pd.to_datetime([Arrow(2018, 1, 29, 22, 35, 0).datetime, Arrow(2018, 1, 30, 4, 10, 0).datetime], utc=True), 'open_index': [78, 184], 'close_index': [125, 192], @@ -475,12 +475,12 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: pd.testing.assert_frame_equal(results, expected) data_pair = processed[pair] for _, t in results.iterrows(): - ln = data_pair.loc[data_pair["date"] == t["open_time"]] + ln = data_pair.loc[data_pair["date"] == t["open_date"]] # Check open trade rate alignes to open rate assert ln is not None assert round(ln.iloc[0]["open"], 6) == round(t["open_rate"], 6) # check close trade rate alignes to close rate or is between high and low - ln = data_pair.loc[data_pair["date"] == t["close_time"]] + ln = data_pair.loc[data_pair["date"] == t["close_date"]] assert (round(ln.iloc[0]["open"], 6) == round(t["close_rate"], 6) or round(ln.iloc[0]["low"], 6) < round( t["close_rate"], 6) < round(ln.iloc[0]["high"], 6)) @@ -756,10 +756,10 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC'], 'profit_percent': [0.0, 0.0], 'profit_abs': [0.0, 0.0], - 'open_time': pd.to_datetime(['2018-01-29 18:40:00', + 'open_date': pd.to_datetime(['2018-01-29 18:40:00', '2018-01-30 03:30:00', ], utc=True ), - 'close_time': pd.to_datetime(['2018-01-29 20:45:00', + 'close_date': pd.to_datetime(['2018-01-29 20:45:00', '2018-01-30 05:35:00', ], utc=True), 'open_index': [78, 184], 'close_index': [125, 192], @@ -772,11 +772,11 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat pd.DataFrame({'pair': ['XRP/BTC', 'LTC/BTC', 'ETH/BTC'], 'profit_percent': [0.03, 0.01, 0.1], 'profit_abs': [0.01, 0.02, 0.2], - 'open_time': pd.to_datetime(['2018-01-29 18:40:00', + 'open_date': pd.to_datetime(['2018-01-29 18:40:00', '2018-01-30 03:30:00', '2018-01-30 05:30:00'], utc=True ), - 'close_time': pd.to_datetime(['2018-01-29 20:45:00', + 'close_date': pd.to_datetime(['2018-01-29 20:45:00', '2018-01-30 05:35:00', '2018-01-30 08:30:00'], utc=True), 'open_index': [78, 184, 185], diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 564725709..00edd8ad2 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -46,7 +46,7 @@ def hyperopt_results(): 'profit_abs': [-0.2, 0.4, 0.6], 'trade_duration': [10, 30, 10], 'sell_reason': [SellType.STOP_LOSS, SellType.ROI, SellType.ROI], - 'close_time': + 'close_date': [ datetime(2019, 1, 1, 9, 26, 3, 478039), datetime(2019, 2, 1, 9, 26, 3, 478039), diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 175405e4c..7efd87787 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -204,11 +204,11 @@ def test_backtest_record(default_conf, fee, mocker): "UNITTEST/BTC", "UNITTEST/BTC"], "profit_percent": [0.003312, 0.010801, 0.013803, 0.002780], "profit_abs": [0.000003, 0.000011, 0.000014, 0.000003], - "open_time": [Arrow(2017, 11, 14, 19, 32, 00).datetime, + "open_date": [Arrow(2017, 11, 14, 19, 32, 00).datetime, Arrow(2017, 11, 14, 21, 36, 00).datetime, Arrow(2017, 11, 14, 22, 12, 00).datetime, Arrow(2017, 11, 14, 22, 44, 00).datetime], - "close_time": [Arrow(2017, 11, 14, 21, 35, 00).datetime, + "close_date": [Arrow(2017, 11, 14, 21, 35, 00).datetime, Arrow(2017, 11, 14, 22, 10, 00).datetime, Arrow(2017, 11, 14, 22, 43, 00).datetime, Arrow(2017, 11, 14, 22, 58, 00).datetime], diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 05805eb24..83a41deeb 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -267,7 +267,7 @@ def test_generate_profit_graph(testdatadir): trades = load_backtest_data(filename) timerange = TimeRange.parse_timerange("20180110-20180112") pairs = ["TRX/BTC", "XLM/BTC"] - trades = trades[trades['close_time'] < pd.Timestamp('2018-01-12', tz='UTC')] + trades = trades[trades['close_date'] < pd.Timestamp('2018-01-12', tz='UTC')] data = history.load_data(datadir=testdatadir, pairs=pairs, From 04cbc2cde5a832119db5c95b75e720974794fa5d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 09:22:50 +0200 Subject: [PATCH 040/285] Shorten variable --- freqtrade/optimize/optimize_reports.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 63c2d2022..de609589a 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -1,5 +1,5 @@ import logging -from datetime import datetime, timedelta, timezone +from datetime import datetime, timedelta from pathlib import Path from typing import Any, Dict, List @@ -348,21 +348,21 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") -def text_table_add_metrics(strategy_results: Dict) -> str: - if len(strategy_results['trades']) > 0: - min_trade = min(strategy_results['trades'], key=lambda x: x['open_date']) +def text_table_add_metrics(strat_results: Dict) -> str: + if len(strat_results['trades']) > 0: + min_trade = min(strat_results['trades'], key=lambda x: x['open_date']) metrics = [ - ('Total trades', strategy_results['total_trades']), + ('Total trades', strat_results['total_trades']), ('First trade', min_trade['open_date'].strftime(DATETIME_PRINT_FORMAT)), ('First trade Pair', min_trade['pair']), - ('Backtesting from', strategy_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), - ('Backtesting to', strategy_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), - ('Trades per day', strategy_results['trades_per_day']), + ('Backtesting from', strat_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), + ('Backtesting to', strat_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), + ('Trades per day', strat_results['trades_per_day']), ('', ''), # Empty line to improve readability - ('Max Drawdown', f"{round(strategy_results['max_drawdown'] * 100, 2)}%"), - ('Drawdown Start', strategy_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), - ('Drawdown End', strategy_results['drawdown_end'].strftime(DATETIME_PRINT_FORMAT)), - ('Market change', f"{round(strategy_results['market_change'] * 100, 2)}%"), + ('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)), + ('Market change', f"{round(strat_results['market_change'] * 100, 2)}%"), ] return tabulate(metrics, headers=["Metric", "Value"], tablefmt="orgtbl") From 0fa56be9d2a06fcc11b4f9bcdfa5b3564315539d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 09:27:07 +0200 Subject: [PATCH 041/285] remove openIndex and closeIndex from backtest-report --- freqtrade/edge/edge_positioning.py | 2 -- freqtrade/optimize/backtesting.py | 6 ------ freqtrade/optimize/optimize_reports.py | 4 +++- tests/edge/test_edge.py | 6 ------ tests/optimize/test_backtesting.py | 6 ------ tests/optimize/test_optimize_reports.py | 2 -- 6 files changed, 3 insertions(+), 23 deletions(-) diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index 169732314..9843d4e83 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -429,8 +429,6 @@ class Edge: 'profit_abs': '', 'open_date': date_column[open_trade_index], 'close_date': date_column[exit_index], - 'open_index': start_point + open_trade_index, - 'close_index': start_point + exit_index, 'trade_duration': '', 'open_rate': round(open_price, 15), 'close_rate': round(exit_price, 15), diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 4197ec087..1eef4f4b9 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -41,8 +41,6 @@ class BacktestResult(NamedTuple): profit_abs: float open_date: datetime close_date: datetime - open_index: int - close_index: int trade_duration: float open_at_end: bool open_rate: float @@ -251,8 +249,6 @@ class Backtesting: open_date=buy_row.date, close_date=sell_row.date, trade_duration=trade_dur, - open_index=buy_row.Index, - close_index=sell_row.Index, open_at_end=False, open_rate=buy_row.open, close_rate=closerate, @@ -268,8 +264,6 @@ class Backtesting: close_date=sell_row.date, trade_duration=int(( sell_row.date - buy_row.date).total_seconds() // 60), - open_index=buy_row.Index, - close_index=sell_row.Index, open_at_end=True, open_rate=buy_row.open, close_rate=sell_row.open, diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index de609589a..8f9104640 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -52,8 +52,10 @@ def backtest_result_to_list(results: DataFrame) -> List[List]: :param results: Dataframe containing results for one strategy :return: List of Lists containing the trades """ + # Return 0 as "index" for compatibility reasons (for now) + # TODO: Evaluate if we can remove this return [[t.pair, t.profit_percent, t.open_date.timestamp(), - t.open_date.timestamp(), t.open_index - 1, t.trade_duration, + t.open_date.timestamp(), 0, t.trade_duration, t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value] for index, t in results.iterrows()] diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index ea1e709a2..cd5f623e3 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -356,8 +356,6 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc 'profit_abs': '', 'open_date': np.datetime64('2018-10-03T00:05:00.000000000'), 'close_date': np.datetime64('2018-10-03T00:10:00.000000000'), - 'open_index': 1, - 'close_index': 1, 'trade_duration': '', 'open_rate': 17, 'close_rate': 17, @@ -369,8 +367,6 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc 'profit_abs': '', 'open_date': np.datetime64('2018-10-03T00:20:00.000000000'), 'close_date': np.datetime64('2018-10-03T00:25:00.000000000'), - 'open_index': 4, - 'close_index': 4, 'trade_duration': '', 'open_rate': 20, 'close_rate': 20, @@ -382,8 +378,6 @@ def test_process_expectancy(mocker, edge_conf, fee, risk_reward_ratio, expectanc 'profit_abs': '', 'open_date': np.datetime64('2018-10-03T00:30:00.000000000'), 'close_date': np.datetime64('2018-10-03T00:40:00.000000000'), - 'open_index': 6, - 'close_index': 7, 'trade_duration': '', 'open_rate': 26, 'close_rate': 34, diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index e7a13f251..c0a9e798a 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -464,8 +464,6 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: ), 'close_date': pd.to_datetime([Arrow(2018, 1, 29, 22, 35, 0).datetime, Arrow(2018, 1, 30, 4, 10, 0).datetime], utc=True), - 'open_index': [78, 184], - 'close_index': [125, 192], 'trade_duration': [235, 40], 'open_at_end': [False, False], 'open_rate': [0.104445, 0.10302485], @@ -761,8 +759,6 @@ 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), - 'open_index': [78, 184], - 'close_index': [125, 192], 'trade_duration': [235, 40], 'open_at_end': [False, False], 'open_rate': [0.104445, 0.10302485], @@ -779,8 +775,6 @@ 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', '2018-01-30 08:30:00'], utc=True), - 'open_index': [78, 184, 185], - 'close_index': [125, 224, 205], 'trade_duration': [47, 40, 20], 'open_at_end': [False, False, False], 'open_rate': [0.104445, 0.10302485, 0.122541], diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 7efd87787..9f06043cc 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -214,8 +214,6 @@ def test_backtest_record(default_conf, fee, mocker): Arrow(2017, 11, 14, 22, 58, 00).datetime], "open_rate": [0.002543, 0.003003, 0.003089, 0.003214], "close_rate": [0.002546, 0.003014, 0.003103, 0.003217], - "open_index": [1, 119, 153, 185], - "close_index": [118, 151, 184, 199], "trade_duration": [123, 34, 31, 14], "open_at_end": [False, False, False, True], "sell_reason": [SellType.ROI, SellType.STOP_LOSS, From dacb40a9765249c949beb1e07ce57db1915b7eb2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 09:34:18 +0200 Subject: [PATCH 042/285] Add get_latest_backtest_filename --- freqtrade/data/btanalysis.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index f174b8ea9..89380059f 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -20,6 +20,34 @@ BT_DATA_COLUMNS = ["pair", "profit_percent", "open_date", "close_date", "index", "open_rate", "close_rate", "open_at_end", "sell_reason"] +def get_latest_backtest_filename(directory: Union[Path, str]) -> str: + """ + Get latest backtest export based on '.last_result.json'. + :param directory: Directory to search for last result + :return: string containing the filename of the latest backtest result + :raises: ValueError in the following cases: + * Directory does not exist + * `directory/.last_result.json` does not exist + * `directory/.last_result.json` has the wrong content + """ + if isinstance(directory, str): + directory = Path(directory) + if not directory.is_dir(): + raise ValueError(f"Directory {directory} does not exist.") + filename = directory / '.last_result.json' + + if not filename.is_file(): + raise ValueError(f"Directory {directory} does not seem to contain backtest statistics yet.") + + with filename.open() as file: + data = json_load(file) + + if 'latest_backtest' not in data: + raise ValueError("Invalid .last_result.json format") + + return data['latest_backtest'] + + def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]: """ Load backtest statistics file. From 075eb0a161496a59d067ef4385ffc51997d4e87a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 19:20:51 +0200 Subject: [PATCH 043/285] Fix sequence of saving --- freqtrade/optimize/backtesting.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 1eef4f4b9..30418f0d7 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -409,11 +409,11 @@ class Backtesting: position_stacking=position_stacking, ) - if self.config.get('export', False): - store_backtest_result(self.config['exportfilename'], all_results) - # Show backtest results stats = generate_backtest_stats(self.config, data, all_results, min_date=min_date, max_date=max_date) - show_backtest_results(self.config, stats) if self.config.get('export', False): + store_backtest_result(self.config['exportfilename'], all_results) store_backtest_stats(self.config['exportfilename'], stats) + + # Show backtest results + show_backtest_results(self.config, stats) From af9a9592b78330925c4bd640b3280fdd4a96caff Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 19:32:47 +0200 Subject: [PATCH 044/285] Remove unnecessary statement --- freqtrade/data/btanalysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 89380059f..d6af67a32 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -141,7 +141,6 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: :param db_url: Sqlite url (default format sqlite:///tradesv3.dry-run.sqlite) :return: Dataframe containing Trades """ - trades: pd.DataFrame = pd.DataFrame([], columns=BT_DATA_COLUMNS) persistence.init(db_url, clean_open_orders=False) columns = ["pair", "open_date", "close_date", "profit", "profit_percent", From 03ab61959b6f0a53f74c50ca52190e96677ea45b Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 20:08:45 +0200 Subject: [PATCH 045/285] Add test for generate_backtest_stats --- freqtrade/optimize/optimize_reports.py | 10 +-- tests/optimize/test_optimize_reports.py | 81 +++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 8f9104640..d1c58617d 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -1,5 +1,5 @@ import logging -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Any, Dict, List @@ -266,10 +266,10 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], except ValueError: strat_stats.update({ 'max_drawdown': 0.0, - 'drawdown_start': datetime.min, - 'drawdown_start_ts': datetime(1970, 1, 1).timestamp(), - 'drawdown_end': datetime.min, - 'drawdown_end_ts': datetime(1970, 1, 1).timestamp(), + 'drawdown_start': datetime(1970, 1, 1, tzinfo=timezone.utc), + 'drawdown_start_ts': 0, + 'drawdown_end': datetime(1970, 1, 1, tzinfo=timezone.utc), + 'drawdown_end_ts': 0, }) strategy_results = generate_strategy_metrics(stake_currency=stake_currency, diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 9f06043cc..c46b96ab2 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -1,14 +1,22 @@ +from datetime import datetime from pathlib import Path import pandas as pd import pytest from arrow import Arrow +from freqtrade.configuration import TimeRange +from freqtrade.data import history from freqtrade.edge import PairInfo -from freqtrade.optimize.optimize_reports import ( - generate_pair_metrics, generate_edge_table, generate_sell_reason_stats, - text_table_bt_results, text_table_sell_reason, generate_strategy_metrics, - text_table_strategy, store_backtest_result) +from freqtrade.optimize.optimize_reports import (generate_backtest_stats, + generate_edge_table, + generate_pair_metrics, + generate_sell_reason_stats, + generate_strategy_metrics, + store_backtest_result, + text_table_bt_results, + text_table_sell_reason, + text_table_strategy) from freqtrade.strategy.interface import SellType from tests.conftest import patch_exchange @@ -43,6 +51,71 @@ def test_text_table_bt_results(default_conf, mocker): assert text_table_bt_results(pair_results, stake_currency='BTC') == result_str +def test_generate_backtest_stats(default_conf, testdatadir): + results = {'DefStrat': pd.DataFrame({"pair": ["UNITTEST/BTC", "UNITTEST/BTC", + "UNITTEST/BTC", "UNITTEST/BTC"], + "profit_percent": [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, + Arrow(2017, 11, 14, 22, 12, 00).datetime, + Arrow(2017, 11, 14, 22, 44, 00).datetime], + "close_date": [Arrow(2017, 11, 14, 21, 35, 00).datetime, + Arrow(2017, 11, 14, 22, 10, 00).datetime, + Arrow(2017, 11, 14, 22, 43, 00).datetime, + Arrow(2017, 11, 14, 22, 58, 00).datetime], + "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], + "sell_reason": [SellType.ROI, SellType.STOP_LOSS, + SellType.ROI, SellType.FORCE_SELL] + })} + timerange = TimeRange.parse_timerange('1510688220-1510700340') + min_date = Arrow.fromtimestamp(1510688220) + max_date = Arrow.fromtimestamp(1510700340) + btdata = history.load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange, + fill_up_missing=True) + + stats = generate_backtest_stats(default_conf, btdata, results, min_date, max_date) + assert isinstance(stats, dict) + assert 'strategy' in stats + assert 'DefStrat' in stats['strategy'] + assert 'strategy_comparison' in stats + strat_stats = stats['strategy']['DefStrat'] + assert strat_stats['backtest_start'] == min_date.datetime + assert strat_stats['backtest_end'] == max_date.datetime + assert strat_stats['total_trades'] == len(results['DefStrat']) + # Above sample had no loosing trade + assert strat_stats['max_drawdown'] == 0.0 + + results = {'DefStrat': pd.DataFrame({"pair": ["UNITTEST/BTC", "UNITTEST/BTC", + "UNITTEST/BTC", "UNITTEST/BTC"], + "profit_percent": [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, + Arrow(2017, 11, 14, 22, 12, 00).datetime, + Arrow(2017, 11, 14, 22, 44, 00).datetime], + "close_date": [Arrow(2017, 11, 14, 21, 35, 00).datetime, + Arrow(2017, 11, 14, 22, 10, 00).datetime, + Arrow(2017, 11, 14, 22, 43, 00).datetime, + Arrow(2017, 11, 14, 22, 58, 00).datetime], + "open_rate": [0.002543, 0.003003, 0.003089, 0.003214], + "close_rate": [0.002546, 0.003014, 0.0032903, 0.003217], + "trade_duration": [123, 34, 31, 14], + "open_at_end": [False, False, False, True], + "sell_reason": [SellType.ROI, SellType.STOP_LOSS, + SellType.ROI, SellType.FORCE_SELL] + })} + + assert strat_stats['max_drawdown'] == 0.0 + assert strat_stats['drawdown_start'] == Arrow.fromtimestamp(0).datetime + assert strat_stats['drawdown_end'] == Arrow.fromtimestamp(0).datetime + assert strat_stats['drawdown_end_ts'] == 0 + assert strat_stats['drawdown_start_ts'] == 0 + + def test_generate_pair_metrics(default_conf, mocker): results = pd.DataFrame( From 6e947346787560085dcdb51970ddaa68e9525597 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 20:21:08 +0200 Subject: [PATCH 046/285] Add fee to backtestresult --- freqtrade/optimize/backtesting.py | 18 ++++++++++++------ tests/optimize/test_backtesting.py | 6 ++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 30418f0d7..7021e85b6 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -40,11 +40,13 @@ class BacktestResult(NamedTuple): profit_percent: float profit_abs: float open_date: datetime + open_rate: float + open_fee: float close_date: datetime + close_rate: float + close_fee: float trade_duration: float open_at_end: bool - open_rate: float - close_rate: float sell_reason: SellType @@ -247,11 +249,13 @@ class Backtesting: profit_percent=trade.calc_profit_ratio(rate=closerate), profit_abs=trade.calc_profit(rate=closerate), open_date=buy_row.date, + open_rate=buy_row.open, + open_fee=self.fee, close_date=sell_row.date, + close_rate=closerate, + close_fee=self.fee, trade_duration=trade_dur, open_at_end=False, - open_rate=buy_row.open, - close_rate=closerate, sell_reason=sell.sell_type ) if partial_ohlcv: @@ -261,12 +265,14 @@ class Backtesting: profit_percent=trade.calc_profit_ratio(rate=sell_row.open), profit_abs=trade.calc_profit(rate=sell_row.open), open_date=buy_row.date, + open_rate=buy_row.open, + open_fee=self.fee, close_date=sell_row.date, + close_rate=sell_row.open, + close_fee=self.fee, trade_duration=int(( sell_row.date - buy_row.date).total_seconds() // 60), open_at_end=True, - open_rate=buy_row.open, - close_rate=sell_row.open, sell_reason=SellType.FORCE_SELL ) logger.debug(f"{pair} - Force selling still open trade, " diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index c0a9e798a..4ee03f6ba 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -462,12 +462,14 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: '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), + 'close_rate': [0.104969, 0.103541], + 'close_fee': [0.0025, 0.0025], 'trade_duration': [235, 40], 'open_at_end': [False, False], - 'open_rate': [0.104445, 0.10302485], - 'close_rate': [0.104969, 0.103541], 'sell_reason': [SellType.ROI, SellType.ROI] }) pd.testing.assert_frame_equal(results, expected) From f368aabcc7bce32752f93f26d020be7222e12678 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 20:51:36 +0200 Subject: [PATCH 047/285] Add amount to backtest-result --- freqtrade/optimize/backtesting.py | 3 +++ freqtrade/optimize/optimize_reports.py | 1 + tests/optimize/test_backtesting.py | 1 + 3 files changed, 5 insertions(+) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 7021e85b6..d00f033cd 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -45,6 +45,7 @@ class BacktestResult(NamedTuple): close_date: datetime close_rate: float close_fee: float + amount: float trade_duration: float open_at_end: bool sell_reason: SellType @@ -254,6 +255,7 @@ class Backtesting: close_date=sell_row.date, close_rate=closerate, close_fee=self.fee, + amount=trade.amount, trade_duration=trade_dur, open_at_end=False, sell_reason=sell.sell_type @@ -270,6 +272,7 @@ class Backtesting: close_date=sell_row.date, close_rate=sell_row.open, close_fee=self.fee, + amount=trade.amount, trade_duration=int(( sell_row.date - buy_row.date).total_seconds() // 60), open_at_end=True, diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index d1c58617d..a7cc8a7d6 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -250,6 +250,7 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'backtest_days': backtest_days, 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None, 'market_change': market_change, + 'stake_amount': config['stake_amount'] } result['strategy'][strategy] = strat_stats diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 4ee03f6ba..d5a6f8888 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -468,6 +468,7 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: Arrow(2018, 1, 30, 4, 10, 0).datetime], utc=True), 'close_rate': [0.104969, 0.103541], 'close_fee': [0.0025, 0.0025], + 'amount': [0.009574, 0.009706], 'trade_duration': [235, 40], 'open_at_end': [False, False], 'sell_reason': [SellType.ROI, SellType.ROI] From 7727292861d661a09926cc1da3a5b9aaf4f501bf Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 26 Jun 2020 21:04:40 +0200 Subject: [PATCH 048/285] Rename duration to trade_duration --- freqtrade/data/btanalysis.py | 4 ++-- freqtrade/optimize/backtesting.py | 2 +- freqtrade/plot/plotting.py | 3 ++- tests/optimize/test_backtesting.py | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index d6af67a32..f34dbf313 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -16,7 +16,7 @@ from freqtrade.persistence import Trade logger = logging.getLogger(__name__) # must align with columns in backtest.py -BT_DATA_COLUMNS = ["pair", "profit_percent", "open_date", "close_date", "index", "duration", +BT_DATA_COLUMNS = ["pair", "profit_percent", "open_date", "close_date", "index", "trade_duration", "open_rate", "close_rate", "open_at_end", "sell_reason"] @@ -144,7 +144,7 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: persistence.init(db_url, clean_open_orders=False) columns = ["pair", "open_date", "close_date", "profit", "profit_percent", - "open_rate", "close_rate", "amount", "duration", "sell_reason", + "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"] diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index d00f033cd..18881f9db 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -228,7 +228,7 @@ class Backtesting: open_rate=buy_row.open, open_date=buy_row.date, stake_amount=stake_amount, - amount=stake_amount / buy_row.open, + amount=round(stake_amount / buy_row.open, 8), fee_open=self.fee, fee_close=self.fee, is_open=True, diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 6d50defaf..eee338a42 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -163,7 +163,8 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: 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)}%, " - f"{row['sell_reason']}, {row['duration']} min", + f"{row['sell_reason']}, " + f"{row['trade_duration']} min", axis=1) trade_buys = go.Scatter( x=trades["open_date"], diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index d5a6f8888..2c855fbc0 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -468,7 +468,7 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: Arrow(2018, 1, 30, 4, 10, 0).datetime], utc=True), 'close_rate': [0.104969, 0.103541], 'close_fee': [0.0025, 0.0025], - 'amount': [0.009574, 0.009706], + 'amount': [0.00957442, 0.0097064], 'trade_duration': [235, 40], 'open_at_end': [False, False], 'sell_reason': [SellType.ROI, SellType.ROI] From 04eaf2c39cc41d67e599dc8114f3247931110e9a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 06:46:54 +0200 Subject: [PATCH 049/285] Add test for get_last_backtest_Result --- freqtrade/data/btanalysis.py | 6 +++--- tests/data/test_btanalysis.py | 19 +++++++++++++++++++ tests/testdata/.last_result.json | 1 + tests/testdata/backtest-result_new.json | 1 + tests/testdata/backtest-result_test copy.json | 7 ------- 5 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 tests/testdata/.last_result.json create mode 100644 tests/testdata/backtest-result_new.json delete mode 100644 tests/testdata/backtest-result_test copy.json diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index f34dbf313..a556207e5 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -33,17 +33,17 @@ def get_latest_backtest_filename(directory: Union[Path, str]) -> str: if isinstance(directory, str): directory = Path(directory) if not directory.is_dir(): - raise ValueError(f"Directory {directory} does not exist.") + raise ValueError(f"Directory '{directory}' does not exist.") filename = directory / '.last_result.json' if not filename.is_file(): - raise ValueError(f"Directory {directory} does not seem to contain backtest statistics yet.") + raise ValueError(f"Directory '{directory}' does not seem to contain backtest statistics yet.") with filename.open() as file: data = json_load(file) if 'latest_backtest' not in data: - raise ValueError("Invalid .last_result.json format") + raise ValueError("Invalid '.last_result.json' format.") return data['latest_backtest'] diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 077db19f1..fd3783bf2 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -13,12 +13,31 @@ from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, combine_dataframes_with_mean, create_cum_profit, extract_trades_of_period, + get_latest_backtest_filename, 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 +def test_get_latest_backtest_filename(testdatadir, mocker): + with pytest.raises(ValueError, match=r"Directory .* does not exist\."): + get_latest_backtest_filename(testdatadir / 'does_not_exist') + + with pytest.raises(ValueError, + match=r"Directory .* does not seem to contain .*"): + get_latest_backtest_filename(testdatadir.parent) + + res = get_latest_backtest_filename(testdatadir) + assert res == 'backtest-result_new.json' + + mocker.patch("freqtrade.data.btanalysis.json_load", return_value={}) + + + with pytest.raises(ValueError, match=r"Invalid '.last_result.json' format."): + get_latest_backtest_filename(testdatadir) + + def test_load_backtest_data(testdatadir): filename = testdatadir / "backtest-result_test.json" diff --git a/tests/testdata/.last_result.json b/tests/testdata/.last_result.json new file mode 100644 index 000000000..98448e10f --- /dev/null +++ b/tests/testdata/.last_result.json @@ -0,0 +1 @@ +{"latest_backtest":"backtest-result_new.json"} diff --git a/tests/testdata/backtest-result_new.json b/tests/testdata/backtest-result_new.json new file mode 100644 index 000000000..457ad1bc7 --- /dev/null +++ b/tests/testdata/backtest-result_new.json @@ -0,0 +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", "profit": 4.348872180451118e-06, "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", "profit": 2.1455639097744267e-06, "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", "profit": 1.506315789473681e-06, "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", "profit": 4.3741353383458455e-06, "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", "profit": 0.0004726817042606385, "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", "profit": 0.00040896345864661204, "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", "profit": 0.0002323284210526272, "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", "profit": 1.5368421052630647e-07, "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", "profit": 8.471127819548868e-05, "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", "profit": 0.0004577728320801916, "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", "profit": 0.00044601518796991146, "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", "profit": 0.00042907308270676014, "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", "profit": 3.745609022556351e-05, "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", "profit": 1.5147869674185174e-07, "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", "profit": 6.107769423558838e-05, "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", "profit": 0.0007175643609022495, "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", "profit": -3.650999999999996e-06, "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", "profit": 0.0013269330827067605, "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", "profit": 1.2180451127819219e-05, "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", "profit": 0.001139113784461146, "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", "profit": 8.4511278195488e-07, "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", "profit": 0.0006626566416040071, "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", "profit": 0.0004417042606516125, "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", "profit": 0.00013451513784460897, "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", "profit": 1.232832080200495e-06, "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", "profit": 0.0004403456641603881, "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", "profit": 2.558897243107704e-07, "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", "profit": 5.954887218045116e-07, "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", "profit": 1.4461152882205115e-07, "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", "profit": 0.0003977443609022545, "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", "profit": 0.00024060150375938838, "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", "profit": 1.1759398496240516e-06, "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", "profit": 1.2880501253132587e-05, "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", "profit": 3.138847117794446e-07, "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", "profit": 2.3709273182957117e-07, "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", "profit": 3.039097744360846e-07, "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", "profit": 5.554887218044781e-07, "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", "profit": 2.9724310776941686e-07, "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", "profit": 0.00024310791979949287, "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", "profit": 0.0004924821553884823, "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", "profit": 3.0165413533833987e-07, "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", "profit": 0.0004891728822054991, "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", "profit": 4.676691729323286e-05, "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", "profit": 1.5659197994987058e-05, "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", "profit": 8.755839598997492e-05, "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", "profit": 0.00036826295739347814, "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", "profit": 0.0004911979949874384, "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", "profit": 0.0004841604010024786, "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", "profit": 1.501804511278178e-06, "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", "profit": 0.0004756736842105175, "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", "profit": 0.00035588972431077615, "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", "profit": 0.00023060155388470588, "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", "profit": 4.7308270676692514e-07, "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", "profit": 0.0001523810025062626, "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", "profit": -5.8369999999999985e-06, "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", "profit": 0.00023075689223057277, "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", "profit": 1.4378446115287727e-05, "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", "profit": 0.00033743132832080025, "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", "profit": 0.0004620357894736804, "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", "profit": 0.00041353383458646656, "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", "profit": 3.587819548872171e-06, "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", "profit": 0.00022657644110275071, "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", "profit": 7.891729323308177e-07, "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", "profit": 0.0001449783458646603, "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", "profit": 1.2927318295739246e-06, "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", "profit": 0.00042529804511277913, "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", "profit": 0.0006552757894736777, "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", "profit": 8.063157894736843e-07, "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", "profit": 2.6576441102756397e-07, "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", "profit": 0.0013729321804511196, "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", "profit": 9.543859649122774e-07, "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", "profit": 0.00042270857142856846, "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", "profit": -0.000258379, "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", "profit": -2.5590000000000004e-06, "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", "profit": -7.619999999999998e-06, "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", "profit": 0.00010368902255639091, "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", "profit": 0.0006812030075187946, "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", "profit": 0.00010632000000000003, "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", "profit": 0.0015806817042606502, "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", "profit": 9.924812030075114e-07, "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", "profit": 7.479699248120277e-07, "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", "profit": 1.7814536340851996e-06, "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", "profit": 0.0002168922305764362, "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", "profit": 2.504761904761831e-07, "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", "profit": 0.00034269764411026804, "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", "profit": 1.8195488721804031e-07, "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", "profit": 0.0001408521303258095, "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", "profit": 0.00043363413533832607, "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", "profit": 2.8235588972430847e-07, "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", "profit": 0.0010509013533834544, "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", "profit": 2.779448621553787e-07, "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", "profit": 8.188105263157511e-05, "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", "profit": 1.3520501253133123e-05, "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", "profit": 1.1215538847117757e-06, "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", "profit": 4.1954887218044365e-07, "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", "profit": 0.00022252260651629135, "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", "profit": 2.2506265664159932e-07, "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", "profit": 0.00014310776942355607, "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", "profit": 2.905263157894727e-07, "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", "profit": 0.0002175600501253122, "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", "profit": 0.0002232809523809512, "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", "profit": 2.817042606516199e-07, "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", "profit": 2.174937343358337e-07, "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", "profit": 5.057644110275549e-07, "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", "profit": 1.3559147869673764e-05, "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", "profit": 0.00015037604010024672, "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", "profit": 2.736842105263053e-07, "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", "profit": -0.0030822220000000025, "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", "profit": 0.00044962401002504593, "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", "profit": 8.182962406014932e-05, "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", "profit": 0.00035357393483707866, "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", "profit": 2.657142857142672e-07, "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", "profit": 1.9824561403508552e-07, "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", "profit": 3.8872932330826816e-05, "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", "profit": 1.9563909774435151e-07, "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", "profit": 2.624561403508717e-07, "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", "profit": 4.5253132832080657e-07, "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", "profit": 1.3468671679197925e-05, "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", "profit": 2.0892230576441054e-07, "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", "profit": 1.326466165413529e-06, "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", "profit": 2.592481203007459e-07, "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", "profit": 7.5839598997494e-07, "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", "profit": 0.00035408521303258167, "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", "profit": 8.243022556390922e-05, "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", "profit": 6.512781954887175e-07, "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", "profit": 8.020050125313278e-07, "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", "profit": 0.0004595341353383492, "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", "profit": 0.0003471167919799484, "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", "profit": 1.594987468671663e-07, "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", "profit": 0.0002049122807017481, "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", "profit": 2.5814536340851513e-07, "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", "profit": 0.00045472170426064107, "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", "profit": 1.5679197994986587e-07, "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", "profit": 4.789473684210343e-07, "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", "profit": 0.00020451132832080554, "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", "profit": 2.587969924812037e-07, "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", "profit": 0.0002025454135338306, "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", "profit": 2.5724310776941724e-07, "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", "profit": 2.344962406015033e-06, "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", "profit": 1.5308270676691466e-07, "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", "profit": 4.6431077694236234e-07, "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", "profit": 2.7639097744360576e-07, "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", "profit": 2.4666666666666543e-07, "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", "profit": 1.3032581453634e-05, "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", "profit": 0.00014034441102756326, "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", "profit": 0.00020445624060149575, "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", "profit": 1.4486215538846723e-07, "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", "profit": 0.00020603007518796984, "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", "profit": 8.162406015037611e-07, "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", "profit": 2.713784461152774e-07, "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", "profit": 0.0002075577443608964, "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", "profit": 1.2747318295739177e-05, "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", "profit": 2.810526315789381e-07, "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", "profit": 1.2722105263157733e-05, "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", "profit": 0.00020802005012530989, "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", "profit": 8.00150375939842e-07, "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", "profit": 0.00013894967418546025, "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", "profit": 0.00047425268170424306, "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", "profit": 2.814536340852038e-07, "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", "profit": -4.120000000000001e-06, "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", "profit": 0.0003458647117794422, "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", "profit": 0.0004736834586466093, "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", "profit": -0.001781610000000003, "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", "profit": 0.00014285714285713902, "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", "profit": 0.00014367779448621124, "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", "profit": 0.00047810025062657024, "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", "profit": 0.00033880160401002224, "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", "profit": 1.2957443609021985e-05, "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", "profit": 0.00033576451127818874, "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", "profit": 0.0003394370927318202, "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", "profit": 2.6140350877192417e-07, "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", "profit": 4.117428571428529e-05, "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", "profit": 4.129804511278194e-05, "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", "profit": 8.132721804511231e-05, "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", "profit": 0.00034586466165412166, "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", "profit": 4.3884711779447504e-07, "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", "profit": 0.00034214350877191657, "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", "profit": 0.0003365359398496137, "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", "profit": -1.3399999999999973e-06, "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}}, "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}]} diff --git a/tests/testdata/backtest-result_test copy.json b/tests/testdata/backtest-result_test copy.json deleted file mode 100644 index 0395830d4..000000000 --- a/tests/testdata/backtest-result_test copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ASDF": {, - "trades": [], - "metrics":[], - } -} -[["TRX/BTC",0.03990025,1515568500.0,1515568800.0,27,5,9.64e-05,0.00010074887218045112,false,"roi"],["ADA/BTC",0.03990025,1515568500.0,1515569400.0,27,15,4.756e-05,4.9705563909774425e-05,false,"roi"],["XLM/BTC",0.03990025,1515569100.0,1515569700.0,29,10,3.339e-05,3.489631578947368e-05,false,"roi"],["TRX/BTC",0.03990025,1515569100.0,1515570000.0,29,15,9.696e-05,0.00010133413533834584,false,"roi"],["ETH/BTC",-0.0,1515569700.0,1515573300.0,31,60,0.0943,0.09477268170426063,false,"roi"],["XMR/BTC",0.00997506,1515570000.0,1515571800.0,32,30,0.02719607,0.02760503345864661,false,"roi"],["ZEC/BTC",0.0,1515572100.0,1515578100.0,39,100,0.04634952,0.046581848421052625,false,"roi"],["NXT/BTC",-0.0,1515595500.0,1515599400.0,117,65,3.066e-05,3.081368421052631e-05,false,"roi"],["LTC/BTC",0.0,1515602100.0,1515604500.0,139,40,0.0168999,0.016984611278195488,false,"roi"],["ETH/BTC",-0.0,1515602400.0,1515604800.0,140,40,0.09132568,0.0917834528320802,false,"roi"],["ETH/BTC",-0.0,1515610200.0,1515613500.0,166,55,0.08898003,0.08942604518796991,false,"roi"],["ETH/BTC",0.0,1515622500.0,1515625200.0,207,45,0.08560008,0.08602915308270676,false,"roi"],["ETC/BTC",0.00997506,1515624600.0,1515626400.0,214,30,0.00249083,0.0025282860902255634,false,"roi"],["NXT/BTC",-0.0,1515626100.0,1515629700.0,219,60,3.022e-05,3.037147869674185e-05,false,"roi"],["ETC/BTC",0.01995012,1515627600.0,1515629100.0,224,25,0.002437,0.0024980776942355883,false,"roi"],["ZEC/BTC",0.00997506,1515628800.0,1515630900.0,228,35,0.04771803,0.04843559436090225,false,"roi"],["XLM/BTC",-0.10448878,1515642000.0,1515644700.0,272,45,3.651e-05,3.2859000000000005e-05,false,"stop_loss"],["ETH/BTC",0.00997506,1515642900.0,1515644700.0,275,30,0.08824105,0.08956798308270676,false,"roi"],["ETC/BTC",-0.0,1515643200.0,1515646200.0,276,50,0.00243,0.002442180451127819,false,"roi"],["ZEC/BTC",0.01995012,1515645000.0,1515646500.0,282,25,0.04545064,0.046589753784461146,false,"roi"],["XLM/BTC",0.01995012,1515645000.0,1515646200.0,282,20,3.372e-05,3.456511278195488e-05,false,"roi"],["XMR/BTC",0.01995012,1515646500.0,1515647700.0,287,20,0.02644,0.02710265664160401,false,"roi"],["ETH/BTC",-0.0,1515669600.0,1515672000.0,364,40,0.08812,0.08856170426065162,false,"roi"],["XMR/BTC",-0.0,1515670500.0,1515672900.0,367,40,0.02683577,0.026970285137844607,false,"roi"],["ADA/BTC",0.01995012,1515679200.0,1515680700.0,396,25,4.919e-05,5.04228320802005e-05,false,"roi"],["ETH/BTC",-0.0,1515698700.0,1515702900.0,461,70,0.08784896,0.08828930566416039,false,"roi"],["ADA/BTC",-0.0,1515710100.0,1515713400.0,499,55,5.105e-05,5.130588972431077e-05,false,"roi"],["XLM/BTC",0.00997506,1515711300.0,1515713100.0,503,30,3.96e-05,4.019548872180451e-05,false,"roi"],["NXT/BTC",-0.0,1515711300.0,1515713700.0,503,40,2.885e-05,2.899461152882205e-05,false,"roi"],["XMR/BTC",0.00997506,1515713400.0,1515715500.0,510,35,0.02645,0.026847744360902256,false,"roi"],["ZEC/BTC",-0.0,1515714900.0,1515719700.0,515,80,0.048,0.04824060150375939,false,"roi"],["XLM/BTC",0.01995012,1515791700.0,1515793200.0,771,25,4.692e-05,4.809593984962405e-05,false,"roi"],["ETC/BTC",-0.0,1515804900.0,1515824400.0,815,325,0.00256966,0.0025825405012531327,false,"roi"],["ADA/BTC",0.0,1515840900.0,1515843300.0,935,40,6.262e-05,6.293388471177944e-05,false,"roi"],["XLM/BTC",0.0,1515848700.0,1516025400.0,961,2945,4.73e-05,4.753709273182957e-05,false,"roi"],["ADA/BTC",-0.0,1515850200.0,1515854700.0,966,75,6.063e-05,6.0933909774436085e-05,false,"roi"],["TRX/BTC",-0.0,1515850800.0,1515886200.0,968,590,0.00011082,0.00011137548872180449,false,"roi"],["ADA/BTC",-0.0,1515856500.0,1515858900.0,987,40,5.93e-05,5.9597243107769415e-05,false,"roi"],["ZEC/BTC",-0.0,1515861000.0,1515863400.0,1002,40,0.04850003,0.04874313791979949,false,"roi"],["ETH/BTC",-0.0,1515881100.0,1515911100.0,1069,500,0.09825019,0.09874267215538847,false,"roi"],["ADA/BTC",0.0,1515889200.0,1515970500.0,1096,1355,6.018e-05,6.048165413533834e-05,false,"roi"],["ETH/BTC",-0.0,1515933900.0,1515936300.0,1245,40,0.09758999,0.0980791628822055,false,"roi"],["ETC/BTC",0.00997506,1515943800.0,1515945600.0,1278,30,0.00311,0.0031567669172932328,false,"roi"],["ETC/BTC",-0.0,1515962700.0,1515968100.0,1341,90,0.00312401,0.003139669197994987,false,"roi"],["LTC/BTC",0.0,1515972900.0,1515976200.0,1375,55,0.0174679,0.017555458395989976,false,"roi"],["DASH/BTC",-0.0,1515973500.0,1515975900.0,1377,40,0.07346846,0.07383672295739348,false,"roi"],["ETH/BTC",-0.0,1515983100.0,1515985500.0,1409,40,0.097994,0.09848519799498745,false,"roi"],["ETH/BTC",-0.0,1516000800.0,1516003200.0,1468,40,0.09659,0.09707416040100249,false,"roi"],["TRX/BTC",0.00997506,1516004400.0,1516006500.0,1480,35,9.987e-05,0.00010137180451127818,false,"roi"],["ETH/BTC",0.0,1516018200.0,1516071000.0,1526,880,0.0948969,0.09537257368421052,false,"roi"],["DASH/BTC",-0.0,1516025400.0,1516038000.0,1550,210,0.071,0.07135588972431077,false,"roi"],["ZEC/BTC",-0.0,1516026600.0,1516029000.0,1554,40,0.04600501,0.046235611553884705,false,"roi"],["TRX/BTC",-0.0,1516039800.0,1516044300.0,1598,75,9.438e-05,9.485308270676691e-05,false,"roi"],["XMR/BTC",-0.0,1516041300.0,1516043700.0,1603,40,0.03040001,0.030552391002506264,false,"roi"],["ADA/BTC",-0.10448878,1516047900.0,1516091100.0,1625,720,5.837e-05,5.2533e-05,false,"stop_loss"],["ZEC/BTC",-0.0,1516048800.0,1516053600.0,1628,80,0.046036,0.04626675689223057,false,"roi"],["ETC/BTC",-0.0,1516062600.0,1516065000.0,1674,40,0.0028685,0.0028828784461152877,false,"roi"],["DASH/BTC",0.0,1516065300.0,1516070100.0,1683,80,0.06731755,0.0676549813283208,false,"roi"],["ETH/BTC",0.0,1516088700.0,1516092000.0,1761,55,0.09217614,0.09263817578947368,false,"roi"],["LTC/BTC",0.01995012,1516091700.0,1516092900.0,1771,20,0.0165,0.016913533834586467,false,"roi"],["TRX/BTC",0.03990025,1516091700.0,1516092000.0,1771,5,7.953e-05,8.311781954887218e-05,false,"roi"],["ZEC/BTC",-0.0,1516092300.0,1516096200.0,1773,65,0.045202,0.04542857644110275,false,"roi"],["ADA/BTC",0.00997506,1516094100.0,1516095900.0,1779,30,5.248e-05,5.326917293233082e-05,false,"roi"],["XMR/BTC",0.0,1516094100.0,1516096500.0,1779,40,0.02892318,0.02906815834586466,false,"roi"],["ADA/BTC",0.01995012,1516096200.0,1516097400.0,1786,20,5.158e-05,5.287273182957392e-05,false,"roi"],["ZEC/BTC",0.00997506,1516097100.0,1516099200.0,1789,35,0.04357584,0.044231115789473675,false,"roi"],["XMR/BTC",0.00997506,1516097100.0,1516098900.0,1789,30,0.02828232,0.02870761804511278,false,"roi"],["ADA/BTC",0.00997506,1516110300.0,1516112400.0,1833,35,5.362e-05,5.4426315789473676e-05,false,"roi"],["ADA/BTC",-0.0,1516123800.0,1516127100.0,1878,55,5.302e-05,5.328576441102756e-05,false,"roi"],["ETH/BTC",0.00997506,1516126500.0,1516128300.0,1887,30,0.09129999,0.09267292218045112,false,"roi"],["XLM/BTC",0.01995012,1516126500.0,1516127700.0,1887,20,3.808e-05,3.903438596491228e-05,false,"roi"],["XMR/BTC",0.00997506,1516129200.0,1516131000.0,1896,30,0.02811012,0.028532828571428567,false,"roi"],["ETC/BTC",-0.10448878,1516137900.0,1516141500.0,1925,60,0.00258379,0.002325411,false,"stop_loss"],["NXT/BTC",-0.10448878,1516137900.0,1516142700.0,1925,80,2.559e-05,2.3031e-05,false,"stop_loss"],["TRX/BTC",-0.10448878,1516138500.0,1516141500.0,1927,50,7.62e-05,6.858e-05,false,"stop_loss"],["LTC/BTC",0.03990025,1516141800.0,1516142400.0,1938,10,0.0151,0.015781203007518795,false,"roi"],["ETC/BTC",0.03990025,1516141800.0,1516142100.0,1938,5,0.00229844,0.002402129022556391,false,"roi"],["ETC/BTC",0.03990025,1516142400.0,1516142700.0,1940,5,0.00235676,0.00246308,false,"roi"],["DASH/BTC",0.01995012,1516142700.0,1516143900.0,1941,20,0.0630692,0.06464988170426066,false,"roi"],["NXT/BTC",0.03990025,1516143000.0,1516143300.0,1942,5,2.2e-05,2.2992481203007514e-05,false,"roi"],["ADA/BTC",0.00997506,1516159800.0,1516161600.0,1998,30,4.974e-05,5.048796992481203e-05,false,"roi"],["TRX/BTC",0.01995012,1516161300.0,1516162500.0,2003,20,7.108e-05,7.28614536340852e-05,false,"roi"],["ZEC/BTC",-0.0,1516181700.0,1516184100.0,2071,40,0.04327,0.04348689223057644,false,"roi"],["ADA/BTC",-0.0,1516184400.0,1516208400.0,2080,400,4.997e-05,5.022047619047618e-05,false,"roi"],["DASH/BTC",-0.0,1516185000.0,1516188300.0,2082,55,0.06836818,0.06871087764411027,false,"roi"],["XLM/BTC",-0.0,1516185000.0,1516187400.0,2082,40,3.63e-05,3.648195488721804e-05,false,"roi"],["XMR/BTC",-0.0,1516192200.0,1516226700.0,2106,575,0.0281,0.02824085213032581,false,"roi"],["ETH/BTC",-0.0,1516192500.0,1516208100.0,2107,260,0.08651001,0.08694364413533832,false,"roi"],["ADA/BTC",-0.0,1516251600.0,1516254900.0,2304,55,5.633e-05,5.6612355889724306e-05,false,"roi"],["DASH/BTC",0.00997506,1516252800.0,1516254900.0,2308,35,0.06988494,0.07093584135338346,false,"roi"],["ADA/BTC",-0.0,1516260900.0,1516263300.0,2335,40,5.545e-05,5.572794486215538e-05,false,"roi"],["LTC/BTC",-0.0,1516266000.0,1516268400.0,2352,40,0.01633527,0.016417151052631574,false,"roi"],["ETC/BTC",-0.0,1516293600.0,1516296000.0,2444,40,0.00269734,0.0027108605012531326,false,"roi"],["XLM/BTC",0.01995012,1516298700.0,1516300200.0,2461,25,4.475e-05,4.587155388471177e-05,false,"roi"],["NXT/BTC",0.00997506,1516299900.0,1516301700.0,2465,30,2.79e-05,2.8319548872180444e-05,false,"roi"],["ZEC/BTC",0.0,1516306200.0,1516308600.0,2486,40,0.04439326,0.04461578260651629,false,"roi"],["XLM/BTC",0.0,1516311000.0,1516322100.0,2502,185,4.49e-05,4.51250626566416e-05,false,"roi"],["XMR/BTC",-0.0,1516312500.0,1516338300.0,2507,430,0.02855,0.028693107769423555,false,"roi"],["ADA/BTC",0.0,1516313400.0,1516315800.0,2510,40,5.796e-05,5.8250526315789473e-05,false,"roi"],["ZEC/BTC",0.0,1516319400.0,1516321800.0,2530,40,0.04340323,0.04362079005012531,false,"roi"],["ZEC/BTC",0.0,1516380300.0,1516383300.0,2733,50,0.04454455,0.04476783095238095,false,"roi"],["ADA/BTC",-0.0,1516382100.0,1516391700.0,2739,160,5.62e-05,5.648170426065162e-05,false,"roi"],["XLM/BTC",-0.0,1516382400.0,1516392900.0,2740,175,4.339e-05,4.360749373433584e-05,false,"roi"],["TRX/BTC",0.0,1516423500.0,1516469700.0,2877,770,0.0001009,0.00010140576441102757,false,"roi"],["ETC/BTC",-0.0,1516423800.0,1516461300.0,2878,625,0.00270505,0.002718609147869674,false,"roi"],["XMR/BTC",-0.0,1516423800.0,1516431600.0,2878,130,0.03000002,0.030150396040100245,false,"roi"],["ADA/BTC",-0.0,1516438800.0,1516441200.0,2928,40,5.46e-05,5.4873684210526304e-05,false,"roi"],["XMR/BTC",-0.10448878,1516472700.0,1516852200.0,3041,6325,0.03082222,0.027739998000000002,false,"stop_loss"],["ETH/BTC",-0.0,1516487100.0,1516490100.0,3089,50,0.08969999,0.09014961401002504,false,"roi"],["LTC/BTC",0.0,1516503000.0,1516545000.0,3142,700,0.01632501,0.01640683962406015,false,"roi"],["DASH/BTC",-0.0,1516530000.0,1516532400.0,3232,40,0.070538,0.07089157393483708,false,"roi"],["ADA/BTC",-0.0,1516549800.0,1516560300.0,3298,175,5.301e-05,5.3275714285714276e-05,false,"roi"],["XLM/BTC",0.0,1516551600.0,1516554000.0,3304,40,3.955e-05,3.9748245614035085e-05,false,"roi"],["ETC/BTC",0.00997506,1516569300.0,1516571100.0,3363,30,0.00258505,0.002623922932330827,false,"roi"],["XLM/BTC",-0.0,1516569300.0,1516571700.0,3363,40,3.903e-05,3.922563909774435e-05,false,"roi"],["ADA/BTC",-0.0,1516581300.0,1516617300.0,3403,600,5.236e-05,5.262245614035087e-05,false,"roi"],["TRX/BTC",0.0,1516584600.0,1516587000.0,3414,40,9.028e-05,9.073253132832079e-05,false,"roi"],["ETC/BTC",-0.0,1516623900.0,1516631700.0,3545,130,0.002687,0.002700468671679198,false,"roi"],["XLM/BTC",-0.0,1516626900.0,1516629300.0,3555,40,4.168e-05,4.1888922305764405e-05,false,"roi"],["TRX/BTC",0.00997506,1516629600.0,1516631400.0,3564,30,8.821e-05,8.953646616541353e-05,false,"roi"],["ADA/BTC",-0.0,1516636500.0,1516639200.0,3587,45,5.172e-05,5.1979248120300745e-05,false,"roi"],["NXT/BTC",0.01995012,1516637100.0,1516638300.0,3589,20,3.026e-05,3.101839598997494e-05,false,"roi"],["DASH/BTC",0.0,1516650600.0,1516666200.0,3634,260,0.07064,0.07099408521303258,false,"roi"],["LTC/BTC",0.0,1516656300.0,1516658700.0,3653,40,0.01644483,0.01652726022556391,false,"roi"],["XLM/BTC",0.00997506,1516665900.0,1516667700.0,3685,30,4.331e-05,4.3961278195488714e-05,false,"roi"],["NXT/BTC",0.01995012,1516672200.0,1516673700.0,3706,25,3.2e-05,3.2802005012531326e-05,false,"roi"],["ETH/BTC",0.0,1516681500.0,1516684500.0,3737,50,0.09167706,0.09213659413533835,false,"roi"],["DASH/BTC",0.0,1516692900.0,1516698000.0,3775,85,0.0692498,0.06959691679197995,false,"roi"],["NXT/BTC",0.0,1516704600.0,1516712700.0,3814,135,3.182e-05,3.197949874686716e-05,false,"roi"],["ZEC/BTC",-0.0,1516705500.0,1516723500.0,3817,300,0.04088,0.04108491228070175,false,"roi"],["ADA/BTC",-0.0,1516719300.0,1516721700.0,3863,40,5.15e-05,5.175814536340851e-05,false,"roi"],["ETH/BTC",0.0,1516725300.0,1516752300.0,3883,450,0.09071698,0.09117170170426064,false,"roi"],["NXT/BTC",-0.0,1516728300.0,1516733100.0,3893,80,3.128e-05,3.1436791979949865e-05,false,"roi"],["TRX/BTC",-0.0,1516738500.0,1516744800.0,3927,105,9.555e-05,9.602894736842104e-05,false,"roi"],["ZEC/BTC",-0.0,1516746600.0,1516749000.0,3954,40,0.04080001,0.041004521328320796,false,"roi"],["ADA/BTC",-0.0,1516751400.0,1516764900.0,3970,225,5.163e-05,5.1888796992481196e-05,false,"roi"],["ZEC/BTC",0.0,1516753200.0,1516758600.0,3976,90,0.04040781,0.04061035541353383,false,"roi"],["ADA/BTC",-0.0,1516776300.0,1516778700.0,4053,40,5.132e-05,5.157724310776942e-05,false,"roi"],["ADA/BTC",0.03990025,1516803300.0,1516803900.0,4143,10,5.198e-05,5.432496240601503e-05,false,"roi"],["NXT/BTC",-0.0,1516805400.0,1516811700.0,4150,105,3.054e-05,3.069308270676692e-05,false,"roi"],["TRX/BTC",0.0,1516806600.0,1516810500.0,4154,65,9.263e-05,9.309431077694235e-05,false,"roi"],["ADA/BTC",-0.0,1516833600.0,1516836300.0,4244,45,5.514e-05,5.5416390977443596e-05,false,"roi"],["XLM/BTC",0.0,1516841400.0,1516843800.0,4270,40,4.921e-05,4.9456666666666664e-05,false,"roi"],["ETC/BTC",0.0,1516868100.0,1516882500.0,4359,240,0.0026,0.002613032581453634,false,"roi"],["XMR/BTC",-0.0,1516875900.0,1516896900.0,4385,350,0.02799871,0.028139054411027563,false,"roi"],["ZEC/BTC",-0.0,1516878000.0,1516880700.0,4392,45,0.04078902,0.0409934762406015,false,"roi"],["NXT/BTC",-0.0,1516885500.0,1516887900.0,4417,40,2.89e-05,2.904486215538847e-05,false,"roi"],["ZEC/BTC",-0.0,1516886400.0,1516889100.0,4420,45,0.041103,0.041309030075187964,false,"roi"],["XLM/BTC",0.00997506,1516895100.0,1516896900.0,4449,30,5.428e-05,5.5096240601503756e-05,false,"roi"],["XLM/BTC",-0.0,1516902300.0,1516922100.0,4473,330,5.414e-05,5.441137844611528e-05,false,"roi"],["ZEC/BTC",-0.0,1516914900.0,1516917300.0,4515,40,0.04140777,0.0416153277443609,false,"roi"],["ETC/BTC",0.0,1516932300.0,1516934700.0,4573,40,0.00254309,0.002555837318295739,false,"roi"],["ADA/BTC",-0.0,1516935300.0,1516979400.0,4583,735,5.607e-05,5.6351052631578935e-05,false,"roi"],["ETC/BTC",0.0,1516947000.0,1516958700.0,4622,195,0.00253806,0.0025507821052631577,false,"roi"],["ZEC/BTC",-0.0,1516951500.0,1516960500.0,4637,150,0.0415,0.04170802005012531,false,"roi"],["XLM/BTC",0.00997506,1516960500.0,1516962300.0,4667,30,5.321e-05,5.401015037593984e-05,false,"roi"],["XMR/BTC",-0.0,1516982700.0,1516985100.0,4741,40,0.02772046,0.02785940967418546,false,"roi"],["ETH/BTC",0.0,1517009700.0,1517012100.0,4831,40,0.09461341,0.09508766268170425,false,"roi"],["XLM/BTC",-0.0,1517013300.0,1517016600.0,4843,55,5.615e-05,5.643145363408521e-05,false,"roi"],["ADA/BTC",-0.07877175,1517013900.0,1517287500.0,4845,4560,5.556e-05,5.144e-05,true,"force_sell"],["DASH/BTC",-0.0,1517020200.0,1517052300.0,4866,535,0.06900001,0.06934587471177944,false,"roi"],["ETH/BTC",-0.0,1517034300.0,1517036700.0,4913,40,0.09449985,0.09497353345864659,false,"roi"],["ZEC/BTC",-0.04815133,1517046000.0,1517287200.0,4952,4020,0.0410697,0.03928809,true,"force_sell"],["XMR/BTC",-0.0,1517053500.0,1517056200.0,4977,45,0.0285,0.02864285714285714,false,"roi"],["XMR/BTC",-0.0,1517056500.0,1517066700.0,4987,170,0.02866372,0.02880739779448621,false,"roi"],["ETH/BTC",-0.0,1517068200.0,1517071800.0,5026,60,0.095381,0.09585910025062655,false,"roi"],["DASH/BTC",-0.0,1517072700.0,1517075100.0,5041,40,0.06759092,0.06792972160401002,false,"roi"],["ETC/BTC",-0.0,1517096400.0,1517101500.0,5120,85,0.00258501,0.002597967443609022,false,"roi"],["DASH/BTC",-0.0,1517106300.0,1517127000.0,5153,345,0.06698502,0.0673207845112782,false,"roi"],["DASH/BTC",-0.0,1517135100.0,1517157000.0,5249,365,0.0677177,0.06805713709273183,false,"roi"],["XLM/BTC",0.0,1517171700.0,1517175300.0,5371,60,5.215e-05,5.2411403508771925e-05,false,"roi"],["ETC/BTC",0.00997506,1517176800.0,1517178600.0,5388,30,0.00273809,0.002779264285714285,false,"roi"],["ETC/BTC",0.00997506,1517184000.0,1517185800.0,5412,30,0.00274632,0.002787618045112782,false,"roi"],["LTC/BTC",0.0,1517192100.0,1517194800.0,5439,45,0.01622478,0.016306107218045113,false,"roi"],["DASH/BTC",-0.0,1517195100.0,1517197500.0,5449,40,0.069,0.06934586466165413,false,"roi"],["TRX/BTC",-0.0,1517203200.0,1517208900.0,5476,95,8.755e-05,8.798884711779448e-05,false,"roi"],["DASH/BTC",-0.0,1517209200.0,1517253900.0,5496,745,0.06825763,0.06859977350877192,false,"roi"],["DASH/BTC",-0.0,1517255100.0,1517257500.0,5649,40,0.06713892,0.06747545593984962,false,"roi"],["TRX/BTC",-0.0199116,1517268600.0,1517287500.0,5694,315,8.934e-05,8.8e-05,true,"force_sell"]] From 133947988238905752513992b4ad2caafb5eead3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 07:08:16 +0200 Subject: [PATCH 050/285] Have sell_type stringify correctly --- freqtrade/strategy/interface.py | 4 ++++ tests/test_freqtradebot.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index f9f3a3678..cee217ed5 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -45,6 +45,10 @@ class SellType(Enum): EMERGENCY_SELL = "emergency_sell" NONE = "" + def __str__(self): + # explicitly convert to String to help with exporting data. + return self.value + class SellCheckTuple(NamedTuple): """ diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 6496043f9..89991fde8 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -320,7 +320,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, caplog, mocker, edge_conf # stoploss shoud be hit assert freqtrade.handle_trade(trade) is True - assert log_has('Executing Sell for NEO/BTC. Reason: SellType.STOP_LOSS', caplog) + assert log_has('Executing Sell for NEO/BTC. Reason: stop_loss', caplog) assert trade.sell_reason == SellType.STOP_LOSS.value From c13ec4a1d485e372c905a75a38ecc1bc42a60c6a Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 07:15:33 +0200 Subject: [PATCH 051/285] implement fallback loading for load_backtest_data --- freqtrade/data/btanalysis.py | 45 ++++++++++++++------------ freqtrade/optimize/optimize_reports.py | 2 +- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index a556207e5..adf01e33d 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -70,29 +70,34 @@ def load_backtest_data(filename: Union[Path, str]) -> pd.DataFrame: Load backtest data file. :param filename: pathlib.Path object, or string pointing to the file. :return: a dataframe with the analysis results + :raise: ValueError if loading goes wrong. """ - if isinstance(filename, str): - filename = Path(filename) + data = load_backtest_stats(filename) + if not isinstance(data, list): + # new format + if 'strategy' not in data: + raise ValueError("Unknown dataformat") + if len(data['strategy']) != 1: + raise ValueError("Detected new Format with more than one strategy") + strategy = list(data['strategy'].keys())[0] + data = data['strategy'][strategy]['trades'] + df = pd.DataFrame(data) - if not filename.is_file(): - raise ValueError(f"File {filename} does not exist.") + else: + # old format - only with lists. + df = pd.DataFrame(data, columns=BT_DATA_COLUMNS) - with filename.open() as file: - data = json_load(file) - - df = pd.DataFrame(data, columns=BT_DATA_COLUMNS) - - df['open_date'] = pd.to_datetime(df['open_date'], - unit='s', - utc=True, - infer_datetime_format=True - ) - df['close_date'] = pd.to_datetime(df['close_date'], - unit='s', - utc=True, - infer_datetime_format=True - ) - df['profit'] = df['close_rate'] - df['open_rate'] + df['open_date'] = pd.to_datetime(df['open_date'], + unit='s', + utc=True, + infer_datetime_format=True + ) + df['close_date'] = pd.to_datetime(df['close_date'], + unit='s', + utc=True, + infer_datetime_format=True + ) + df['profit_abs'] = df['close_rate'] - df['open_rate'] df = df.sort_values("open_date").reset_index(drop=True) return df diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index a7cc8a7d6..6f9d3f34e 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -55,7 +55,7 @@ def backtest_result_to_list(results: DataFrame) -> List[List]: # Return 0 as "index" for compatibility reasons (for now) # TODO: Evaluate if we can remove this return [[t.pair, t.profit_percent, t.open_date.timestamp(), - t.open_date.timestamp(), 0, t.trade_duration, + t.close_date.timestamp(), 0, t.trade_duration, t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value] for index, t in results.iterrows()] From afefe92523421c87b0e968aa79e25fde175687ba Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 09:56:37 +0200 Subject: [PATCH 052/285] Add multi-strategy loading logic --- freqtrade/data/btanalysis.py | 47 ++++++++++++++----- .../testdata/backtest-result_multistrat.json | 1 + 2 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 tests/testdata/backtest-result_multistrat.json diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index adf01e33d..17d3fed14 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -3,7 +3,7 @@ Helpers when analyzing backtest data """ import logging from pathlib import Path -from typing import Dict, Union, Tuple, Any +from typing import Dict, Union, Tuple, Any, Optional import numpy as np import pandas as pd @@ -65,24 +65,41 @@ def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]: return data -def load_backtest_data(filename: Union[Path, str]) -> pd.DataFrame: +def load_backtest_data(filename: Union[Path, str], strategy: Optional[str] = None) -> pd.DataFrame: """ Load backtest data file. :param filename: pathlib.Path object, or string pointing to the file. + :param strategy: Strategy to load - mainly relevant for multi-strategy backtests + Can also serve as protection to load the correct result. :return: a dataframe with the analysis results :raise: ValueError if loading goes wrong. """ data = load_backtest_stats(filename) if not isinstance(data, list): - # new format + # new, nested format if 'strategy' not in data: - raise ValueError("Unknown dataformat") - if len(data['strategy']) != 1: - raise ValueError("Detected new Format with more than one strategy") - strategy = list(data['strategy'].keys())[0] + raise ValueError("Unknown dataformat.") + + if not strategy: + if len(data['strategy']) == 1: + strategy = list(data['strategy'].keys())[0] + else: + raise ValueError("Detected backtest result with more than one strategy. " + "Please specify a strategy.") + + if strategy not in data['strategy']: + raise ValueError(f"Strategy {strategy} not available in the backtest result.") + data = data['strategy'][strategy]['trades'] df = pd.DataFrame(data) - + df['open_date'] = pd.to_datetime(df['open_date'], + utc=True, + infer_datetime_format=True + ) + df['close_date'] = pd.to_datetime(df['close_date'], + utc=True, + infer_datetime_format=True + ) else: # old format - only with lists. df = pd.DataFrame(data, columns=BT_DATA_COLUMNS) @@ -140,10 +157,12 @@ def evaluate_result_multi(results: pd.DataFrame, timeframe: str, return df_final[df_final['open_trades'] > max_open_trades] -def load_trades_from_db(db_url: str) -> pd.DataFrame: +def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataFrame: """ Load trades from a DB (using dburl) :param db_url: Sqlite url (default format sqlite:///tradesv3.dry-run.sqlite) + :param strategy: Strategy to load - mainly relevant for multi-strategy backtests + Can also serve as protection to load the correct result. :return: Dataframe containing Trades """ persistence.init(db_url, clean_open_orders=False) @@ -154,6 +173,10 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: "stake_amount", "max_rate", "min_rate", "id", "exchange", "stop_loss", "initial_stop_loss", "strategy", "timeframe"] + filters = [] + if strategy: + filters = 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, @@ -172,14 +195,14 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: t.stop_loss, t.initial_stop_loss, t.strategy, t.timeframe ) - for t in Trade.get_trades().all()], + for t in Trade.get_trades(filters).all()], columns=columns) return trades def load_trades(source: str, db_url: str, exportfilename: Path, - no_trades: bool = False) -> pd.DataFrame: + no_trades: bool = False, strategy: Optional[str] = None) -> pd.DataFrame: """ Based on configuration option "trade_source": * loads data from DB (using `db_url`) @@ -197,7 +220,7 @@ def load_trades(source: str, db_url: str, exportfilename: Path, if source == "DB": return load_trades_from_db(db_url) elif source == "file": - return load_backtest_data(exportfilename) + return load_backtest_data(exportfilename, strategy) def extract_trades_of_period(dataframe: pd.DataFrame, trades: pd.DataFrame, diff --git a/tests/testdata/backtest-result_multistrat.json b/tests/testdata/backtest-result_multistrat.json new file mode 100644 index 000000000..a58ab28cb --- /dev/null +++ b/tests/testdata/backtest-result_multistrat.json @@ -0,0 +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", "profit": 4.348872180451118e-06, "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", "profit": 2.1455639097744267e-06, "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", "profit": 1.506315789473681e-06, "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", "profit": 4.3741353383458455e-06, "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", "profit": 0.0004726817042606385, "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", "profit": 0.00040896345864661204, "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", "profit": 0.0002323284210526272, "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", "profit": 1.5368421052630647e-07, "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", "profit": 8.471127819548868e-05, "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", "profit": 0.0004577728320801916, "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", "profit": 0.00044601518796991146, "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", "profit": 0.00042907308270676014, "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", "profit": 3.745609022556351e-05, "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", "profit": 1.5147869674185174e-07, "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", "profit": 6.107769423558838e-05, "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", "profit": 0.0007175643609022495, "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", "profit": -3.650999999999996e-06, "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", "profit": 0.0013269330827067605, "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", "profit": 1.2180451127819219e-05, "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", "profit": 0.001139113784461146, "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", "profit": 8.4511278195488e-07, "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", "profit": 0.0006626566416040071, "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", "profit": 0.0004417042606516125, "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", "profit": 0.00013451513784460897, "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", "profit": 1.232832080200495e-06, "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", "profit": 0.0004403456641603881, "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", "profit": 2.558897243107704e-07, "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", "profit": 5.954887218045116e-07, "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", "profit": 1.4461152882205115e-07, "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", "profit": 0.0003977443609022545, "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", "profit": 0.00024060150375938838, "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", "profit": 1.1759398496240516e-06, "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", "profit": 1.2880501253132587e-05, "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", "profit": 3.138847117794446e-07, "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", "profit": 2.3709273182957117e-07, "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", "profit": 3.039097744360846e-07, "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", "profit": 5.554887218044781e-07, "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", "profit": 2.9724310776941686e-07, "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", "profit": 0.00024310791979949287, "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", "profit": 0.0004924821553884823, "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", "profit": 3.0165413533833987e-07, "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", "profit": 0.0004891728822054991, "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", "profit": 4.676691729323286e-05, "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", "profit": 1.5659197994987058e-05, "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", "profit": 8.755839598997492e-05, "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", "profit": 0.00036826295739347814, "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", "profit": 0.0004911979949874384, "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", "profit": 0.0004841604010024786, "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", "profit": 1.501804511278178e-06, "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", "profit": 0.0004756736842105175, "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", "profit": 0.00035588972431077615, "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", "profit": 0.00023060155388470588, "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", "profit": 4.7308270676692514e-07, "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", "profit": 0.0001523810025062626, "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", "profit": -5.8369999999999985e-06, "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", "profit": 0.00023075689223057277, "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", "profit": 1.4378446115287727e-05, "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", "profit": 0.00033743132832080025, "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", "profit": 0.0004620357894736804, "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", "profit": 0.00041353383458646656, "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", "profit": 3.587819548872171e-06, "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", "profit": 0.00022657644110275071, "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", "profit": 7.891729323308177e-07, "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", "profit": 0.0001449783458646603, "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", "profit": 1.2927318295739246e-06, "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", "profit": 0.00042529804511277913, "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", "profit": 0.0006552757894736777, "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", "profit": 8.063157894736843e-07, "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", "profit": 2.6576441102756397e-07, "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", "profit": 0.0013729321804511196, "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", "profit": 9.543859649122774e-07, "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", "profit": 0.00042270857142856846, "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", "profit": -0.000258379, "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", "profit": -2.5590000000000004e-06, "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", "profit": -7.619999999999998e-06, "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", "profit": 0.00010368902255639091, "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", "profit": 0.0006812030075187946, "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", "profit": 0.00010632000000000003, "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", "profit": 0.0015806817042606502, "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", "profit": 9.924812030075114e-07, "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", "profit": 7.479699248120277e-07, "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", "profit": 1.7814536340851996e-06, "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", "profit": 0.0002168922305764362, "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", "profit": 2.504761904761831e-07, "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", "profit": 0.00034269764411026804, "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", "profit": 1.8195488721804031e-07, "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", "profit": 0.0001408521303258095, "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", "profit": 0.00043363413533832607, "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", "profit": 2.8235588972430847e-07, "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", "profit": 0.0010509013533834544, "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", "profit": 2.779448621553787e-07, "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", "profit": 8.188105263157511e-05, "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", "profit": 1.3520501253133123e-05, "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", "profit": 1.1215538847117757e-06, "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", "profit": 4.1954887218044365e-07, "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", "profit": 0.00022252260651629135, "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", "profit": 2.2506265664159932e-07, "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", "profit": 0.00014310776942355607, "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", "profit": 2.905263157894727e-07, "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", "profit": 0.0002175600501253122, "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", "profit": 0.0002232809523809512, "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", "profit": 2.817042606516199e-07, "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", "profit": 2.174937343358337e-07, "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", "profit": 5.057644110275549e-07, "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", "profit": 1.3559147869673764e-05, "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", "profit": 0.00015037604010024672, "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", "profit": 2.736842105263053e-07, "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", "profit": -0.0030822220000000025, "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", "profit": 0.00044962401002504593, "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", "profit": 8.182962406014932e-05, "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", "profit": 0.00035357393483707866, "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", "profit": 2.657142857142672e-07, "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", "profit": 1.9824561403508552e-07, "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", "profit": 3.8872932330826816e-05, "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", "profit": 1.9563909774435151e-07, "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", "profit": 2.624561403508717e-07, "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", "profit": 4.5253132832080657e-07, "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", "profit": 1.3468671679197925e-05, "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", "profit": 2.0892230576441054e-07, "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", "profit": 1.326466165413529e-06, "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", "profit": 2.592481203007459e-07, "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", "profit": 7.5839598997494e-07, "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", "profit": 0.00035408521303258167, "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", "profit": 8.243022556390922e-05, "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", "profit": 6.512781954887175e-07, "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", "profit": 8.020050125313278e-07, "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", "profit": 0.0004595341353383492, "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", "profit": 0.0003471167919799484, "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", "profit": 1.594987468671663e-07, "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", "profit": 0.0002049122807017481, "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", "profit": 2.5814536340851513e-07, "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", "profit": 0.00045472170426064107, "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", "profit": 1.5679197994986587e-07, "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", "profit": 4.789473684210343e-07, "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", "profit": 0.00020451132832080554, "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", "profit": 2.587969924812037e-07, "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", "profit": 0.0002025454135338306, "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", "profit": 2.5724310776941724e-07, "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", "profit": 2.344962406015033e-06, "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", "profit": 1.5308270676691466e-07, "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", "profit": 4.6431077694236234e-07, "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", "profit": 2.7639097744360576e-07, "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", "profit": 2.4666666666666543e-07, "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", "profit": 1.3032581453634e-05, "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", "profit": 0.00014034441102756326, "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", "profit": 0.00020445624060149575, "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", "profit": 1.4486215538846723e-07, "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", "profit": 0.00020603007518796984, "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", "profit": 8.162406015037611e-07, "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", "profit": 2.713784461152774e-07, "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", "profit": 0.0002075577443608964, "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", "profit": 1.2747318295739177e-05, "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", "profit": 2.810526315789381e-07, "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", "profit": 1.2722105263157733e-05, "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", "profit": 0.00020802005012530989, "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", "profit": 8.00150375939842e-07, "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", "profit": 0.00013894967418546025, "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", "profit": 0.00047425268170424306, "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", "profit": 2.814536340852038e-07, "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", "profit": -4.120000000000001e-06, "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", "profit": 0.0003458647117794422, "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", "profit": 0.0004736834586466093, "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", "profit": -0.001781610000000003, "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", "profit": 0.00014285714285713902, "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", "profit": 0.00014367779448621124, "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", "profit": 0.00047810025062657024, "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", "profit": 0.00033880160401002224, "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", "profit": 1.2957443609021985e-05, "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", "profit": 0.00033576451127818874, "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", "profit": 0.0003394370927318202, "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", "profit": 2.6140350877192417e-07, "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", "profit": 4.117428571428529e-05, "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", "profit": 4.129804511278194e-05, "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", "profit": 8.132721804511231e-05, "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", "profit": 0.00034586466165412166, "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", "profit": 4.3884711779447504e-07, "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", "profit": 0.00034214350877191657, "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", "profit": 0.0003365359398496137, "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", "profit": -1.3399999999999973e-06, "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}, "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", "profit": 4.348872180451118e-06, "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", "profit": 2.1455639097744267e-06, "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", "profit": 1.506315789473681e-06, "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", "profit": 4.3741353383458455e-06, "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", "profit": 0.0004726817042606385, "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", "profit": 0.00040896345864661204, "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", "profit": 0.0002323284210526272, "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", "profit": 1.5368421052630647e-07, "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", "profit": 8.471127819548868e-05, "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", "profit": 0.0004577728320801916, "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", "profit": 0.00044601518796991146, "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", "profit": 0.00042907308270676014, "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", "profit": 3.745609022556351e-05, "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", "profit": 1.5147869674185174e-07, "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", "profit": 6.107769423558838e-05, "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", "profit": 0.0007175643609022495, "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", "profit": -3.650999999999996e-06, "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", "profit": 0.0013269330827067605, "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", "profit": 1.2180451127819219e-05, "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", "profit": 0.001139113784461146, "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", "profit": 8.4511278195488e-07, "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", "profit": 0.0006626566416040071, "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", "profit": 0.0004417042606516125, "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", "profit": 0.00013451513784460897, "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", "profit": 1.232832080200495e-06, "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", "profit": 0.0004403456641603881, "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", "profit": 2.558897243107704e-07, "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", "profit": 5.954887218045116e-07, "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", "profit": 1.4461152882205115e-07, "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", "profit": 0.0003977443609022545, "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", "profit": 0.00024060150375938838, "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", "profit": 1.1759398496240516e-06, "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", "profit": 1.2880501253132587e-05, "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", "profit": 3.138847117794446e-07, "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", "profit": 2.3709273182957117e-07, "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", "profit": 3.039097744360846e-07, "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", "profit": 5.554887218044781e-07, "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", "profit": 2.9724310776941686e-07, "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", "profit": 0.00024310791979949287, "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", "profit": 0.0004924821553884823, "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", "profit": 3.0165413533833987e-07, "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", "profit": 0.0004891728822054991, "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", "profit": 4.676691729323286e-05, "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", "profit": 1.5659197994987058e-05, "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", "profit": 8.755839598997492e-05, "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", "profit": 0.00036826295739347814, "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", "profit": 0.0004911979949874384, "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", "profit": 0.0004841604010024786, "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", "profit": 1.501804511278178e-06, "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", "profit": 0.0004756736842105175, "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", "profit": 0.00035588972431077615, "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", "profit": 0.00023060155388470588, "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", "profit": 4.7308270676692514e-07, "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", "profit": 0.0001523810025062626, "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", "profit": -5.8369999999999985e-06, "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", "profit": 0.00023075689223057277, "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", "profit": 1.4378446115287727e-05, "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", "profit": 0.00033743132832080025, "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", "profit": 0.0004620357894736804, "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", "profit": 0.00041353383458646656, "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", "profit": 3.587819548872171e-06, "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", "profit": 0.00022657644110275071, "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", "profit": 7.891729323308177e-07, "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", "profit": 0.0001449783458646603, "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", "profit": 1.2927318295739246e-06, "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", "profit": 0.00042529804511277913, "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", "profit": 0.0006552757894736777, "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", "profit": 8.063157894736843e-07, "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", "profit": 2.6576441102756397e-07, "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", "profit": 0.0013729321804511196, "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", "profit": 9.543859649122774e-07, "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", "profit": 0.00042270857142856846, "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", "profit": -0.000258379, "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", "profit": -2.5590000000000004e-06, "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", "profit": -7.619999999999998e-06, "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", "profit": 0.00010368902255639091, "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", "profit": 0.0006812030075187946, "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", "profit": 0.00010632000000000003, "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", "profit": 0.0015806817042606502, "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", "profit": 9.924812030075114e-07, "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", "profit": 7.479699248120277e-07, "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", "profit": 1.7814536340851996e-06, "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", "profit": 0.0002168922305764362, "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", "profit": 2.504761904761831e-07, "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", "profit": 0.00034269764411026804, "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", "profit": 1.8195488721804031e-07, "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", "profit": 0.0001408521303258095, "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", "profit": 0.00043363413533832607, "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", "profit": 2.8235588972430847e-07, "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", "profit": 0.0010509013533834544, "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", "profit": 2.779448621553787e-07, "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", "profit": 8.188105263157511e-05, "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", "profit": 1.3520501253133123e-05, "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", "profit": 1.1215538847117757e-06, "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", "profit": 4.1954887218044365e-07, "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", "profit": 0.00022252260651629135, "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", "profit": 2.2506265664159932e-07, "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", "profit": 0.00014310776942355607, "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", "profit": 2.905263157894727e-07, "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", "profit": 0.0002175600501253122, "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", "profit": 0.0002232809523809512, "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", "profit": 2.817042606516199e-07, "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", "profit": 2.174937343358337e-07, "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", "profit": 5.057644110275549e-07, "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", "profit": 1.3559147869673764e-05, "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", "profit": 0.00015037604010024672, "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", "profit": 2.736842105263053e-07, "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", "profit": -0.0030822220000000025, "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", "profit": 0.00044962401002504593, "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", "profit": 8.182962406014932e-05, "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", "profit": 0.00035357393483707866, "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", "profit": 2.657142857142672e-07, "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", "profit": 1.9824561403508552e-07, "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", "profit": 3.8872932330826816e-05, "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", "profit": 1.9563909774435151e-07, "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", "profit": 2.624561403508717e-07, "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", "profit": 4.5253132832080657e-07, "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", "profit": 1.3468671679197925e-05, "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", "profit": 2.0892230576441054e-07, "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", "profit": 1.326466165413529e-06, "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", "profit": 2.592481203007459e-07, "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", "profit": 7.5839598997494e-07, "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", "profit": 0.00035408521303258167, "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", "profit": 8.243022556390922e-05, "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", "profit": 6.512781954887175e-07, "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", "profit": 8.020050125313278e-07, "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", "profit": 0.0004595341353383492, "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", "profit": 0.0003471167919799484, "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", "profit": 1.594987468671663e-07, "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", "profit": 0.0002049122807017481, "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", "profit": 2.5814536340851513e-07, "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", "profit": 0.00045472170426064107, "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", "profit": 1.5679197994986587e-07, "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", "profit": 4.789473684210343e-07, "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", "profit": 0.00020451132832080554, "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", "profit": 2.587969924812037e-07, "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", "profit": 0.0002025454135338306, "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", "profit": 2.5724310776941724e-07, "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", "profit": 2.344962406015033e-06, "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", "profit": 1.5308270676691466e-07, "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", "profit": 4.6431077694236234e-07, "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", "profit": 2.7639097744360576e-07, "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", "profit": 2.4666666666666543e-07, "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", "profit": 1.3032581453634e-05, "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", "profit": 0.00014034441102756326, "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", "profit": 0.00020445624060149575, "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", "profit": 1.4486215538846723e-07, "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", "profit": 0.00020603007518796984, "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", "profit": 8.162406015037611e-07, "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", "profit": 2.713784461152774e-07, "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", "profit": 0.0002075577443608964, "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", "profit": 1.2747318295739177e-05, "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", "profit": 2.810526315789381e-07, "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", "profit": 1.2722105263157733e-05, "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", "profit": 0.00020802005012530989, "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", "profit": 8.00150375939842e-07, "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", "profit": 0.00013894967418546025, "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", "profit": 0.00047425268170424306, "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", "profit": 2.814536340852038e-07, "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", "profit": -4.120000000000001e-06, "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", "profit": 0.0003458647117794422, "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", "profit": 0.0004736834586466093, "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", "profit": -0.001781610000000003, "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", "profit": 0.00014285714285713902, "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", "profit": 0.00014367779448621124, "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", "profit": 0.00047810025062657024, "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", "profit": 0.00033880160401002224, "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", "profit": 1.2957443609021985e-05, "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", "profit": 0.00033576451127818874, "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", "profit": 0.0003394370927318202, "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", "profit": 2.6140350877192417e-07, "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", "profit": 4.117428571428529e-05, "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", "profit": 4.129804511278194e-05, "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", "profit": 8.132721804511231e-05, "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", "profit": 0.00034586466165412166, "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", "profit": 4.3884711779447504e-07, "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", "profit": 0.00034214350877191657, "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", "profit": 0.0003365359398496137, "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", "profit": -1.3399999999999973e-06, "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}}, "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}]} \ No newline at end of file From 573502d97226bdaea5ebb1d8eb92cdb078ad748d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 09:59:23 +0200 Subject: [PATCH 053/285] Update test for load_trades_from_db --- tests/conftest.py | 9 ++++++--- tests/data/test_btanalysis.py | 9 +++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index f2143e60e..62810bd6e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -180,7 +180,8 @@ def create_mock_trades(fee): fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', - open_order_id='dry_run_buy_12345' + open_order_id='dry_run_buy_12345', + strategy='DefaultStrategy', ) Trade.session.add(trade) @@ -195,7 +196,8 @@ def create_mock_trades(fee): close_profit=0.005, exchange='bittrex', is_open=False, - open_order_id='dry_run_sell_12345' + open_order_id='dry_run_sell_12345', + strategy='DefaultStrategy', ) Trade.session.add(trade) @@ -208,7 +210,8 @@ def create_mock_trades(fee): fee_close=fee.return_value, open_rate=0.123, exchange='bittrex', - open_order_id='prod_buy_12345' + open_order_id='prod_buy_12345', + strategy='DefaultStrategy', ) Trade.session.add(trade) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index fd3783bf2..32e476b6b 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -43,7 +43,7 @@ def test_load_backtest_data(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"] + assert list(bt_data.columns) == BT_DATA_COLUMNS + ["profit_abs"] assert len(bt_data) == 179 # Test loading from string (must yield same result) @@ -72,6 +72,10 @@ def test_load_trades_from_db(default_conf, fee, mocker): for col in BT_DATA_COLUMNS: if col not in ['index', 'open_at_end']: assert col in trades.columns + trades = load_trades_from_db(db_url=default_conf['db_url'], strategy='DefaultStrategy') + assert len(trades) == 3 + trades = load_trades_from_db(db_url=default_conf['db_url'], strategy='NoneStrategy') + assert len(trades) == 0 def test_extract_trades_of_period(testdatadir): @@ -125,7 +129,8 @@ def test_load_trades(default_conf, mocker): load_trades("DB", db_url=default_conf.get('db_url'), exportfilename=default_conf.get('exportfilename'), - no_trades=False + no_trades=False, + strategy="DefaultStrategy", ) assert db_mock.call_count == 1 From f952f74bf18c71de95eb5db9e92218f3e166c567 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 10:06:59 +0200 Subject: [PATCH 054/285] Add test for new format --- tests/data/test_btanalysis.py | 19 ++++++++++++++++++- tests/testdata/backtest-result_new.json | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 32e476b6b..9ae67ed58 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -17,6 +17,7 @@ from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, 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 @@ -38,7 +39,7 @@ def test_get_latest_backtest_filename(testdatadir, mocker): get_latest_backtest_filename(testdatadir) -def test_load_backtest_data(testdatadir): +def test_load_backtest_data_old_format(testdatadir): filename = testdatadir / "backtest-result_test.json" bt_data = load_backtest_data(filename) @@ -54,6 +55,22 @@ def test_load_backtest_data(testdatadir): load_backtest_data(str("filename") + "nofile") +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 len(bt_data) == 179 + + # Test loading from string (must yield same result) + bt_data2 = load_backtest_data(str(filename)) + assert bt_data.equals(bt_data2) + + with pytest.raises(ValueError, match=r"File .* does not exist\."): + load_backtest_data(str("filename") + "nofile") + + @pytest.mark.usefixtures("init_persistence") def test_load_trades_from_db(default_conf, fee, mocker): diff --git a/tests/testdata/backtest-result_new.json b/tests/testdata/backtest-result_new.json index 457ad1bc7..a44597e82 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", "profit": 4.348872180451118e-06, "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", "profit": 2.1455639097744267e-06, "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", "profit": 1.506315789473681e-06, "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", "profit": 4.3741353383458455e-06, "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", "profit": 0.0004726817042606385, "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", "profit": 0.00040896345864661204, "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", "profit": 0.0002323284210526272, "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", "profit": 1.5368421052630647e-07, "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", "profit": 8.471127819548868e-05, "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", "profit": 0.0004577728320801916, "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", "profit": 0.00044601518796991146, "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", "profit": 0.00042907308270676014, "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", "profit": 3.745609022556351e-05, "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", "profit": 1.5147869674185174e-07, "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", "profit": 6.107769423558838e-05, "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", "profit": 0.0007175643609022495, "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", "profit": -3.650999999999996e-06, "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", "profit": 0.0013269330827067605, "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", "profit": 1.2180451127819219e-05, "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", "profit": 0.001139113784461146, "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", "profit": 8.4511278195488e-07, "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", "profit": 0.0006626566416040071, "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", "profit": 0.0004417042606516125, "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", "profit": 0.00013451513784460897, "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", "profit": 1.232832080200495e-06, "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", "profit": 0.0004403456641603881, "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", "profit": 2.558897243107704e-07, "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", "profit": 5.954887218045116e-07, "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", "profit": 1.4461152882205115e-07, "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", "profit": 0.0003977443609022545, "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", "profit": 0.00024060150375938838, "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", "profit": 1.1759398496240516e-06, "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", "profit": 1.2880501253132587e-05, "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", "profit": 3.138847117794446e-07, "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", "profit": 2.3709273182957117e-07, "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", "profit": 3.039097744360846e-07, "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", "profit": 5.554887218044781e-07, "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", "profit": 2.9724310776941686e-07, "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", "profit": 0.00024310791979949287, "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", "profit": 0.0004924821553884823, "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", "profit": 3.0165413533833987e-07, "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", "profit": 0.0004891728822054991, "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", "profit": 4.676691729323286e-05, "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", "profit": 1.5659197994987058e-05, "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", "profit": 8.755839598997492e-05, "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", "profit": 0.00036826295739347814, "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", "profit": 0.0004911979949874384, "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", "profit": 0.0004841604010024786, "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", "profit": 1.501804511278178e-06, "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", "profit": 0.0004756736842105175, "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", "profit": 0.00035588972431077615, "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", "profit": 0.00023060155388470588, "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", "profit": 4.7308270676692514e-07, "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", "profit": 0.0001523810025062626, "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", "profit": -5.8369999999999985e-06, "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", "profit": 0.00023075689223057277, "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", "profit": 1.4378446115287727e-05, "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", "profit": 0.00033743132832080025, "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", "profit": 0.0004620357894736804, "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", "profit": 0.00041353383458646656, "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", "profit": 3.587819548872171e-06, "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", "profit": 0.00022657644110275071, "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", "profit": 7.891729323308177e-07, "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", "profit": 0.0001449783458646603, "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", "profit": 1.2927318295739246e-06, "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", "profit": 0.00042529804511277913, "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", "profit": 0.0006552757894736777, "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", "profit": 8.063157894736843e-07, "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", "profit": 2.6576441102756397e-07, "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", "profit": 0.0013729321804511196, "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", "profit": 9.543859649122774e-07, "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", "profit": 0.00042270857142856846, "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", "profit": -0.000258379, "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", "profit": -2.5590000000000004e-06, "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", "profit": -7.619999999999998e-06, "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", "profit": 0.00010368902255639091, "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", "profit": 0.0006812030075187946, "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", "profit": 0.00010632000000000003, "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", "profit": 0.0015806817042606502, "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", "profit": 9.924812030075114e-07, "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", "profit": 7.479699248120277e-07, "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", "profit": 1.7814536340851996e-06, "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", "profit": 0.0002168922305764362, "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", "profit": 2.504761904761831e-07, "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", "profit": 0.00034269764411026804, "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", "profit": 1.8195488721804031e-07, "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", "profit": 0.0001408521303258095, "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", "profit": 0.00043363413533832607, "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", "profit": 2.8235588972430847e-07, "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", "profit": 0.0010509013533834544, "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", "profit": 2.779448621553787e-07, "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", "profit": 8.188105263157511e-05, "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", "profit": 1.3520501253133123e-05, "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", "profit": 1.1215538847117757e-06, "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", "profit": 4.1954887218044365e-07, "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", "profit": 0.00022252260651629135, "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", "profit": 2.2506265664159932e-07, "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", "profit": 0.00014310776942355607, "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", "profit": 2.905263157894727e-07, "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", "profit": 0.0002175600501253122, "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", "profit": 0.0002232809523809512, "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", "profit": 2.817042606516199e-07, "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", "profit": 2.174937343358337e-07, "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", "profit": 5.057644110275549e-07, "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", "profit": 1.3559147869673764e-05, "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", "profit": 0.00015037604010024672, "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", "profit": 2.736842105263053e-07, "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", "profit": -0.0030822220000000025, "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", "profit": 0.00044962401002504593, "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", "profit": 8.182962406014932e-05, "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", "profit": 0.00035357393483707866, "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", "profit": 2.657142857142672e-07, "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", "profit": 1.9824561403508552e-07, "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", "profit": 3.8872932330826816e-05, "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", "profit": 1.9563909774435151e-07, "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", "profit": 2.624561403508717e-07, "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", "profit": 4.5253132832080657e-07, "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", "profit": 1.3468671679197925e-05, "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", "profit": 2.0892230576441054e-07, "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", "profit": 1.326466165413529e-06, "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", "profit": 2.592481203007459e-07, "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", "profit": 7.5839598997494e-07, "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", "profit": 0.00035408521303258167, "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", "profit": 8.243022556390922e-05, "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", "profit": 6.512781954887175e-07, "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", "profit": 8.020050125313278e-07, "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", "profit": 0.0004595341353383492, "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", "profit": 0.0003471167919799484, "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", "profit": 1.594987468671663e-07, "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", "profit": 0.0002049122807017481, "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", "profit": 2.5814536340851513e-07, "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", "profit": 0.00045472170426064107, "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", "profit": 1.5679197994986587e-07, "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", "profit": 4.789473684210343e-07, "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", "profit": 0.00020451132832080554, "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", "profit": 2.587969924812037e-07, "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", "profit": 0.0002025454135338306, "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", "profit": 2.5724310776941724e-07, "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", "profit": 2.344962406015033e-06, "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", "profit": 1.5308270676691466e-07, "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", "profit": 4.6431077694236234e-07, "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", "profit": 2.7639097744360576e-07, "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", "profit": 2.4666666666666543e-07, "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", "profit": 1.3032581453634e-05, "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", "profit": 0.00014034441102756326, "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", "profit": 0.00020445624060149575, "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", "profit": 1.4486215538846723e-07, "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", "profit": 0.00020603007518796984, "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", "profit": 8.162406015037611e-07, "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", "profit": 2.713784461152774e-07, "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", "profit": 0.0002075577443608964, "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", "profit": 1.2747318295739177e-05, "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", "profit": 2.810526315789381e-07, "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", "profit": 1.2722105263157733e-05, "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", "profit": 0.00020802005012530989, "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", "profit": 8.00150375939842e-07, "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", "profit": 0.00013894967418546025, "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", "profit": 0.00047425268170424306, "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", "profit": 2.814536340852038e-07, "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", "profit": -4.120000000000001e-06, "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", "profit": 0.0003458647117794422, "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", "profit": 0.0004736834586466093, "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", "profit": -0.001781610000000003, "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", "profit": 0.00014285714285713902, "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", "profit": 0.00014367779448621124, "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", "profit": 0.00047810025062657024, "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", "profit": 0.00033880160401002224, "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", "profit": 1.2957443609021985e-05, "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", "profit": 0.00033576451127818874, "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", "profit": 0.0003394370927318202, "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", "profit": 2.6140350877192417e-07, "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", "profit": 4.117428571428529e-05, "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", "profit": 4.129804511278194e-05, "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", "profit": 8.132721804511231e-05, "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", "profit": 0.00034586466165412166, "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", "profit": 4.3884711779447504e-07, "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", "profit": 0.00034214350877191657, "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", "profit": 0.0003365359398496137, "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", "profit": -1.3399999999999973e-06, "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}}, "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", "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}}, "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 5b1a7ba00f8d9dbde687ba5f26ebfec3c420f38f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 15:59:22 +0200 Subject: [PATCH 055/285] Test multistrat loading --- tests/data/test_btanalysis.py | 27 ++++++++++++++++++- .../testdata/backtest-result_multistrat.json | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 9ae67ed58..63fe26eaa 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -32,8 +32,10 @@ def test_get_latest_backtest_filename(testdatadir, mocker): res = get_latest_backtest_filename(testdatadir) assert res == 'backtest-result_new.json' - mocker.patch("freqtrade.data.btanalysis.json_load", return_value={}) + res = get_latest_backtest_filename(str(testdatadir)) + assert res == 'backtest-result_new.json' + mocker.patch("freqtrade.data.btanalysis.json_load", return_value={}) with pytest.raises(ValueError, match=r"Invalid '.last_result.json' format."): get_latest_backtest_filename(testdatadir) @@ -70,6 +72,29 @@ def test_load_backtest_data_new_format(testdatadir): with pytest.raises(ValueError, match=r"File .* does not exist\."): load_backtest_data(str("filename") + "nofile") + with pytest.raises(ValueError, match=r"Unknown dataformat."): + load_backtest_data(testdatadir / '.last_result.json') + + +def test_load_backtest_data_multi(testdatadir): + + filename = testdatadir / "backtest-result_multistrat.json" + 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 len(bt_data) == 179 + + # Test loading from string (must yield same result) + bt_data2 = load_backtest_data(str(filename), strategy=strategy) + assert bt_data.equals(bt_data2) + + with pytest.raises(ValueError, match=r"Strategy XYZ not available in the backtest result\."): + load_backtest_data(filename, strategy='XYZ') + + with pytest.raises(ValueError, match=r"Detected backtest result with more than one strategy.*"): + load_backtest_data(filename) + @pytest.mark.usefixtures("init_persistence") def test_load_trades_from_db(default_conf, fee, mocker): diff --git a/tests/testdata/backtest-result_multistrat.json b/tests/testdata/backtest-result_multistrat.json index a58ab28cb..88f021cb8 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", "profit": 4.348872180451118e-06, "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", "profit": 2.1455639097744267e-06, "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", "profit": 1.506315789473681e-06, "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", "profit": 4.3741353383458455e-06, "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", "profit": 0.0004726817042606385, "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", "profit": 0.00040896345864661204, "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", "profit": 0.0002323284210526272, "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", "profit": 1.5368421052630647e-07, "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", "profit": 8.471127819548868e-05, "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", "profit": 0.0004577728320801916, "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", "profit": 0.00044601518796991146, "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", "profit": 0.00042907308270676014, "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", "profit": 3.745609022556351e-05, "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", "profit": 1.5147869674185174e-07, "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", "profit": 6.107769423558838e-05, "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", "profit": 0.0007175643609022495, "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", "profit": -3.650999999999996e-06, "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", "profit": 0.0013269330827067605, "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", "profit": 1.2180451127819219e-05, "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", "profit": 0.001139113784461146, "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", "profit": 8.4511278195488e-07, "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", "profit": 0.0006626566416040071, "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", "profit": 0.0004417042606516125, "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", "profit": 0.00013451513784460897, "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", "profit": 1.232832080200495e-06, "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", "profit": 0.0004403456641603881, "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", "profit": 2.558897243107704e-07, "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", "profit": 5.954887218045116e-07, "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", "profit": 1.4461152882205115e-07, "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", "profit": 0.0003977443609022545, "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", "profit": 0.00024060150375938838, "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", "profit": 1.1759398496240516e-06, "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", "profit": 1.2880501253132587e-05, "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", "profit": 3.138847117794446e-07, "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", "profit": 2.3709273182957117e-07, "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", "profit": 3.039097744360846e-07, "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", "profit": 5.554887218044781e-07, "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", "profit": 2.9724310776941686e-07, "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", "profit": 0.00024310791979949287, "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", "profit": 0.0004924821553884823, "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", "profit": 3.0165413533833987e-07, "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", "profit": 0.0004891728822054991, "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", "profit": 4.676691729323286e-05, "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", "profit": 1.5659197994987058e-05, "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", "profit": 8.755839598997492e-05, "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", "profit": 0.00036826295739347814, "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", "profit": 0.0004911979949874384, "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", "profit": 0.0004841604010024786, "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", "profit": 1.501804511278178e-06, "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", "profit": 0.0004756736842105175, "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", "profit": 0.00035588972431077615, "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", "profit": 0.00023060155388470588, "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", "profit": 4.7308270676692514e-07, "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", "profit": 0.0001523810025062626, "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", "profit": -5.8369999999999985e-06, "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", "profit": 0.00023075689223057277, "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", "profit": 1.4378446115287727e-05, "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", "profit": 0.00033743132832080025, "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", "profit": 0.0004620357894736804, "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", "profit": 0.00041353383458646656, "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", "profit": 3.587819548872171e-06, "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", "profit": 0.00022657644110275071, "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", "profit": 7.891729323308177e-07, "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", "profit": 0.0001449783458646603, "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", "profit": 1.2927318295739246e-06, "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", "profit": 0.00042529804511277913, "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", "profit": 0.0006552757894736777, "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", "profit": 8.063157894736843e-07, "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", "profit": 2.6576441102756397e-07, "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", "profit": 0.0013729321804511196, "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", "profit": 9.543859649122774e-07, "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", "profit": 0.00042270857142856846, "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", "profit": -0.000258379, "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", "profit": -2.5590000000000004e-06, "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", "profit": -7.619999999999998e-06, "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", "profit": 0.00010368902255639091, "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", "profit": 0.0006812030075187946, "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", "profit": 0.00010632000000000003, "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", "profit": 0.0015806817042606502, "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", "profit": 9.924812030075114e-07, "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", "profit": 7.479699248120277e-07, "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", "profit": 1.7814536340851996e-06, "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", "profit": 0.0002168922305764362, "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", "profit": 2.504761904761831e-07, "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", "profit": 0.00034269764411026804, "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", "profit": 1.8195488721804031e-07, "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", "profit": 0.0001408521303258095, "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", "profit": 0.00043363413533832607, "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", "profit": 2.8235588972430847e-07, "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", "profit": 0.0010509013533834544, "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", "profit": 2.779448621553787e-07, "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", "profit": 8.188105263157511e-05, "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", "profit": 1.3520501253133123e-05, "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", "profit": 1.1215538847117757e-06, "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", "profit": 4.1954887218044365e-07, "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", "profit": 0.00022252260651629135, "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", "profit": 2.2506265664159932e-07, "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", "profit": 0.00014310776942355607, "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", "profit": 2.905263157894727e-07, "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", "profit": 0.0002175600501253122, "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", "profit": 0.0002232809523809512, "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", "profit": 2.817042606516199e-07, "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", "profit": 2.174937343358337e-07, "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", "profit": 5.057644110275549e-07, "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", "profit": 1.3559147869673764e-05, "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", "profit": 0.00015037604010024672, "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", "profit": 2.736842105263053e-07, "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", "profit": -0.0030822220000000025, "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", "profit": 0.00044962401002504593, "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", "profit": 8.182962406014932e-05, "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", "profit": 0.00035357393483707866, "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", "profit": 2.657142857142672e-07, "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", "profit": 1.9824561403508552e-07, "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", "profit": 3.8872932330826816e-05, "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", "profit": 1.9563909774435151e-07, "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", "profit": 2.624561403508717e-07, "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", "profit": 4.5253132832080657e-07, "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", "profit": 1.3468671679197925e-05, "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", "profit": 2.0892230576441054e-07, "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", "profit": 1.326466165413529e-06, "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", "profit": 2.592481203007459e-07, "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", "profit": 7.5839598997494e-07, "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", "profit": 0.00035408521303258167, "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", "profit": 8.243022556390922e-05, "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", "profit": 6.512781954887175e-07, "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", "profit": 8.020050125313278e-07, "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", "profit": 0.0004595341353383492, "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", "profit": 0.0003471167919799484, "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", "profit": 1.594987468671663e-07, "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", "profit": 0.0002049122807017481, "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", "profit": 2.5814536340851513e-07, "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", "profit": 0.00045472170426064107, "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", "profit": 1.5679197994986587e-07, "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", "profit": 4.789473684210343e-07, "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", "profit": 0.00020451132832080554, "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", "profit": 2.587969924812037e-07, "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", "profit": 0.0002025454135338306, "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", "profit": 2.5724310776941724e-07, "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", "profit": 2.344962406015033e-06, "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", "profit": 1.5308270676691466e-07, "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", "profit": 4.6431077694236234e-07, "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", "profit": 2.7639097744360576e-07, "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", "profit": 2.4666666666666543e-07, "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", "profit": 1.3032581453634e-05, "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", "profit": 0.00014034441102756326, "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", "profit": 0.00020445624060149575, "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", "profit": 1.4486215538846723e-07, "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", "profit": 0.00020603007518796984, "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", "profit": 8.162406015037611e-07, "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", "profit": 2.713784461152774e-07, "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", "profit": 0.0002075577443608964, "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", "profit": 1.2747318295739177e-05, "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", "profit": 2.810526315789381e-07, "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", "profit": 1.2722105263157733e-05, "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", "profit": 0.00020802005012530989, "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", "profit": 8.00150375939842e-07, "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", "profit": 0.00013894967418546025, "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", "profit": 0.00047425268170424306, "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", "profit": 2.814536340852038e-07, "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", "profit": -4.120000000000001e-06, "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", "profit": 0.0003458647117794422, "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", "profit": 0.0004736834586466093, "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", "profit": -0.001781610000000003, "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", "profit": 0.00014285714285713902, "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", "profit": 0.00014367779448621124, "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", "profit": 0.00047810025062657024, "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", "profit": 0.00033880160401002224, "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", "profit": 1.2957443609021985e-05, "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", "profit": 0.00033576451127818874, "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", "profit": 0.0003394370927318202, "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", "profit": 2.6140350877192417e-07, "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", "profit": 4.117428571428529e-05, "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", "profit": 4.129804511278194e-05, "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", "profit": 8.132721804511231e-05, "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", "profit": 0.00034586466165412166, "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", "profit": 4.3884711779447504e-07, "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", "profit": 0.00034214350877191657, "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", "profit": 0.0003365359398496137, "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", "profit": -1.3399999999999973e-06, "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}, "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", "profit": 4.348872180451118e-06, "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", "profit": 2.1455639097744267e-06, "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", "profit": 1.506315789473681e-06, "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", "profit": 4.3741353383458455e-06, "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", "profit": 0.0004726817042606385, "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", "profit": 0.00040896345864661204, "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", "profit": 0.0002323284210526272, "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", "profit": 1.5368421052630647e-07, "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", "profit": 8.471127819548868e-05, "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", "profit": 0.0004577728320801916, "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", "profit": 0.00044601518796991146, "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", "profit": 0.00042907308270676014, "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", "profit": 3.745609022556351e-05, "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", "profit": 1.5147869674185174e-07, "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", "profit": 6.107769423558838e-05, "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", "profit": 0.0007175643609022495, "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", "profit": -3.650999999999996e-06, "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", "profit": 0.0013269330827067605, "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", "profit": 1.2180451127819219e-05, "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", "profit": 0.001139113784461146, "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", "profit": 8.4511278195488e-07, "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", "profit": 0.0006626566416040071, "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", "profit": 0.0004417042606516125, "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", "profit": 0.00013451513784460897, "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", "profit": 1.232832080200495e-06, "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", "profit": 0.0004403456641603881, "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", "profit": 2.558897243107704e-07, "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", "profit": 5.954887218045116e-07, "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", "profit": 1.4461152882205115e-07, "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", "profit": 0.0003977443609022545, "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", "profit": 0.00024060150375938838, "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", "profit": 1.1759398496240516e-06, "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", "profit": 1.2880501253132587e-05, "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", "profit": 3.138847117794446e-07, "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", "profit": 2.3709273182957117e-07, "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", "profit": 3.039097744360846e-07, "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", "profit": 5.554887218044781e-07, "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", "profit": 2.9724310776941686e-07, "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", "profit": 0.00024310791979949287, "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", "profit": 0.0004924821553884823, "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", "profit": 3.0165413533833987e-07, "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", "profit": 0.0004891728822054991, "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", "profit": 4.676691729323286e-05, "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", "profit": 1.5659197994987058e-05, "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", "profit": 8.755839598997492e-05, "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", "profit": 0.00036826295739347814, "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", "profit": 0.0004911979949874384, "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", "profit": 0.0004841604010024786, "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", "profit": 1.501804511278178e-06, "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", "profit": 0.0004756736842105175, "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", "profit": 0.00035588972431077615, "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", "profit": 0.00023060155388470588, "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", "profit": 4.7308270676692514e-07, "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", "profit": 0.0001523810025062626, "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", "profit": -5.8369999999999985e-06, "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", "profit": 0.00023075689223057277, "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", "profit": 1.4378446115287727e-05, "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", "profit": 0.00033743132832080025, "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", "profit": 0.0004620357894736804, "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", "profit": 0.00041353383458646656, "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", "profit": 3.587819548872171e-06, "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", "profit": 0.00022657644110275071, "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", "profit": 7.891729323308177e-07, "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", "profit": 0.0001449783458646603, "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", "profit": 1.2927318295739246e-06, "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", "profit": 0.00042529804511277913, "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", "profit": 0.0006552757894736777, "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", "profit": 8.063157894736843e-07, "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", "profit": 2.6576441102756397e-07, "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", "profit": 0.0013729321804511196, "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", "profit": 9.543859649122774e-07, "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", "profit": 0.00042270857142856846, "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", "profit": -0.000258379, "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", "profit": -2.5590000000000004e-06, "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", "profit": -7.619999999999998e-06, "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", "profit": 0.00010368902255639091, "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", "profit": 0.0006812030075187946, "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", "profit": 0.00010632000000000003, "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", "profit": 0.0015806817042606502, "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", "profit": 9.924812030075114e-07, "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", "profit": 7.479699248120277e-07, "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", "profit": 1.7814536340851996e-06, "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", "profit": 0.0002168922305764362, "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", "profit": 2.504761904761831e-07, "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", "profit": 0.00034269764411026804, "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", "profit": 1.8195488721804031e-07, "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", "profit": 0.0001408521303258095, "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", "profit": 0.00043363413533832607, "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", "profit": 2.8235588972430847e-07, "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", "profit": 0.0010509013533834544, "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", "profit": 2.779448621553787e-07, "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", "profit": 8.188105263157511e-05, "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", "profit": 1.3520501253133123e-05, "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", "profit": 1.1215538847117757e-06, "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", "profit": 4.1954887218044365e-07, "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", "profit": 0.00022252260651629135, "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", "profit": 2.2506265664159932e-07, "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", "profit": 0.00014310776942355607, "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", "profit": 2.905263157894727e-07, "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", "profit": 0.0002175600501253122, "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", "profit": 0.0002232809523809512, "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", "profit": 2.817042606516199e-07, "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", "profit": 2.174937343358337e-07, "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", "profit": 5.057644110275549e-07, "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", "profit": 1.3559147869673764e-05, "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", "profit": 0.00015037604010024672, "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", "profit": 2.736842105263053e-07, "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", "profit": -0.0030822220000000025, "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", "profit": 0.00044962401002504593, "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", "profit": 8.182962406014932e-05, "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", "profit": 0.00035357393483707866, "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", "profit": 2.657142857142672e-07, "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", "profit": 1.9824561403508552e-07, "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", "profit": 3.8872932330826816e-05, "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", "profit": 1.9563909774435151e-07, "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", "profit": 2.624561403508717e-07, "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", "profit": 4.5253132832080657e-07, "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", "profit": 1.3468671679197925e-05, "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", "profit": 2.0892230576441054e-07, "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", "profit": 1.326466165413529e-06, "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", "profit": 2.592481203007459e-07, "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", "profit": 7.5839598997494e-07, "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", "profit": 0.00035408521303258167, "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", "profit": 8.243022556390922e-05, "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", "profit": 6.512781954887175e-07, "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", "profit": 8.020050125313278e-07, "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", "profit": 0.0004595341353383492, "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", "profit": 0.0003471167919799484, "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", "profit": 1.594987468671663e-07, "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", "profit": 0.0002049122807017481, "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", "profit": 2.5814536340851513e-07, "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", "profit": 0.00045472170426064107, "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", "profit": 1.5679197994986587e-07, "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", "profit": 4.789473684210343e-07, "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", "profit": 0.00020451132832080554, "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", "profit": 2.587969924812037e-07, "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", "profit": 0.0002025454135338306, "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", "profit": 2.5724310776941724e-07, "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", "profit": 2.344962406015033e-06, "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", "profit": 1.5308270676691466e-07, "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", "profit": 4.6431077694236234e-07, "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", "profit": 2.7639097744360576e-07, "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", "profit": 2.4666666666666543e-07, "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", "profit": 1.3032581453634e-05, "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", "profit": 0.00014034441102756326, "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", "profit": 0.00020445624060149575, "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", "profit": 1.4486215538846723e-07, "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", "profit": 0.00020603007518796984, "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", "profit": 8.162406015037611e-07, "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", "profit": 2.713784461152774e-07, "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", "profit": 0.0002075577443608964, "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", "profit": 1.2747318295739177e-05, "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", "profit": 2.810526315789381e-07, "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", "profit": 1.2722105263157733e-05, "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", "profit": 0.00020802005012530989, "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", "profit": 8.00150375939842e-07, "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", "profit": 0.00013894967418546025, "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", "profit": 0.00047425268170424306, "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", "profit": 2.814536340852038e-07, "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", "profit": -4.120000000000001e-06, "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", "profit": 0.0003458647117794422, "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", "profit": 0.0004736834586466093, "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", "profit": -0.001781610000000003, "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", "profit": 0.00014285714285713902, "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", "profit": 0.00014367779448621124, "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", "profit": 0.00047810025062657024, "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", "profit": 0.00033880160401002224, "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", "profit": 1.2957443609021985e-05, "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", "profit": 0.00033576451127818874, "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", "profit": 0.0003394370927318202, "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", "profit": 2.6140350877192417e-07, "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", "profit": 4.117428571428529e-05, "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", "profit": 4.129804511278194e-05, "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", "profit": 8.132721804511231e-05, "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", "profit": 0.00034586466165412166, "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", "profit": 4.3884711779447504e-07, "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", "profit": 0.00034214350877191657, "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", "profit": 0.0003365359398496137, "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", "profit": -1.3399999999999973e-06, "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}}, "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}]} \ No newline at end of file +{"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}, "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}}, "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}]} \ No newline at end of file From 59ac4b9c9a2d0568252c82f8b48c833cb76bfd9e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 27 Jun 2020 19:48:45 +0200 Subject: [PATCH 056/285] Test writing statistics --- tests/data/test_history.py | 2 +- tests/optimize/test_optimize_reports.py | 27 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index c2eb2d715..8b3a3c568 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -36,7 +36,7 @@ def _backup_file(file: Path, copy_file: bool = False) -> None: """ Backup existing file to avoid deleting the user file :param file: complete path to the file - :param touch_file: create an empty file in replacement + :param copy_file: keep file in place too. :return: None """ file_swp = str(file) + '.swp' diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index c46b96ab2..690847adc 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -2,23 +2,27 @@ from datetime import datetime from pathlib import Path import pandas as pd +import re import pytest from arrow import Arrow from freqtrade.configuration import TimeRange from freqtrade.data import history from freqtrade.edge import PairInfo +from freqtrade.data.btanalysis import get_latest_backtest_filename from freqtrade.optimize.optimize_reports import (generate_backtest_stats, generate_edge_table, generate_pair_metrics, generate_sell_reason_stats, generate_strategy_metrics, store_backtest_result, + store_backtest_stats, text_table_bt_results, text_table_sell_reason, text_table_strategy) from freqtrade.strategy.interface import SellType from tests.conftest import patch_exchange +from tests.data.test_history import _backup_file, _clean_test_file def test_text_table_bt_results(default_conf, mocker): @@ -115,6 +119,29 @@ def test_generate_backtest_stats(default_conf, testdatadir): assert strat_stats['drawdown_end_ts'] == 0 assert strat_stats['drawdown_start_ts'] == 0 + # Test storing stats + filename = Path(testdatadir / 'btresult.json') + filename_last = Path(testdatadir / '.last_result.json') + _backup_file(filename_last, copy_file=True) + assert not filename.is_file() + + store_backtest_stats(filename, stats) + + # get real Filename (it's btresult-.json) + last_fn = get_latest_backtest_filename(filename_last.parent) + assert re.match(r"btresult-.*\.json", last_fn) + + filename1 = (testdatadir / last_fn) + assert filename1.is_file() + content = filename1.read_text() + assert 'max_drawdown' in content + assert 'strategy' in content + + assert filename_last.is_file() + + _clean_test_file(filename_last) + filename1.unlink() + def test_generate_pair_metrics(default_conf, mocker): From 59e0ca0aaab0543933d8bcd0961a62bb37db8916 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 28 Jun 2020 09:04:19 +0200 Subject: [PATCH 057/285] Add pairlist to backtest-result --- freqtrade/optimize/optimize_reports.py | 1 + tests/optimize/test_optimize_reports.py | 2 ++ tests/testdata/backtest-result_multistrat.json | 2 +- tests/testdata/backtest-result_new.json | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 6f9d3f34e..b93e60dca 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -250,6 +250,7 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'backtest_days': backtest_days, 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None, 'market_change': market_change, + 'pairlist': list(btdata.keys()), 'stake_amount': config['stake_amount'] } result['strategy'][strategy] = strat_stats diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 690847adc..f908677d7 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -118,6 +118,7 @@ def test_generate_backtest_stats(default_conf, testdatadir): assert strat_stats['drawdown_end'] == Arrow.fromtimestamp(0).datetime assert strat_stats['drawdown_end_ts'] == 0 assert strat_stats['drawdown_start_ts'] == 0 + assert strat_stats['pairlist'] == ['UNITTEST/BTC'] # Test storing stats filename = Path(testdatadir / 'btresult.json') @@ -136,6 +137,7 @@ def test_generate_backtest_stats(default_conf, testdatadir): content = filename1.read_text() assert 'max_drawdown' in content assert 'strategy' in content + assert 'pairlist' in content assert filename_last.is_file() diff --git a/tests/testdata/backtest-result_multistrat.json b/tests/testdata/backtest-result_multistrat.json index 88f021cb8..0e5386ef3 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}, "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}}, "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}]} \ No newline at end of file +{"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}]} diff --git a/tests/testdata/backtest-result_new.json b/tests/testdata/backtest-result_new.json index a44597e82..f004e879a 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}}, "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", "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}]} From 2ed808da1f4f45342a0a8fd41b158fb7b0e26b0d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 28 Jun 2020 09:27:19 +0200 Subject: [PATCH 058/285] Extract .last_result.json to constant --- freqtrade/constants.py | 2 ++ freqtrade/data/btanalysis.py | 5 +-- freqtrade/optimize/optimize_reports.py | 5 ++- tests/data/test_btanalysis.py | 3 +- tests/optimize/test_optimize_reports.py | 46 ++++++++++++------------- 5 files changed, 32 insertions(+), 29 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index ccb05a60f..1b414adb4 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -33,6 +33,8 @@ DEFAULT_DATAFRAME_COLUMNS = ['date', 'open', 'high', 'low', 'close', 'volume'] # it has wide consequences for stored trades files DEFAULT_TRADES_COLUMNS = ['timestamp', 'id', 'type', 'side', 'price', 'amount', 'cost'] +LAST_BT_RESULT_FN = '.last_result.json' + USERPATH_HYPEROPTS = 'hyperopts' USERPATH_STRATEGIES = 'strategies' USERPATH_NOTEBOOKS = 'notebooks' diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 17d3fed14..0ae1809f3 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -10,6 +10,7 @@ import pandas as pd from datetime import timezone from freqtrade import persistence +from freqtrade.constants import LAST_BT_RESULT_FN from freqtrade.misc import json_load from freqtrade.persistence import Trade @@ -34,7 +35,7 @@ def get_latest_backtest_filename(directory: Union[Path, str]) -> str: directory = Path(directory) if not directory.is_dir(): raise ValueError(f"Directory '{directory}' does not exist.") - filename = directory / '.last_result.json' + filename = directory / LAST_BT_RESULT_FN if not filename.is_file(): raise ValueError(f"Directory '{directory}' does not seem to contain backtest statistics yet.") @@ -43,7 +44,7 @@ def get_latest_backtest_filename(directory: Union[Path, str]) -> str: data = json_load(file) if 'latest_backtest' not in data: - raise ValueError("Invalid '.last_result.json' format.") + raise ValueError(f"Invalid '{LAST_BT_RESULT_FN}' format.") return data['latest_backtest'] diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index b93e60dca..d1c45bd94 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -7,7 +7,7 @@ from arrow import Arrow from pandas import DataFrame from tabulate import tabulate -from freqtrade.constants import DATETIME_PRINT_FORMAT +from freqtrade.constants import DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN from freqtrade.data.btanalysis import calculate_max_drawdown, calculate_market_change from freqtrade.misc import file_dump_json @@ -21,8 +21,7 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N ).with_suffix(recordfilename.suffix) file_dump_json(filename, stats) - latest_filename = Path.joinpath(recordfilename.parent, - '.last_result.json') + latest_filename = Path.joinpath(recordfilename.parent, LAST_BT_RESULT_FN) file_dump_json(latest_filename, {'latest_backtest': str(filename.name)}) diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 63fe26eaa..144dc5162 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -6,6 +6,7 @@ from arrow import Arrow 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, @@ -73,7 +74,7 @@ def test_load_backtest_data_new_format(testdatadir): load_backtest_data(str("filename") + "nofile") with pytest.raises(ValueError, match=r"Unknown dataformat."): - load_backtest_data(testdatadir / '.last_result.json') + load_backtest_data(testdatadir / LAST_BT_RESULT_FN) def test_load_backtest_data_multi(testdatadir): diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index f908677d7..2431fa716 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -1,15 +1,15 @@ -from datetime import datetime +import re from pathlib import Path import pandas as pd -import re import pytest from arrow import Arrow from freqtrade.configuration import TimeRange +from freqtrade.constants import LAST_BT_RESULT_FN from freqtrade.data import history -from freqtrade.edge import PairInfo from freqtrade.data.btanalysis import get_latest_backtest_filename +from freqtrade.edge import PairInfo from freqtrade.optimize.optimize_reports import (generate_backtest_stats, generate_edge_table, generate_pair_metrics, @@ -93,25 +93,25 @@ def test_generate_backtest_stats(default_conf, testdatadir): # Above sample had no loosing trade assert strat_stats['max_drawdown'] == 0.0 - results = {'DefStrat': pd.DataFrame({"pair": ["UNITTEST/BTC", "UNITTEST/BTC", - "UNITTEST/BTC", "UNITTEST/BTC"], - "profit_percent": [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, - Arrow(2017, 11, 14, 22, 12, 00).datetime, - Arrow(2017, 11, 14, 22, 44, 00).datetime], - "close_date": [Arrow(2017, 11, 14, 21, 35, 00).datetime, - Arrow(2017, 11, 14, 22, 10, 00).datetime, - Arrow(2017, 11, 14, 22, 43, 00).datetime, - Arrow(2017, 11, 14, 22, 58, 00).datetime], - "open_rate": [0.002543, 0.003003, 0.003089, 0.003214], - "close_rate": [0.002546, 0.003014, 0.0032903, 0.003217], - "trade_duration": [123, 34, 31, 14], - "open_at_end": [False, False, False, True], - "sell_reason": [SellType.ROI, SellType.STOP_LOSS, - SellType.ROI, SellType.FORCE_SELL] - })} + results = {'DefStrat': pd.DataFrame( + {"pair": ["UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC", "UNITTEST/BTC"], + "profit_percent": [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, + Arrow(2017, 11, 14, 22, 12, 00).datetime, + Arrow(2017, 11, 14, 22, 44, 00).datetime], + "close_date": [Arrow(2017, 11, 14, 21, 35, 00).datetime, + Arrow(2017, 11, 14, 22, 10, 00).datetime, + Arrow(2017, 11, 14, 22, 43, 00).datetime, + Arrow(2017, 11, 14, 22, 58, 00).datetime], + "open_rate": [0.002543, 0.003003, 0.003089, 0.003214], + "close_rate": [0.002546, 0.003014, 0.0032903, 0.003217], + "trade_duration": [123, 34, 31, 14], + "open_at_end": [False, False, False, True], + "sell_reason": [SellType.ROI, SellType.STOP_LOSS, + SellType.ROI, SellType.FORCE_SELL] + })} assert strat_stats['max_drawdown'] == 0.0 assert strat_stats['drawdown_start'] == Arrow.fromtimestamp(0).datetime @@ -122,7 +122,7 @@ def test_generate_backtest_stats(default_conf, testdatadir): # Test storing stats filename = Path(testdatadir / 'btresult.json') - filename_last = Path(testdatadir / '.last_result.json') + filename_last = Path(testdatadir / LAST_BT_RESULT_FN) _backup_file(filename_last, copy_file=True) assert not filename.is_file() From 7c5587aeaafb0948e507d34cac6914a89b09af0e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 28 Jun 2020 09:45:23 +0200 Subject: [PATCH 059/285] exportfilename can be a file or directory --- freqtrade/configuration/configuration.py | 2 +- freqtrade/data/btanalysis.py | 7 +++++-- freqtrade/optimize/optimize_reports.py | 13 +++++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 139e42084..bbd6ce747 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -199,7 +199,7 @@ class Configuration: config['exportfilename'] = Path(config['exportfilename']) else: config['exportfilename'] = (config['user_data_dir'] - / 'backtest_results/backtest-result.json') + / 'backtest_results') def _process_optimize_options(self, config: Dict[str, Any]) -> None: diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 0ae1809f3..07834d729 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -38,7 +38,8 @@ def get_latest_backtest_filename(directory: Union[Path, str]) -> str: filename = directory / LAST_BT_RESULT_FN if not filename.is_file(): - raise ValueError(f"Directory '{directory}' does not seem to contain backtest statistics yet.") + raise ValueError( + f"Directory '{directory}' does not seem to contain backtest statistics yet.") with filename.open() as file: data = json_load(file) @@ -57,9 +58,11 @@ def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]: """ if isinstance(filename, str): filename = Path(filename) + if filename.is_dir(): + filename = get_latest_backtest_filename(filename) if not filename.is_file(): raise ValueError(f"File {filename} does not exist.") - + logger.info(f"Loading backtest result from {filename}") with filename.open() as file: data = json_load(file) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index d1c45bd94..d0e29d98f 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -16,12 +16,17 @@ logger = logging.getLogger(__name__) def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> None: - filename = Path.joinpath(recordfilename.parent, - f'{recordfilename.stem}-{datetime.now().isoformat()}' - ).with_suffix(recordfilename.suffix) + if recordfilename.is_dir(): + filename = recordfilename / \ + f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.json' + else: + filename = Path.joinpath( + recordfilename.parent, + f'{recordfilename.stem}-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}' + ).with_suffix(recordfilename.suffix) file_dump_json(filename, stats) - latest_filename = Path.joinpath(recordfilename.parent, LAST_BT_RESULT_FN) + latest_filename = Path.joinpath(filename.parent, LAST_BT_RESULT_FN) file_dump_json(latest_filename, {'latest_backtest': str(filename.name)}) From d999fa2a7e82b3e1fb1c9e0da9b726379f1dc52d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 28 Jun 2020 09:51:49 +0200 Subject: [PATCH 060/285] Test autogetting result filename --- freqtrade/data/btanalysis.py | 2 +- tests/data/test_btanalysis.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 07834d729..6931b1685 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -59,7 +59,7 @@ def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]: if isinstance(filename, str): filename = Path(filename) if filename.is_dir(): - filename = get_latest_backtest_filename(filename) + filename = filename / get_latest_backtest_filename(filename) if not filename.is_file(): raise ValueError(f"File {filename} does not exist.") logger.info(f"Loading backtest result from {filename}") diff --git a/tests/data/test_btanalysis.py b/tests/data/test_btanalysis.py index 144dc5162..5e44b7d87 100644 --- a/tests/data/test_btanalysis.py +++ b/tests/data/test_btanalysis.py @@ -70,6 +70,10 @@ def test_load_backtest_data_new_format(testdatadir): bt_data2 = load_backtest_data(str(filename)) assert bt_data.equals(bt_data2) + # Test loading from folder (must yield same result) + bt_data3 = load_backtest_data(testdatadir) + assert bt_data.equals(bt_data3) + with pytest.raises(ValueError, match=r"File .* does not exist\."): load_backtest_data(str("filename") + "nofile") From 16a842f9f60f1c916d77a243e2f2e169dc0611fc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 28 Jun 2020 10:17:08 +0200 Subject: [PATCH 061/285] Have plotting support folder-based exportfilename --- freqtrade/plot/plotting.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index eee338a42..16afaec3b 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -8,7 +8,9 @@ from freqtrade.configuration import TimeRange from freqtrade.data.btanalysis import (calculate_max_drawdown, combine_dataframes_with_mean, create_cum_profit, - extract_trades_of_period, load_trades) + extract_trades_of_period, + get_latest_backtest_filename, + load_trades) from freqtrade.data.converter import trim_dataframe from freqtrade.data.history import load_data from freqtrade.exceptions import OperationalException @@ -51,16 +53,18 @@ def init_plotscript(config): ) no_trades = False + filename = config.get('exportfilename') if config.get('no_trades', False): no_trades = True - elif not config['exportfilename'].is_file() and config['trade_source'] == 'file': - logger.warning("Backtest file is missing skipping trades.") - no_trades = True + elif config['trade_source'] == 'file': + 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=config.get('exportfilename'), + exportfilename=filename, no_trades=no_trades ) trades = trim_dataframe(trades, timerange, 'open_date') From 619eb183fe2454bce969760129385e142946ec4e Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 06:58:06 +0200 Subject: [PATCH 062/285] Allow strategy for plot-profit to allow loading of multi-backtest files --- docs/plotting.md | 8 +++++++- freqtrade/commands/arguments.py | 2 +- freqtrade/plot/plotting.py | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/plotting.md b/docs/plotting.md index d3a2df1c1..7de5626b2 100644 --- a/docs/plotting.md +++ b/docs/plotting.md @@ -224,7 +224,8 @@ Possible options for the `freqtrade plot-profit` subcommand: ``` usage: freqtrade plot-profit [-h] [-v] [--logfile FILE] [-V] [-c PATH] - [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] + [-d PATH] [--userdir PATH] [-s NAME] + [--strategy-path PATH] [-p PAIRS [PAIRS ...]] [--timerange TIMERANGE] [--export EXPORT] [--export-filename PATH] [--db-url PATH] [--trade-source {DB,file}] [-i TIMEFRAME] @@ -270,6 +271,11 @@ Common arguments: --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. ``` The `-p/--pairs` argument, can be used to limit the pairs that are considered for this calculation. diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index 72f2a02f0..6114fc589 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -354,7 +354,7 @@ class Arguments: plot_profit_cmd = subparsers.add_parser( 'plot-profit', help='Generate plot showing profits.', - parents=[_common_parser], + parents=[_common_parser, _strategy_parser], ) plot_profit_cmd.set_defaults(func=start_plot_profit) self._build_args(optionlist=ARGS_PLOT_PROFIT, parser=plot_profit_cmd) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 16afaec3b..b11f093d9 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -9,7 +9,6 @@ from freqtrade.data.btanalysis import (calculate_max_drawdown, combine_dataframes_with_mean, create_cum_profit, extract_trades_of_period, - get_latest_backtest_filename, load_trades) from freqtrade.data.converter import trim_dataframe from freqtrade.data.history import load_data @@ -65,7 +64,8 @@ def init_plotscript(config): config['trade_source'], db_url=config.get('db_url'), exportfilename=filename, - no_trades=no_trades + no_trades=no_trades, + strategy=config.get("strategy"), ) trades = trim_dataframe(trades, timerange, 'open_date') From d56f9655e2b019cf95af75c613257b9049661944 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 07:20:43 +0200 Subject: [PATCH 063/285] Update notebook with new statistics example --- docs/plotting.md | 2 +- docs/strategy_analysis_example.md | 44 +++++++++++++++-- freqtrade/data/btanalysis.py | 2 +- .../templates/strategy_analysis_example.ipynb | 47 +++++++++++++++++-- 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/docs/plotting.md b/docs/plotting.md index 7de5626b2..09eb6ddb5 100644 --- a/docs/plotting.md +++ b/docs/plotting.md @@ -285,7 +285,7 @@ Examples: Use custom backtest-export file ``` bash -freqtrade plot-profit -p LTC/BTC --export-filename user_data/backtest_results/backtest-result-Strategy005.json +freqtrade plot-profit -p LTC/BTC --export-filename user_data/backtest_results/backtest-result.json ``` Use custom database diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index 6b4ad567f..8915ebe37 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -18,7 +18,7 @@ config = Configuration.from_files([]) # config = Configuration.from_files(["config.json"]) # Define some constants -config["timeframe"] = "5m" +config["ticker_interval"] = "5m" # Name of the strategy class config["strategy"] = "SampleStrategy" # Location of the data @@ -33,7 +33,7 @@ pair = "BTC_USDT" from freqtrade.data.history import load_pair_history candles = load_pair_history(datadir=data_location, - timeframe=config["timeframe"], + timeframe=config["ticker_interval"], pair=pair) # Confirm success @@ -85,10 +85,44 @@ Analyze a trades dataframe (also used below for plotting) ```python -from freqtrade.data.btanalysis import load_backtest_data +from freqtrade.data.btanalysis import load_backtest_data, load_backtest_stats -# Load backtest results -trades = load_backtest_data(config["user_data_dir"] / "backtest_results/backtest-result.json") +# if backtest_dir points to a directory, it'll automatically load the last backtest file. +backtest_dir = config["user_data_dir"] / "backtest_results" +# backtest_dir can also point to a specific file +# backtest_dir = config["user_data_dir"] / "backtest_results/backtest-result-2020-07-01_20-04-22.json" +``` + + +```python +# You can get the full backtest statistics by using the following command. +# This contains all information used to generate the backtest result. +stats = load_backtest_stats(backtest_dir) + +strategy = 'SampleStrategy' +# All statistics are available per strategy, so if `--strategy-list` was used during backtest, this will be reflected here as well. +# Example usages: +print(stats['strategy'][strategy]['results_per_pair']) +# Get pairlist used for this backtest +print(stats['strategy'][strategy]['pairlist']) +# Get market change (average change of all pairs from start to end of the backtest period) +print(stats['strategy'][strategy]['market_change']) +# Maximum drawdown () +print(stats['strategy'][strategy]['max_drawdown']) +# Maximum drawdown start and end +print(stats['strategy'][strategy]['drawdown_start']) +print(stats['strategy'][strategy]['drawdown_end']) + + +# Get strategy comparison (only relevant if multiple strategies were compared) +print(stats['strategy_comparison']) + +``` + + +```python +# Load backtested trades as dataframe +trades = load_backtest_data(backtest_dir) # Show value-counts per pair trades.groupby("pair")["sell_reason"].value_counts() diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 6931b1685..cf6e18e64 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -72,7 +72,7 @@ def load_backtest_stats(filename: Union[Path, str]) -> Dict[str, Any]: def load_backtest_data(filename: Union[Path, str], strategy: Optional[str] = None) -> pd.DataFrame: """ Load backtest data file. - :param filename: pathlib.Path object, or string pointing to the file. + :param filename: pathlib.Path object, or string pointing to a file or directory :param strategy: Strategy to load - mainly relevant for multi-strategy backtests Can also serve as protection to load the correct result. :return: a dataframe with the analysis results diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index dffa308ce..31a5b536a 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -136,10 +136,51 @@ "metadata": {}, "outputs": [], "source": [ - "from freqtrade.data.btanalysis import load_backtest_data\n", + "from freqtrade.data.btanalysis import load_backtest_data, load_backtest_stats\n", "\n", - "# Load backtest results\n", - "trades = load_backtest_data(config[\"user_data_dir\"] / \"backtest_results/backtest-result.json\")\n", + "# if backtest_dir points to a directory, it'll automatically load the last backtest file.\n", + "backtest_dir = config[\"user_data_dir\"] / \"backtest_results\"\n", + "# backtest_dir can also point to a specific file \n", + "# backtest_dir = config[\"user_data_dir\"] / \"backtest_results/backtest-result-2020-07-01_20-04-22.json\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# You can get the full backtest statistics by using the following command.\n", + "# This contains all information used to generate the backtest result.\n", + "stats = load_backtest_stats(backtest_dir)\n", + "\n", + "strategy = 'SampleStrategy'\n", + "# All statistics are available per strategy, so if `--strategy-list` was used during backtest, this will be reflected here as well.\n", + "# Example usages:\n", + "print(stats['strategy'][strategy]['results_per_pair'])\n", + "# Get pairlist used for this backtest\n", + "print(stats['strategy'][strategy]['pairlist'])\n", + "# Get market change (average change of all pairs from start to end of the backtest period)\n", + "print(stats['strategy'][strategy]['market_change'])\n", + "# Maximum drawdown ()\n", + "print(stats['strategy'][strategy]['max_drawdown'])\n", + "# Maximum drawdown start and end\n", + "print(stats['strategy'][strategy]['drawdown_start'])\n", + "print(stats['strategy'][strategy]['drawdown_end'])\n", + "\n", + "\n", + "# Get strategy comparison (only relevant if multiple strategies were compared)\n", + "print(stats['strategy_comparison'])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Load backtested trades as dataframe\n", + "trades = load_backtest_data(backtest_dir)\n", "\n", "# Show value-counts per pair\n", "trades.groupby(\"pair\")[\"sell_reason\"].value_counts()" From 804c42933d5d1eb58e102dbbcb66e55f801b0bc8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 08:02:27 +0200 Subject: [PATCH 064/285] Document summary-statistics --- docs/backtesting.md | 69 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index ecd48bdc9..52506215d 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -157,17 +157,28 @@ A backtesting result will look like that: | ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 | 0 | 0 | | LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 | 0 | 0 | | TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 | 0 | 0 | +============ SUMMARY METRICS ============= +| Metric | Value | +|------------------+---------------------| +| Total trades | 429 | +| First trade | 2019-01-01 18:30:00 | +| First trade Pair | EOS/USDT | +| Backtesting from | 2019-01-01 00:00:00 | +| Backtesting to | 2019-05-01 00:00:00 | +| Trades per day | 3.575 | +| | | +| Max Drawdown | 50.63% | +| Drawdown Start | 2019-02-15 14:10:00 | +| Drawdown End | 2019-04-11 18:15:00 | +| Market change | -5.88% | +========================================== + ``` +### Backtesting report table + The 1st table contains all trades the bot made, including "left open trades". -The 2nd table contains a recap of sell reasons. -This table can tell you which area needs some additional work (i.e. all `sell_signal` trades are losses, so we should disable the sell-signal or work on improving that). - -The 3rd table contains all trades the bot had to `forcesell` at the end of the backtest period to present a full picture. -This is necessary to simulate realistic behaviour, since the backtest period has to end at some point, while realistically, you could leave the bot running forever. -These trades are also included in the first table, but are extracted separately for clarity. - The last line will give you the overall performance of your strategy, here: @@ -196,6 +207,50 @@ On the other hand, if you set a too high `minimal_roi` like `"0": 0.55` (55%), there is almost no chance that the bot will ever reach this profit. Hence, keep in mind that your performance is an integral mix of all different elements of the strategy, your configuration, and the crypto-currency pairs you have set up. +### Sell reasons table + +The 2nd table contains a recap of sell reasons. +This table can tell you which area needs some additional work (i.e. all `sell_signal` trades are losses, so we should disable the sell-signal or work on improving that). + +### Left open trades table + +The 3rd table contains all trades the bot had to `forcesell` at the end of the backtest period to present a full picture. +This is necessary to simulate realistic behaviour, since the backtest period has to end at some point, while realistically, you could leave the bot running forever. +These trades are also included in the first table, but are extracted separately for clarity. + +### Summary metrics + +The last element of the backtest report is the summary metrics table. +It contains some useful key metrics about your strategy. + +``` +============ SUMMARY METRICS ============= +| Metric | Value | +|------------------+---------------------| +| Total trades | 429 | +| First trade | 2019-01-01 18:30:00 | +| First trade Pair | EOS/USDT | +| Backtesting from | 2019-01-01 00:00:00 | +| Backtesting to | 2019-05-01 00:00:00 | +| Trades per day | 3.575 | +| | | +| Max Drawdown | 50.63% | +| Drawdown Start | 2019-02-15 14:10:00 | +| Drawdown End | 2019-04-11 18:15:00 | +| Market change | -5.88% | +========================================== + +``` + +- `Total trades`: Identical to the total trades of the backtest output table. +- `First trade`: First trade entered. +- `First trade pair`: Which pair was part of the first trade +- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined as `--timerange from-to`) +- `Trades per day`: Total trades / Backtest duration (this will give you information about how many trades to expect from the strategy) +- `Max Drawdown`: Maximum drawown experienced. a value of 50% means that from highest to subsequent lowest point, a 50% drop was experiened). +- `Drawdown Start` / `Drawdown End`: From when to when was this large drawdown (can also be visualized via `plot-dataframe` subcommand) +- `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. + ### Assumptions made by backtesting Since backtesting lacks some detailed information about what happens within a candle, it needs to take a few assumptions: From 42868ad24ac8812ec295867fd5f9728aaad9635a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 19:30:29 +0200 Subject: [PATCH 065/285] Add best / worst day to statistics --- docs/backtesting.md | 11 +++++++---- freqtrade/optimize/optimize_reports.py | 8 ++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 52506215d..6c01e1c62 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -233,6 +233,8 @@ It contains some useful key metrics about your strategy. | Backtesting from | 2019-01-01 00:00:00 | | Backtesting to | 2019-05-01 00:00:00 | | Trades per day | 3.575 | +| Best day | 25.27% | +| Worst day | -30.67% | | | | | Max Drawdown | 50.63% | | Drawdown Start | 2019-02-15 14:10:00 | @@ -244,11 +246,12 @@ It contains some useful key metrics about your strategy. - `Total trades`: Identical to the total trades of the backtest output table. - `First trade`: First trade entered. -- `First trade pair`: Which pair was part of the first trade -- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined as `--timerange from-to`) -- `Trades per day`: Total trades / Backtest duration (this will give you information about how many trades to expect from the strategy) +- `First trade pair`: Which pair was part of the first trade. +- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined as `--timerange from-to`). +- `Trades per day`: Total trades / Backtest duration (this will give you information about how many trades to expect from the strategy). +- `Best day` / `Worst day`: Best and worst day based on daily profit. - `Max Drawdown`: Maximum drawown experienced. a value of 50% means that from highest to subsequent lowest point, a 50% drop was experiened). -- `Drawdown Start` / `Drawdown End`: From when to when was this large drawdown (can also be visualized via `plot-dataframe` subcommand) +- `Drawdown Start` / `Drawdown End`: From when to when was this large drawdown (can also be visualized via `plot-dataframe` subcommand). - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. ### Assumptions made by backtesting diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index d0e29d98f..4f169c53a 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -239,6 +239,9 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], max_open_trades=max_open_trades, results=results.loc[results['open_at_end']], skip_nan=True) + daily_profit = results.resample('1d', on='close_date')['profit_percent'].sum() + worst = min(daily_profit) + best = max(daily_profit) backtest_days = (max_date - min_date).days strat_stats = { @@ -252,6 +255,9 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'backtest_end': max_date.datetime, 'backtest_end_ts': max_date.timestamp, 'backtest_days': backtest_days, + 'backtest_best_day': best, + 'backtest_worst_day': worst, + 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None, 'market_change': market_change, 'pairlist': list(btdata.keys()), @@ -366,6 +372,8 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Backtesting from', strat_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strat_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Trades per day', strat_results['trades_per_day']), + ('Best day', f"{round(strat_results['backtest_best_day'] * 100, 2)}%"), + ('Worst day', f"{round(strat_results['backtest_worst_day'] * 100, 2)}%"), ('', ''), # Empty line to improve readability ('Max Drawdown', f"{round(strat_results['max_drawdown'] * 100, 2)}%"), ('Drawdown Start', strat_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), From 8e0ff4bd86effd9d44fb0d0fd82c10ce246c6141 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 19:45:45 +0200 Subject: [PATCH 066/285] Add Win / draw / losing days --- freqtrade/optimize/optimize_reports.py | 28 ++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 4f169c53a..33157d50a 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -210,6 +210,23 @@ def generate_edge_table(results: dict) -> str: floatfmt=floatfmt, tablefmt="orgtbl", stralign="right") # type: ignore +def generate_daily_stats(results: DataFrame) -> Dict[str, Any]: + daily_profit = results.resample('1d', on='close_date')['profit_percent'].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) + + return { + 'backtest_best_day': best, + 'backtest_worst_day': worst, + 'winning_days': winning_days, + 'draw_days': draw_days, + 'losing_days': losing_days, + } + + def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], all_results: Dict[str, DataFrame], min_date: Arrow, max_date: Arrow @@ -239,9 +256,7 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], max_open_trades=max_open_trades, results=results.loc[results['open_at_end']], skip_nan=True) - daily_profit = results.resample('1d', on='close_date')['profit_percent'].sum() - worst = min(daily_profit) - best = max(daily_profit) + daily_stats = generate_daily_stats(results) backtest_days = (max_date - min_date).days strat_stats = { @@ -255,13 +270,12 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'backtest_end': max_date.datetime, 'backtest_end_ts': max_date.timestamp, 'backtest_days': backtest_days, - 'backtest_best_day': best, - 'backtest_worst_day': worst, 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None, 'market_change': market_change, 'pairlist': list(btdata.keys()), - 'stake_amount': config['stake_amount'] + 'stake_amount': config['stake_amount'], + **daily_stats, } result['strategy'][strategy] = strat_stats @@ -374,6 +388,8 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Trades per day', strat_results['trades_per_day']), ('Best day', f"{round(strat_results['backtest_best_day'] * 100, 2)}%"), ('Worst day', f"{round(strat_results['backtest_worst_day'] * 100, 2)}%"), + ('Days win/draw/lose', f"{strat_results['winning_days']} / " + f"{strat_results['draw_days']} / {strat_results['losing_days']}"), ('', ''), # Empty line to improve readability ('Max Drawdown', f"{round(strat_results['max_drawdown'] * 100, 2)}%"), ('Drawdown Start', strat_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), From 987188e41f15e5914686c2637f4ddee418af9be8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 19:58:02 +0200 Subject: [PATCH 067/285] Add avgduration for winners and losers --- docs/backtesting.md | 40 ++++++++++++++------------ freqtrade/optimize/optimize_reports.py | 9 ++++++ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 6c01e1c62..cb20c3e43 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -224,23 +224,26 @@ The last element of the backtest report is the summary metrics table. It contains some useful key metrics about your strategy. ``` -============ SUMMARY METRICS ============= -| Metric | Value | -|------------------+---------------------| -| Total trades | 429 | -| First trade | 2019-01-01 18:30:00 | -| First trade Pair | EOS/USDT | -| Backtesting from | 2019-01-01 00:00:00 | -| Backtesting to | 2019-05-01 00:00:00 | -| Trades per day | 3.575 | -| Best day | 25.27% | -| Worst day | -30.67% | -| | | -| Max Drawdown | 50.63% | -| Drawdown Start | 2019-02-15 14:10:00 | -| Drawdown End | 2019-04-11 18:15:00 | -| Market change | -5.88% | -========================================== +=============== SUMMARY METRICS =============== +| Metric | Value | +|-----------------------+---------------------| + +| Total trades | 429 | +| First trade | 2019-01-01 18:30:00 | +| First trade Pair | EOS/USDT | +| Backtesting from | 2019-01-01 00:00:00 | +| Backtesting to | 2019-05-01 00:00:00 | +| Trades per day | 3.575 | +| Best day | 25.27% | +| Worst day | -30.67% | +| Avg. Duration Winners | 4:23:00 | +| Avg. Duration Loser | 6:55:00 | +| | | +| Max Drawdown | 50.63% | +| Drawdown Start | 2019-02-15 14:10:00 | +| Drawdown End | 2019-04-11 18:15:00 | +| Market change | -5.88% | +=============================================== ``` @@ -250,10 +253,11 @@ It contains some useful key metrics about your strategy. - `Backtesting from` / `Backtesting to`: Backtesting range (usually defined as `--timerange from-to`). - `Trades per day`: Total trades / Backtest duration (this will give you information about how many trades to expect from the strategy). - `Best day` / `Worst day`: Best and worst day based on daily profit. +- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades. - `Max Drawdown`: Maximum drawown experienced. a value of 50% means that from highest to subsequent lowest point, a 50% drop was experiened). - `Drawdown Start` / `Drawdown End`: From when to when was this large drawdown (can also be visualized via `plot-dataframe` subcommand). - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. - + ### Assumptions made by backtesting Since backtesting lacks some detailed information about what happens within a candle, it needs to take a few assumptions: diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 33157d50a..f9b38caf0 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -218,12 +218,19 @@ def generate_daily_stats(results: DataFrame) -> Dict[str, Any]: 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] + return { 'backtest_best_day': best, 'backtest_worst_day': worst, 'winning_days': winning_days, 'draw_days': draw_days, 'losing_days': losing_days, + 'winner_holding_avg': (timedelta(minutes=round(winning_trades['trade_duration'].mean())) + if not winning_trades.empty else '0:00'), + 'loser_holding_avg': (timedelta(minutes=round(losing_trades['trade_duration'].mean())) + if not losing_trades.empty else '0:00'), } @@ -390,6 +397,8 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Worst day', f"{round(strat_results['backtest_worst_day'] * 100, 2)}%"), ('Days win/draw/lose', f"{strat_results['winning_days']} / " f"{strat_results['draw_days']} / {strat_results['losing_days']}"), + ('Avg. Duration Winners', f"{strat_results['winner_holding_avg']}"), + ('Avg. Duration Loser', f"{strat_results['loser_holding_avg']}"), ('', ''), # Empty line to improve readability ('Max Drawdown', f"{round(strat_results['max_drawdown'] * 100, 2)}%"), ('Drawdown Start', strat_results['drawdown_start'].strftime(DATETIME_PRINT_FORMAT)), From 523437d9707e941c8ddd2e7a5585c97199300c80 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 20:03:33 +0200 Subject: [PATCH 068/285] Add tst for daily stats --- tests/optimize/test_optimize_reports.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 2431fa716..6c1009e22 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -1,4 +1,5 @@ import re +from datetime import timedelta from pathlib import Path import pandas as pd @@ -8,9 +9,11 @@ from arrow import Arrow from freqtrade.configuration import TimeRange from freqtrade.constants import LAST_BT_RESULT_FN from freqtrade.data import history -from freqtrade.data.btanalysis import get_latest_backtest_filename +from freqtrade.data.btanalysis import (get_latest_backtest_filename, + load_backtest_data) from freqtrade.edge import PairInfo from freqtrade.optimize.optimize_reports import (generate_backtest_stats, + generate_daily_stats, generate_edge_table, generate_pair_metrics, generate_sell_reason_stats, @@ -170,6 +173,21 @@ def test_generate_pair_metrics(default_conf, mocker): pytest.approx(pair_results[-1]['profit_sum_pct']) == pair_results[-1]['profit_sum'] * 100) +def test_generate_daily_stats(testdatadir): + + filename = testdatadir / "backtest-result_new.json" + bt_data = load_backtest_data(filename) + res = generate_daily_stats(bt_data) + assert isinstance(res, dict) + assert round(res['backtest_best_day'], 4) == 0.1796 + assert round(res['backtest_worst_day'], 4) == -0.1468 + assert res['winning_days'] == 14 + assert res['draw_days'] == 4 + assert res['losing_days'] == 3 + assert res['winner_holding_avg'] == timedelta(seconds=1440) + assert res['loser_holding_avg'] == timedelta(days=1, seconds=21420) + + def test_text_table_sell_reason(default_conf): results = pd.DataFrame( From 0d15a87af8de45799677a221c7311390b7dbb7b3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 20:15:20 +0200 Subject: [PATCH 069/285] Remove old store_backtest method --- freqtrade/optimize/backtesting.py | 2 - freqtrade/optimize/optimize_reports.py | 20 ------- tests/optimize/test_backtesting.py | 1 + tests/optimize/test_optimize_reports.py | 74 ------------------------- 4 files changed, 1 insertion(+), 96 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 18881f9db..3cd4f4fa2 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -21,7 +21,6 @@ from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes, timeframe_to_seconds from freqtrade.optimize.optimize_reports import (generate_backtest_stats, show_backtest_results, - store_backtest_result, store_backtest_stats) from freqtrade.pairlist.pairlistmanager import PairListManager from freqtrade.persistence import Trade @@ -421,7 +420,6 @@ class Backtesting: stats = generate_backtest_stats(self.config, data, all_results, min_date=min_date, max_date=max_date) if self.config.get('export', False): - store_backtest_result(self.config['exportfilename'], all_results) store_backtest_stats(self.config['exportfilename'], stats) # Show backtest results diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index f9b38caf0..67c8e3077 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -30,26 +30,6 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N file_dump_json(latest_filename, {'latest_backtest': str(filename.name)}) -def store_backtest_result(recordfilename: Path, all_results: Dict[str, DataFrame]) -> None: - """ - Stores backtest results to file (one file per strategy) - :param recordfilename: Destination filename - :param all_results: Dict of Dataframes, one results dataframe per strategy - """ - for strategy, results in all_results.items(): - records = backtest_result_to_list(results) - - if records: - filename = recordfilename - if len(all_results) > 1: - # Inject strategy to filename - filename = Path.joinpath( - recordfilename.parent, - f'{recordfilename.stem}-{strategy}').with_suffix(recordfilename.suffix) - logger.info(f'Dumping backtest results to {filename}') - file_dump_json(filename, records) - - def backtest_result_to_list(results: DataFrame) -> List[List]: """ Converts a list of Backtest-results to list diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 2c855fbc0..04417848f 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -703,6 +703,7 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir): generate_pair_metrics=MagicMock(), generate_sell_reason_stats=sell_reason_mock, generate_strategy_metrics=strat_summary, + generate_daily_stats=MagicMock(), ) patched_configuration_load_config_file(mocker, default_conf) diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 6c1009e22..2fab4578c 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -18,13 +18,11 @@ from freqtrade.optimize.optimize_reports import (generate_backtest_stats, generate_pair_metrics, generate_sell_reason_stats, generate_strategy_metrics, - store_backtest_result, store_backtest_stats, text_table_bt_results, text_table_sell_reason, text_table_strategy) from freqtrade.strategy.interface import SellType -from tests.conftest import patch_exchange from tests.data.test_history import _backup_file, _clean_test_file @@ -308,75 +306,3 @@ def test_generate_edge_table(edge_conf, mocker): assert generate_edge_table(results).count('| ETH/BTC |') == 1 assert generate_edge_table(results).count( '| Risk Reward Ratio | Required Risk Reward | Expectancy |') == 1 - - -def test_backtest_record(default_conf, fee, mocker): - names = [] - records = [] - patch_exchange(mocker) - mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) - mocker.patch( - 'freqtrade.optimize.optimize_reports.file_dump_json', - new=lambda n, r: (names.append(n), records.append(r)) - ) - - results = {'DefStrat': pd.DataFrame({"pair": ["UNITTEST/BTC", "UNITTEST/BTC", - "UNITTEST/BTC", "UNITTEST/BTC"], - "profit_percent": [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, - Arrow(2017, 11, 14, 22, 12, 00).datetime, - Arrow(2017, 11, 14, 22, 44, 00).datetime], - "close_date": [Arrow(2017, 11, 14, 21, 35, 00).datetime, - Arrow(2017, 11, 14, 22, 10, 00).datetime, - Arrow(2017, 11, 14, 22, 43, 00).datetime, - Arrow(2017, 11, 14, 22, 58, 00).datetime], - "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], - "sell_reason": [SellType.ROI, SellType.STOP_LOSS, - SellType.ROI, SellType.FORCE_SELL] - })} - store_backtest_result(Path("backtest-result.json"), results) - # Assert file_dump_json was only called once - assert names == [Path('backtest-result.json')] - records = records[0] - # Ensure records are of correct type - assert len(records) == 4 - - # reset test to test with strategy name - names = [] - records = [] - results['Strat'] = results['DefStrat'] - results['Strat2'] = results['DefStrat'] - store_backtest_result(Path("backtest-result.json"), results) - assert names == [ - Path('backtest-result-DefStrat.json'), - Path('backtest-result-Strat.json'), - Path('backtest-result-Strat2.json'), - ] - records = records[0] - # Ensure records are of correct type - assert len(records) == 4 - - # ('UNITTEST/BTC', 0.00331158, '1510684320', '1510691700', 0, 117) - # Below follows just a typecheck of the schema/type of trade-records - oix = None - for (pair, profit, date_buy, date_sell, buy_index, dur, - openr, closer, open_at_end, sell_reason) in records: - assert pair == 'UNITTEST/BTC' - assert isinstance(profit, float) - # FIX: buy/sell should be converted to ints - assert isinstance(date_buy, float) - assert isinstance(date_sell, float) - assert isinstance(openr, float) - assert isinstance(closer, float) - assert isinstance(open_at_end, bool) - assert isinstance(sell_reason, str) - isinstance(buy_index, pd._libs.tslib.Timestamp) - if oix: - assert buy_index > oix - oix = buy_index - assert dur > 0 From ea5e47657a9bf4d3969db4a762ea73d283d3abc3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 20:26:55 +0200 Subject: [PATCH 070/285] Remove ticker_interval from jupyter notebook --- docs/strategy_analysis_example.md | 4 ++-- freqtrade/templates/strategy_analysis_example.ipynb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/strategy_analysis_example.md b/docs/strategy_analysis_example.md index 8915ebe37..90e39fd76 100644 --- a/docs/strategy_analysis_example.md +++ b/docs/strategy_analysis_example.md @@ -18,7 +18,7 @@ config = Configuration.from_files([]) # config = Configuration.from_files(["config.json"]) # Define some constants -config["ticker_interval"] = "5m" +config["timeframe"] = "5m" # Name of the strategy class config["strategy"] = "SampleStrategy" # Location of the data @@ -33,7 +33,7 @@ pair = "BTC_USDT" from freqtrade.data.history import load_pair_history candles = load_pair_history(datadir=data_location, - timeframe=config["ticker_interval"], + timeframe=config["timeframe"], pair=pair) # Confirm success diff --git a/freqtrade/templates/strategy_analysis_example.ipynb b/freqtrade/templates/strategy_analysis_example.ipynb index 31a5b536a..c6e64c74e 100644 --- a/freqtrade/templates/strategy_analysis_example.ipynb +++ b/freqtrade/templates/strategy_analysis_example.ipynb @@ -34,7 +34,7 @@ "# config = Configuration.from_files([\"config.json\"])\n", "\n", "# Define some constants\n", - "config[\"ticker_interval\"] = \"5m\"\n", + "config[\"timeframe\"] = \"5m\"\n", "# Name of the strategy class\n", "config[\"strategy\"] = \"SampleStrategy\"\n", "# Location of the data\n", @@ -53,7 +53,7 @@ "from freqtrade.data.history import load_pair_history\n", "\n", "candles = load_pair_history(datadir=data_location,\n", - " timeframe=config[\"ticker_interval\"],\n", + " timeframe=config[\"timeframe\"],\n", " pair=pair)\n", "\n", "# Confirm success\n", From 1fc4451d2f59e7631131c9409a101c3c6abf63e1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 3 Jul 2020 20:32:04 +0200 Subject: [PATCH 071/285] Avoid \ linebreak --- freqtrade/optimize/optimize_reports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 67c8e3077..63fbfb48c 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -17,8 +17,8 @@ logger = logging.getLogger(__name__) def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> None: if recordfilename.is_dir(): - filename = recordfilename / \ - f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.json' + filename = (recordfilename / + f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.json') else: filename = Path.joinpath( recordfilename.parent, From 2417898d0078143be347d50cecacfe04a9900fae Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 14 Jul 2020 19:27:52 +0200 Subject: [PATCH 072/285] Apply documentation suggestions from code review Co-authored-by: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> --- docs/backtesting.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index cb20c3e43..7d6759df0 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -210,18 +210,18 @@ Hence, keep in mind that your performance is an integral mix of all different el ### Sell reasons table The 2nd table contains a recap of sell reasons. -This table can tell you which area needs some additional work (i.e. all `sell_signal` trades are losses, so we should disable the sell-signal or work on improving that). +This table can tell you which area needs some additional work (e,g. all or many of the `sell_signal` trades are losses, so we should disable the sell-signal or work on improving that). ### Left open trades table -The 3rd table contains all trades the bot had to `forcesell` at the end of the backtest period to present a full picture. +The 3rd table contains all trades the bot had to `forcesell` at the end of the backtesting period to present you the full picture. This is necessary to simulate realistic behaviour, since the backtest period has to end at some point, while realistically, you could leave the bot running forever. -These trades are also included in the first table, but are extracted separately for clarity. +These trades are also included in the first table, but are also shown separately in this table for clarity. ### Summary metrics The last element of the backtest report is the summary metrics table. -It contains some useful key metrics about your strategy. +It contains some useful key metrics about performance of your strategy on backtesting data. ``` =============== SUMMARY METRICS =============== @@ -250,12 +250,12 @@ It contains some useful key metrics about your strategy. - `Total trades`: Identical to the total trades of the backtest output table. - `First trade`: First trade entered. - `First trade pair`: Which pair was part of the first trade. -- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined as `--timerange from-to`). -- `Trades per day`: Total trades / Backtest duration (this will give you information about how many trades to expect from the strategy). +- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option). +- `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 day` / `Worst day`: Best and worst day based on daily profit. - `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades. -- `Max Drawdown`: Maximum drawown experienced. a value of 50% means that from highest to subsequent lowest point, a 50% drop was experiened). -- `Drawdown Start` / `Drawdown End`: From when to when was this large drawdown (can also be visualized via `plot-dataframe` subcommand). +- `Max Drawdown`: Maximum drawdown experienced. For example, the value of 50% means that from highest to subsequent lowest point, a 50% drop was experienced). +- `Drawdown Start` / `Drawdown End`: Start and end datetimes for this largest drawdown (can also be visualized via the `plot-dataframe` subcommand). - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. ### Assumptions made by backtesting From bdf611352e7e516d6789cb6b5a40f89c38953f59 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 14 Jul 2020 19:34:01 +0200 Subject: [PATCH 073/285] Update summary-metrics output --- docs/backtesting.md | 40 ++++++++++++++------------ freqtrade/optimize/optimize_reports.py | 4 +-- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 7d6759df0..b1dcd5dba 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -157,22 +157,25 @@ A backtesting result will look like that: | ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 | 0 | 0 | | LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 | 0 | 0 | | TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 | 0 | 0 | -============ SUMMARY METRICS ============= -| Metric | Value | -|------------------+---------------------| -| Total trades | 429 | -| First trade | 2019-01-01 18:30:00 | -| First trade Pair | EOS/USDT | -| Backtesting from | 2019-01-01 00:00:00 | -| Backtesting to | 2019-05-01 00:00:00 | -| Trades per day | 3.575 | -| | | -| Max Drawdown | 50.63% | -| Drawdown Start | 2019-02-15 14:10:00 | -| Drawdown End | 2019-04-11 18:15:00 | -| Market change | -5.88% | -========================================== - +=============== SUMMARY METRICS =============== +| Metric | Value | +|-----------------------+---------------------| +| Backtesting from | 2019-01-01 00:00:00 | +| Backtesting to | 2019-05-01 00:00:00 | +| Total trades | 429 | +| First trade | 2019-01-01 18:30:00 | +| First trade Pair | EOS/USDT | +| Trades per day | 3.575 | +| Best day | 25.27% | +| Worst day | -30.67% | +| Avg. Duration Winners | 4:23:00 | +| Avg. Duration Loser | 6:55:00 | +| | | +| Max Drawdown | 50.63% | +| Drawdown Start | 2019-02-15 14:10:00 | +| Drawdown End | 2019-04-11 18:15:00 | +| Market change | -5.88% | +=============================================== ``` ### Backtesting report table @@ -227,12 +230,11 @@ It contains some useful key metrics about performance of your strategy on backte =============== SUMMARY METRICS =============== | Metric | Value | |-----------------------+---------------------| - +| Backtesting from | 2019-01-01 00:00:00 | +| Backtesting to | 2019-05-01 00:00:00 | | Total trades | 429 | | First trade | 2019-01-01 18:30:00 | | First trade Pair | EOS/USDT | -| Backtesting from | 2019-01-01 00:00:00 | -| Backtesting to | 2019-05-01 00:00:00 | | Trades per day | 3.575 | | Best day | 25.27% | | Worst day | -30.67% | diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 63fbfb48c..3a42ba4a9 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -367,11 +367,11 @@ def text_table_add_metrics(strat_results: Dict) -> str: if len(strat_results['trades']) > 0: min_trade = min(strat_results['trades'], key=lambda x: x['open_date']) metrics = [ + ('Backtesting from', strat_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), + ('Backtesting to', strat_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Total trades', strat_results['total_trades']), ('First trade', min_trade['open_date'].strftime(DATETIME_PRINT_FORMAT)), ('First trade Pair', min_trade['pair']), - ('Backtesting from', strat_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), - ('Backtesting to', strat_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Trades per day', strat_results['trades_per_day']), ('Best day', f"{round(strat_results['backtest_best_day'] * 100, 2)}%"), ('Worst day', f"{round(strat_results['backtest_worst_day'] * 100, 2)}%"), From 82c68f07cd281e86ea39db9571cd3a4cae6a7481 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 14 Jul 2020 20:16:18 +0200 Subject: [PATCH 074/285] Add stoploss-distance (to current price) to /status output --- freqtrade/rpc/rpc.py | 1 + freqtrade/rpc/telegram.py | 21 +++++++++++---------- tests/rpc/test_rpc.py | 2 ++ tests/rpc/test_rpc_apiserver.py | 1 + tests/rpc/test_rpc_telegram.py | 4 +++- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index c73fcbf54..4e4d3ed6a 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -158,6 +158,7 @@ class RPC: current_profit_abs=current_profit_abs, stoploss_current_dist=stoploss_current_dist, stoploss_current_dist_ratio=round(stoploss_current_dist_ratio, 8), + stoploss_current_dist_pct=round(stoploss_current_dist_ratio * 100, 2), stoploss_entry_dist=stoploss_entry_dist, stoploss_entry_dist_ratio=round(stoploss_entry_dist_ratio, 8), open_order='({} {} rem={:.8f})'.format( diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 13cc1afaf..09be60795 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -236,17 +236,18 @@ class Telegram(RPC): ("*Close Profit:* `{close_profit_pct}`" if r['close_profit_pct'] is not None else ""), "*Current Profit:* `{current_profit_pct:.2f}%`", - - # Adding initial stoploss only if it is different from stoploss - "*Initial Stoploss:* `{initial_stop_loss:.8f}` " + - ("`({initial_stop_loss_pct:.2f}%)`") if ( - r['stop_loss'] != r['initial_stop_loss'] - and r['initial_stop_loss_pct'] is not None) else "", - - # Adding stoploss and stoploss percentage only if it is not None - "*Stoploss:* `{stop_loss:.8f}` " + - ("`({stop_loss_pct:.2f}%)`" if r['stop_loss_pct'] else ""), ] + if (r['stop_loss'] != r['initial_stop_loss'] + and r['initial_stop_loss_pct'] is not None): + # Adding initial stoploss only if it is different from stoploss + lines.append("*Initial Stoploss:* `{initial_stop_loss:.8f}` " + "`({initial_stop_loss_pct:.2f}%)`") + + # Adding stoploss and stoploss percentage only if it is not None + lines.append("*Stoploss:* `{stop_loss:.8f}` " + + ("`({stop_loss_pct:.2f}%)`" if r['stop_loss_pct'] else "")) + lines.append("*Stoploss distance:* `{stoploss_current_dist:.8f}` " + "`({stoploss_current_dist_pct:.2f}%)`") if r['open_order']: if r['sell_order_status']: lines.append("*Open Order:* `{open_order}` - `{sell_order_status}`") diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index de9327ba9..6d2c38868 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -100,6 +100,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'initial_stop_loss_ratio': -0.1, 'stoploss_current_dist': -1.1080000000000002e-06, 'stoploss_current_dist_ratio': -0.10081893, + 'stoploss_current_dist_pct': -10.08, 'stoploss_entry_dist': -0.00010475, 'stoploss_entry_dist_ratio': -0.10448878, 'open_order': None, @@ -163,6 +164,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'initial_stop_loss_ratio': -0.1, 'stoploss_current_dist': ANY, 'stoploss_current_dist_ratio': ANY, + 'stoploss_current_dist_pct': ANY, 'stoploss_entry_dist': -0.00010475, 'stoploss_entry_dist_ratio': -0.10448878, 'open_order': None, diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 355b63f48..04f9fc493 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -552,6 +552,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets): 'initial_stop_loss_ratio': -0.1, 'stoploss_current_dist': -1.1080000000000002e-06, 'stoploss_current_dist_ratio': -0.10081893, + 'stoploss_current_dist_pct': -10.08, 'stoploss_entry_dist': -0.00010475, 'stoploss_entry_dist_ratio': -0.10448878, 'trade_id': 1, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 0a4352f5b..a13d2e6c7 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -144,7 +144,7 @@ def test_authorized_only_exception(default_conf, mocker, caplog) -> None: assert log_has('Exception occurred within Telegram module', caplog) -def test_status(default_conf, update, mocker, fee, ticker,) -> None: +def test_telegram_status(default_conf, update, mocker, fee, ticker,) -> None: update.message.chat.id = "123" default_conf['telegram']['enabled'] = False default_conf['telegram']['chat_id'] = "123" @@ -174,6 +174,8 @@ def test_status(default_conf, update, mocker, fee, ticker,) -> None: 'stop_loss': 1.099e-05, 'sell_order_status': None, 'initial_stop_loss_pct': -0.05, + 'stoploss_current_dist': 1e-08, + 'stoploss_current_dist_pct': -0.02, 'stop_loss_pct': -0.01, 'open_order': '(limit buy rem=0.00000000)' }]), From d13cb4c05569e1116f07f5fef0fb896f42c13b7d Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jul 2020 19:49:51 +0200 Subject: [PATCH 075/285] Introduce safe_value_fallback_2 --- freqtrade/exchange/exchange.py | 6 ++--- freqtrade/freqtradebot.py | 4 ++-- freqtrade/misc.py | 16 ++++++++++++- tests/test_misc.py | 42 +++++++++++++++++++++++----------- 4 files changed, 49 insertions(+), 19 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index a3a548176..5c4e4c530 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -24,7 +24,7 @@ from freqtrade.exceptions import (DDosProtection, ExchangeError, InvalidOrderException, OperationalException, RetryableOrderError, TemporaryError) from freqtrade.exchange.common import BAD_EXCHANGES, retrier, retrier_async -from freqtrade.misc import deep_merge_dicts, safe_value_fallback +from freqtrade.misc import deep_merge_dicts, safe_value_fallback2 CcxtModuleType = Any @@ -1139,7 +1139,7 @@ class Exchange: if fee_curr in self.get_pair_base_currency(order['symbol']): # Base currency - divide by amount return round( - order['fee']['cost'] / safe_value_fallback(order, order, 'filled', 'amount'), 8) + order['fee']['cost'] / safe_value_fallback2(order, order, 'filled', 'amount'), 8) elif fee_curr in self.get_pair_quote_currency(order['symbol']): # Quote currency - divide by cost return round(order['fee']['cost'] / order['cost'], 8) if order['cost'] else None @@ -1152,7 +1152,7 @@ class Exchange: comb = self.get_valid_pair_combination(fee_curr, self._config['stake_currency']) tick = self.fetch_ticker(comb) - fee_to_quote_rate = safe_value_fallback(tick, tick, 'last', 'ask') + fee_to_quote_rate = safe_value_fallback2(tick, tick, 'last', 'ask') return round((order['fee']['cost'] * fee_to_quote_rate) / order['cost'], 8) except ExchangeError: return None diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ab7c2b527..9a0b3c40f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -20,7 +20,7 @@ from freqtrade.edge import Edge from freqtrade.exceptions import (DependencyException, ExchangeError, InvalidOrderException, PricingError) from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date -from freqtrade.misc import safe_value_fallback +from freqtrade.misc import safe_value_fallback2 from freqtrade.pairlist.pairlistmanager import PairListManager from freqtrade.persistence import Trade from freqtrade.resolvers import ExchangeResolver, StrategyResolver @@ -984,7 +984,7 @@ class FreqtradeBot: logger.info('Buy order %s for %s.', reason, trade) # Using filled to determine the filled amount - filled_amount = safe_value_fallback(corder, order, 'filled', 'filled') + filled_amount = safe_value_fallback2(corder, order, 'filled', 'filled') if isclose(filled_amount, 0.0, abs_tol=constants.MATH_CLOSE_PREC): logger.info('Buy order fully cancelled. Removing %s from database.', trade) diff --git a/freqtrade/misc.py b/freqtrade/misc.py index ac6084eb7..623f6cb8f 100644 --- a/freqtrade/misc.py +++ b/freqtrade/misc.py @@ -134,7 +134,21 @@ def round_dict(d, n): return {k: (round(v, n) if isinstance(v, float) else v) for k, v in d.items()} -def safe_value_fallback(dict1: dict, dict2: dict, key1: str, key2: str, default_value=None): +def safe_value_fallback(obj: dict, key1: str, key2: str, default_value=None): + """ + Search a value in obj, return this if it's not None. + Then search key2 in obj - return that if it's not none - then use default_value. + Else falls back to None. + """ + if key1 in obj and obj[key1] is not None: + return obj[key1] + else: + if key2 in obj and obj[key2] is not None: + return obj[key2] + return default_value + + +def safe_value_fallback2(dict1: dict, dict2: dict, key1: str, key2: str, default_value=None): """ Search a value in dict1, return this if it's not None. Fall back to dict2 - return key2 from dict2 if it's not None. diff --git a/tests/test_misc.py b/tests/test_misc.py index 9fd6164d5..a185cbba4 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -11,7 +11,7 @@ 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, - shorten_date) + safe_value_fallback2, shorten_date) def test_shorten_date() -> None: @@ -96,24 +96,40 @@ def test_format_ms_time() -> None: def test_safe_value_fallback(): + dict1 = {'keya': None, 'keyb': 2, 'keyc': 5, 'keyd': None} + assert safe_value_fallback(dict1, 'keya', 'keyb') == 2 + assert safe_value_fallback(dict1, 'keyb', 'keya') == 2 + + assert safe_value_fallback(dict1, 'keyb', 'keyc') == 2 + assert safe_value_fallback(dict1, 'keya', 'keyc') == 5 + + assert safe_value_fallback(dict1, 'keyc', 'keyb') == 5 + + assert safe_value_fallback(dict1, 'keya', 'keyd') is None + + assert safe_value_fallback(dict1, 'keyNo', 'keyNo') is None + assert safe_value_fallback(dict1, 'keyNo', 'keyNo', 55) == 55 + + +def test_safe_value_fallback2(): dict1 = {'keya': None, 'keyb': 2, 'keyc': 5, 'keyd': None} dict2 = {'keya': 20, 'keyb': None, 'keyc': 6, 'keyd': None} - assert safe_value_fallback(dict1, dict2, 'keya', 'keya') == 20 - assert safe_value_fallback(dict2, dict1, 'keya', 'keya') == 20 + assert safe_value_fallback2(dict1, dict2, 'keya', 'keya') == 20 + assert safe_value_fallback2(dict2, dict1, 'keya', 'keya') == 20 - assert safe_value_fallback(dict1, dict2, 'keyb', 'keyb') == 2 - assert safe_value_fallback(dict2, dict1, 'keyb', 'keyb') == 2 + assert safe_value_fallback2(dict1, dict2, 'keyb', 'keyb') == 2 + assert safe_value_fallback2(dict2, dict1, 'keyb', 'keyb') == 2 - assert safe_value_fallback(dict1, dict2, 'keyc', 'keyc') == 5 - assert safe_value_fallback(dict2, dict1, 'keyc', 'keyc') == 6 + assert safe_value_fallback2(dict1, dict2, 'keyc', 'keyc') == 5 + assert safe_value_fallback2(dict2, dict1, 'keyc', 'keyc') == 6 - assert safe_value_fallback(dict1, dict2, 'keyd', 'keyd') is None - assert safe_value_fallback(dict2, dict1, 'keyd', 'keyd') is None - assert safe_value_fallback(dict2, dict1, 'keyd', 'keyd', 1234) == 1234 + assert safe_value_fallback2(dict1, dict2, 'keyd', 'keyd') is None + assert safe_value_fallback2(dict2, dict1, 'keyd', 'keyd') is None + assert safe_value_fallback2(dict2, dict1, 'keyd', 'keyd', 1234) == 1234 - assert safe_value_fallback(dict1, dict2, 'keyNo', 'keyNo') is None - assert safe_value_fallback(dict2, dict1, 'keyNo', 'keyNo') is None - assert safe_value_fallback(dict2, dict1, 'keyNo', 'keyNo', 1234) == 1234 + assert safe_value_fallback2(dict1, dict2, 'keyNo', 'keyNo') is None + assert safe_value_fallback2(dict2, dict1, 'keyNo', 'keyNo') is None + assert safe_value_fallback2(dict2, dict1, 'keyNo', 'keyNo', 1234) == 1234 def test_plural() -> None: From c826f7a7077715f71416dd77001d927b858b0184 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jul 2020 20:15:29 +0200 Subject: [PATCH 076/285] Add amount_requested to database --- freqtrade/persistence.py | 9 ++++++--- tests/test_persistence.py | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index a6c1de402..bdbb7628a 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -86,7 +86,7 @@ def check_migrate(engine) -> None: logger.debug(f'trying {table_back_name}') # Check for latest column - if not has_column(cols, 'timeframe'): + if not has_column(cols, 'amount_requested'): logger.info(f'Running database migration - backup available as {table_back_name}') fee_open = get_column_def(cols, 'fee_open', 'fee') @@ -119,6 +119,7 @@ def check_migrate(engine) -> None: cols, 'close_profit_abs', f"(amount * close_rate * (1 - {fee_close})) - {open_trade_price}") sell_order_status = get_column_def(cols, 'sell_order_status', 'null') + amount_requested = get_column_def(cols, 'amount_requested', 'amount') # Schema migration necessary engine.execute(f"alter table trades rename to {table_back_name}") @@ -134,7 +135,7 @@ def check_migrate(engine) -> None: fee_open, fee_open_cost, fee_open_currency, fee_close, fee_close_cost, fee_open_currency, open_rate, open_rate_requested, close_rate, close_rate_requested, close_profit, - stake_amount, amount, open_date, close_date, open_order_id, + stake_amount, amount, amount_requested, open_date, close_date, open_order_id, stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct, stoploss_order_id, stoploss_last_update, max_rate, min_rate, sell_reason, sell_order_status, strategy, @@ -153,7 +154,7 @@ def check_migrate(engine) -> None: {fee_close_cost} fee_close_cost, {fee_close_currency} fee_close_currency, open_rate, {open_rate_requested} open_rate_requested, close_rate, {close_rate_requested} close_rate_requested, close_profit, - stake_amount, amount, open_date, close_date, open_order_id, + stake_amount, amount, {amount_requested}, open_date, close_date, open_order_id, {stop_loss} stop_loss, {stop_loss_pct} stop_loss_pct, {initial_stop_loss} initial_stop_loss, {initial_stop_loss_pct} initial_stop_loss_pct, @@ -215,6 +216,7 @@ class Trade(_DECL_BASE): close_profit_abs = Column(Float) stake_amount = Column(Float, nullable=False) amount = Column(Float) + amount_requested = Column(Float) open_date = Column(DateTime, nullable=False, default=datetime.utcnow) close_date = Column(DateTime) open_order_id = Column(String) @@ -256,6 +258,7 @@ class Trade(_DECL_BASE): 'is_open': self.is_open, 'exchange': self.exchange, 'amount': round(self.amount, 8), + 'amount_requested': round(self.amount_requested, 8), 'stake_amount': round(self.stake_amount, 8), 'strategy': self.strategy, 'ticker_interval': self.timeframe, # DEPRECATED diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 8dd27e53a..c39b2015e 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -457,6 +457,7 @@ def test_migrate_old(mocker, default_conf, fee): assert trade.close_rate_requested is None assert trade.is_open == 1 assert trade.amount == amount + assert trade.amount_requested == amount assert trade.stake_amount == default_conf.get("stake_amount") assert trade.pair == "ETC/BTC" assert trade.exchange == "bittrex" @@ -546,6 +547,7 @@ def test_migrate_new(mocker, default_conf, fee, caplog): assert trade.close_rate_requested is None assert trade.is_open == 1 assert trade.amount == amount + assert trade.amount_requested == amount assert trade.stake_amount == default_conf.get("stake_amount") assert trade.pair == "ETC/BTC" assert trade.exchange == "binance" @@ -725,6 +727,7 @@ def test_to_json(default_conf, fee): pair='ETH/BTC', stake_amount=0.001, amount=123.0, + amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_date=arrow.utcnow().shift(hours=-2).datetime, @@ -757,6 +760,7 @@ def test_to_json(default_conf, fee): 'close_rate': None, 'close_rate_requested': None, 'amount': 123.0, + 'amount_requested': 123.0, 'stake_amount': 0.001, 'close_profit': None, 'close_profit_abs': None, @@ -786,6 +790,7 @@ def test_to_json(default_conf, fee): pair='XRP/BTC', stake_amount=0.001, amount=100.0, + amount_requested=101.0, fee_open=fee.return_value, fee_close=fee.return_value, open_date=arrow.utcnow().shift(hours=-2).datetime, @@ -808,6 +813,7 @@ def test_to_json(default_conf, fee): 'open_rate': 0.123, 'close_rate': 0.125, 'amount': 100.0, + 'amount_requested': 101.0, 'stake_amount': 0.001, 'stop_loss': None, 'stop_loss_abs': None, From eafab38db3b35d66ba927b0bc69934c40178bdde Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jul 2020 20:20:14 +0200 Subject: [PATCH 077/285] Complete implementation of amount_requested --- freqtrade/freqtradebot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 9a0b3c40f..c1149b8c2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -532,6 +532,7 @@ class FreqtradeBot: # we assume the order is executed at the price requested buy_limit_filled_price = buy_limit_requested + amount_requested = amount if order_status == 'expired' or order_status == 'rejected': order_tif = self.strategy.order_time_in_force['buy'] @@ -568,6 +569,7 @@ class FreqtradeBot: pair=pair, stake_amount=stake_amount, amount=amount, + amount_requested=amount_requested, fee_open=fee, fee_close=fee, open_rate=buy_limit_filled_price, From c1c018d8feb1843c18271f821dd5d36185db3d13 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jul 2020 20:27:00 +0200 Subject: [PATCH 078/285] Fix tests that require amount_requested --- tests/conftest.py | 3 +++ tests/rpc/test_rpc.py | 2 ++ tests/rpc/test_rpc_apiserver.py | 3 +++ 3 files changed, 8 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 43dc8ca78..8501a98b9 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -176,6 +176,7 @@ def create_mock_trades(fee): pair='ETH/BTC', stake_amount=0.001, amount=123.0, + amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, @@ -188,6 +189,7 @@ def create_mock_trades(fee): pair='ETC/BTC', stake_amount=0.001, amount=123.0, + amount_requested=123.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, @@ -204,6 +206,7 @@ def create_mock_trades(fee): pair='ETC/BTC', stake_amount=0.001, amount=123.0, + amount_requested=124.0, fee_open=fee.return_value, fee_close=fee.return_value, open_rate=0.123, diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index de9327ba9..ddbbe395c 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: 'close_rate': None, 'current_rate': 1.099e-05, 'amount': 91.07468124, + 'amount_requested': 91.07468124, 'stake_amount': 0.001, 'close_profit': None, 'close_profit_pct': None, @@ -143,6 +144,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'close_rate': None, 'current_rate': ANY, 'amount': 91.07468124, + 'amount_requested': 91.07468124, 'stake_amount': 0.001, 'close_profit': None, 'close_profit_pct': None, diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 355b63f48..13c11d29d 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -520,6 +520,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets): assert_response(rc) assert len(rc.json) == 1 assert rc.json == [{'amount': 91.07468124, + 'amount_requested': 91.07468124, 'base_currency': 'BTC', 'close_date': None, 'close_date_hum': None, @@ -641,6 +642,7 @@ def test_api_forcebuy(botclient, mocker, fee): fbuy_mock = MagicMock(return_value=Trade( pair='ETH/ETH', amount=1, + amount_requested=1, exchange='bittrex', stake_amount=1, open_rate=0.245441, @@ -657,6 +659,7 @@ def test_api_forcebuy(botclient, mocker, fee): data='{"pair": "ETH/BTC"}') assert_response(rc) assert rc.json == {'amount': 1, + 'amount_requested': 1, 'trade_id': None, 'close_date': None, 'close_date_hum': None, From 3721736aafbcbd06b8cfd1e94e8244360d481b7b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jul 2020 20:28:07 +0200 Subject: [PATCH 079/285] Convert to real amount before placing order to keep the correct amount in the database --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index c1149b8c2..5c0de94a1 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -523,7 +523,7 @@ class FreqtradeBot: time_in_force=time_in_force): logger.info(f"User requested abortion of buying {pair}") return False - + amount = self.exchange.amount_to_precision(pair, amount) order = self.exchange.buy(pair=pair, ordertype=order_type, amount=amount, rate=buy_limit_requested, time_in_force=time_in_force) From 98f2e79f27292b8e8d6feac5c6cd00660635c069 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jul 2020 20:51:52 +0200 Subject: [PATCH 080/285] Adjust tests to use correctly trimmed amount --- freqtrade/persistence.py | 2 +- tests/rpc/test_rpc.py | 8 ++++---- tests/rpc/test_rpc_apiserver.py | 6 +++--- tests/rpc/test_rpc_telegram.py | 12 ++++++------ tests/test_freqtradebot.py | 20 ++++++++++---------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index bdbb7628a..245b1c790 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -276,7 +276,7 @@ class Trade(_DECL_BASE): 'open_timestamp': int(self.open_date.timestamp() * 1000), 'open_rate': self.open_rate, 'open_rate_requested': self.open_rate_requested, - 'open_trade_price': self.open_trade_price, + 'open_trade_price': round(self.open_trade_price, 8), 'close_date_hum': (arrow.get(self.close_date).humanize() if self.close_date else None), diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index ddbbe395c..2d5370e1e 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -79,8 +79,8 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'open_rate': 1.098e-05, 'close_rate': None, 'current_rate': 1.099e-05, - 'amount': 91.07468124, - 'amount_requested': 91.07468124, + 'amount': 91.07468123, + 'amount_requested': 91.07468123, 'stake_amount': 0.001, 'close_profit': None, 'close_profit_pct': None, @@ -143,8 +143,8 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: 'open_rate': 1.098e-05, 'close_rate': None, 'current_rate': ANY, - 'amount': 91.07468124, - 'amount_requested': 91.07468124, + 'amount': 91.07468123, + 'amount_requested': 91.07468123, 'stake_amount': 0.001, 'close_profit': None, 'close_profit_pct': None, diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 13c11d29d..c7259bdc6 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -519,8 +519,8 @@ def test_api_status(botclient, mocker, ticker, fee, markets): rc = client_get(client, f"{BASE_URI}/status") assert_response(rc) assert len(rc.json) == 1 - assert rc.json == [{'amount': 91.07468124, - 'amount_requested': 91.07468124, + assert rc.json == [{'amount': 91.07468123, + 'amount_requested': 91.07468123, 'base_currency': 'BTC', 'close_date': None, 'close_date_hum': None, @@ -696,7 +696,7 @@ def test_api_forcebuy(botclient, mocker, fee): 'min_rate': None, 'open_order_id': '123456', 'open_rate_requested': None, - 'open_trade_price': 0.2460546025, + 'open_trade_price': 0.24605460, 'sell_reason': None, 'sell_order_status': None, 'strategy': None, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 0a4352f5b..669c6dc89 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -690,7 +690,7 @@ def test_reload_config_handle(default_conf, update, mocker) -> None: assert 'reloading config' in msg_mock.call_args_list[0][0][0] -def test_forcesell_handle(default_conf, update, ticker, fee, +def test_telegram_forcesell_handle(default_conf, update, ticker, fee, ticker_sell_up, mocker) -> None: mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock()) @@ -729,7 +729,7 @@ def test_forcesell_handle(default_conf, update, ticker, fee, 'pair': 'ETH/BTC', 'gain': 'profit', 'limit': 1.173e-05, - 'amount': 91.07468123861567, + 'amount': 91.07468123, 'order_type': 'limit', 'open_rate': 1.098e-05, 'current_rate': 1.173e-05, @@ -743,8 +743,8 @@ def test_forcesell_handle(default_conf, update, ticker, fee, } == last_msg -def test_forcesell_down_handle(default_conf, update, ticker, fee, - ticker_sell_down, mocker) -> None: +def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee, + ticker_sell_down, mocker) -> None: mocker.patch('freqtrade.rpc.fiat_convert.CryptoToFiatConverter._find_price', return_value=15000.0) rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock()) @@ -788,7 +788,7 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee, 'pair': 'ETH/BTC', 'gain': 'loss', 'limit': 1.043e-05, - 'amount': 91.07468123861567, + 'amount': 91.07468123, 'order_type': 'limit', 'open_rate': 1.098e-05, 'current_rate': 1.043e-05, @@ -836,7 +836,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None 'pair': 'ETH/BTC', 'gain': 'loss', 'limit': 1.099e-05, - 'amount': 91.07468123861567, + 'amount': 91.07468123, 'order_type': 'limit', 'open_rate': 1.098e-05, 'current_rate': 1.099e-05, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index ada0d87fd..685b269d7 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -595,7 +595,7 @@ def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order, freqtrade.create_trade('ETH/BTC') rate, amount = buy_mock.call_args[1]['rate'], buy_mock.call_args[1]['amount'] - assert rate * amount >= default_conf['stake_amount'] + assert rate * amount <= default_conf['stake_amount'] def test_create_trade_too_small_stake_amount(default_conf, ticker, limit_buy_order, @@ -782,7 +782,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order, assert trade.open_date is not None assert trade.exchange == 'bittrex' assert trade.open_rate == 0.00001098 - assert trade.amount == 91.07468123861567 + assert trade.amount == 91.07468123 assert log_has( 'Buy signal found: about create a new trade with stake_amount: 0.001 ...', caplog @@ -1009,7 +1009,7 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order) -> None: call_args = buy_mm.call_args_list[0][1] assert call_args['pair'] == pair assert call_args['rate'] == bid - assert call_args['amount'] == stake_amount / bid + assert call_args['amount'] == round(stake_amount / bid, 8) buy_rate_mock.reset_mock() # Should create an open trade with an open order id @@ -1029,7 +1029,7 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order) -> None: call_args = buy_mm.call_args_list[1][1] assert call_args['pair'] == pair assert call_args['rate'] == fix_price - assert call_args['amount'] == stake_amount / fix_price + assert call_args['amount'] == round(stake_amount / fix_price, 8) # In case of closed order limit_buy_order['status'] = 'closed' @@ -1407,7 +1407,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog, 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.32423208191126, + stoploss_order_mock.assert_called_once_with(amount=85.32423208, pair='ETH/BTC', order_types=freqtrade.strategy.order_types, stop_price=0.00002346 * 0.95) @@ -1595,7 +1595,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog, # stoploss should be set to 1% as trailing is on assert trade.stop_loss == 0.00002346 * 0.99 cancel_order_mock.assert_called_once_with(100, 'NEO/BTC') - stoploss_order_mock.assert_called_once_with(amount=2132892.491467577, + stoploss_order_mock.assert_called_once_with(amount=2132892.49146757, pair='NEO/BTC', order_types=freqtrade.strategy.order_types, stop_price=0.00002346 * 0.99) @@ -2577,7 +2577,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, mocker) -> N 'pair': 'ETH/BTC', 'gain': 'profit', 'limit': 1.172e-05, - 'amount': 91.07468123861567, + 'amount': 91.07468123, 'order_type': 'limit', 'open_rate': 1.098e-05, 'current_rate': 1.173e-05, @@ -2626,7 +2626,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, mocker) 'pair': 'ETH/BTC', 'gain': 'loss', 'limit': 1.044e-05, - 'amount': 91.07468123861567, + 'amount': 91.07468123, 'order_type': 'limit', 'open_rate': 1.098e-05, 'current_rate': 1.043e-05, @@ -2682,7 +2682,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe 'pair': 'ETH/BTC', 'gain': 'loss', 'limit': 1.08801e-05, - 'amount': 91.07468123861567, + 'amount': 91.07468123, 'order_type': 'limit', 'open_rate': 1.098e-05, 'current_rate': 1.043e-05, @@ -2887,7 +2887,7 @@ def test_execute_sell_market_order(default_conf, ticker, fee, 'pair': 'ETH/BTC', 'gain': 'profit', 'limit': 1.172e-05, - 'amount': 91.07468123861567, + 'amount': 91.07468123, 'order_type': 'market', 'open_rate': 1.098e-05, 'current_rate': 1.173e-05, From de46744aa9c80437767e86cf77aa95e8c43cddbd Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 15 Jul 2020 21:02:31 +0200 Subject: [PATCH 081/285] Use filled before amount for order data closes #3579 --- freqtrade/exchange/exchange.py | 1 - freqtrade/freqtradebot.py | 11 ++++++----- freqtrade/persistence.py | 3 ++- tests/rpc/test_rpc_telegram.py | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 5c4e4c530..e6ea75a63 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -1167,7 +1167,6 @@ class Exchange: return (order['fee']['cost'], order['fee']['currency'], self.calculate_fee_rate(order)) - # calculate rate ? (order['fee']['cost'] / (order['amount'] * order['price'])) def is_exchange_bad(exchange_name: str) -> bool: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 5c0de94a1..5da7223c4 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -20,7 +20,7 @@ from freqtrade.edge import Edge from freqtrade.exceptions import (DependencyException, ExchangeError, InvalidOrderException, PricingError) from freqtrade.exchange import timeframe_to_minutes, timeframe_to_next_date -from freqtrade.misc import safe_value_fallback2 +from freqtrade.misc import safe_value_fallback, safe_value_fallback2 from freqtrade.pairlist.pairlistmanager import PairListManager from freqtrade.persistence import Trade from freqtrade.resolvers import ExchangeResolver, StrategyResolver @@ -553,14 +553,14 @@ class FreqtradeBot: order['filled'], order['amount'], order['remaining'] ) stake_amount = order['cost'] - amount = order['amount'] + amount = order['filled'] buy_limit_filled_price = order['price'] order_id = None # in case of FOK the order may be filled immediately and fully elif order_status == 'closed': stake_amount = order['cost'] - amount = order['amount'] + amount = safe_value_fallback(order, 'filled', 'amount') buy_limit_filled_price = order['price'] # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL @@ -1249,7 +1249,8 @@ class FreqtradeBot: # Try update amount (binance-fix) try: new_amount = self.get_real_amount(trade, order, order_amount) - if not isclose(order['amount'], new_amount, abs_tol=constants.MATH_CLOSE_PREC): + if not isclose(safe_value_fallback(order, 'filled', 'amount'), new_amount, + abs_tol=constants.MATH_CLOSE_PREC): order['amount'] = new_amount order.pop('filled', None) trade.recalc_open_trade_price() @@ -1295,7 +1296,7 @@ class FreqtradeBot: """ # Init variables if order_amount is None: - order_amount = order['amount'] + order_amount = safe_value_fallback(order, 'filled', 'amount') # Only run for closed orders if trade.fee_updated(order.get('side', '')) or order['status'] == 'open': return order_amount diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 245b1c790..7dc533c07 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -17,6 +17,7 @@ from sqlalchemy.orm.session import sessionmaker from sqlalchemy.pool import StaticPool from freqtrade.exceptions import OperationalException +from freqtrade.misc import safe_value_fallback logger = logging.getLogger(__name__) @@ -376,7 +377,7 @@ class Trade(_DECL_BASE): if order_type in ('market', 'limit') and order['side'] == 'buy': # Update open rate and actual amount self.open_rate = Decimal(order['price']) - self.amount = Decimal(order.get('filled', order['amount'])) + self.amount = Decimal(safe_value_fallback(order, 'filled', 'amount')) self.recalc_open_trade_price() logger.info('%s_BUY has been fulfilled for %s.', order_type.upper(), self) self.open_order_id = None diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 669c6dc89..08d4dc7ec 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -691,7 +691,7 @@ def test_reload_config_handle(default_conf, update, mocker) -> None: def test_telegram_forcesell_handle(default_conf, update, ticker, fee, - ticker_sell_up, mocker) -> None: + ticker_sell_up, mocker) -> None: mocker.patch('freqtrade.rpc.rpc.CryptoToFiatConverter._find_price', return_value=15000.0) rpc_mock = mocker.patch('freqtrade.rpc.telegram.Telegram.send_msg', MagicMock()) mocker.patch('freqtrade.rpc.telegram.Telegram._init', MagicMock()) From 47748961697994c82fa30b8b825699382ae0d446 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 20 Jul 2020 19:39:12 +0200 Subject: [PATCH 082/285] Evaluate average before price in order returns --- freqtrade/exchange/exchange.py | 1 + freqtrade/freqtradebot.py | 4 ++-- freqtrade/persistence.py | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index e6ea75a63..9858eb518 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -475,6 +475,7 @@ class Exchange: "id": order_id, 'pair': pair, 'price': rate, + 'average': rate, 'amount': _amount, 'cost': _amount * rate, 'type': ordertype, diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 5da7223c4..8c5b5b460 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -554,14 +554,14 @@ class FreqtradeBot: ) stake_amount = order['cost'] amount = order['filled'] - buy_limit_filled_price = order['price'] + buy_limit_filled_price = safe_value_fallback(order, 'average', 'price') order_id = None # in case of FOK the order may be filled immediately and fully elif order_status == 'closed': stake_amount = order['cost'] amount = safe_value_fallback(order, 'filled', 'amount') - buy_limit_filled_price = order['price'] + buy_limit_filled_price = safe_value_fallback(order, 'average', 'price') # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 7dc533c07..fdb816eab 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -369,20 +369,20 @@ class Trade(_DECL_BASE): """ order_type = order['type'] # Ignore open and cancelled orders - if order['status'] == 'open' or order['price'] is None: + if order['status'] == 'open' or safe_value_fallback(order, 'average', 'price') is None: return logger.info('Updating trade (id=%s) ...', self.id) if order_type in ('market', 'limit') and order['side'] == 'buy': # Update open rate and actual amount - self.open_rate = Decimal(order['price']) + self.open_rate = Decimal(safe_value_fallback(order, 'average', 'price')) self.amount = Decimal(safe_value_fallback(order, 'filled', 'amount')) self.recalc_open_trade_price() logger.info('%s_BUY has been fulfilled for %s.', order_type.upper(), self) self.open_order_id = None elif order_type in ('market', 'limit') and order['side'] == 'sell': - self.close(order['price']) + self.close(safe_value_fallback(order, 'average', 'price')) logger.info('%s_SELL has been fulfilled for %s.', order_type.upper(), self) elif order_type in ('stop_loss_limit', 'stop-loss', 'stop'): self.stoploss_order_id = None From f6bde8bd9cbad8a50b75d5c26c16011b3d5448d0 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 21:43:15 +0300 Subject: [PATCH 083/285] Improve exception message wordings --- freqtrade/pairlist/AgeFilter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/pairlist/AgeFilter.py b/freqtrade/pairlist/AgeFilter.py index 7b6b126c3..d199154ba 100644 --- a/freqtrade/pairlist/AgeFilter.py +++ b/freqtrade/pairlist/AgeFilter.py @@ -26,9 +26,9 @@ class AgeFilter(IPairList): self._min_days_listed = pairlistconfig.get('min_days_listed', 10) if self._min_days_listed < 1: - raise OperationalException("AgeFilter requires min_days_listed must be >= 1") + raise OperationalException("AgeFilter requires min_days_listed be >= 1") if self._min_days_listed > exchange.ohlcv_candle_limit: - raise OperationalException("AgeFilter requires min_days_listed must not exceed " + raise OperationalException("AgeFilter requires min_days_listed be not exceeding " "exchange max request size " f"({exchange.ohlcv_candle_limit})") self._enabled = self._min_days_listed >= 1 From 5213abf510de8a3b43b671c9cfab65a6f81896b1 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 21:44:39 +0300 Subject: [PATCH 084/285] AgeFilter is always enabled --- freqtrade/pairlist/AgeFilter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/pairlist/AgeFilter.py b/freqtrade/pairlist/AgeFilter.py index d199154ba..56e56ceeb 100644 --- a/freqtrade/pairlist/AgeFilter.py +++ b/freqtrade/pairlist/AgeFilter.py @@ -31,7 +31,6 @@ class AgeFilter(IPairList): raise OperationalException("AgeFilter requires min_days_listed be not exceeding " "exchange max request size " f"({exchange.ohlcv_candle_limit})") - self._enabled = self._min_days_listed >= 1 @property def needstickers(self) -> bool: From daee414d7a83e15123e025d4c6107ad0435f9d0f Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 21:51:25 +0300 Subject: [PATCH 085/285] Fix docs formatting --- docs/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/configuration.md b/docs/configuration.md index a200d6411..0e3d23927 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -663,6 +663,7 @@ Filters low-value coins which would not allow setting stoplosses. #### PriceFilter The `PriceFilter` allows filtering of pairs by price. Currently the following price filters are supported: + * `min_price` * `max_price` * `low_price_ratio` From a1e292f56a068a2183aa59e59036bb5ce8abe0c5 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 22:09:30 +0300 Subject: [PATCH 086/285] Improve docs --- docs/configuration.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 0e3d23927..f39a3c62d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -669,19 +669,21 @@ The `PriceFilter` allows filtering of pairs by price. Currently the following pr * `low_price_ratio` The `min_price` setting removes pairs where the price is below the specified price. This is useful if you wish to avoid trading very low-priced pairs. -This option is disabled by default, and will only apply if set to <> 0. +This option is disabled by default (or set to 0), and will only apply if set to > 0. The `max_price` setting removes pairs where the price is above the specified price. This is useful if you wish to trade only low-priced pairs. -This option is disabled by default, and will only apply if set to <> 0. +This option is disabled by default (or set to 0), and will only apply if set to > 0. The `low_price_ratio` setting removes pairs where a raise of 1 price unit (pip) is above the `low_price_ratio` ratio. -This option is disabled by default, and will only apply if set to <> 0. +This option is disabled by default (or set to 0), and will only apply if set to > 0. + +For `PriceFiler` at least one of its `min_price`, `max_price` or `low_price_ratio` settings must be applied. Calculation example: -Min price precision is 8 decimals. If price is 0.00000011 - one step would be 0.00000012 - which is almost 10% higher than the previous value. +Min price precision for SHITCOIN/BTC is 8 decimals. If its price is 0.00000011 - one price step above would be 0.00000012, which is ~9% higher than the previous price value. You may filter out this pair by using PriceFilter with `low_price_ratio` set to 0.09 (9%) or with `min_price` set to 0.00000011, correspondingly. -These pairs are dangerous since it may be impossible to place the desired stoploss - and often result in high losses. +Low priced pairs are dangerous since they are often illiquid and it may also be impossible to place the desired stoploss, which can often result in high losses. Consider using PriceFilter with `low_price_ratio` set to a value which is less than the absolute value of your stoploss (for example, if your stoploss is -5% (-0.05), then the value for `low_price_ratio` can be 0.04 or even 0.02). #### ShuffleFilter From c78199d3d9fdd3c2a040a0fb476c053d60b6d7a1 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 22:21:30 +0300 Subject: [PATCH 087/285] Add checks for parameters of PriceFilter --- freqtrade/pairlist/PriceFilter.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/freqtrade/pairlist/PriceFilter.py b/freqtrade/pairlist/PriceFilter.py index b3b2f43dc..ae3ab9230 100644 --- a/freqtrade/pairlist/PriceFilter.py +++ b/freqtrade/pairlist/PriceFilter.py @@ -4,6 +4,7 @@ Price pair list filter import logging from typing import Any, Dict +from freqtrade.exceptions import OperationalException from freqtrade.pairlist.IPairList import IPairList @@ -18,11 +19,17 @@ class PriceFilter(IPairList): super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) self._low_price_ratio = pairlistconfig.get('low_price_ratio', 0) + if self._low_price_ratio < 0: + raise OperationalException("PriceFilter requires low_price_ratio be >= 0") self._min_price = pairlistconfig.get('min_price', 0) + if self._min_price < 0: + raise OperationalException("PriceFilter requires min_price be >= 0") self._max_price = pairlistconfig.get('max_price', 0) - self._enabled = ((self._low_price_ratio != 0) or - (self._min_price != 0) or - (self._max_price != 0)) + if self._max_price < 0: + raise OperationalException("PriceFilter requires max_price be >= 0") + self._enabled = ((self._low_price_ratio > 0) or + (self._min_price > 0) or + (self._max_price > 0)) @property def needstickers(self) -> bool: From 5c2481082ef11633c56bd5d631550b746b18d271 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 22:46:30 +0300 Subject: [PATCH 088/285] Add tests for PriceFilter --- tests/pairlist/test_pairlist.py | 56 +++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index efe4a784b..5a9472ef9 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -590,34 +590,58 @@ def test_agefilter_caching(mocker, markets, whitelist_conf_3, tickers, ohlcv_his assert freqtrade.exchange.get_historic_ohlcv.call_count == previous_call_count -@pytest.mark.parametrize("pairlistconfig,expected", [ +@pytest.mark.parametrize("pairlistconfig,desc_expected,exception_expected", [ ({"method": "PriceFilter", "low_price_ratio": 0.001, "min_price": 0.00000010, - "max_price": 1.0}, "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below " - "0.1% or below 0.00000010 or above 1.00000000.'}]" - ), + "max_price": 1.0}, + "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below " + "0.1% or below 0.00000010 or above 1.00000000.'}]", + None + ), ({"method": "PriceFilter", "low_price_ratio": 0.001, "min_price": 0.00000010}, - "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.1% or below 0.00000010.'}]" - ), + "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.1% or below 0.00000010.'}]", + None + ), ({"method": "PriceFilter", "low_price_ratio": 0.001, "max_price": 1.00010000}, - "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.1% or above 1.00010000.'}]" - ), + "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.1% or above 1.00010000.'}]", + None + ), ({"method": "PriceFilter", "min_price": 0.00002000}, - "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.00002000.'}]" - ), + "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.00002000.'}]", + None + ), ({"method": "PriceFilter"}, - "[{'PriceFilter': 'PriceFilter - No price filters configured.'}]" - ), + "[{'PriceFilter': 'PriceFilter - No price filters configured.'}]", + None + ), + ({"method": "PriceFilter", "low_price_ratio": -0.001}, + None, + "PriceFilter requires low_price_ratio be >= 0" + ), # OperationalException expected + ({"method": "PriceFilter", "min_price": -0.00000010}, + None, + "PriceFilter requires min_price be >= 0" + ), # OperationalException expected + ({"method": "PriceFilter", "max_price": -1.00010000}, + None, + "PriceFilter requires max_price be >= 0" + ), # OperationalException expected ]) -def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig, expected): +def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig, + desc_expected, exception_expected): mocker.patch.multiple('freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets), exchange_has=MagicMock(return_value=True) ) whitelist_conf['pairlists'] = [pairlistconfig] - freqtrade = get_patched_freqtradebot(mocker, whitelist_conf) - short_desc = str(freqtrade.pairlists.short_desc()) - assert short_desc == expected + if desc_expected is not None: + freqtrade = get_patched_freqtradebot(mocker, whitelist_conf) + short_desc = str(freqtrade.pairlists.short_desc()) + assert short_desc == desc_expected + else: # # OperationalException expected + with pytest.raises(OperationalException, + match=exception_expected): + freqtrade = get_patched_freqtradebot(mocker, whitelist_conf) def test_pairlistmanager_no_pairlist(mocker, markets, whitelist_conf, caplog): From 50767cd5694a79a4ac10ccba28f677470eb16725 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 22:48:29 +0300 Subject: [PATCH 089/285] Adjust tests for AgeFilter --- tests/pairlist/test_pairlist.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index 5a9472ef9..27b13bf69 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -547,7 +547,7 @@ def test_agefilter_min_days_listed_too_small(mocker, default_conf, markets, tick ) with pytest.raises(OperationalException, - match=r'AgeFilter requires min_days_listed must be >= 1'): + match=r'AgeFilter requires min_days_listed be >= 1'): get_patched_freqtradebot(mocker, default_conf) @@ -562,7 +562,7 @@ def test_agefilter_min_days_listed_too_large(mocker, default_conf, markets, tick ) with pytest.raises(OperationalException, - match=r'AgeFilter requires min_days_listed must not exceed ' + match=r'AgeFilter requires min_days_listed be not exceeding ' r'exchange max request size \([0-9]+\)'): get_patched_freqtradebot(mocker, default_conf) From f48250b4142acbe91c43e18f246b9f5889263095 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 22 Jul 2020 22:56:24 +0300 Subject: [PATCH 090/285] Make flake happy --- tests/pairlist/test_pairlist.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index 27b13bf69..c235367be 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -596,35 +596,35 @@ def test_agefilter_caching(mocker, markets, whitelist_conf_3, tickers, ohlcv_his "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below " "0.1% or below 0.00000010 or above 1.00000000.'}]", None - ), + ), ({"method": "PriceFilter", "low_price_ratio": 0.001, "min_price": 0.00000010}, "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.1% or below 0.00000010.'}]", None - ), + ), ({"method": "PriceFilter", "low_price_ratio": 0.001, "max_price": 1.00010000}, "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.1% or above 1.00010000.'}]", None - ), + ), ({"method": "PriceFilter", "min_price": 0.00002000}, "[{'PriceFilter': 'PriceFilter - Filtering pairs priced below 0.00002000.'}]", None - ), + ), ({"method": "PriceFilter"}, "[{'PriceFilter': 'PriceFilter - No price filters configured.'}]", None - ), + ), ({"method": "PriceFilter", "low_price_ratio": -0.001}, None, "PriceFilter requires low_price_ratio be >= 0" - ), # OperationalException expected + ), # OperationalException expected ({"method": "PriceFilter", "min_price": -0.00000010}, None, "PriceFilter requires min_price be >= 0" - ), # OperationalException expected + ), # OperationalException expected ({"method": "PriceFilter", "max_price": -1.00010000}, None, "PriceFilter requires max_price be >= 0" - ), # OperationalException expected + ), # OperationalException expected ]) def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig, desc_expected, exception_expected): @@ -638,7 +638,7 @@ def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig, freqtrade = get_patched_freqtradebot(mocker, whitelist_conf) short_desc = str(freqtrade.pairlists.short_desc()) assert short_desc == desc_expected - else: # # OperationalException expected + else: # OperationalException expected with pytest.raises(OperationalException, match=exception_expected): freqtrade = get_patched_freqtradebot(mocker, whitelist_conf) From 0614e599661a459d27a96bdbec00b4221709301d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Jul 2020 20:06:59 +0200 Subject: [PATCH 091/285] Add tables dependency --- freqtrade/commands/arguments.py | 2 +- freqtrade/constants.py | 2 +- requirements-common.txt | 1 + setup.py | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index e6f6f8167..0899321db 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -15,7 +15,7 @@ ARGS_STRATEGY = ["strategy", "strategy_path"] ARGS_TRADE = ["db_url", "sd_notify", "dry_run"] -ARGS_COMMON_OPTIMIZE = ["timeframe", "timerange", +ARGS_COMMON_OPTIMIZE = ["timeframe", "timerange", "dataformat_ohlcv", "max_open_trades", "stake_amount", "fee"] ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions", diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 1dadc6e16..a5a5a3339 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -24,7 +24,7 @@ ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', 'AgeFilter', 'PrecisionFilter', 'PriceFilter', 'ShuffleFilter', 'SpreadFilter'] -AVAILABLE_DATAHANDLERS = ['json', 'jsongz'] +AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5'] DRY_RUN_WALLET = 1000 MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons DEFAULT_DATAFRAME_COLUMNS = ['date', 'open', 'high', 'low', 'close', 'volume'] diff --git a/requirements-common.txt b/requirements-common.txt index d5c5fd832..604a769d4 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -13,6 +13,7 @@ TA-Lib==0.4.18 tabulate==0.8.7 pycoingecko==1.3.0 jinja2==2.11.2 +tables==3.6.1 # find first, C search in arrays py_find_1st==1.1.4 diff --git a/setup.py b/setup.py index 6d832e3f5..b1b500cc8 100644 --- a/setup.py +++ b/setup.py @@ -85,6 +85,7 @@ setup(name='freqtrade', # from requirements.txt 'numpy', 'pandas', + 'tables', ], extras_require={ 'api': api, From 55591e287c567d1671811c441c15c3df0b0d0d85 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Jul 2020 20:17:21 +0200 Subject: [PATCH 092/285] First version of hdf5handler - no proper support for trades yet --- freqtrade/data/history/hdf5datahandler.py | 184 ++++++++++++++++++++++ freqtrade/data/history/idatahandler.py | 7 +- 2 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 freqtrade/data/history/hdf5datahandler.py diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py new file mode 100644 index 000000000..21f521cc3 --- /dev/null +++ b/freqtrade/data/history/hdf5datahandler.py @@ -0,0 +1,184 @@ +import logging +import re +from pathlib import Path +from typing import List, Optional + +import pandas as pd + +from freqtrade import misc +from freqtrade.configuration import TimeRange +from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS + +from .idatahandler import IDataHandler, TradeList + +logger = logging.getLogger(__name__) + + +class HDF5Handler(IDataHandler): + + _columns = DEFAULT_DATAFRAME_COLUMNS + + @classmethod + def ohlcv_get_pairs(cls, datadir: Path, timeframe: str) -> List[str]: + """ + Returns a list of all pairs with ohlcv data available in this datadir + for the specified timeframe + :param datadir: Directory to search for ohlcv files + :param timeframe: Timeframe to search pairs for + :return: List of Pairs + """ + + _tmp = [re.search(r'^(\S+)(?=\-' + timeframe + '.h5)', p.name) + for p in datadir.glob(f"*{timeframe}.{cls._get_file_extension()}")] + # Check if regex found something and only return these results + return [match[0].replace('_', '/') for match in _tmp if match] + + def ohlcv_store(self, pair: str, timeframe: str, data: pd.DataFrame) -> None: + """ + Store data in hdf5 file. + :param pair: Pair - used to generate filename + :timeframe: Timeframe - used to generate filename + :data: Dataframe containing OHLCV data + :return: None + """ + key = self._pair_ohlcv_key(pair, timeframe) + _data = data.copy() + # Convert date to int + # _data['date'] = _data['date'].astype(np.int64) // 1000 // 1000 + + filename = self._pair_data_filename(self._datadir, pair, timeframe) + ds = pd.HDFStore(filename, mode='a', complevel=9) + ds.put(key, _data.loc[:, self._columns], format='table', data_columns=['date']) + + ds.close() + + def _ohlcv_load(self, pair: str, timeframe: str, + timerange: Optional[TimeRange] = None) -> pd.DataFrame: + """ + Internal method used to load data for one pair from disk. + Implements the loading and conversion to a Pandas dataframe. + Timerange trimming and dataframe validation happens outside of this method. + :param pair: Pair to load data + :param timeframe: Timeframe (e.g. "5m") + :param timerange: Limit data to be loaded to this timerange. + Optionally implemented by subclasses to avoid loading + all data where possible. + :return: DataFrame with ohlcv data, or empty DataFrame + """ + key = self._pair_ohlcv_key(pair, timeframe) + filename = self._pair_data_filename(self._datadir, pair, timeframe) + + if not filename.exists(): + return pd.DataFrame(columns=self._columns) + where = [] + if timerange: + if timerange.starttype == 'date': + where.append(f"date >= Timestamp({timerange.startts * 1e9})") + if timerange.stoptype == 'date': + where.append(f"date < Timestamp({timerange.stopts * 1e9})") + + pairdata = pd.read_hdf(filename, key=key, mode="r", where=where) + + if list(pairdata.columns) != self._columns: + raise ValueError("Wrong dataframe format") + pairdata = pairdata.astype(dtype={'open': 'float', 'high': 'float', + 'low': 'float', 'close': 'float', 'volume': 'float'}) + return pairdata + + def ohlcv_purge(self, pair: str, timeframe: str) -> bool: + """ + Remove data for this pair + :param pair: Delete data for this pair. + :param timeframe: Timeframe (e.g. "5m") + :return: True when deleted, false if file did not exist. + """ + filename = self._pair_data_filename(self._datadir, pair, timeframe) + if filename.exists(): + filename.unlink() + return True + return False + + def ohlcv_append(self, pair: str, timeframe: str, data: pd.DataFrame) -> None: + """ + Append data to existing data structures + :param pair: Pair + :param timeframe: Timeframe this ohlcv data is for + :param data: Data to append. + """ + raise NotImplementedError() + + @classmethod + def trades_get_pairs(cls, datadir: Path) -> List[str]: + """ + Returns a list of all pairs for which trade data is available in this + :param datadir: Directory to search for ohlcv files + :return: List of Pairs + """ + _tmp = [re.search(r'^(\S+)(?=\-trades.h5)', p.name) + for p in datadir.glob(f"*trades.{cls._get_file_extension()}")] + # Check if regex found something and only return these results to avoid exceptions. + return [match[0].replace('_', '/') for match in _tmp if match] + + def trades_store(self, pair: str, data: TradeList) -> None: + """ + Store trades data (list of Dicts) to file + :param pair: Pair - used for filename + :param data: List of Lists containing trade data, + column sequence as in DEFAULT_TRADES_COLUMNS + """ + key = self._pair_trades_key(pair) + ds = pd.HDFStore(self.filename_trades, mode='a', complevel=9) + ds.put(key, pd.DataFrame(data, columns=DEFAULT_TRADES_COLUMNS), + format='table', data_columns=['timestamp']) + ds.close() + + def trades_append(self, pair: str, data: TradeList): + """ + Append data to existing files + :param pair: Pair - used for filename + :param data: List of Lists containing trade data, + column sequence as in DEFAULT_TRADES_COLUMNS + """ + raise NotImplementedError() + + def _trades_load(self, pair: str, timerange: Optional[TimeRange] = None) -> TradeList: + """ + Load a pair from file, either .json.gz or .json + # TODO: respect timerange ... + :param pair: Load trades for this pair + :param timerange: Timerange to load trades for - currently not implemented + :return: List of trades + """ + raise NotImplementedError() + + def trades_purge(self, pair: str) -> bool: + """ + Remove data for this pair + :param pair: Delete data for this pair. + :return: True when deleted, false if file did not exist. + """ + filename = self._pair_trades_filename(self._datadir, pair) + if filename.exists(): + filename.unlink() + return True + return False + + @classmethod + def _pair_ohlcv_key(cls, pair: str, timeframe: str) -> Path: + return f"{pair}/ohlcv/tf_{timeframe}" + + @classmethod + def _pair_trades_key(cls, pair: str) -> Path: + return f"{pair}/trades" + + @classmethod + def _pair_data_filename(cls, datadir: Path, pair: str, timeframe: str) -> Path: + pair_s = misc.pair_to_filename(pair) + filename = datadir.joinpath(f'{pair_s}-{timeframe}.h5') + return filename + + @classmethod + def _pair_trades_filename(cls, datadir: Path, pair: str) -> Path: + pair_s = misc.pair_to_filename(pair) + filename = datadir.joinpath(f'{pair_s}-trades.h5') + return filename diff --git a/freqtrade/data/history/idatahandler.py b/freqtrade/data/history/idatahandler.py index 96d288e01..be3e34e04 100644 --- a/freqtrade/data/history/idatahandler.py +++ b/freqtrade/data/history/idatahandler.py @@ -50,9 +50,7 @@ class IDataHandler(ABC): @abstractmethod def ohlcv_store(self, pair: str, timeframe: str, data: DataFrame) -> None: """ - Store data in json format "values". - format looks as follows: - [[,,,,]] + Store ohlcv data. :param pair: Pair - used to generate filename :timeframe: Timeframe - used to generate filename :data: Dataframe containing OHLCV data @@ -239,6 +237,9 @@ def get_datahandlerclass(datatype: str) -> Type[IDataHandler]: elif datatype == 'jsongz': from .jsondatahandler import JsonGzDataHandler return JsonGzDataHandler + elif datatype == 'hdf5': + from .hdf5datahandler import HDF5Handler + return HDF5Handler else: raise ValueError(f"No datahandler for datatype {datatype} available.") From d4540c846ae9fdf427364b8dd1664b3d0b604347 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 12 Jul 2020 20:41:25 +0200 Subject: [PATCH 093/285] Add trades_load method --- freqtrade/data/history/hdf5datahandler.py | 26 ++++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index 21f521cc3..c99436b3c 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -7,7 +7,7 @@ import pandas as pd from freqtrade import misc from freqtrade.configuration import TimeRange -from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS +from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS from .idatahandler import IDataHandler, TradeList @@ -29,7 +29,7 @@ class HDF5Handler(IDataHandler): """ _tmp = [re.search(r'^(\S+)(?=\-' + timeframe + '.h5)', p.name) - for p in datadir.glob(f"*{timeframe}.{cls._get_file_extension()}")] + for p in datadir.glob(f"*{timeframe}.h5")] # Check if regex found something and only return these results return [match[0].replace('_', '/') for match in _tmp if match] @@ -43,8 +43,6 @@ class HDF5Handler(IDataHandler): """ key = self._pair_ohlcv_key(pair, timeframe) _data = data.copy() - # Convert date to int - # _data['date'] = _data['date'].astype(np.int64) // 1000 // 1000 filename = self._pair_data_filename(self._datadir, pair, timeframe) ds = pd.HDFStore(filename, mode='a', complevel=9) @@ -115,7 +113,7 @@ class HDF5Handler(IDataHandler): :return: List of Pairs """ _tmp = [re.search(r'^(\S+)(?=\-trades.h5)', p.name) - for p in datadir.glob(f"*trades.{cls._get_file_extension()}")] + for p in datadir.glob("*trades.h5")] # Check if regex found something and only return these results to avoid exceptions. return [match[0].replace('_', '/') for match in _tmp if match] @@ -143,13 +141,25 @@ class HDF5Handler(IDataHandler): def _trades_load(self, pair: str, timerange: Optional[TimeRange] = None) -> TradeList: """ - Load a pair from file, either .json.gz or .json - # TODO: respect timerange ... + Load a pair from h5 file. :param pair: Load trades for this pair :param timerange: Timerange to load trades for - currently not implemented :return: List of trades """ - raise NotImplementedError() + key = self._pair_trades_key(pair) + filename = self._pair_trades_filename(self._datadir, pair) + + if not filename.exists(): + return [] + where = [] + if timerange: + if timerange.starttype == 'date': + where.append(f"timestamp >= {timerange.startts * 1e3}") + if timerange.stoptype == 'date': + where.append(f"timestamp < {timerange.stopts * 1e3}") + + trades = pd.read_hdf(filename, key=key, mode="r", where=where) + return trades.values.tolist() def trades_purge(self, pair: str) -> bool: """ From 31df42e7376b024c6a5cf7e6b8c01aff40be1734 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 17:30:16 +0200 Subject: [PATCH 094/285] Implement get_available_data --- freqtrade/data/history/hdf5datahandler.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index c99436b3c..82298f38b 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -7,7 +7,9 @@ import pandas as pd from freqtrade import misc from freqtrade.configuration import TimeRange -from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS +from freqtrade.constants import (DEFAULT_DATAFRAME_COLUMNS, + DEFAULT_TRADES_COLUMNS, + ListPairsWithTimeframes) from .idatahandler import IDataHandler, TradeList @@ -18,6 +20,18 @@ class HDF5Handler(IDataHandler): _columns = DEFAULT_DATAFRAME_COLUMNS + @classmethod + def ohlcv_get_available_data(cls, datadir: Path) -> ListPairsWithTimeframes: + """ + Returns a list of all pairs with ohlcv data available in this datadir + :param datadir: Directory to search for ohlcv files + :return: List of Tuples of (pair, timeframe) + """ + _tmp = [re.search(r'^([a-zA-Z_]+)\-(\d+\S+)(?=.h5)', p.name) + for p in datadir.glob("*.h5")] + return [(match[1].replace('_', '/'), match[2]) for match in _tmp + if match and len(match.groups()) > 1] + @classmethod def ohlcv_get_pairs(cls, datadir: Path, timeframe: str) -> List[str]: """ @@ -45,7 +59,7 @@ class HDF5Handler(IDataHandler): _data = data.copy() filename = self._pair_data_filename(self._datadir, pair, timeframe) - ds = pd.HDFStore(filename, mode='a', complevel=9) + ds = pd.HDFStore(filename, mode='a', complevel=9, complib='blosc') ds.put(key, _data.loc[:, self._columns], format='table', data_columns=['date']) ds.close() From 0f08addfbea44fd3bd3ce83bbffc2e81c5290333 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 17:37:07 +0200 Subject: [PATCH 095/285] Don't store empty arrays --- freqtrade/data/converter.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/freqtrade/data/converter.py b/freqtrade/data/converter.py index 46b653eb0..100a578a2 100644 --- a/freqtrade/data/converter.py +++ b/freqtrade/data/converter.py @@ -255,7 +255,8 @@ def convert_ohlcv_format(config: Dict[str, Any], convert_from: str, convert_to: drop_incomplete=False, startup_candles=0) logger.info(f"Converting {len(data)} candles for {pair}") - trg.ohlcv_store(pair=pair, timeframe=timeframe, data=data) - if erase and convert_from != convert_to: - logger.info(f"Deleting source data for {pair} / {timeframe}") - src.ohlcv_purge(pair=pair, timeframe=timeframe) + if len(data) > 0: + trg.ohlcv_store(pair=pair, timeframe=timeframe, data=data) + if erase and convert_from != convert_to: + logger.info(f"Deleting source data for {pair} / {timeframe}") + src.ohlcv_purge(pair=pair, timeframe=timeframe) From 3171ad33b756183e7240c38314abca4832583340 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 17:44:29 +0200 Subject: [PATCH 096/285] Add blosc compression --- freqtrade/data/history/hdf5datahandler.py | 2 +- requirements-common.txt | 1 + setup.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index 82298f38b..d27b28c2d 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -139,7 +139,7 @@ class HDF5Handler(IDataHandler): column sequence as in DEFAULT_TRADES_COLUMNS """ key = self._pair_trades_key(pair) - ds = pd.HDFStore(self.filename_trades, mode='a', complevel=9) + ds = pd.HDFStore(self.filename_trades, mode='a', complevel=9, complib='blosc') ds.put(key, pd.DataFrame(data, columns=DEFAULT_TRADES_COLUMNS), format='table', data_columns=['timestamp']) ds.close() diff --git a/requirements-common.txt b/requirements-common.txt index 604a769d4..3e58f15b4 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -14,6 +14,7 @@ tabulate==0.8.7 pycoingecko==1.3.0 jinja2==2.11.2 tables==3.6.1 +blosc==1.9.1 # find first, C search in arrays py_find_1st==1.1.4 diff --git a/setup.py b/setup.py index b1b500cc8..7213d3092 100644 --- a/setup.py +++ b/setup.py @@ -86,6 +86,7 @@ setup(name='freqtrade', 'numpy', 'pandas', 'tables', + 'blosc', ], extras_require={ 'api': api, From 861e7099ccf14427313b79c5ceecd300963b3459 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 19:23:37 +0200 Subject: [PATCH 097/285] Rename hdf5handler to hdf5DataHandler --- freqtrade/data/history/hdf5datahandler.py | 2 +- freqtrade/data/history/idatahandler.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index d27b28c2d..debbcce8b 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -16,7 +16,7 @@ from .idatahandler import IDataHandler, TradeList logger = logging.getLogger(__name__) -class HDF5Handler(IDataHandler): +class HDF5DataHandler(IDataHandler): _columns = DEFAULT_DATAFRAME_COLUMNS diff --git a/freqtrade/data/history/idatahandler.py b/freqtrade/data/history/idatahandler.py index be3e34e04..01b14f501 100644 --- a/freqtrade/data/history/idatahandler.py +++ b/freqtrade/data/history/idatahandler.py @@ -238,8 +238,8 @@ def get_datahandlerclass(datatype: str) -> Type[IDataHandler]: from .jsondatahandler import JsonGzDataHandler return JsonGzDataHandler elif datatype == 'hdf5': - from .hdf5datahandler import HDF5Handler - return HDF5Handler + from .hdf5datahandler import HDF5DataHandler + return HDF5DataHandler else: raise ValueError(f"No datahandler for datatype {datatype} available.") From 6a0c84b64924db4889363e8b062d769c46f7deb4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 19:23:56 +0200 Subject: [PATCH 098/285] Add tests for hdf5 --- tests/data/test_history.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index d84c212b1..fd4f5a449 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -1,5 +1,6 @@ # pragma pylint: disable=missing-docstring, protected-access, C0103 +from freqtrade.data.history.hdf5datahandler import HDF5DataHandler import json import uuid from pathlib import Path @@ -12,6 +13,7 @@ from pandas import DataFrame from pandas.testing import assert_frame_equal from freqtrade.configuration import TimeRange +from freqtrade.constants import AVAILABLE_DATAHANDLERS from freqtrade.data.converter import ohlcv_to_dataframe from freqtrade.data.history.history_utils import ( _download_pair_history, _download_trades_history, @@ -682,14 +684,16 @@ def test_jsondatahandler_trades_purge(mocker, testdatadir): assert dh.trades_purge('UNITTEST/NONEXIST') -def test_jsondatahandler_ohlcv_append(testdatadir): - dh = JsonGzDataHandler(testdatadir) +@pytest.mark.parametrize('datahandler', AVAILABLE_DATAHANDLERS) +def test_datahandler_ohlcv_append(datahandler, testdatadir, ): + dh = get_datahandler(testdatadir, datahandler) with pytest.raises(NotImplementedError): dh.ohlcv_append('UNITTEST/ETH', '5m', DataFrame()) -def test_jsondatahandler_trades_append(testdatadir): - dh = JsonGzDataHandler(testdatadir) +@pytest.mark.parametrize('datahandler', AVAILABLE_DATAHANDLERS) +def test_datahandler_trades_append(datahandler, testdatadir): + dh = get_datahandler(testdatadir, datahandler) with pytest.raises(NotImplementedError): dh.trades_append('UNITTEST/ETH', []) @@ -702,6 +706,9 @@ def test_gethandlerclass(): assert cl == JsonGzDataHandler assert issubclass(cl, IDataHandler) assert issubclass(cl, JsonDataHandler) + cl = get_datahandlerclass('hdf5') + assert cl == HDF5DataHandler + assert issubclass(cl, IDataHandler) with pytest.raises(ValueError, match=r"No datahandler for .*"): get_datahandlerclass('DeadBeef') @@ -713,3 +720,6 @@ def test_get_datahandler(testdatadir): assert type(dh) == JsonGzDataHandler dh1 = get_datahandler(testdatadir, 'jsongz', dh) assert id(dh1) == id(dh) + + dh = get_datahandler(testdatadir, 'hdf5') + assert type(dh) == HDF5DataHandler From e26e658f99bc82f9cd194a0dfb2239397cfc60e2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 19:33:27 +0200 Subject: [PATCH 099/285] Improve a few tests --- tests/data/test_history.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index fd4f5a449..2c0665b69 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -622,7 +622,7 @@ def test_convert_trades_to_ohlcv(mocker, default_conf, testdatadir, caplog): _clean_test_file(file5) -def test_jsondatahandler_ohlcv_get_pairs(testdatadir): +def test_datahandler_ohlcv_get_pairs(testdatadir): pairs = JsonDataHandler.ohlcv_get_pairs(testdatadir, '5m') # Convert to set to avoid failures due to sorting assert set(pairs) == {'UNITTEST/BTC', 'XLM/BTC', 'ETH/BTC', 'TRX/BTC', 'LTC/BTC', @@ -632,8 +632,11 @@ def test_jsondatahandler_ohlcv_get_pairs(testdatadir): pairs = JsonGzDataHandler.ohlcv_get_pairs(testdatadir, '8m') assert set(pairs) == {'UNITTEST/BTC'} + pairs = HDF5DataHandler.ohlcv_get_pairs(testdatadir, '5m') + assert set(pairs) == {'UNITTEST/BTC'} -def test_jsondatahandler_ohlcv_get_available_data(testdatadir): + +def test_datahandler_ohlcv_get_available_data(testdatadir): paircombs = JsonDataHandler.ohlcv_get_available_data(testdatadir) # Convert to set to avoid failures due to sorting assert set(paircombs) == {('UNITTEST/BTC', '5m'), ('ETH/BTC', '5m'), ('XLM/BTC', '5m'), @@ -645,6 +648,8 @@ def test_jsondatahandler_ohlcv_get_available_data(testdatadir): paircombs = JsonGzDataHandler.ohlcv_get_available_data(testdatadir) assert set(paircombs) == {('UNITTEST/BTC', '8m')} + paircombs = HDF5DataHandler.ohlcv_get_available_data(testdatadir) + assert set(paircombs) == {('UNITTEST/BTC', '5m')} def test_jsondatahandler_trades_get_pairs(testdatadir): @@ -655,12 +660,14 @@ def test_jsondatahandler_trades_get_pairs(testdatadir): def test_jsondatahandler_ohlcv_purge(mocker, testdatadir): mocker.patch.object(Path, "exists", MagicMock(return_value=False)) - mocker.patch.object(Path, "unlink", MagicMock()) + unlinkmock = mocker.patch.object(Path, "unlink", MagicMock()) dh = JsonGzDataHandler(testdatadir) assert not dh.ohlcv_purge('UNITTEST/NONEXIST', '5m') + assert unlinkmock.call_count == 0 mocker.patch.object(Path, "exists", MagicMock(return_value=True)) assert dh.ohlcv_purge('UNITTEST/NONEXIST', '5m') + assert unlinkmock.call_count == 1 def test_jsondatahandler_trades_load(mocker, testdatadir, caplog): @@ -676,12 +683,14 @@ def test_jsondatahandler_trades_load(mocker, testdatadir, caplog): def test_jsondatahandler_trades_purge(mocker, testdatadir): mocker.patch.object(Path, "exists", MagicMock(return_value=False)) - mocker.patch.object(Path, "unlink", MagicMock()) + unlinkmock = mocker.patch.object(Path, "unlink", MagicMock()) dh = JsonGzDataHandler(testdatadir) assert not dh.trades_purge('UNITTEST/NONEXIST') + assert unlinkmock.call_count == 0 mocker.patch.object(Path, "exists", MagicMock(return_value=True)) assert dh.trades_purge('UNITTEST/NONEXIST') + assert unlinkmock.call_count == 1 @pytest.mark.parametrize('datahandler', AVAILABLE_DATAHANDLERS) From 0a28818b46bf1ded08579c41e951db45ff31fdc9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 19:37:37 +0200 Subject: [PATCH 100/285] Add some tests for hdf5 --- freqtrade/data/history/hdf5datahandler.py | 3 ++- tests/data/test_history.py | 6 ++++++ tests/testdata/UNITTEST_BTC-5m.h5 | Bin 0 -> 261142 bytes tests/testdata/XRP_ETH-trades.h5 | Bin 0 -> 310513 bytes 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/testdata/UNITTEST_BTC-5m.h5 create mode 100644 tests/testdata/XRP_ETH-trades.h5 diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index debbcce8b..6a4f45fa9 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -139,7 +139,8 @@ class HDF5DataHandler(IDataHandler): column sequence as in DEFAULT_TRADES_COLUMNS """ key = self._pair_trades_key(pair) - ds = pd.HDFStore(self.filename_trades, mode='a', complevel=9, complib='blosc') + ds = pd.HDFStore(self._pair_trades_filename(self._datadir, pair), + mode='a', complevel=9, complib='blosc') ds.put(key, pd.DataFrame(data, columns=DEFAULT_TRADES_COLUMNS), format='table', data_columns=['timestamp']) ds.close() diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 2c0665b69..003e90fbb 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -707,6 +707,12 @@ def test_datahandler_trades_append(datahandler, testdatadir): dh.trades_append('UNITTEST/ETH', []) +def test_hdf5datahandler_trades_get_pairs(testdatadir): + pairs = HDF5DataHandler.trades_get_pairs(testdatadir) + # Convert to set to avoid failures due to sorting + assert set(pairs) == {'XRP/ETH'} + + def test_gethandlerclass(): cl = get_datahandlerclass('json') assert cl == JsonDataHandler diff --git a/tests/testdata/UNITTEST_BTC-5m.h5 b/tests/testdata/UNITTEST_BTC-5m.h5 new file mode 100644 index 0000000000000000000000000000000000000000..52232af9e6a3fb48a11b1e28434d9ade31b363d2 GIT binary patch literal 261142 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%0DH8)0H> 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 M0Koj;+GPBH05iAmr~m)} literal 0 HcmV?d00001 diff --git a/tests/testdata/XRP_ETH-trades.h5 b/tests/testdata/XRP_ETH-trades.h5 new file mode 100644 index 0000000000000000000000000000000000000000..c13789e2acc9f44a81dbcc5907a7050fc3b933c7 GIT binary patch literal 310513 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

T;^Q^qt>Gk#(5KGYRvJ&9zjaUv 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%0AdKwn?Z%@4G@`=UNuYIClBntX=}?+m{x-Wg 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

    p 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 42Oawj1bj`}UciI)yUx96!Ft_&el5e!G%N>J$JI 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

    k* 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 z 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 literal 0 HcmV?d00001 From d9b339ee183f2dd276d5153d39b92ccd033e0f1f Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 20:09:59 +0200 Subject: [PATCH 101/285] Add some more tests for hdf5 --- tests/data/test_history.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 003e90fbb..2e703c72b 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -713,6 +713,41 @@ def test_hdf5datahandler_trades_get_pairs(testdatadir): assert set(pairs) == {'XRP/ETH'} +def test_hdf5datahandler_trades_load(mocker, testdatadir, caplog): + dh = HDF5DataHandler(testdatadir) + trades = dh.trades_load('XRP/ETH') + assert isinstance(trades, list) + + +def test_hdf5datahandler_trades_store(mocker, testdatadir, caplog): + dh = HDF5DataHandler(testdatadir) + trades = dh.trades_load('XRP/ETH') + + dh.trades_store('XRP/NEW', trades) + file = testdatadir / 'XRP_NEW-trades.h5' + assert file.is_file() + # Load trades back + trades_new = dh.trades_load('XRP/NEW') + + assert len(trades_new) == len(trades) + assert trades[0][0] == trades_new[0][0] + assert trades[0][1] == trades_new[0][1] + # assert trades[0][2] == trades_new[0][2] # This is nan - so comparison does not make sense + assert trades[0][3] == trades_new[0][3] + assert trades[0][4] == trades_new[0][4] + assert trades[0][5] == trades_new[0][5] + assert trades[0][6] == trades_new[0][6] + assert trades[-1][0] == trades_new[-1][0] + assert trades[-1][1] == trades_new[-1][1] + # assert trades[-1][2] == trades_new[-1][2] # This is nan - so comparison does not make sense + assert trades[-1][3] == trades_new[-1][3] + assert trades[-1][4] == trades_new[-1][4] + assert trades[-1][5] == trades_new[-1][5] + assert trades[-1][6] == trades_new[-1][6] + + _clean_test_file(file) + + def test_gethandlerclass(): cl = get_datahandlerclass('json') assert cl == JsonDataHandler From ed33d4781d9bce146e85ee23ddc46e840e9c20c8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 20:19:34 +0200 Subject: [PATCH 102/285] Add more hdf5 tests --- tests/data/test_history.py | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 2e703c72b..3b20bd61d 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -670,7 +670,7 @@ def test_jsondatahandler_ohlcv_purge(mocker, testdatadir): assert unlinkmock.call_count == 1 -def test_jsondatahandler_trades_load(mocker, testdatadir, caplog): +def test_jsondatahandler_trades_load(testdatadir, caplog): dh = JsonGzDataHandler(testdatadir) logmsg = "Old trades format detected - converting" dh.trades_load('XRP/ETH') @@ -713,13 +713,13 @@ def test_hdf5datahandler_trades_get_pairs(testdatadir): assert set(pairs) == {'XRP/ETH'} -def test_hdf5datahandler_trades_load(mocker, testdatadir, caplog): +def test_hdf5datahandler_trades_load(testdatadir): dh = HDF5DataHandler(testdatadir) trades = dh.trades_load('XRP/ETH') assert isinstance(trades, list) -def test_hdf5datahandler_trades_store(mocker, testdatadir, caplog): +def test_hdf5datahandler_trades_store(testdatadir): dh = HDF5DataHandler(testdatadir) trades = dh.trades_load('XRP/ETH') @@ -748,6 +748,26 @@ def test_hdf5datahandler_trades_store(mocker, testdatadir, caplog): _clean_test_file(file) +def test_hdf5datahandler_ohlcv_load_and_resave(testdatadir): + dh = HDF5DataHandler(testdatadir) + ohlcv = dh.ohlcv_load('UNITTEST/BTC', '5m') + assert isinstance(ohlcv, DataFrame) + assert len(ohlcv) > 0 + + file = testdatadir / 'UNITTEST_NEW-5m.h5' + assert not file.is_file() + + dh.ohlcv_store('UNITTEST/NEW', '5m', ohlcv) + assert file.is_file() + + ohlcv1 = dh.ohlcv_load('UNITTEST/NEW', '5m') + # Account for the automatically dropped last candle + assert len(ohlcv) - 1 == len(ohlcv1) + assert ohlcv.iloc[:-1].equals(ohlcv1) + + _clean_test_file(file) + + def test_gethandlerclass(): cl = get_datahandlerclass('json') assert cl == JsonDataHandler From ae1c99bdd010c7f4e1bc122eb3e68a539a4f9912 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 20:36:30 +0200 Subject: [PATCH 103/285] more tests --- tests/data/test_history.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 3b20bd61d..41b20e35b 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -718,6 +718,23 @@ def test_hdf5datahandler_trades_load(testdatadir): trades = dh.trades_load('XRP/ETH') assert isinstance(trades, list) + trades1 = dh.trades_load('UNITTEST/NONEXIST') + assert trades1 == [] + # data goes from 2019-10-11 - 2019-10-13 + timerange = TimeRange.parse_timerange('20191011-20191012') + + trades2 = dh._trades_load('XRP/ETH', timerange) + assert len(trades) > len(trades2) + + # unfiltered load has trades before starttime + assert len([t for t in trades if t[0] < timerange.startts * 1000]) >= 0 + # filtered list does not have trades before starttime + assert len([t for t in trades2 if t[0] < timerange.startts * 1000]) == 0 + # unfiltered load has trades after endtime + assert len([t for t in trades if t[0] > timerange.stopts * 1000]) > 0 + # filtered list does not have trades after endtime + assert len([t for t in trades2 if t[0] > timerange.stopts * 1000]) == 0 + def test_hdf5datahandler_trades_store(testdatadir): dh = HDF5DataHandler(testdatadir) @@ -760,13 +777,25 @@ def test_hdf5datahandler_ohlcv_load_and_resave(testdatadir): dh.ohlcv_store('UNITTEST/NEW', '5m', ohlcv) assert file.is_file() - ohlcv1 = dh.ohlcv_load('UNITTEST/NEW', '5m') - # Account for the automatically dropped last candle - assert len(ohlcv) - 1 == len(ohlcv1) - assert ohlcv.iloc[:-1].equals(ohlcv1) + assert not ohlcv[ohlcv['date'] < '2018-01-15'].empty + + # Data gores from 2018-01-10 - 2018-01-30 + timerange = TimeRange.parse_timerange('20180115-20180119') + + # Call private function to ensure timerange is filtered in hdf5 + ohlcv = dh._ohlcv_load('UNITTEST/BTC', '5m', timerange) + ohlcv1 = dh._ohlcv_load('UNITTEST/NEW', '5m', timerange) + assert len(ohlcv) == len(ohlcv1) + assert ohlcv.equals(ohlcv1) + assert ohlcv[ohlcv['date'] < '2018-01-15'].empty + assert ohlcv[ohlcv['date'] > '2018-01-19'].empty _clean_test_file(file) + # Try loading inexisting file + ohlcv = dh.ohlcv_load('UNITTEST/NONEXIST', '5m') + assert ohlcv.empty + def test_gethandlerclass(): cl = get_datahandlerclass('json') From edb582e5229b18052dd82ee930d0af2fa859732d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 24 Jul 2020 20:40:07 +0200 Subject: [PATCH 104/285] Add more tests --- tests/data/test_history.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index 41b20e35b..c89156f4c 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -765,6 +765,18 @@ def test_hdf5datahandler_trades_store(testdatadir): _clean_test_file(file) +def test_hdf5datahandler_trades_purge(mocker, testdatadir): + mocker.patch.object(Path, "exists", MagicMock(return_value=False)) + unlinkmock = mocker.patch.object(Path, "unlink", MagicMock()) + dh = HDF5DataHandler(testdatadir) + assert not dh.trades_purge('UNITTEST/NONEXIST') + assert unlinkmock.call_count == 0 + + mocker.patch.object(Path, "exists", MagicMock(return_value=True)) + assert dh.trades_purge('UNITTEST/NONEXIST') + assert unlinkmock.call_count == 1 + + def test_hdf5datahandler_ohlcv_load_and_resave(testdatadir): dh = HDF5DataHandler(testdatadir) ohlcv = dh.ohlcv_load('UNITTEST/BTC', '5m') @@ -797,6 +809,18 @@ def test_hdf5datahandler_ohlcv_load_and_resave(testdatadir): assert ohlcv.empty +def test_hdf5datahandler_ohlcv_purge(mocker, testdatadir): + mocker.patch.object(Path, "exists", MagicMock(return_value=False)) + unlinkmock = mocker.patch.object(Path, "unlink", MagicMock()) + dh = HDF5DataHandler(testdatadir) + assert not dh.ohlcv_purge('UNITTEST/NONEXIST', '5m') + assert unlinkmock.call_count == 0 + + mocker.patch.object(Path, "exists", MagicMock(return_value=True)) + assert dh.ohlcv_purge('UNITTEST/NONEXIST', '5m') + assert unlinkmock.call_count == 1 + + def test_gethandlerclass(): cl = get_datahandlerclass('json') assert cl == JsonDataHandler From 119bf2a8ea66ecafc900677f998be2317c458f5b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Jul 2020 17:06:58 +0200 Subject: [PATCH 105/285] Document hdf5 dataformat --- docs/data-download.md | 118 ++++++++++++++-------- freqtrade/data/history/hdf5datahandler.py | 2 + freqtrade/data/history/history_utils.py | 8 +- 3 files changed, 84 insertions(+), 44 deletions(-) diff --git a/docs/data-download.md b/docs/data-download.md index a2bbec837..0b22ec9ce 100644 --- a/docs/data-download.md +++ b/docs/data-download.md @@ -15,61 +15,91 @@ Otherwise `--exchange` becomes mandatory. ### Usage ``` -usage: freqtrade download-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] - [--pairs-file FILE] [--days INT] [--dl-trades] [--exchange EXCHANGE] +usage: freqtrade download-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] + [-p PAIRS [PAIRS ...]] [--pairs-file FILE] + [--days INT] [--dl-trades] + [--exchange EXCHANGE] [-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} ...]] - [--erase] [--data-format-ohlcv {json,jsongz}] [--data-format-trades {json,jsongz}] + [--erase] + [--data-format-ohlcv {json,jsongz,hdf5}] + [--data-format-trades {json,jsongz,hdf5}] optional arguments: -h, --help show this help message and exit -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] - Show profits for only these pairs. Pairs are space-separated. + Show profits for only these pairs. Pairs are space- + separated. --pairs-file FILE File containing a list of pairs to download. --days INT Download data for given number of days. - --dl-trades Download trades instead of OHLCV data. The bot will resample trades to the desired timeframe as specified as - --timeframes/-t. - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no config is provided. + --dl-trades Download trades instead of OHLCV data. The bot will + resample trades to the desired timeframe as specified + as --timeframes/-t. + --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no + config is provided. -t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} ...], --timeframes {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} ...] - Specify which tickers to download. Space-separated list. Default: `1m 5m`. - --erase Clean all existing data for the selected exchange/pairs/timeframes. - --data-format-ohlcv {json,jsongz} - Storage format for downloaded candle (OHLCV) data. (default: `json`). - --data-format-trades {json,jsongz} - Storage format for downloaded trades data. (default: `jsongz`). + Specify which tickers to download. Space-separated + list. Default: `1m 5m`. + --erase Clean all existing data for the selected + exchange/pairs/timeframes. + --data-format-ohlcv {json,jsongz,hdf5} + Storage format for downloaded candle (OHLCV) data. + (default: `json`). + --data-format-trades {json,jsongz,hdf5} + Storage format for downloaded trades data. (default: + `jsongz`). 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. + --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: `config.json`). Multiple --config options may be used. Can be set to `-` - to read config from stdin. + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. -d PATH, --datadir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. + ``` ### Data format -Freqtrade currently supports 2 dataformats, `json` (plain "text" json files) and `jsongz` (a gzipped version of json files). +Freqtrade currently supports 3 data-formats for both OHLCV and trades data: + +* `json` (plain "text" json files) +* `jsongz` (a gzip-zipped version of json files) +* `hdf5` (a high performance datastore) + By default, OHLCV data is stored as `json` data, while trades data is stored as `jsongz` data. -This can be changed via the `--data-format-ohlcv` and `--data-format-trades` parameters respectivly. +This can be changed via the `--data-format-ohlcv` and `--data-format-trades` command line arguments respectively. +To persist this change, you can should also add the following snippet to your configuration, so you don't have to insert the above arguments each time: -If the default dataformat has been changed during download, then the keys `dataformat_ohlcv` and `dataformat_trades` in the configuration file need to be adjusted to the selected dataformat as well. +``` jsonc + // ... + "dataformat_ohlcv": "hdf5", + "dataformat_trades": "hdf5", + // ... +``` + +If the default data-format has been changed during download, then the keys `dataformat_ohlcv` and `dataformat_trades` in the configuration file need to be adjusted to the selected dataformat as well. !!! Note - You can convert between data-formats using the [convert-data](#subcommand-convert-data) and [convert-trade-data](#subcommand-convert-trade-data) methods. + You can convert between data-formats using the [convert-data](#sub-command-convert-data) and [convert-trade-data](#sub-command-convert-trade-data) methods. -#### Subcommand convert data +#### Sub-command convert data ``` usage: freqtrade convert-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] --format-from - {json,jsongz} --format-to {json,jsongz} - [--erase] + {json,jsongz,hdf5} --format-to + {json,jsongz,hdf5} [--erase] [-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w} ...]] optional arguments: @@ -77,9 +107,9 @@ optional arguments: -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] Show profits for only these pairs. Pairs are space- separated. - --format-from {json,jsongz} + --format-from {json,jsongz,hdf5} Source format for data conversion. - --format-to {json,jsongz} + --format-to {json,jsongz,hdf5} Destination format for data conversion. --erase Clean all existing data for the selected exchange/pairs/timeframes. @@ -94,9 +124,10 @@ Common arguments: details. -V, --version show program's version number and exit -c PATH, --config PATH - Specify configuration file (default: `config.json`). - Multiple --config options may be used. Can be set to - `-` to read config from stdin. + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. -d PATH, --datadir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH @@ -112,23 +143,23 @@ It'll also remove original json data files (`--erase` parameter). freqtrade convert-data --format-from json --format-to jsongz --datadir ~/.freqtrade/data/binance -t 5m 15m --erase ``` -#### Subcommand convert-trade data +#### Sub-command convert trade data ``` usage: freqtrade convert-trade-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] --format-from - {json,jsongz} --format-to {json,jsongz} - [--erase] + {json,jsongz,hdf5} --format-to + {json,jsongz,hdf5} [--erase] optional arguments: -h, --help show this help message and exit -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] Show profits for only these pairs. Pairs are space- separated. - --format-from {json,jsongz} + --format-from {json,jsongz,hdf5} Source format for data conversion. - --format-to {json,jsongz} + --format-to {json,jsongz,hdf5} Destination format for data conversion. --erase Clean all existing data for the selected exchange/pairs/timeframes. @@ -140,13 +171,15 @@ Common arguments: details. -V, --version show program's version number and exit -c PATH, --config PATH - Specify configuration file (default: `config.json`). - Multiple --config options may be used. Can be set to - `-` to read config from stdin. + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. -d PATH, --datadir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. + ``` ##### Example converting trades @@ -158,21 +191,21 @@ It'll also remove original jsongz data files (`--erase` parameter). freqtrade convert-trade-data --format-from jsongz --format-to json --datadir ~/.freqtrade/data/kraken --erase ``` -### Subcommand list-data +### Sub-command list-data -You can get a list of downloaded data using the `list-data` subcommand. +You can get a list of downloaded data using the `list-data` sub-command. ``` usage: freqtrade list-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--exchange EXCHANGE] - [--data-format-ohlcv {json,jsongz}] + [--data-format-ohlcv {json,jsongz,hdf5}] [-p PAIRS [PAIRS ...]] optional arguments: -h, --help show this help message and exit --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no config is provided. - --data-format-ohlcv {json,jsongz} + --data-format-ohlcv {json,jsongz,hdf5} Storage format for downloaded candle (OHLCV) data. (default: `json`). -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] @@ -194,6 +227,7 @@ Common arguments: Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. + ``` #### Example list-data @@ -249,7 +283,7 @@ This will download historical candle (OHLCV) data for all the currency pairs you ### Other Notes - To use a different directory than the exchange specific default, use `--datadir user_data/data/some_directory`. -- To change the exchange used to download the historical data from, please use a different configuration file (you'll probably need to adjust ratelimits etc.) +- To change the exchange used to download the historical data from, please use a different configuration file (you'll probably need to adjust rate limits etc.) - To use `pairs.json` from some other directory, use `--pairs-file some_other_dir/pairs.json`. - To download historical candle (OHLCV) data for only 10 days, use `--days 10` (defaults to 30 days). - Use `--timeframes` to specify what timeframe download the historical candle (OHLCV) data for. Default is `--timeframes 1m 5m` which will download 1-minute and 5-minute data. @@ -257,7 +291,7 @@ This will download historical candle (OHLCV) data for all the currency pairs you ### Trades (tick) data -By default, `download-data` subcommand downloads Candles (OHLCV) data. Some exchanges also provide historic trade-data via their API. +By default, `download-data` sub-command downloads Candles (OHLCV) data. Some exchanges also provide historic trade-data via their API. This data can be useful if you need many different timeframes, since it is only downloaded once, and then resampled locally to the desired timeframes. Since this data is large by default, the files use gzip by default. They are stored in your data-directory with the naming convention of `-trades.json.gz` (`ETH_BTC-trades.json.gz`). Incremental mode is also supported, as for historic OHLCV data, so downloading the data once per week with `--days 8` will create an incremental data-repository. diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index 6a4f45fa9..c55c0c1e5 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -59,6 +59,7 @@ class HDF5DataHandler(IDataHandler): _data = data.copy() filename = self._pair_data_filename(self._datadir, pair, timeframe) + ds = pd.HDFStore(filename, mode='a', complevel=9, complib='blosc') ds.put(key, _data.loc[:, self._columns], format='table', data_columns=['date']) @@ -139,6 +140,7 @@ class HDF5DataHandler(IDataHandler): column sequence as in DEFAULT_TRADES_COLUMNS """ key = self._pair_trades_key(pair) + ds = pd.HDFStore(self._pair_trades_filename(self._datadir, pair), mode='a', complevel=9, complib='blosc') ds.put(key, pd.DataFrame(data, columns=DEFAULT_TRADES_COLUMNS), diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index 58bd752ea..dd09c4c05 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -9,7 +9,8 @@ from pandas import DataFrame from freqtrade.configuration import TimeRange from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS -from freqtrade.data.converter import (ohlcv_to_dataframe, +from freqtrade.data.converter import (clean_ohlcv_dataframe, + ohlcv_to_dataframe, trades_remove_duplicates, trades_to_ohlcv) from freqtrade.data.history.idatahandler import IDataHandler, get_datahandler @@ -202,7 +203,10 @@ def _download_pair_history(datadir: Path, if data.empty: data = new_dataframe else: - data = data.append(new_dataframe) + # Run cleaning again to ensure there were no duplicate candles + # Especially between existing and new data. + data = clean_ohlcv_dataframe(data.append(new_dataframe), timeframe, pair, + fill_missing=False, drop_incomplete=False) logger.debug("New Start: %s", f"{data.iloc[0]['date']:%Y-%m-%d %H:%M:%S}" if not data.empty else 'None') From bad89307dd752195100855a1c4f9cc942b9ef59d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 25 Jul 2020 17:19:41 +0200 Subject: [PATCH 106/285] Fix mypy error --- freqtrade/data/history/hdf5datahandler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index c55c0c1e5..594a1598a 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -191,11 +191,11 @@ class HDF5DataHandler(IDataHandler): return False @classmethod - def _pair_ohlcv_key(cls, pair: str, timeframe: str) -> Path: + def _pair_ohlcv_key(cls, pair: str, timeframe: str) -> str: return f"{pair}/ohlcv/tf_{timeframe}" @classmethod - def _pair_trades_key(cls, pair: str) -> Path: + def _pair_trades_key(cls, pair: str) -> str: return f"{pair}/trades" @classmethod From 902e8fa62fce59c77bc809f4edad640e727c6f15 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Jul 2020 14:39:00 +0200 Subject: [PATCH 107/285] Fix wrong spelling in one subcomponent --- freqtrade/optimize/optimize_reports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 3a42ba4a9..7e0a60566 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -142,7 +142,7 @@ def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List 'profit_sum': profit_sum, 'profit_sum_pct': round(profit_sum * 100, 2), 'profit_total_abs': result['profit_abs'].sum(), - 'profit_pct_total': profit_percent_tot, + 'profit_total_pct': profit_percent_tot, } ) return tabular_data @@ -338,7 +338,7 @@ 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_pct_total'], + t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'], t['profit_total_pct'], ] for t in sell_reason_stats] return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right") From 9ed5fed88738214c5b22acfe0fb0c8b7d72cc2ac Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Jul 2020 15:17:54 +0200 Subject: [PATCH 108/285] Fix output format to be of an identical type --- freqtrade/optimize/optimize_reports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 7e0a60566..2db941db4 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -208,9 +208,9 @@ def generate_daily_stats(results: DataFrame) -> Dict[str, Any]: 'draw_days': draw_days, 'losing_days': losing_days, 'winner_holding_avg': (timedelta(minutes=round(winning_trades['trade_duration'].mean())) - if not winning_trades.empty else '0:00'), + if not winning_trades.empty else timedelta()), 'loser_holding_avg': (timedelta(minutes=round(losing_trades['trade_duration'].mean())) - if not losing_trades.empty else '0:00'), + if not losing_trades.empty else timedelta()), } From 8d0f338bf2eed48e5ec9d61a9a98ddf0ec575502 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Jul 2020 15:23:21 +0200 Subject: [PATCH 109/285] Timestamps should be in ms --- freqtrade/optimize/optimize_reports.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 2db941db4..c0e1347cc 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -253,9 +253,9 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'left_open_trades': left_open_results, 'total_trades': len(results), 'backtest_start': min_date.datetime, - 'backtest_start_ts': min_date.timestamp, + 'backtest_start_ts': min_date.timestamp * 1000, 'backtest_end': max_date.datetime, - 'backtest_end_ts': max_date.timestamp, + 'backtest_end_ts': max_date.timestamp * 1000, 'backtest_days': backtest_days, 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None, @@ -272,9 +272,9 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], strat_stats.update({ 'max_drawdown': max_drawdown, 'drawdown_start': drawdown_start, - 'drawdown_start_ts': drawdown_start.timestamp(), + 'drawdown_start_ts': drawdown_start.timestamp() * 1000, 'drawdown_end': drawdown_end, - 'drawdown_end_ts': drawdown_end.timestamp(), + 'drawdown_end_ts': drawdown_end.timestamp() * 1000, }) except ValueError: strat_stats.update({ From 454046f74596123f7b0b3ba3f2a96f3d8dce32ef Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Jul 2020 15:55:54 +0200 Subject: [PATCH 110/285] Add stake_currency and max_opeN_trades to backtest result --- freqtrade/optimize/optimize_reports.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index c0e1347cc..587ed303d 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -262,6 +262,8 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'market_change': market_change, 'pairlist': list(btdata.keys()), 'stake_amount': config['stake_amount'], + 'stake_currency': config['stake_currency'], + 'max_open_trades': config['max_open_trades'], **daily_stats, } result['strategy'][strategy] = strat_stats From 977a6d4e9cd8388eaf9a926aa7beaeb688573b3d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Jul 2020 16:10:48 +0200 Subject: [PATCH 111/285] Add profit_total to results line --- freqtrade/optimize/optimize_reports.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 587ed303d..6e0f9acea 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -72,6 +72,7 @@ def _generate_result_line(result: DataFrame, max_open_trades: int, first_column: 'profit_sum': result['profit_percent'].sum(), 'profit_sum_pct': result['profit_percent'].sum() * 100.0, 'profit_total_abs': result['profit_abs'].sum(), + 'profit_total': result['profit_percent'].sum() / max_open_trades, 'profit_total_pct': result['profit_percent'].sum() * 100.0 / max_open_trades, 'duration_avg': str(timedelta( minutes=round(result['trade_duration'].mean())) From aab5596fa6ed145a5bf3afb9a700272704bffd9b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 27 Jul 2020 07:20:40 +0200 Subject: [PATCH 112/285] Convert trade open / close to timestamp (to allow uniform analysis of backtest and real trade data - while giving control of date-formatting to the endsystem. --- freqtrade/optimize/optimize_reports.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 6e0f9acea..f917e7cab 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -5,6 +5,7 @@ from typing import Any, Dict, List from arrow import Arrow from pandas import DataFrame +from numpy import int64 from tabulate import tabulate from freqtrade.constants import DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN @@ -246,6 +247,9 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], skip_nan=True) daily_stats = generate_daily_stats(results) + results['open_timestamp'] = results['open_date'].astype(int64) // 1e6 + results['close_timestamp'] = results['close_date'].astype(int64) // 1e6 + backtest_days = (max_date - min_date).days strat_stats = { 'trades': results.to_dict(orient='records'), From 8b6d10daf1cf3b384eb4732597e5835b97ced143 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 6 Aug 2020 08:50:41 +0200 Subject: [PATCH 113/285] Move DefaultHyperopt to test folder (aligned to strategy) --- .../optimize => tests/optimize/hyperopts}/default_hyperopt.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {freqtrade/optimize => tests/optimize/hyperopts}/default_hyperopt.py (100%) diff --git a/freqtrade/optimize/default_hyperopt.py b/tests/optimize/hyperopts/default_hyperopt.py similarity index 100% rename from freqtrade/optimize/default_hyperopt.py rename to tests/optimize/hyperopts/default_hyperopt.py From 081625c5dcf14206683daa7c73f9a1848a157d9a Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 6 Aug 2020 08:51:01 +0200 Subject: [PATCH 114/285] Have hyperopt tests use new hyperopt location --- tests/optimize/test_hyperopt.py | 235 ++++++++++++++------------------ 1 file changed, 106 insertions(+), 129 deletions(-) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 564725709..2f9f9bc56 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -3,6 +3,7 @@ import locale import logging from datetime import datetime from pathlib import Path +from copy import deepcopy from typing import Dict, List from unittest.mock import MagicMock, PropertyMock @@ -16,7 +17,6 @@ from freqtrade.commands.optimize_commands import (setup_optimize_configuration, start_hyperopt) from freqtrade.data.history import load_data from freqtrade.exceptions import DependencyException, OperationalException -from freqtrade.optimize.default_hyperopt import DefaultHyperOpt from freqtrade.optimize.default_hyperopt_loss import DefaultHyperOptLoss from freqtrade.optimize.hyperopt import Hyperopt from freqtrade.resolvers.hyperopt_resolver import (HyperOptLossResolver, @@ -26,15 +26,28 @@ from freqtrade.strategy.interface import SellType from tests.conftest import (get_args, log_has, log_has_re, patch_exchange, patched_configuration_load_config_file) +from .hyperopts.default_hyperopt import DefaultHyperOpt + @pytest.fixture(scope='function') -def hyperopt(default_conf, mocker): - default_conf.update({ - 'spaces': ['default'], - 'hyperopt': 'DefaultHyperOpt', - }) +def hyperopt_conf(default_conf): + hyperconf = deepcopy(default_conf) + hyperconf.update({ + 'hyperopt': 'DefaultHyperOpt', + 'hyperopt_path': str(Path(__file__).parent / 'hyperopts'), + 'epochs': 1, + 'timerange': None, + 'spaces': ['default'], + 'hyperopt_jobs': 1, + }) + return hyperconf + + +@pytest.fixture(scope='function') +def hyperopt(hyperopt_conf, mocker): + patch_exchange(mocker) - return Hyperopt(default_conf) + return Hyperopt(hyperopt_conf) @pytest.fixture(scope='function') @@ -160,7 +173,7 @@ def test_setup_hyperopt_configuration_with_arguments(mocker, default_conf, caplo assert log_has('Parameter --print-all detected ...', caplog) -def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_conf, caplog) -> None: +def test_setup_hyperopt_configuration_unlimited_stake_amount(mocker, default_conf) -> None: default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT patched_configuration_load_config_file(mocker, default_conf) @@ -201,7 +214,7 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None: assert hasattr(x, "timeframe") -def test_hyperoptresolver_wrongname(mocker, default_conf, caplog) -> None: +def test_hyperoptresolver_wrongname(default_conf) -> None: default_conf.update({'hyperopt': "NonExistingHyperoptClass"}) with pytest.raises(OperationalException, match=r'Impossible to load Hyperopt.*'): @@ -216,7 +229,7 @@ def test_hyperoptresolver_noname(default_conf): HyperOptResolver.load_hyperopt(default_conf) -def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None: +def test_hyperoptlossresolver(mocker, default_conf) -> None: hl = DefaultHyperOptLoss mocker.patch( @@ -227,14 +240,14 @@ def test_hyperoptlossresolver(mocker, default_conf, caplog) -> None: assert hasattr(x, "hyperopt_loss_function") -def test_hyperoptlossresolver_wrongname(mocker, default_conf, caplog) -> None: +def test_hyperoptlossresolver_wrongname(default_conf) -> None: default_conf.update({'hyperopt_loss': "NonExistingLossClass"}) with pytest.raises(OperationalException, match=r'Impossible to load HyperoptLoss.*'): HyperOptLossResolver.load_hyperoptloss(default_conf) -def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None: +def test_start_not_installed(mocker, default_conf) -> None: start_mock = MagicMock() patched_configuration_load_config_file(mocker, default_conf) @@ -253,9 +266,9 @@ def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None start_hyperopt(pargs) -def test_start(mocker, default_conf, caplog) -> None: +def test_start(mocker, hyperopt_conf, caplog) -> None: start_mock = MagicMock() - patched_configuration_load_config_file(mocker, default_conf) + patched_configuration_load_config_file(mocker, hyperopt_conf) mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock) patch_exchange(mocker) @@ -272,8 +285,8 @@ def test_start(mocker, default_conf, caplog) -> None: assert start_mock.call_count == 1 -def test_start_no_data(mocker, default_conf, caplog) -> None: - patched_configuration_load_config_file(mocker, default_conf) +def test_start_no_data(mocker, hyperopt_conf) -> None: + patched_configuration_load_config_file(mocker, hyperopt_conf) mocker.patch('freqtrade.data.history.load_pair_history', MagicMock(return_value=pd.DataFrame)) mocker.patch( 'freqtrade.optimize.hyperopt.get_timerange', @@ -293,9 +306,9 @@ def test_start_no_data(mocker, default_conf, caplog) -> None: start_hyperopt(pargs) -def test_start_filelock(mocker, default_conf, caplog) -> None: - start_mock = MagicMock(side_effect=Timeout(Hyperopt.get_lock_filename(default_conf))) - patched_configuration_load_config_file(mocker, default_conf) +def test_start_filelock(mocker, hyperopt_conf, caplog) -> None: + start_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) patch_exchange(mocker) @@ -519,7 +532,7 @@ def test_roi_table_generation(hyperopt) -> None: assert hyperopt.custom_hyperopt.generate_roi_table(params) == {0: 6, 15: 3, 25: 1, 30: 0} -def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: +def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -545,15 +558,9 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: ) patch_exchange(mocker) # Co-test loading timeframe from strategy - del default_conf['timeframe'] - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, }) + del hyperopt_conf['timeframe'] - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -569,7 +576,7 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None: assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == default_conf['max_open_trades'] + assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") @@ -686,13 +693,36 @@ def test_buy_strategy_generator(hyperopt, testdatadir) -> None: assert 1 in result['buy'] -def test_generate_optimizer(mocker, default_conf) -> None: - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'timerange': None, - 'spaces': 'all', - 'hyperopt_min_trades': 1, - }) +def test_sell_strategy_generator(hyperopt, testdatadir) -> None: + data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], fill_up_missing=True) + dataframes = hyperopt.backtesting.strategy.ohlcvdata_to_dataframe(data) + dataframe = hyperopt.custom_hyperopt.populate_indicators(dataframes['UNITTEST/BTC'], + {'pair': 'UNITTEST/BTC'}) + + populate_sell_trend = hyperopt.custom_hyperopt.sell_strategy_generator( + { + 'sell-adx-value': 20, + 'sell-fastd-value': 75, + 'sell-mfi-value': 80, + 'sell-rsi-value': 20, + 'sell-adx-enabled': True, + 'sell-fastd-enabled': True, + 'sell-mfi-enabled': True, + 'sell-rsi-enabled': True, + 'sell-trigger': 'sell-bb_upper' + } + ) + result = populate_sell_trend(dataframe, {'pair': 'UNITTEST/BTC'}) + # Check if some indicators are generated. We will not test all of them + print(result) + assert 'sell' in result + assert 1 in result['sell'] + + +def test_generate_optimizer(mocker, hyperopt_conf) -> None: + hyperopt_conf.update({'spaces': 'all', + 'hyperopt_min_trades': 1, + }) trades = [ ('TRX/BTC', 0.023117, 0.000233, 100) @@ -783,48 +813,35 @@ def test_generate_optimizer(mocker, default_conf) -> None: 'total_profit': 0.00023300 } - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.dimensions = hyperopt.hyperopt_space() generate_optimizer_value = hyperopt.generate_optimizer(list(optimizer_param.values())) assert generate_optimizer_value == response_expected -def test_clean_hyperopt(mocker, default_conf, caplog): +def test_clean_hyperopt(mocker, hyperopt_conf, caplog): patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - }) + mocker.patch("freqtrade.optimize.hyperopt.Path.is_file", MagicMock(return_value=True)) unlinkmock = mocker.patch("freqtrade.optimize.hyperopt.Path.unlink", MagicMock()) - h = Hyperopt(default_conf) + h = Hyperopt(hyperopt_conf) assert unlinkmock.call_count == 2 assert log_has(f"Removing `{h.data_pickle_file}`.", caplog) -def test_continue_hyperopt(mocker, default_conf, caplog): +def test_continue_hyperopt(mocker, hyperopt_conf, caplog): patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - 'hyperopt_continue': True - }) + hyperopt_conf.update({'hyperopt_continue': True}) mocker.patch("freqtrade.optimize.hyperopt.Path.is_file", MagicMock(return_value=True)) unlinkmock = mocker.patch("freqtrade.optimize.hyperopt.Path.unlink", MagicMock()) - Hyperopt(default_conf) + Hyperopt(hyperopt_conf) assert unlinkmock.call_count == 0 assert log_has("Continuing on previous hyperopt results.", caplog) -def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: +def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -855,16 +872,12 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'all', - 'hyperopt_jobs': 1, - 'print_json': True, - }) + hyperopt_conf.update({'spaces': 'all', + 'hyperopt_jobs': 1, + 'print_json': True, + }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -883,7 +896,7 @@ def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: assert dumper.call_count == 2 -def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None: +def test_print_json_spaces_default(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -913,16 +926,9 @@ def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'default', - 'hyperopt_jobs': 1, - 'print_json': True, - }) + hyperopt_conf.update({'print_json': True}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -937,7 +943,7 @@ def test_print_json_spaces_default(mocker, default_conf, caplog, capsys) -> None assert dumper.call_count == 2 -def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> None: +def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -963,16 +969,12 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'roi stoploss', - 'hyperopt_jobs': 1, - 'print_json': True, - }) + hyperopt_conf.update({'spaces': 'roi stoploss', + 'hyperopt_jobs': 1, + 'print_json': True, + }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -987,7 +989,7 @@ def test_print_json_spaces_roi_stoploss(mocker, default_conf, caplog, capsys) -> assert dumper.call_count == 2 -def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1012,14 +1014,9 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'roi stoploss', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'roi stoploss'}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1040,11 +1037,11 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys) assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == default_conf['max_open_trades'] + assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") -def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1055,14 +1052,9 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) - patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'all', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'all', }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1075,7 +1067,7 @@ def test_simplified_interface_all_failed(mocker, default_conf, caplog, capsys) - hyperopt.start() -def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1100,14 +1092,9 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'buy', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'buy'}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1128,11 +1115,11 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None: assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == default_conf['max_open_trades'] + assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") -def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None: +def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None: dumper = mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1157,14 +1144,9 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None ) patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': 'sell', - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': 'sell', }) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) @@ -1185,7 +1167,7 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None assert hasattr(hyperopt.backtesting.strategy, "advise_sell") assert hasattr(hyperopt.backtesting.strategy, "advise_buy") assert hasattr(hyperopt, "max_open_trades") - assert hyperopt.max_open_trades == default_conf['max_open_trades'] + assert hyperopt.max_open_trades == hyperopt_conf['max_open_trades'] assert hasattr(hyperopt, "position_stacking") @@ -1195,7 +1177,7 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None ('sell_strategy_generator', 'sell'), ('sell_indicator_space', 'sell'), ]) -def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, method, space) -> None: +def test_simplified_interface_failed(mocker, hyperopt_conf, method, space) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', MagicMock(return_value=(MagicMock(), None))) @@ -1206,14 +1188,9 @@ def test_simplified_interface_failed(mocker, default_conf, caplog, capsys, metho patch_exchange(mocker) - default_conf.update({'config': 'config.json.example', - 'hyperopt': 'DefaultHyperOpt', - 'epochs': 1, - 'timerange': None, - 'spaces': space, - 'hyperopt_jobs': 1, }) + hyperopt_conf.update({'spaces': space}) - hyperopt = Hyperopt(default_conf) + hyperopt = Hyperopt(hyperopt_conf) hyperopt.backtesting.strategy.ohlcvdata_to_dataframe = MagicMock() hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) From 59370672b811aba5bcee1f3597f59375c5df2994 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 6 Aug 2020 09:00:28 +0200 Subject: [PATCH 115/285] Fix more tests --- tests/commands/test_commands.py | 5 ++--- tests/optimize/test_hyperopt.py | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 3ec7e4798..6837ebe98 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -667,7 +667,7 @@ def test_start_list_hyperopts(mocker, caplog, capsys): args = [ "list-hyperopts", "--hyperopt-path", - str(Path(__file__).parent.parent / "optimize"), + str(Path(__file__).parent.parent / "optimize" / "hyperopts"), "-1" ] pargs = get_args(args) @@ -683,7 +683,7 @@ def test_start_list_hyperopts(mocker, caplog, capsys): args = [ "list-hyperopts", "--hyperopt-path", - str(Path(__file__).parent.parent / "optimize"), + str(Path(__file__).parent.parent / "optimize" / "hyperopts"), ] pargs = get_args(args) # pargs['config'] = None @@ -692,7 +692,6 @@ def test_start_list_hyperopts(mocker, caplog, capsys): assert "TestHyperoptLegacy" not in captured.out assert "legacy_hyperopt.py" not in captured.out assert "DefaultHyperOpt" in captured.out - assert "test_hyperopt.py" in captured.out def test_start_test_pairlist(mocker, caplog, tickers, default_conf, capsys): diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 2f9f9bc56..0d2ebf213 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -247,7 +247,7 @@ def test_hyperoptlossresolver_wrongname(default_conf) -> None: HyperOptLossResolver.load_hyperoptloss(default_conf) -def test_start_not_installed(mocker, default_conf) -> None: +def test_start_not_installed(mocker, default_conf, import_fails) -> None: start_mock = MagicMock() patched_configuration_load_config_file(mocker, default_conf) @@ -258,6 +258,8 @@ def test_start_not_installed(mocker, default_conf) -> None: 'hyperopt', '--config', 'config.json', '--hyperopt', 'DefaultHyperOpt', + '--hyperopt-path', + str(Path(__file__).parent / "hyperopts"), '--epochs', '5' ] pargs = get_args(args) From 995d3e1ed5ee8548e55e5f5075b4533b6ff5d907 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 6 Aug 2020 09:07:48 +0200 Subject: [PATCH 116/285] Don't search internal path for Hyperopt files --- freqtrade/resolvers/hyperopt_resolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/resolvers/hyperopt_resolver.py b/freqtrade/resolvers/hyperopt_resolver.py index abbfee6ed..5dcf73d67 100644 --- a/freqtrade/resolvers/hyperopt_resolver.py +++ b/freqtrade/resolvers/hyperopt_resolver.py @@ -23,7 +23,7 @@ class HyperOptResolver(IResolver): object_type = IHyperOpt object_type_str = "Hyperopt" user_subdir = USERPATH_HYPEROPTS - initial_search_path = Path(__file__).parent.parent.joinpath('optimize').resolve() + initial_search_path = None @staticmethod def load_hyperopt(config: Dict) -> IHyperOpt: From d01070dba81b19e3e3f9fc715e4d22022259e4b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 6 Aug 2020 09:22:41 +0200 Subject: [PATCH 117/285] Increase coverage of edge_cli --- tests/optimize/test_edge_cli.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/optimize/test_edge_cli.py b/tests/optimize/test_edge_cli.py index acec51f66..188b4aa5f 100644 --- a/tests/optimize/test_edge_cli.py +++ b/tests/optimize/test_edge_cli.py @@ -105,3 +105,17 @@ def test_edge_init_fee(mocker, edge_conf) -> None: edge_cli = EdgeCli(edge_conf) assert edge_cli.edge.fee == 0.1234 assert fee_mock.call_count == 0 + + +def test_edge_start(mocker, edge_conf) -> None: + mock_calculate = mocker.patch('freqtrade.edge.edge_positioning.Edge.calculate', + return_value=True) + table_mock = mocker.patch('freqtrade.optimize.edge_cli.generate_edge_table') + + patch_exchange(mocker) + edge_conf['stake_amount'] = 20 + + edge_cli = EdgeCli(edge_conf) + edge_cli.start() + assert mock_calculate.call_count == 1 + assert table_mock.call_count == 1 From dd430455e411bdfae6bef3162d03e3c893b2e883 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Aug 2020 17:04:32 +0200 Subject: [PATCH 118/285] Enable dataprovier for hyperopt --- freqtrade/optimize/backtesting.py | 5 ++--- freqtrade/optimize/hyperopt.py | 15 +++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 214c92e0e..d058493cf 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -65,9 +65,8 @@ class Backtesting: self.strategylist: List[IStrategy] = [] self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) - if self.config.get('runmode') != RunMode.HYPEROPT: - self.dataprovider = DataProvider(self.config, self.exchange) - IStrategy.dp = self.dataprovider + dataprovider = DataProvider(self.config, self.exchange) + IStrategy.dp = dataprovider if self.config.get('strategy_list', None): for strat in list(self.config['strategy_list']): diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 153ae3861..9bc0dadc0 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -4,26 +4,26 @@ This module contains the hyperopt logic """ +import io import locale import logging import random import warnings -from math import ceil from collections import OrderedDict +from math import ceil from operator import itemgetter +from os import path from pathlib import Path from pprint import pformat from typing import Any, Dict, List, Optional +import progressbar import rapidjson +import tabulate from colorama import Fore, Style from joblib import (Parallel, cpu_count, delayed, dump, load, wrap_non_picklable_objects) -from pandas import DataFrame, json_normalize, isna -import progressbar -import tabulate -from os import path -import io +from pandas import DataFrame, isna, json_normalize from freqtrade.data.converter import trim_dataframe from freqtrade.data.history import get_timerange @@ -35,6 +35,7 @@ from freqtrade.optimize.hyperopt_interface import IHyperOpt # noqa: F401 from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss # noqa: F401 from freqtrade.resolvers.hyperopt_resolver import (HyperOptLossResolver, HyperOptResolver) +from freqtrade.strategy import IStrategy # Suppress scikit-learn FutureWarnings from skopt with warnings.catch_warnings(): @@ -634,6 +635,8 @@ class Hyperopt: # We don't need exchange instance anymore while running hyperopt self.backtesting.exchange = None # type: ignore self.backtesting.pairlists = None # type: ignore + self.backtesting.strategy.dp = None # type: ignore + IStrategy.dp = None # type: ignore self.epochs = self.load_previous_results(self.results_file) From 5e1032c4af168aa744dccc626a17ee339219450f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Aug 2020 17:08:38 +0200 Subject: [PATCH 119/285] Simplify strategy documentation, move "substrategies" to advanced page --- docs/strategy-advanced.md | 21 +++++++++ docs/strategy-customization.md | 78 +++++++++------------------------- 2 files changed, 42 insertions(+), 57 deletions(-) diff --git a/docs/strategy-advanced.md b/docs/strategy-advanced.md index e4bab303e..359280694 100644 --- a/docs/strategy-advanced.md +++ b/docs/strategy-advanced.md @@ -199,3 +199,24 @@ class Awesomestrategy(IStrategy): return True ``` + +## Derived strategies + +The strategies can be derived from other strategies. This avoids duplication of your custom strategy code. You can use this technique to override small parts of your main strategy, leaving the rest untouched: + +``` python +class MyAwesomeStrategy(IStrategy): + ... + stoploss = 0.13 + trailing_stop = False + # All other attributes and methods are here as they + # should be in any custom strategy... + ... + +class MyAwesomeStrategy2(MyAwesomeStrategy): + # Override something + stoploss = 0.08 + trailing_stop = True +``` + +Both attributes and methods may be overriden, altering behavior of the original strategy in a way you need. diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 98c71b4b2..ec521470a 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -355,7 +355,7 @@ def informative_pairs(self): *** -### Additional data (DataProvider) +## Additional data (DataProvider) The strategy provides access to the `DataProvider`. This allows you to get additional data to use in your strategy. @@ -363,7 +363,7 @@ All methods return `None` in case of failure (do not raise an exception). Please always check the mode of operation to select the correct method to get data (samples see below). -#### Possible options for DataProvider +### Possible options for DataProvider - [`available_pairs`](#available_pairs) - Property with tuples listing cached pairs with their intervals (pair, interval). - [`current_whitelist()`](#current_whitelist) - Returns a current list of whitelisted pairs. Useful for accessing dynamic whitelists (ie. VolumePairlist) @@ -376,9 +376,9 @@ Please always check the mode of operation to select the correct method to get da - [`ticker(pair)`](#tickerpair) - Returns current ticker data for the pair. See [ccxt documentation](https://github.com/ccxt/ccxt/wiki/Manual#price-tickers) for more details on the Ticker data structure. - `runmode` - Property containing the current runmode. -#### Example Usages: +### Example Usages -#### *available_pairs* +### *available_pairs* ``` python if self.dp: @@ -386,7 +386,7 @@ if self.dp: print(f"available {pair}, {timeframe}") ``` -#### *current_whitelist()* +### *current_whitelist()* Imagine you've developed a strategy that trades the `5m` timeframe using signals generated from a `1d` timeframe on the top 10 volume pairs by volume. @@ -420,7 +420,7 @@ class SampleStrategy(IStrategy): inf_tf = '1d' # Get the informative pair - informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d') + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=inf_tf) # Get the 14 day rsi informative['rsi'] = ta.RSI(informative, timeperiod=14) @@ -455,7 +455,7 @@ class SampleStrategy(IStrategy): ``` -#### *get_pair_dataframe(pair, timeframe)* +### *get_pair_dataframe(pair, timeframe)* ``` python # fetch live / historical candle (OHLCV) data for the first informative pair @@ -468,12 +468,9 @@ if self.dp: !!! Warning "Warning about backtesting" Be careful when using dataprovider in backtesting. `historic_ohlcv()` (and `get_pair_dataframe()` for the backtesting runmode) provides the full time-range in one go, - so please be aware of it and make sure to not "look into the future" to avoid surprises when running in dry/live mode). + so please be aware of it and make sure to not "look into the future" to avoid surprises when running in dry/live mode. -!!! Warning "Warning in hyperopt" - This option cannot currently be used during hyperopt. - -#### *get_analyzed_dataframe(pair, timeframe)* +### *get_analyzed_dataframe(pair, timeframe)* This method is used by freqtrade internally to determine the last signal. It can also be used in specific callbacks to get the signal that caused the action (see [Advanced Strategy Documentation](strategy-advanced.md) for more details on available callbacks). @@ -489,10 +486,7 @@ if self.dp: Returns an empty dataframe if the requested pair was not cached. This should not happen when using whitelisted pairs. -!!! Warning "Warning in hyperopt" - This option cannot currently be used during hyperopt. - -#### *orderbook(pair, maximum)* +### *orderbook(pair, maximum)* ``` python if self.dp: @@ -503,10 +497,9 @@ if self.dp: ``` !!! Warning - The order book is not part of the historic data which means backtesting and hyperopt will not work if this - method is used. + The order book is not part of the historic data which means backtesting and hyperopt will not work correctly if this method is used. -#### *ticker(pair)* +### *ticker(pair)* ``` python if self.dp: @@ -525,7 +518,7 @@ if self.dp: *** -### Additional data (Wallets) +## Additional data (Wallets) The strategy provides access to the `Wallets` object. This contains the current balances on the exchange. @@ -541,7 +534,7 @@ if self.wallets: total_eth = self.wallets.get_total('ETH') ``` -#### Possible options for Wallets +### Possible options for Wallets - `get_free(asset)` - currently available balance to trade - `get_used(asset)` - currently tied up balance (open orders) @@ -549,7 +542,7 @@ if self.wallets: *** -### Additional data (Trades) +## Additional data (Trades) A history of Trades can be retrieved in the strategy by querying the database. @@ -595,13 +588,13 @@ Sample return value: ETH/BTC had 5 trades, with a total profit of 1.5% (ratio of !!! Warning Trade history is not available during backtesting or hyperopt. -### Prevent trades from happening for a specific pair +## Prevent trades from happening for a specific pair Freqtrade locks pairs automatically for the current candle (until that candle is over) when a pair is sold, preventing an immediate re-buy of that pair. Locked pairs will show the message `Pair is currently locked.`. -#### Locking pairs from within the strategy +### Locking pairs from within the strategy Sometimes it may be desired to lock a pair after certain events happen (e.g. multiple losing trades in a row). @@ -618,7 +611,7 @@ To verify if a pair is currently locked, use `self.is_pair_locked(pair)`. !!! Warning Locking pairs is not functioning during backtesting. -##### Pair locking example +#### Pair locking example ``` python from freqtrade.persistence import Trade @@ -640,7 +633,7 @@ if self.config['runmode'].value in ('live', 'dry_run'): self.lock_pair(metadata['pair'], until=datetime.now(timezone.utc) + timedelta(hours=12)) ``` -### Print created dataframe +## Print created dataframe To inspect the created dataframe, you can issue a print-statement in either `populate_buy_trend()` or `populate_sell_trend()`. You may also want to print the pair so it's clear what data is currently shown. @@ -664,36 +657,7 @@ def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: Printing more than a few rows is also possible (simply use `print(dataframe)` instead of `print(dataframe.tail())`), however not recommended, as that will be very verbose (~500 lines per pair every 5 seconds). -### Specify custom strategy location - -If you want to use a strategy from a different directory you can pass `--strategy-path` - -```bash -freqtrade trade --strategy AwesomeStrategy --strategy-path /some/directory -``` - -### Derived strategies - -The strategies can be derived from other strategies. This avoids duplication of your custom strategy code. You can use this technique to override small parts of your main strategy, leaving the rest untouched: - -``` python -class MyAwesomeStrategy(IStrategy): - ... - stoploss = 0.13 - trailing_stop = False - # All other attributes and methods are here as they - # should be in any custom strategy... - ... - -class MyAwesomeStrategy2(MyAwesomeStrategy): - # Override something - stoploss = 0.08 - trailing_stop = True -``` - -Both attributes and methods may be overriden, altering behavior of the original strategy in a way you need. - -### Common mistakes when developing strategies +## Common mistakes when developing strategies Backtesting analyzes the whole time-range at once for performance reasons. Because of this, strategy authors need to make sure that strategies do not look-ahead into the future. This is a common pain-point, which can cause huge differences between backtesting and dry/live run methods, since they all use data which is not available during dry/live runs, so these strategies will perform well during backtesting, but will fail / perform badly in real conditions. @@ -705,7 +669,7 @@ The following lists some common patterns which should be avoided to prevent frus - don't use `dataframe['volume'].mean()`. This uses the full DataFrame for backtesting, including data from the future. Use `dataframe['volume'].rolling().mean()` instead - don't use `.resample('1h')`. This uses the left border of the interval, so moves data from an hour to the start of the hour. Use `.resample('1h', label='right')` instead. -### Further strategy ideas +## Further strategy ideas To get additional Ideas for strategies, head over to our [strategy repository](https://github.com/freqtrade/freqtrade-strategies). Feel free to use them as they are - but results will depend on the current market situation, pairs used etc. - therefore please backtest the strategy for your exchange/desired pairs first, evaluate carefully, use at your own risk. Feel free to use any of them as inspiration for your own strategies. From 09aa954b68f5ca64ffec9508ff94cfb0998a97df Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Aug 2020 17:24:19 +0200 Subject: [PATCH 120/285] Update strategy-customization documentation --- docs/strategy-customization.md | 141 ++++++++++++++++++++------------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index ec521470a..633b82385 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -58,12 +58,12 @@ file as reference.** !!! Note "Strategies and Backtesting" To avoid problems and unexpected differences between Backtesting and dry/live modes, please be aware - that during backtesting the full time-interval is passed to the `populate_*()` methods at once. + that during backtesting the full time range is passed to the `populate_*()` methods at once. It is therefore best to use vectorized operations (across the whole dataframe, not loops) and avoid index referencing (`df.iloc[-1]`), but instead use `df.shift()` to get to the previous candle. !!! Warning "Warning: Using future data" - Since backtesting passes the full time interval to the `populate_*()` methods, the strategy author + Since backtesting passes the full time range to the `populate_*()` methods, the strategy author needs to take care to avoid having the strategy utilize data from the future. Some common patterns for this are listed in the [Common Mistakes](#common-mistakes-when-developing-strategies) section of this document. @@ -251,7 +251,7 @@ minimal_roi = { While technically not completely disabled, this would sell once the trade reaches 10000% Profit. To use times based on candle duration (timeframe), the following snippet can be handy. -This will allow you to change the ticket_interval for the strategy, and ROI times will still be set as candles (e.g. after 3 candles ...) +This will allow you to change the timeframe for the strategy, and ROI times will still be set as candles (e.g. after 3 candles ...) ``` python from freqtrade.exchange import timeframe_to_minutes @@ -285,7 +285,7 @@ If your exchange supports it, it's recommended to also set `"stoploss_on_exchang For more information on order_types please look [here](configuration.md#understand-order_types). -### Timeframe (ticker interval) +### Timeframe (formerly ticker interval) This is the set of candles the bot should download and use for the analysis. Common values are `"1m"`, `"5m"`, `"15m"`, `"1h"`, however all values supported by your exchange should work. @@ -333,10 +333,10 @@ class Awesomestrategy(IStrategy): #### Get data for non-tradeable pairs Data for additional, informative pairs (reference pairs) can be beneficial for some strategies. -Ohlcv data for these pairs will be downloaded as part of the regular whitelist refresh process and is available via `DataProvider` just as other pairs (see below). +OHLCV data for these pairs will be downloaded as part of the regular whitelist refresh process and is available via `DataProvider` just as other pairs (see below). These parts will **not** be traded unless they are also specified in the pair whitelist, or have been selected by Dynamic Whitelisting. -The pairs need to be specified as tuples in the format `("pair", "interval")`, with pair as the first and time interval as the second argument. +The pairs need to be specified as tuples in the format `("pair", "timeframe")`, with pair as the first and timeframe as the second argument. Sample: @@ -349,8 +349,8 @@ def informative_pairs(self): !!! Warning As these pairs will be refreshed as part of the regular whitelist refresh, it's best to keep this list short. - All intervals and all pairs can be specified as long as they are available (and active) on the used exchange. - It is however better to use resampling to longer time-intervals when possible + All timeframes and all pairs can be specified as long as they are available (and active) on the used exchange. + It is however better to use resampling to longer timeframes whenever possible to avoid hammering the exchange with too many requests and risk being blocked. *** @@ -363,10 +363,14 @@ All methods return `None` in case of failure (do not raise an exception). Please always check the mode of operation to select the correct method to get data (samples see below). +!!! Warning "Hyperopt" + Dataprovider is available during hyperopt, however it can only be used in `populate_indicators()`. + It is not available in `populate_buy()` and `populate_sell()` methods. + ### Possible options for DataProvider -- [`available_pairs`](#available_pairs) - Property with tuples listing cached pairs with their intervals (pair, interval). -- [`current_whitelist()`](#current_whitelist) - Returns a current list of whitelisted pairs. Useful for accessing dynamic whitelists (ie. VolumePairlist) +- [`available_pairs`](#available_pairs) - Property with tuples listing cached pairs with their timeframe (pair, timeframe). +- [`current_whitelist()`](#current_whitelist) - Returns a current list of whitelisted pairs. Useful for accessing dynamic whitelists (i.e. VolumePairlist) - [`get_pair_dataframe(pair, timeframe)`](#get_pair_dataframepair-timeframe) - This is a universal method, which returns either historical data (for backtesting) or cached live data (for the Dry-Run and Live-Run modes). - [`get_analyzed_dataframe(pair, timeframe)`](#get_analyzed_dataframepair-timeframe) - Returns the analyzed dataframe (after calling `populate_indicators()`, `populate_buy()`, `populate_sell()`) and the time of the latest analysis. - `historic_ohlcv(pair, timeframe)` - Returns historical data stored on disk. @@ -401,58 +405,13 @@ Since we can't resample our data we will have to use an informative pair; and si This is where calling `self.dp.current_whitelist()` comes in handy. ```python -class SampleStrategy(IStrategy): - # strategy init stuff... - - timeframe = '5m' - - # more strategy init stuff.. - def informative_pairs(self): # get access to all pairs available in whitelist. pairs = self.dp.current_whitelist() # Assign tf to each pair so they can be downloaded and cached for strategy. informative_pairs = [(pair, '1d') for pair in pairs] - return informative_pairs - - def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - - inf_tf = '1d' - # Get the informative pair - informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=inf_tf) - # Get the 14 day rsi - informative['rsi'] = ta.RSI(informative, timeperiod=14) - - # Rename columns to be unique - informative.columns = [f"{col}_{inf_tf}" for col in informative.columns] - # Assuming inf_tf = '1d' - then the columns will now be: - # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d - - # Combine the 2 dataframes - # all indicators on the informative sample MUST be calculated before this point - dataframe = pd.merge(dataframe, informative, left_on='date', right_on=f'date_{inf_tf}', how='left') - # FFill to have the 1d value available in every row throughout the day. - # Without this, comparisons would only work once per day. - dataframe = dataframe.ffill() - # Calculate rsi of the original dataframe (5m timeframe) - dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) - - # Do other stuff - # ... - - return dataframe - - def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - - dataframe.loc[ - ( - (qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30 - (dataframe['rsi_1d'] < 30) & # Ensure daily RSI is < 30 - (dataframe['volume'] > 0) # Ensure this candle had volume (important for backtesting) - ), - 'buy'] = 1 - + return informative_pairs ``` ### *get_pair_dataframe(pair, timeframe)* @@ -479,7 +438,7 @@ It can also be used in specific callbacks to get the signal that caused the acti # fetch current dataframe if self.dp: dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=metadata['pair'], - timeframe=self.ticker_interval) + timeframe=self.timeframe) ``` !!! Note "No data available" @@ -516,6 +475,74 @@ if self.dp: does not always fills in the `last` field (so it can be None), etc. So you need to carefully verify the ticker data returned from the exchange and add appropriate error handling / defaults. +!!! Warning "Warning about backtesting" + This method will always return up-to-date values - so usage during backtesting / hyperopt will lead to wrong results. + +### Complete Data-provider sample + +```python +class SampleStrategy(IStrategy): + # strategy init stuff... + + timeframe = '5m' + + # more strategy init stuff.. + + def informative_pairs(self): + + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, '1d') for pair in pairs] + # Optionally Add additional "static" pairs + informative_pairs += [("ETH/USDT", "5m"), + ("BTC/TUSD", "15m"), + ] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + if not self.dp: + # Don't do anything if DataProvider is not available. + return dataframe + + inf_tf = '1d' + # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=inf_tf) + # Get the 14 day rsi + informative['rsi'] = ta.RSI(informative, timeperiod=14) + + # Rename columns to be unique + informative.columns = [f"{col}_{inf_tf}" for col in informative.columns] + # Assuming inf_tf = '1d' - then the columns will now be: + # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d + + # Combine the 2 dataframes + # all indicators on the informative sample MUST be calculated before this point + dataframe = pd.merge(dataframe, informative, left_on='date', right_on=f'date_{inf_tf}', how='left') + # FFill to have the 1d value available in every row throughout the day. + # Without this, comparisons would only work once per day. + dataframe = dataframe.ffill() + + # Calculate rsi of the original dataframe (5m timeframe) + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + + # Do other stuff + # ... + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30 + (dataframe['rsi_1d'] < 30) & # Ensure daily RSI is < 30 + (dataframe['volume'] > 0) # Ensure this candle had volume (important for backtesting) + ), + 'buy'] = 1 + +``` + *** ## Additional data (Wallets) From 2afe1d5b11b1e63ee403b147fcd0572a9723a716 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Aug 2020 17:27:22 +0200 Subject: [PATCH 121/285] Add link to full sample --- docs/strategy-customization.md | 6 ++++-- freqtrade/optimize/backtesting.py | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 633b82385..73d085abd 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -328,9 +328,9 @@ class Awesomestrategy(IStrategy): *** -### Additional data (informative_pairs) +## Additional data (informative_pairs) -#### Get data for non-tradeable pairs +### Get data for non-tradeable pairs Data for additional, informative pairs (reference pairs) can be beneficial for some strategies. OHLCV data for these pairs will be downloaded as part of the regular whitelist refresh process and is available via `DataProvider` just as other pairs (see below). @@ -347,6 +347,8 @@ def informative_pairs(self): ] ``` +A full sample can be found [in the DataProvider section](#complete-data-provider-sample). + !!! Warning As these pairs will be refreshed as part of the regular whitelist refresh, it's best to keep this list short. All timeframes and all pairs can be specified as long as they are available (and active) on the used exchange. diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index d058493cf..f3070f10f 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -24,7 +24,6 @@ from freqtrade.optimize.optimize_reports import (generate_backtest_stats, from freqtrade.pairlist.pairlistmanager import PairListManager from freqtrade.persistence import Trade from freqtrade.resolvers import ExchangeResolver, StrategyResolver -from freqtrade.state import RunMode from freqtrade.strategy.interface import IStrategy, SellCheckTuple, SellType logger = logging.getLogger(__name__) From fca41a44bb278b7544f6024ebff9f0fb2bd8d359 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 8 Aug 2020 20:20:58 +0200 Subject: [PATCH 122/285] Also logg timeframe --- freqtrade/optimize/optimize_reports.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index f917e7cab..8e25d9d89 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -269,6 +269,7 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'stake_amount': config['stake_amount'], 'stake_currency': config['stake_currency'], 'max_open_trades': config['max_open_trades'], + 'timeframe': config['timeframe'], **daily_stats, } result['strategy'][strategy] = strat_stats From 2663aede24af7e5b3eab2608f9e5be6fef3c00d5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 9 Aug 2020 10:28:11 +0200 Subject: [PATCH 123/285] Update test to reflect new column naming --- tests/edge/test_edge.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/edge/test_edge.py b/tests/edge/test_edge.py index 969b0c44b..d35f7fcf6 100644 --- a/tests/edge/test_edge.py +++ b/tests/edge/test_edge.py @@ -418,8 +418,8 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,): 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:05:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:10:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:05:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:10:00.000000000'), 'open_index': 1, 'close_index': 1, 'trade_duration': '', @@ -431,8 +431,8 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,): 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:20:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:25:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:20:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:25:00.000000000'), 'open_index': 4, 'close_index': 4, 'trade_duration': '', @@ -443,8 +443,8 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,): 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:20:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:25:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:20:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:25:00.000000000'), 'open_index': 4, 'close_index': 4, 'trade_duration': '', @@ -455,8 +455,8 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,): 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:20:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:25:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:20:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:25:00.000000000'), 'open_index': 4, 'close_index': 4, 'trade_duration': '', @@ -467,8 +467,8 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,): 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:20:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:25:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:20:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:25:00.000000000'), 'open_index': 4, 'close_index': 4, 'trade_duration': '', @@ -480,8 +480,8 @@ def test_process_expectancy_remove_pumps(mocker, edge_conf, fee,): 'stoploss': -0.9, 'profit_percent': '', 'profit_abs': '', - 'open_time': np.datetime64('2018-10-03T00:30:00.000000000'), - 'close_time': np.datetime64('2018-10-03T00:40:00.000000000'), + 'open_date': np.datetime64('2018-10-03T00:30:00.000000000'), + 'close_date': np.datetime64('2018-10-03T00:40:00.000000000'), 'open_index': 6, 'close_index': 7, 'trade_duration': '', From 1f1a819b292ecf927c2d332a1fd788ac5b7359a6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 12 Aug 2020 11:21:00 +0200 Subject: [PATCH 124/285] Remove unused 3rd argument to create_stoploss call --- freqtrade/freqtradebot.py | 10 ++++------ tests/test_freqtradebot.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 967f68b90..3168976e2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -768,7 +768,7 @@ class FreqtradeBot: logger.debug('Found no sell signal for %s.', trade) return False - def create_stoploss_order(self, trade: Trade, stop_price: float, rate: float) -> bool: + def create_stoploss_order(self, trade: Trade, stop_price: float) -> bool: """ Abstracts creating stoploss orders from the logic. Handles errors and updates the trade database object. @@ -831,14 +831,13 @@ class FreqtradeBot: stoploss = self.edge.stoploss(pair=trade.pair) if self.edge else self.strategy.stoploss stop_price = trade.open_rate * (1 + stoploss) - if self.create_stoploss_order(trade=trade, stop_price=stop_price, rate=stop_price): + if self.create_stoploss_order(trade=trade, stop_price=stop_price): trade.stoploss_last_update = datetime.now() return False # If stoploss order is canceled for some reason we add it if stoploss_order and stoploss_order['status'] in ('canceled', 'cancelled'): - if self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss, - rate=trade.stop_loss): + if self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss): return False else: trade.stoploss_order_id = None @@ -875,8 +874,7 @@ class FreqtradeBot: f"for pair {trade.pair}") # Create new stoploss order - if not self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss, - rate=trade.stop_loss): + if not self.create_stoploss_order(trade=trade, stop_price=trade.stop_loss): logger.warning(f"Could not create trailing stoploss order " f"for pair {trade.pair}.") diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 5c225bbc0..87071be3e 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1301,7 +1301,7 @@ def test_create_stoploss_order_invalid_order(mocker, default_conf, caplog, fee, freqtrade.enter_positions() trade = Trade.query.first() caplog.clear() - freqtrade.create_stoploss_order(trade, 200, 199) + freqtrade.create_stoploss_order(trade, 200) assert trade.stoploss_order_id is None assert trade.sell_reason == SellType.EMERGENCY_SELL.value assert log_has("Unable to place a stoploss order on exchange. ", caplog) From 6dfa159a914968d6a8838020521bfb1da5f1a905 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 12 Aug 2020 14:11:19 +0200 Subject: [PATCH 125/285] Small comment adjustments in exchange class --- freqtrade/exchange/exchange.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 8438941f7..f8bac3a8d 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -974,7 +974,7 @@ class Exchange: except ccxt.BaseError as e: raise OperationalException(e) from e - # Assign method to fetch_stoploss_order to allow easy overriding in other classes + # Assign method to cancel_stoploss_order to allow easy overriding in other classes cancel_stoploss_order = cancel_order def is_cancel_order_result_suitable(self, corder) -> bool: @@ -1040,10 +1040,10 @@ class Exchange: @retrier def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict: """ - get order book level 2 from exchange - - Notes: - 20180619: bittrex doesnt support limits -.- + Get L2 order book from exchange. + Can be limited to a certain amount (if supported). + Returns a dict in the format + {'asks': [price, volume], 'bids': [price, volume]} """ try: From faa2bbb5553a19b21341c031e9eef46508551254 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 12 Aug 2020 14:25:50 +0200 Subject: [PATCH 126/285] Document exception hierarchy --- docs/developer.md | 29 +++++++++++++++++++++++++++++ freqtrade/exceptions.py | 16 ++++++++-------- freqtrade/freqtradebot.py | 4 ++-- freqtrade/rpc/rpc.py | 6 +++--- tests/test_freqtradebot.py | 3 ++- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/docs/developer.md b/docs/developer.md index 036109d5b..ce454cec2 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -85,6 +85,35 @@ docker-compose exec freqtrade_develop /bin/bash ![image](https://user-images.githubusercontent.com/419355/65456522-ba671a80-de06-11e9-9598-df9ca0d8dcac.png) +## ErrorHandling + +Freqtrade Exceptions all inherit from `FreqtradeException`. +This general class of error should however not be used directly, instead, multiple specialized sub-Exceptions exist. + +Below is an outline of exception inheritance hierarchy: + +``` ++ FreqtradeException +| ++---+ OperationalException +| ++---+ DependencyException +| | +| +---+ PricingError +| | +| +---+ ExchangeError +| | +| +---+ TemporaryError +| | +| +---+ DDosProtection +| | +| +---+ InvalidOrderException +| | +| +---+ RetryableOrderError +| ++---+ StrategyError +``` + ## Modules ### Dynamic Pairlist diff --git a/freqtrade/exceptions.py b/freqtrade/exceptions.py index c85fccc4b..e2bc969a9 100644 --- a/freqtrade/exceptions.py +++ b/freqtrade/exceptions.py @@ -29,7 +29,14 @@ class PricingError(DependencyException): """ -class InvalidOrderException(FreqtradeException): +class ExchangeError(DependencyException): + """ + Error raised out of the exchange. + Has multiple Errors to determine the appropriate error. + """ + + +class InvalidOrderException(ExchangeError): """ This is returned when the order is not valid. Example: If stoploss on exchange order is hit, then trying to cancel the order @@ -44,13 +51,6 @@ class RetryableOrderError(InvalidOrderException): """ -class ExchangeError(DependencyException): - """ - Error raised out of the exchange. - Has multiple Errors to determine the appropriate error. - """ - - class TemporaryError(ExchangeError): """ Temporary network or exchange related error. diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3168976e2..557aefe94 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -919,7 +919,7 @@ class FreqtradeBot: if not trade.open_order_id: continue order = self.exchange.fetch_order(trade.open_order_id, trade.pair) - except (ExchangeError, InvalidOrderException): + except (ExchangeError): logger.info('Cannot query order for %s due to %s', trade, traceback.format_exc()) continue @@ -952,7 +952,7 @@ class FreqtradeBot: for trade in Trade.get_open_order_trades(): try: order = self.exchange.fetch_order(trade.open_order_id, trade.pair) - except (DependencyException, InvalidOrderException): + except (ExchangeError): logger.info('Cannot query order for %s due to %s', trade, traceback.format_exc()) continue diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 8a1ff7e96..f4e20c16f 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union import arrow from numpy import NAN, mean -from freqtrade.exceptions import (ExchangeError, InvalidOrderException, +from freqtrade.exceptions import (ExchangeError, PricingError) from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs from freqtrade.misc import shorten_date @@ -555,7 +555,7 @@ class RPC: try: self._freqtrade.exchange.cancel_order(trade.open_order_id, trade.pair) c_count += 1 - except (ExchangeError, InvalidOrderException): + except (ExchangeError): pass # cancel stoploss on exchange ... @@ -565,7 +565,7 @@ class RPC: self._freqtrade.exchange.cancel_stoploss_order(trade.stoploss_order_id, trade.pair) c_count += 1 - except (ExchangeError, InvalidOrderException): + except (ExchangeError): pass Trade.session.delete(trade) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 87071be3e..2c6d2314c 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1,6 +1,7 @@ # pragma pylint: disable=missing-docstring, C0103 # pragma pylint: disable=protected-access, too-many-lines, invalid-name, too-many-arguments +from freqtrade.exchange.exchange import Exchange import logging import time from copy import deepcopy @@ -4107,7 +4108,7 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order, def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limit_sell_order): default_conf['cancel_open_orders_on_exit'] = True mocker.patch('freqtrade.exchange.Exchange.fetch_order', - side_effect=[DependencyException(), limit_sell_order, limit_buy_order]) + side_effect=[ExchangeError(), limit_sell_order, limit_buy_order]) buy_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_buy') sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_sell') From 815d88fd4a4f2b133653df7fa75d6fa2c40c69ed Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 12 Aug 2020 15:32:56 +0200 Subject: [PATCH 127/285] Fix test after merge, fix forgotten 'amount' --- freqtrade/freqtradebot.py | 2 +- freqtrade/persistence.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index b4ef2b086..816d24e18 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -553,7 +553,7 @@ class FreqtradeBot: order['filled'], order['amount'], order['remaining'] ) stake_amount = order['cost'] - amount = order['filled'] + amount = safe_value_fallback(order, 'filled', 'amount') buy_limit_filled_price = safe_value_fallback(order, 'average', 'price') order_id = None diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index fdb816eab..28753ed48 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -259,7 +259,7 @@ class Trade(_DECL_BASE): 'is_open': self.is_open, 'exchange': self.exchange, 'amount': round(self.amount, 8), - 'amount_requested': round(self.amount_requested, 8), + 'amount_requested': round(self.amount_requested, 8) if self.amount_requested else None, 'stake_amount': round(self.stake_amount, 8), 'strategy': self.strategy, 'ticker_interval': self.timeframe, # DEPRECATED From 3afd5b631e39a85d3c0536979f8e529c6c82a917 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 12 Aug 2020 15:34:29 +0200 Subject: [PATCH 128/285] Remove erroneous import --- tests/test_freqtradebot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 2c6d2314c..ec59ca5b0 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1,7 +1,6 @@ # pragma pylint: disable=missing-docstring, C0103 # pragma pylint: disable=protected-access, too-many-lines, invalid-name, too-many-arguments -from freqtrade.exchange.exchange import Exchange import logging import time from copy import deepcopy From 1dabade883f13dcdff990b6069fe9d8a1aab498c Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Aug 2020 08:02:36 +0200 Subject: [PATCH 129/285] small rewording of FAQ documentation --- docs/faq.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index cc43e326d..514b01085 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -19,11 +19,11 @@ This could have the following reasons: ### I have waited 5 minutes, why hasn't the bot made any trades yet?! -#1 Depending on the buy strategy, the amount of whitelisted coins, the +* Depending on the buy strategy, the amount of whitelisted coins, the situation of the market etc, it can take up to hours to find good entry position for a trade. Be patient! -#2 Or it may because you made an human error? Like writing --dry-run when you wanted to trade live?. Maybe an error with the exchange API? Or something else. You will have to do the hard work of finding out the root cause of the problem :) +* Or it may because of a configuration error? Best check the logs, it's usually telling you if the bot is simply not getting buy signals (only heartbeat messages), or if there is something wrong (errors / exceptions in the log). ### I have made 12 trades already, why is my total profit negative?! @@ -135,7 +135,9 @@ to find a great result (unless if you are very lucky), so you probably have to run it for 10.000 or more. But it will take an eternity to compute. -We recommend you to run between 500-1000 epochs over and over untill you hit at least 10.000 epocs in total. You can best judge by looking at the results - if the bot keep discovering more profitable strategies or not. +Since hyperopt uses Bayesian search, running for too many epochs may not produce greater results. + +It's therefore recommended to run between 500-1000 epochs over and over until you hit at least 10.000 epocs in total (or are satisfied with the result). You can best judge by looking at the results - if the bot keeps discovering better strategies, it's best to keep on going. ```bash freqtrade hyperopt -e 1000 @@ -147,11 +149,11 @@ or if you want intermediate result to see for i in {1..100}; do freqtrade hyperopt -e 1000; done ``` -### Why does it take so long time to run hyperopt? +### Why does it take a long time to run hyperopt? -#1 Discovering a great strategy with Hyperopt takes time. Study www.freqtrade.io, the Freqtrade Github page, join the Freqtrade Discord - or something totally else. While you patiently wait for the most advanced, public known, 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/enQtNjU5ODcwNjI1MDU3LTU1MTgxMjkzNmYxNWE1MDEzYzQ3YmU4N2MwZjUyNjJjODRkMDVkNjg4YTAyZGYzYzlhOTZiMTE4ZjQ4YzM0OGE) - 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. -#2 If you wonder why it can take from 20 minutes to days to do 1000 epocs here are some answers: +* If you wonder why it can take from 20 minutes to days to do 1000 epocs here are some answers: This answer was written during the release 0.15.1, when we had: @@ -163,10 +165,14 @@ The following calculation is still very rough and not very precise but it will give the idea. With only these triggers and guards there is already 8\*10^9\*10 evaluations. A roughly total of 80 billion evals. Did you run 100 000 evals? Congrats, you've done roughly 1 / 100 000 th -of the search space. If we assume that the bot never test the same strategy more than once. +of the search space, assuming that the bot never tests the same parameters more than once. -#3 The time it takes to run 1000 hyperopt epocs depends on things like: The cpu, harddisk, ram, motherboard, indicator settings, indicator count, amount of coins that hyperopt test strategies on, trade count - can be 650 trades in a year or 10.0000 trades depending on if the strategy aims for a high profit rarely or a low profit many many many times. Example: 4% profit 650 times vs 0,3% profit a trade 10.000 times in a year. If we assume you set the --timerange to 365 days. -Example: freqtrade --config config_mcd_1.json --strategy mcd_1 --hyperopt mcd_hyperopt_1 -e 1000 --timerange 20190601-20200601 +* The time it takes to run 1000 hyperopt epocs depends on things like: The available cpu, harddisk, ram, timeframe, timerange, indicator settings, indicator count, amount of coins that hyperopt test strategies on and the resulting trade count - which can be 650 trades in a year or 10.0000 trades depending if the strategy aims for big profits by trading rarely or for many low profit trades. + +Example: 4% profit 650 times vs 0,3% profit a trade 10.000 times in a year. If we assume you set the --timerange to 365 days. + +Example: +`freqtrade --config config.json --strategy SampleStrategy --hyperopt SampleHyperopt -e 1000 --timerange 20190601-20200601` ## Edge module From e45e41adb457d90db1b4c281275779f44f9d6157 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Aug 2020 08:05:05 +0200 Subject: [PATCH 130/285] Improve docs test to catch !!! errors --- tests/test_docs.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_docs.sh b/tests/test_docs.sh index 09e142b99..8a354daad 100755 --- a/tests/test_docs.sh +++ b/tests/test_docs.sh @@ -2,7 +2,8 @@ # Test Documentation boxes - # !!! : is not allowed! # !!! "title" - Title needs to be quoted! -grep -Er '^!{3}\s\S+:|^!{3}\s\S+\s[^"]' docs/* +# !!! Spaces at the beginning are not allowed +grep -Er '^!{3}\s\S+:|^!{3}\s\S+\s[^"]|^\s+!{3}\s\S+' docs/* if [ $? -ne 0 ]; then echo "Docs test success." From 6b85b1a34d65a42a6e24347d9137a6b4f604aef9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 13 Aug 2020 08:06:57 +0200 Subject: [PATCH 131/285] Don't only recommend pycharm, but keep it open to other editors too. --- docs/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq.md b/docs/faq.md index 514b01085..48f52a566 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -2,7 +2,7 @@ ## Beginner Tips & Tricks -#1 When you work with your strategy & hyperopt file you should use a real programmer software like Pycharm. If you by accident moved some code and freqtrade says error and you cant find the place where you moved something, or you cant find line 180 where you messed something up. Then a program like Pycharm shows you where line 180 is in your strategy file so you can fix the problem, or Pycharm shows you with some color marking that "here is a line of code that does not belong here" and you found your error in no time! This will save you many hours of problemsolving when working with the bot. Pycharm also got a usefull "Debug" feature that can tell you exactly what command on that line is making the error :) +* When you work with your strategy & hyperopt file you should use a proper code editor like vscode or Pycharm. A good code editor will provide syntax highlighting as well as line numbers, making it easy to find syntax errors (most likely, pointed out by Freqtrade during startup). ## Freqtrade common issues From 4109b31dac08b607603590c798b41fad745f6bdf Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 06:46:34 +0200 Subject: [PATCH 132/285] Update wording in documentation --- docs/developer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developer.md b/docs/developer.md index ce454cec2..f09ae2c76 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -88,7 +88,7 @@ docker-compose exec freqtrade_develop /bin/bash ## ErrorHandling Freqtrade Exceptions all inherit from `FreqtradeException`. -This general class of error should however not be used directly, instead, multiple specialized sub-Exceptions exist. +This general class of error should however not be used directly. Instead, multiple specialized sub-Exceptions exist. Below is an outline of exception inheritance hierarchy: From d76ee432461a438126439b01e69d00eea3a045fc Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 07:12:57 +0200 Subject: [PATCH 133/285] Show wins / draws / losses in hyperopt table --- freqtrade/optimize/hyperopt.py | 17 +++++++++++++---- tests/optimize/test_hyperopt.py | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 522b217f7..fbd523904 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -312,11 +312,16 @@ class Hyperopt: trials = json_normalize(results, max_level=1) trials['Best'] = '' + if 'results_metrics.winsdrawslosses' not in trials.columns: + # Ensure compatibility with older versions of hyperopt results + trials['results_metrics.winsdrawslosses'] = 'N/A' + trials = trials[['Best', 'current_epoch', 'results_metrics.trade_count', + 'results_metrics.winsdrawslosses', 'results_metrics.avg_profit', 'results_metrics.total_profit', 'results_metrics.profit', 'results_metrics.duration', 'loss', 'is_initial_point', 'is_best']] - trials.columns = ['Best', 'Epoch', 'Trades', 'Avg profit', 'Total profit', + trials.columns = ['Best', 'Epoch', 'Trades', 'W/D/L', 'Avg profit', 'Total profit', 'Profit', 'Avg duration', 'Objective', 'is_initial_point', 'is_best'] trials['is_profit'] = False trials.loc[trials['is_initial_point'], 'Best'] = '* ' @@ -558,11 +563,15 @@ 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]) return { 'trade_count': len(backtesting_results.index), - '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': wins, + 'draws': draws, + 'losses': losses, + 'winsdrawslosses': f"{wins}/{draws}/{losses}", 'avg_profit': backtesting_results.profit_percent.mean() * 100.0, 'median_profit': backtesting_results.profit_percent.median() * 100.0, 'total_profit': backtesting_results.profit_abs.sum(), diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index 4b178ca11..bd86e315f 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -781,6 +781,7 @@ def test_generate_optimizer(mocker, default_conf) -> None: 'draws': 0, 'duration': 100.0, 'losses': 0, + 'winsdrawslosses': '1/0/0', 'median_profit': 2.3117, 'profit': 2.3117, 'total_profit': 0.000233, From b98107375edc44ff6d90bfb67c038d839a5f0d47 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 07:31:14 +0200 Subject: [PATCH 134/285] Improve formatting of result string to be a bit conciser --- freqtrade/optimize/hyperopt.py | 5 ++--- tests/optimize/test_hyperopt.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index fbd523904..6d11e543b 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -585,9 +585,8 @@ class Hyperopt: """ stake_cur = self.config['stake_currency'] return (f"{results_metrics['trade_count']:6d} trades. " - f"{results_metrics['wins']:6d} wins. " - f"{results_metrics['draws']:6d} draws. " - f"{results_metrics['losses']:6d} losses. " + f"{results_metrics['wins']}/{results_metrics['draws']}" + f"/{results_metrics['losses']} Wins/Draws/Losses. " f"Avg profit {results_metrics['avg_profit']: 6.2f}%. " f"Median profit {results_metrics['median_profit']: 6.2f}%. " f"Total profit {results_metrics['total_profit']: 11.8f} {stake_cur} " diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index bd86e315f..a6541f55b 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -744,7 +744,7 @@ def test_generate_optimizer(mocker, default_conf) -> None: } response_expected = { 'loss': 1.9840569076926293, - 'results_explanation': (' 1 trades. 1 wins. 0 draws. 0 losses. ' + 'results_explanation': (' 1 trades. 1/0/0 Wins/Draws/Losses. ' 'Avg profit 2.31%. Median profit 2.31%. Total profit ' '0.00023300 BTC ( 2.31\N{GREEK CAPITAL LETTER SIGMA}%). ' 'Avg duration 100.0 min.' From 48944fd4cb441604703a338336a2786bcbca7a04 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 14:41:46 +0200 Subject: [PATCH 135/285] Logging with queueHandler --- freqtrade/loggers.py | 38 +++++++++++++++++++++++++++++--------- freqtrade/main.py | 13 +++++++------ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index aa08ee8a7..eed480164 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -1,14 +1,15 @@ import logging +import queue import sys - from logging import Formatter -from logging.handlers import RotatingFileHandler, SysLogHandler +from logging.handlers import RotatingFileHandler, SysLogHandler, QueueHandler, QueueListener from typing import Any, Dict, List from freqtrade.exceptions import OperationalException - logger = logging.getLogger(__name__) +log_queue = queue.Queue(-1) +LOGFORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' def _set_loggers(verbosity: int = 0, api_verbosity: str = 'info') -> None: @@ -33,6 +34,25 @@ def _set_loggers(verbosity: int = 0, api_verbosity: str = 'info') -> None: ) +def setup_logging_pre() -> None: + """ + Setup early logging. + This uses a queuehandler, which delays logging. + # TODO: How does QueueHandler work if no listenerhandler is attached?? + """ + logging.root.setLevel(logging.INFO) + fmt = logging.Formatter(LOGFORMAT) + + queue_handler = QueueHandler(log_queue) + queue_handler.setFormatter(fmt) + logger.root.addHandler(queue_handler) + + # Add streamhandler here to capture Errors before QueueListener is started + sth = logging.StreamHandler(sys.stderr) + sth.setFormatter(fmt) + logger.root.addHandler(sth) + + def setup_logging(config: Dict[str, Any]) -> None: """ Process -v/--verbose, --logfile options @@ -41,7 +61,7 @@ def setup_logging(config: Dict[str, Any]) -> None: verbosity = config['verbosity'] # Log to stderr - log_handlers: List[logging.Handler] = [logging.StreamHandler(sys.stderr)] + log_handlers: List[logging.Handler] = [] logfile = config.get('logfile') if logfile: @@ -76,10 +96,10 @@ def setup_logging(config: Dict[str, Any]) -> None: maxBytes=1024 * 1024, # 1Mb backupCount=10)) - logging.basicConfig( - level=logging.INFO if verbosity < 1 else logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', - handlers=log_handlers - ) + listener = QueueListener(log_queue, *log_handlers) + + # logging.root.setFormatter(logging.Formatter(LOGFORMAT)) + logging.root.setLevel(logging.INFO if verbosity < 1 else logging.DEBUG) + listener.start() _set_loggers(verbosity, config.get('api_server', {}).get('verbosity', 'info')) logger.info('Verbosity set to %s', verbosity) diff --git a/freqtrade/main.py b/freqtrade/main.py index 08bdc5e32..eeb975953 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -3,18 +3,18 @@ Main Freqtrade bot script. Read the documentation to know what cli arguments you need. """ - -from freqtrade.exceptions import FreqtradeException, OperationalException +# flake8: noqa E402 +import logging import sys +from typing import Any, List + # check min. python version if sys.version_info < (3, 6): sys.exit("Freqtrade requires Python version >= 3.6") -# flake8: noqa E402 -import logging -from typing import Any, List - from freqtrade.commands import Arguments +from freqtrade.exceptions import FreqtradeException, OperationalException +from freqtrade.loggers import setup_logging_pre logger = logging.getLogger('freqtrade') @@ -28,6 +28,7 @@ def main(sysargv: List[str] = None) -> None: return_code: Any = 1 try: + setup_logging_pre() arguments = Arguments(sysargv) args = arguments.get_parsed_arg() From b989ba0f82c610b06ca8dbb2db4033a8e9b567a6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 14:53:21 +0200 Subject: [PATCH 136/285] Simplify setup of handlers --- freqtrade/loggers.py | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index eed480164..f5f383da7 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -1,9 +1,8 @@ import logging import queue -import sys from logging import Formatter -from logging.handlers import RotatingFileHandler, SysLogHandler, QueueHandler, QueueListener -from typing import Any, Dict, List +from logging.handlers import RotatingFileHandler, SysLogHandler +from typing import Any, Dict from freqtrade.exceptions import OperationalException @@ -40,17 +39,10 @@ def setup_logging_pre() -> None: This uses a queuehandler, which delays logging. # TODO: How does QueueHandler work if no listenerhandler is attached?? """ - logging.root.setLevel(logging.INFO) - fmt = logging.Formatter(LOGFORMAT) - - queue_handler = QueueHandler(log_queue) - queue_handler.setFormatter(fmt) - logger.root.addHandler(queue_handler) - - # Add streamhandler here to capture Errors before QueueListener is started - sth = logging.StreamHandler(sys.stderr) - sth.setFormatter(fmt) - logger.root.addHandler(sth) + logging.basicConfig( + level=logging.INFO, + format=LOGFORMAT, + ) def setup_logging(config: Dict[str, Any]) -> None: @@ -60,9 +52,6 @@ def setup_logging(config: Dict[str, Any]) -> None: # Log level verbosity = config['verbosity'] - # Log to stderr - log_handlers: List[logging.Handler] = [] - logfile = config.get('logfile') if logfile: s = logfile.split(':') @@ -78,7 +67,7 @@ def setup_logging(config: Dict[str, Any]) -> None: # to perform reduction of repeating messages if this is set in the # syslog config. The messages should be equal for this. handler.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s')) - log_handlers.append(handler) + logging.root.addHandler(handler) elif s[0] == 'journald': try: from systemd.journal import JournaldLogHandler @@ -90,16 +79,15 @@ def setup_logging(config: Dict[str, Any]) -> None: # to perform reduction of repeating messages if this is set in the # syslog config. The messages should be equal for this. handler.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s')) - log_handlers.append(handler) + logging.root.addHandler(handler) else: - log_handlers.append(RotatingFileHandler(logfile, - maxBytes=1024 * 1024, # 1Mb - backupCount=10)) + handler = RotatingFileHandler(logfile, + maxBytes=1024 * 1024, # 1Mb + backupCount=10) + handler.setFormatter(Formatter(LOGFORMAT)) + logging.root.addHandler(handler) - listener = QueueListener(log_queue, *log_handlers) - - # logging.root.setFormatter(logging.Formatter(LOGFORMAT)) logging.root.setLevel(logging.INFO if verbosity < 1 else logging.DEBUG) - listener.start() _set_loggers(verbosity, config.get('api_server', {}).get('verbosity', 'info')) + logger.info('Verbosity set to %s', verbosity) From 5f79caa307bcb24e88bd14bba7c691b1ddc238b4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 15:44:36 +0200 Subject: [PATCH 137/285] Implement /logs endpoints in telegram and restAPI --- freqtrade/loggers.py | 7 ++++++- freqtrade/rpc/api_server.py | 13 +++++++++++++ freqtrade/rpc/rpc.py | 22 ++++++++++++++++++++-- freqtrade/rpc/telegram.py | 30 ++++++++++++++++++++++++++++++ tests/rpc/test_rpc_telegram.py | 2 +- 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index f5f383da7..0b1337b2c 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -1,7 +1,7 @@ import logging import queue from logging import Formatter -from logging.handlers import RotatingFileHandler, SysLogHandler +from logging.handlers import RotatingFileHandler, SysLogHandler, BufferingHandler from typing import Any, Dict from freqtrade.exceptions import OperationalException @@ -10,6 +10,10 @@ logger = logging.getLogger(__name__) log_queue = queue.Queue(-1) LOGFORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' +# Initialize bufferhandler - will be used for /log endpoints +bufferHandler = BufferingHandler(1000) +bufferHandler.setFormatter(Formatter(LOGFORMAT)) + def _set_loggers(verbosity: int = 0, api_verbosity: str = 'info') -> None: """ @@ -51,6 +55,7 @@ def setup_logging(config: Dict[str, Any]) -> None: """ # Log level verbosity = config['verbosity'] + logging.root.addHandler(bufferHandler) logfile = config.get('logfile') if logfile: diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index 06926ac35..cb2236878 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -186,6 +186,7 @@ class ApiServer(RPC): self.app.add_url_rule(f'{BASE_URI}/count', 'count', view_func=self._count, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/daily', 'daily', view_func=self._daily, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/edge', 'edge', view_func=self._edge, methods=['GET']) + self.app.add_url_rule(f'{BASE_URI}/logs', 'log', view_func=self._get_logs, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/profit', 'profit', view_func=self._profit, methods=['GET']) self.app.add_url_rule(f'{BASE_URI}/performance', 'performance', @@ -348,6 +349,18 @@ class ApiServer(RPC): return self.rest_dump(stats) + @require_login + @rpc_catch_errors + def _get_logs(self): + """ + Returns latest logs + get: + param: + limit: Only get a certain number of records + """ + limit = int(request.args.get('limit', 0)) or None + return self.rest_dump(self._rpc_get_logs(limit)) + @require_login @rpc_catch_errors def _edge(self): diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index f4e20c16f..5da428a9c 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -11,9 +11,9 @@ from typing import Any, Dict, List, Optional, Tuple, Union import arrow from numpy import NAN, mean -from freqtrade.exceptions import (ExchangeError, - PricingError) +from freqtrade.exceptions import ExchangeError, PricingError from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs +from freqtrade.loggers import bufferHandler from freqtrade.misc import shorten_date from freqtrade.persistence import Trade from freqtrade.rpc.fiat_convert import CryptoToFiatConverter @@ -633,6 +633,24 @@ class RPC: } return res + def _rpc_get_logs(self, limit: Optional[int]) -> Dict[str, List]: + """Returns the last X logs""" + if limit: + buffer = bufferHandler.buffer[-limit:] + else: + buffer = bufferHandler.buffer + records = [[r.asctime, r.created, r.name, r.levelname, r.message] for r in buffer] + + return {'log_count': len(records), 'logs': records} + + def _rpc_get_logs_as_string(self, limit: Optional[int]) -> Dict[str, List]: + """Returns the last X logs""" + if limit: + buffer = bufferHandler.buffer[-limit:] + else: + buffer = bufferHandler.buffer + return [bufferHandler.format(r) for r in buffer] + def _rpc_edge(self) -> List[Dict[str, Any]]: """ Returns information related to Edge """ if not self._freqtrade.edge: diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index f1d3cde21..da93604d1 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -103,6 +103,7 @@ class Telegram(RPC): CommandHandler('stopbuy', self._stopbuy), CommandHandler('whitelist', self._whitelist), CommandHandler('blacklist', self._blacklist), + CommandHandler('logs', self._logs), CommandHandler('edge', self._edge), CommandHandler('help', self._help), CommandHandler('version', self._version), @@ -637,6 +638,34 @@ class Telegram(RPC): except RPCException as e: self._send_msg(str(e)) + @authorized_only + def _logs(self, update: Update, context: CallbackContext) -> None: + """ + Handler for /logs + Shows the latest logs + """ + try: + try: + limit = int(context.args[0]) + except (TypeError, ValueError, IndexError): + limit = 10 + logs = self._rpc_get_logs_as_string(limit) + msg = '' + message_container = "

    {}
    " + for logrec in logs: + if len(msg + logrec) + 10 >= MAX_TELEGRAM_MESSAGE_LENGTH: + # Send message immediately if it would become too long + self._send_msg(message_container.format(msg), parse_mode=ParseMode.HTML) + msg = logrec + '\n' + else: + # Append message to messages to send + msg += logrec + '\n' + + if msg: + self._send_msg(message_container.format(msg), parse_mode=ParseMode.HTML) + except RPCException as e: + self._send_msg(str(e)) + @authorized_only def _edge(self, update: Update, context: CallbackContext) -> None: """ @@ -682,6 +711,7 @@ class Telegram(RPC): "*/stopbuy:* `Stops buying, but handles open trades gracefully` \n" "*/reload_config:* `Reload configuration file` \n" "*/show_config:* `Show running configuration` \n" + "*/logs [limit]:* `Show latest logs - defaults to 10` \n" "*/whitelist:* `Show current whitelist` \n" "*/blacklist [pair]:* `Show current blacklist, or adds one or more pairs " "to the blacklist.` \n" diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index bfa774856..8651b0613 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -76,7 +76,7 @@ def test_telegram_init(default_conf, mocker, caplog) -> None: "['balance'], ['start'], ['stop'], ['forcesell'], ['forcebuy'], ['trades'], " "['delete'], ['performance'], ['daily'], ['count'], ['reload_config', " "'reload_conf'], ['show_config', 'show_conf'], ['stopbuy'], " - "['whitelist'], ['blacklist'], ['edge'], ['help'], ['version']]") + "['whitelist'], ['blacklist'], ['logs'], ['edge'], ['help'], ['version']]") assert log_has(message_str, caplog) From 904c4ecc23f14dd3f549ae9d98e773616206ed61 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 15:44:52 +0200 Subject: [PATCH 138/285] Document /logs endpoints --- docs/rest-api.md | 74 +++++++++++++++++++++++------------------- docs/telegram-usage.md | 1 + scripts/rest_client.py | 8 +++++ 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/docs/rest-api.md b/docs/rest-api.md index 68754f79a..075bd7e64 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -116,6 +116,7 @@ python3 scripts/rest_client.py --config rest_config.json [optional par | `trades` | List last trades. | `delete_trade ` | Remove trade from the database. Tries to close open orders. Requires manual handling of this trade on the exchange. | `show_config` | Shows part of the current configuration with relevant settings to operation +| `logs` | Shows last log messages | `status` | Lists all open trades | `count` | Displays number of trades used and available | `profit` | Display a summary of your profit/loss from close trades and some stats about your performance @@ -138,78 +139,83 @@ python3 scripts/rest_client.py help ``` output Possible commands: + balance - Get the account balance - :returns: json object + Get the account balance. blacklist - Show the current blacklist + Show the current blacklist. + :param add: List of coins to add (example: "BNB/BTC") - :returns: json object count - Returns the amount of open trades - :returns: json object + Return the amount of open trades. daily - Returns the amount of open trades - :returns: json object + Return the amount of open trades. + +delete_trade + Delete trade from the database. + Tries to close open orders. Requires manual handling of this asset on the exchange. + + :param trade_id: Deletes the trade with this ID from the database. edge - Returns information about edge - :returns: json object + Return information about edge. forcebuy - Buy an asset + Buy an asset. + :param pair: Pair to buy (ETH/BTC) :param price: Optional - price to buy - :returns: json object of the trade forcesell - Force-sell a trade + Force-sell a trade. + :param tradeid: Id of the trade (can be received via status command) - :returns: json object + +logs + Show latest logs. + + :param limit: Limits log messages to the last logs. No limit to get all the trades. performance - Returns the performance of the different coins - :returns: json object + Return the performance of the different coins. profit - Returns the profit summary - :returns: json object + Return the profit summary. reload_config - Reload configuration - :returns: json object + Reload configuration. show_config + Returns part of the configuration, relevant for trading operations. - :return: json object containing the version start - Start the bot if it's in stopped state. - :returns: json object + Start the bot if it's in the stopped state. status - Get the status of open trades - :returns: json object + Get the status of open trades. stop - Stop the bot. Use start to restart - :returns: json object + Stop the bot. Use `start` to restart. stopbuy - Stop buying (but handle sells gracefully). - use reload_config to reset - :returns: json object + Stop buying (but handle sells gracefully). Use `reload_config` to reset. + +trades + Return trades history. + + :param limit: Limits trades to the X last trades. No limit to get all the trades. version - Returns the version of the bot - :returns: json object containing the version + Return the version of the bot. whitelist - Show the current whitelist - :returns: json object + Show the current whitelist. + + ``` ## Advanced API usage using JWT tokens diff --git a/docs/telegram-usage.md b/docs/telegram-usage.md index 9776b26ba..5f804386d 100644 --- a/docs/telegram-usage.md +++ b/docs/telegram-usage.md @@ -54,6 +54,7 @@ official commands. You can ask at any moment for help with `/help`. | `/stopbuy` | Stops the trader from opening new trades. Gracefully closes open trades according to their rules. | `/reload_config` | Reloads the configuration file | `/show_config` | Shows part of the current configuration with relevant settings to operation +| `/logs [limit]` | Show last log messages. | `/status` | Lists all open trades | `/status table` | List all open trades in a table format. Pending buy orders are marked with an asterisk (*) Pending sell orders are marked with a double asterisk (**) | `/trades [limit]` | List all recently closed trades in a table format. diff --git a/scripts/rest_client.py b/scripts/rest_client.py index 51ea596f6..b100999a3 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -159,6 +159,14 @@ class FtRestClient(): """ return self._get("show_config") + def logs(self, limit=None): + """Show latest logs. + + :param limit: Limits log messages to the last logs. No limit to get all the trades. + :return: json object + """ + return self._get("logs", params={"limit": limit} if limit else 0) + def trades(self, limit=None): """Return trades history. From 9ad8e74247ed1fb1bb50b39309e22528567e372f Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 19:36:12 +0200 Subject: [PATCH 139/285] Add tests for log-endpoints --- freqtrade/main.py | 1 - freqtrade/rpc/rpc.py | 5 +++-- tests/rpc/test_rpc_apiserver.py | 27 ++++++++++++++++++++++++++- tests/rpc/test_rpc_telegram.py | 21 +++++++++++++++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/freqtrade/main.py b/freqtrade/main.py index eeb975953..dc26c2a46 100755 --- a/freqtrade/main.py +++ b/freqtrade/main.py @@ -3,7 +3,6 @@ Main Freqtrade bot script. Read the documentation to know what cli arguments you need. """ -# flake8: noqa E402 import logging import sys from typing import Any, List diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 5da428a9c..dd35b9613 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -639,12 +639,13 @@ class RPC: buffer = bufferHandler.buffer[-limit:] else: buffer = bufferHandler.buffer - records = [[r.asctime, r.created, r.name, r.levelname, r.message] for r in buffer] + records = [[datetime.fromtimestamp(r.created), r.created, r.name, r.levelname, r.message] + for r in buffer] return {'log_count': len(records), 'logs': records} def _rpc_get_logs_as_string(self, limit: Optional[int]) -> Dict[str, List]: - """Returns the last X logs""" + """Returns the last X logs as formatted string (Using the default log format)""" if limit: buffer = bufferHandler.buffer[-limit:] else: diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 408f7e537..2fb1e3ec1 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -10,10 +10,12 @@ from flask import Flask from requests.auth import _basic_auth_str from freqtrade.__init__ import __version__ +from freqtrade.loggers import setup_logging, setup_logging_pre from freqtrade.persistence import Trade from freqtrade.rpc.api_server import BASE_URI, ApiServer from freqtrade.state import State -from tests.conftest import get_patched_freqtradebot, log_has, patch_get_signal, create_mock_trades +from tests.conftest import (create_mock_trades, get_patched_freqtradebot, + log_has, patch_get_signal) _TEST_USER = "FreqTrader" _TEST_PASS = "SuperSecurePassword1!" @@ -21,6 +23,9 @@ _TEST_PASS = "SuperSecurePassword1!" @pytest.fixture def botclient(default_conf, mocker): + setup_logging_pre() + setup_logging(default_conf) + default_conf.update({"api_server": {"enabled": True, "listen_ip_address": "127.0.0.1", "listen_port": 8080, @@ -423,6 +428,26 @@ def test_api_delete_trade(botclient, mocker, fee, markets): assert stoploss_mock.call_count == 1 +def test_api_logs(botclient): + ftbot, client = botclient + rc = client_get(client, f"{BASE_URI}/logs") + assert_response(rc) + assert len(rc.json) == 2 + assert 'logs' in rc.json + # Using a fixed comparison here would make this test fail! + assert rc.json['log_count'] > 10 + assert len(rc.json['logs']) == rc.json['log_count'] + + assert isinstance(rc.json['logs'][0], list) + # date + assert isinstance(rc.json['logs'][0][0], str) + # created_timestamp + assert isinstance(rc.json['logs'][0][1], float) + assert isinstance(rc.json['logs'][0][2], str) + assert isinstance(rc.json['logs'][0][3], str) + assert isinstance(rc.json['logs'][0][4], str) + + def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot, (True, False)) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 8651b0613..1144d8279 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -16,6 +16,7 @@ from telegram.error import NetworkError from freqtrade import __version__ from freqtrade.edge import PairInfo from freqtrade.freqtradebot import FreqtradeBot +from freqtrade.loggers import setup_logging from freqtrade.persistence import Trade from freqtrade.rpc import RPCMessageType from freqtrade.rpc.telegram import Telegram, authorized_only @@ -1107,6 +1108,26 @@ def test_blacklist_static(default_conf, update, mocker) -> None: assert freqtradebot.pairlists.blacklist == ["DOGE/BTC", "HOT/BTC", "ETH/BTC"] +def test_telegram_logs(default_conf, update, mocker) -> None: + msg_mock = MagicMock() + mocker.patch.multiple( + 'freqtrade.rpc.telegram.Telegram', + _init=MagicMock(), + _send_msg=msg_mock + ) + setup_logging(default_conf) + + freqtradebot = get_patched_freqtradebot(mocker, default_conf) + + telegram = Telegram(freqtradebot) + context = MagicMock() + context.args = [] + telegram._logs(update=update, context=context) + assert msg_mock.call_count == 1 + assert "freqtrade.rpc.telegram" in msg_mock.call_args_list[0][0][0] + assert "freqtrade.resolvers.iresolver" in msg_mock.call_args_list[0][0][0] + + def test_edge_disabled(default_conf, update, mocker) -> None: msg_mock = MagicMock() mocker.patch.multiple( From 122c0e8ddc1771c977b4e42e0785621ea73080d4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 19:50:56 +0200 Subject: [PATCH 140/285] Readd accidentally dropped StreamHandler --- freqtrade/loggers.py | 7 ++++++- tests/test_configuration.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index 0b1337b2c..cb83f9144 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -1,7 +1,9 @@ import logging import queue +import sys from logging import Formatter -from logging.handlers import RotatingFileHandler, SysLogHandler, BufferingHandler +from logging.handlers import (BufferingHandler, RotatingFileHandler, + SysLogHandler) from typing import Any, Dict from freqtrade.exceptions import OperationalException @@ -58,6 +60,9 @@ def setup_logging(config: Dict[str, Any]) -> None: logging.root.addHandler(bufferHandler) logfile = config.get('logfile') + + logging.root.addHandler(logging.StreamHandler(sys.stderr)) + if logfile: s = logfile.split(':') if s[0] == 'syslog': diff --git a/tests/test_configuration.py b/tests/test_configuration.py index ca5d6eadc..dd96f9d73 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -675,7 +675,7 @@ def test_set_loggers_syslog(mocker): } setup_logging(config) - assert len(logger.handlers) == 2 + assert len(logger.handlers) == 3 assert [x for x in logger.handlers if type(x) == logging.handlers.SysLogHandler] assert [x for x in logger.handlers if type(x) == logging.StreamHandler] # reset handlers to not break pytest From 251eb5aa96cbfc385d3eb18347742fd1a10e5db9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 19:51:50 +0200 Subject: [PATCH 141/285] Test for bufferingHandler too --- tests/test_configuration.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index dd96f9d73..8c3a47f87 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -678,6 +678,7 @@ def test_set_loggers_syslog(mocker): assert len(logger.handlers) == 3 assert [x for x in logger.handlers if type(x) == logging.handlers.SysLogHandler] assert [x for x in logger.handlers if type(x) == logging.StreamHandler] + assert [x for x in logger.handlers if type(x) == logging.handlers.BufferingHandler] # reset handlers to not break pytest logger.handlers = orig_handlers From cdfcdb86c96fcb0f9b53236aafe1140964206350 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 20:00:09 +0200 Subject: [PATCH 142/285] Increase logfile size --- freqtrade/loggers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index cb83f9144..80759e202 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -92,7 +92,7 @@ def setup_logging(config: Dict[str, Any]) -> None: logging.root.addHandler(handler) else: handler = RotatingFileHandler(logfile, - maxBytes=1024 * 1024, # 1Mb + maxBytes=1024 * 1024 * 10, # 10Mb backupCount=10) handler.setFormatter(Formatter(LOGFORMAT)) logging.root.addHandler(handler) From c4f78203ab7875c3b23fb0a39787a2e96a469dc4 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 20:08:55 +0200 Subject: [PATCH 143/285] Initialize streamhandler early to have it apply to all logs --- freqtrade/loggers.py | 3 +-- tests/test_configuration.py | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index 80759e202..c4a1af4f3 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -48,6 +48,7 @@ def setup_logging_pre() -> None: logging.basicConfig( level=logging.INFO, format=LOGFORMAT, + handlers=[logging.StreamHandler(sys.stderr)] ) @@ -61,8 +62,6 @@ def setup_logging(config: Dict[str, Any]) -> None: logfile = config.get('logfile') - logging.root.addHandler(logging.StreamHandler(sys.stderr)) - if logfile: s = logfile.split(':') if s[0] == 'syslog': diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 8c3a47f87..30e0718f7 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -21,7 +21,7 @@ from freqtrade.configuration.deprecated_settings import ( from freqtrade.configuration.load_config import load_config_file, log_config_error_range from freqtrade.constants import DEFAULT_DB_DRYRUN_URL, DEFAULT_DB_PROD_URL from freqtrade.exceptions import OperationalException -from freqtrade.loggers import _set_loggers, setup_logging +from freqtrade.loggers import _set_loggers, setup_logging, setup_logging_pre from freqtrade.state import RunMode from tests.conftest import (log_has, log_has_re, patched_configuration_load_config_file) @@ -674,6 +674,7 @@ def test_set_loggers_syslog(mocker): 'logfile': 'syslog:/dev/log', } + setup_logging_pre() setup_logging(config) assert len(logger.handlers) == 3 assert [x for x in logger.handlers if type(x) == logging.handlers.SysLogHandler] From 9659e516c8c8298a376b131e24f281cfea537c0e Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 14 Aug 2020 20:12:59 +0200 Subject: [PATCH 144/285] Remove queue import Improve tests --- freqtrade/loggers.py | 9 ++++----- tests/rpc/test_rpc_apiserver.py | 8 ++++++++ tests/rpc/test_rpc_telegram.py | 15 +++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index c4a1af4f3..6e66abeeb 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -1,5 +1,4 @@ import logging -import queue import sys from logging import Formatter from logging.handlers import (BufferingHandler, RotatingFileHandler, @@ -9,7 +8,6 @@ from typing import Any, Dict from freqtrade.exceptions import OperationalException logger = logging.getLogger(__name__) -log_queue = queue.Queue(-1) LOGFORMAT = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' # Initialize bufferhandler - will be used for /log endpoints @@ -41,9 +39,10 @@ def _set_loggers(verbosity: int = 0, api_verbosity: str = 'info') -> None: def setup_logging_pre() -> None: """ - Setup early logging. - This uses a queuehandler, which delays logging. - # TODO: How does QueueHandler work if no listenerhandler is attached?? + Early setup for logging. + Uses INFO loglevel and only the Streamhandler. + Early messages (before proper logging setup) will therefore only be available + after the proper logging setup. """ logging.basicConfig( level=logging.INFO, diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 2fb1e3ec1..1dd0ecff8 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -447,6 +447,14 @@ def test_api_logs(botclient): assert isinstance(rc.json['logs'][0][3], str) assert isinstance(rc.json['logs'][0][4], str) + rc = client_get(client, f"{BASE_URI}/logs?limit=5") + assert_response(rc) + assert len(rc.json) == 2 + assert 'logs' in rc.json + # Using a fixed comparison here would make this test fail! + assert rc.json['log_count'] == 5 + assert len(rc.json['logs']) == rc.json['log_count'] + def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): ftbot, client = botclient diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 1144d8279..e0df31437 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1127,6 +1127,21 @@ def test_telegram_logs(default_conf, update, mocker) -> None: assert "freqtrade.rpc.telegram" in msg_mock.call_args_list[0][0][0] assert "freqtrade.resolvers.iresolver" in msg_mock.call_args_list[0][0][0] + msg_mock.reset_mock() + context.args = ["1"] + telegram._logs(update=update, context=context) + assert msg_mock.call_count == 1 + + msg_mock.reset_mock() + # Test with changed MaxMessageLength + mocker.patch('freqtrade.rpc.telegram.MAX_TELEGRAM_MESSAGE_LENGTH', 200) + context = MagicMock() + context.args = [] + telegram._logs(update=update, context=context) + # Called at least 3 times. Exact times will change with unrelated changes to setup messages + # Therefore we don't test for this explicitly. + assert msg_mock.call_count > 3 + def test_edge_disabled(default_conf, update, mocker) -> None: msg_mock = MagicMock() From f5863a1c6fd3d8b29cde23561fb8b4dbfc86bf3d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 08:15:18 +0200 Subject: [PATCH 145/285] Fix mypy errors --- freqtrade/loggers.py | 16 ++++++++-------- freqtrade/rpc/rpc.py | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index 6e66abeeb..263f97ce1 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -82,18 +82,18 @@ def setup_logging(config: Dict[str, Any]) -> None: except ImportError: raise OperationalException("You need the systemd python package be installed in " "order to use logging to journald.") - handler = JournaldLogHandler() + handler_jd = JournaldLogHandler() # No datetime field for logging into journald, to allow syslog # to perform reduction of repeating messages if this is set in the # syslog config. The messages should be equal for this. - handler.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s')) - logging.root.addHandler(handler) + handler_jd.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s')) + logging.root.addHandler(handler_jd) else: - handler = RotatingFileHandler(logfile, - maxBytes=1024 * 1024 * 10, # 10Mb - backupCount=10) - handler.setFormatter(Formatter(LOGFORMAT)) - logging.root.addHandler(handler) + handler_rf = RotatingFileHandler(logfile, + maxBytes=1024 * 1024 * 10, # 10Mb + backupCount=10) + handler_rf.setFormatter(Formatter(LOGFORMAT)) + logging.root.addHandler(handler_rf) logging.root.setLevel(logging.INFO if verbosity < 1 else logging.DEBUG) _set_loggers(verbosity, config.get('api_server', {}).get('verbosity', 'info')) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index dd35b9613..37538499d 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -633,7 +633,7 @@ class RPC: } return res - def _rpc_get_logs(self, limit: Optional[int]) -> Dict[str, List]: + def _rpc_get_logs(self, limit: Optional[int]) -> Dict[str, Any]: """Returns the last X logs""" if limit: buffer = bufferHandler.buffer[-limit:] @@ -644,7 +644,7 @@ class RPC: return {'log_count': len(records), 'logs': records} - def _rpc_get_logs_as_string(self, limit: Optional[int]) -> Dict[str, List]: + def _rpc_get_logs_as_string(self, limit: Optional[int]) -> List[str]: """Returns the last X logs as formatted string (Using the default log format)""" if limit: buffer = bufferHandler.buffer[-limit:] From 1ffa3d1ae0e4b12f082bc7628500d2940ae99291 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 08:31:36 +0200 Subject: [PATCH 146/285] Improve telegram message formatting --- freqtrade/rpc/rpc.py | 11 ++--------- freqtrade/rpc/telegram.py | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 37538499d..59c6acafa 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -639,19 +639,12 @@ class RPC: buffer = bufferHandler.buffer[-limit:] else: buffer = bufferHandler.buffer - records = [[datetime.fromtimestamp(r.created), r.created, r.name, r.levelname, r.message] + records = [[datetime.fromtimestamp(r.created).strftime("%Y-%m-%d %H:%M:%S"), + r.created, r.name, r.levelname, r.message] for r in buffer] return {'log_count': len(records), 'logs': records} - def _rpc_get_logs_as_string(self, limit: Optional[int]) -> List[str]: - """Returns the last X logs as formatted string (Using the default log format)""" - if limit: - buffer = bufferHandler.buffer[-limit:] - else: - buffer = bufferHandler.buffer - return [bufferHandler.format(r) for r in buffer] - def _rpc_edge(self) -> List[Dict[str, Any]]: """ Returns information related to Edge """ if not self._freqtrade.edge: diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index da93604d1..23c3e3689 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -649,20 +649,22 @@ class Telegram(RPC): limit = int(context.args[0]) except (TypeError, ValueError, IndexError): limit = 10 - logs = self._rpc_get_logs_as_string(limit) - msg = '' - message_container = "
    {}
    " + logs = self._rpc_get_logs(limit)['logs'] + msgs = '' + msg_template = "*{}* {}: {} - `{}`" for logrec in logs: - if len(msg + logrec) + 10 >= MAX_TELEGRAM_MESSAGE_LENGTH: + msg = msg_template.format(logrec[0], logrec[2], logrec[3], logrec[4]) + + if len(msgs + msg) + 10 >= MAX_TELEGRAM_MESSAGE_LENGTH: # Send message immediately if it would become too long - self._send_msg(message_container.format(msg), parse_mode=ParseMode.HTML) - msg = logrec + '\n' + self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN) + msgs = msg + '\n' else: # Append message to messages to send - msg += logrec + '\n' + msgs += msg + '\n' - if msg: - self._send_msg(message_container.format(msg), parse_mode=ParseMode.HTML) + if msgs: + self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN) except RPCException as e: self._send_msg(str(e)) From f3d4b114bbcb335b7225c0a984c0bdd8018814cd Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 08:47:09 +0200 Subject: [PATCH 147/285] Skip windows test failure --- tests/test_configuration.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 30e0718f7..686f06057 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -729,7 +729,10 @@ def test_set_logfile(default_conf, mocker): assert validated_conf['logfile'] == "test_file.log" f = Path("test_file.log") assert f.is_file() - f.unlink() + try: + f.unlink() + except Exception: + pass def test_load_config_warn_forcebuy(default_conf, mocker, caplog) -> None: From 9dd2800b980d044a07febcc00e471b4691db6a6f Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 09:08:50 +0200 Subject: [PATCH 148/285] Apply some review changes --- docs/configuration.md | 6 +++--- freqtrade/pairlist/AgeFilter.py | 4 ++-- freqtrade/pairlist/PriceFilter.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index f39a3c62d..5fc28f3bf 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -669,13 +669,13 @@ The `PriceFilter` allows filtering of pairs by price. Currently the following pr * `low_price_ratio` The `min_price` setting removes pairs where the price is below the specified price. This is useful if you wish to avoid trading very low-priced pairs. -This option is disabled by default (or set to 0), and will only apply if set to > 0. +This option is disabled by default, and will only apply if set to > 0. The `max_price` setting removes pairs where the price is above the specified price. This is useful if you wish to trade only low-priced pairs. -This option is disabled by default (or set to 0), and will only apply if set to > 0. +This option is disabled by default, and will only apply if set to > 0. The `low_price_ratio` setting removes pairs where a raise of 1 price unit (pip) is above the `low_price_ratio` ratio. -This option is disabled by default (or set to 0), and will only apply if set to > 0. +This option is disabled by default, and will only apply if set to > 0. For `PriceFiler` at least one of its `min_price`, `max_price` or `low_price_ratio` settings must be applied. diff --git a/freqtrade/pairlist/AgeFilter.py b/freqtrade/pairlist/AgeFilter.py index 56e56ceeb..64f01cb61 100644 --- a/freqtrade/pairlist/AgeFilter.py +++ b/freqtrade/pairlist/AgeFilter.py @@ -26,9 +26,9 @@ class AgeFilter(IPairList): self._min_days_listed = pairlistconfig.get('min_days_listed', 10) if self._min_days_listed < 1: - raise OperationalException("AgeFilter requires min_days_listed be >= 1") + raise OperationalException("AgeFilter requires min_days_listed to be >= 1") if self._min_days_listed > exchange.ohlcv_candle_limit: - raise OperationalException("AgeFilter requires min_days_listed be not exceeding " + raise OperationalException("AgeFilter requires min_days_listed to not exceed " "exchange max request size " f"({exchange.ohlcv_candle_limit})") diff --git a/freqtrade/pairlist/PriceFilter.py b/freqtrade/pairlist/PriceFilter.py index ae3ab9230..8cd57ee1d 100644 --- a/freqtrade/pairlist/PriceFilter.py +++ b/freqtrade/pairlist/PriceFilter.py @@ -20,13 +20,13 @@ class PriceFilter(IPairList): self._low_price_ratio = pairlistconfig.get('low_price_ratio', 0) if self._low_price_ratio < 0: - raise OperationalException("PriceFilter requires low_price_ratio be >= 0") + raise OperationalException("PriceFilter requires low_price_ratio to be >= 0") self._min_price = pairlistconfig.get('min_price', 0) if self._min_price < 0: - raise OperationalException("PriceFilter requires min_price be >= 0") + raise OperationalException("PriceFilter requires min_price to be >= 0") self._max_price = pairlistconfig.get('max_price', 0) if self._max_price < 0: - raise OperationalException("PriceFilter requires max_price be >= 0") + raise OperationalException("PriceFilter requires max_price to be >= 0") self._enabled = ((self._low_price_ratio > 0) or (self._min_price > 0) or (self._max_price > 0)) From 142f87b68ce4bbe61d8f52581a3a44aa67ebdfae Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 09:11:46 +0200 Subject: [PATCH 149/285] Adjust tests to new wordings --- tests/pairlist/test_pairlist.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index ad664abd2..9217abc46 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -549,7 +549,7 @@ def test_agefilter_min_days_listed_too_small(mocker, default_conf, markets, tick ) with pytest.raises(OperationalException, - match=r'AgeFilter requires min_days_listed be >= 1'): + match=r'AgeFilter requires min_days_listed to be >= 1'): get_patched_freqtradebot(mocker, default_conf) @@ -564,7 +564,7 @@ def test_agefilter_min_days_listed_too_large(mocker, default_conf, markets, tick ) with pytest.raises(OperationalException, - match=r'AgeFilter requires min_days_listed be not exceeding ' + match=r'AgeFilter requires min_days_listed to not exceed ' r'exchange max request size \([0-9]+\)'): get_patched_freqtradebot(mocker, default_conf) @@ -617,15 +617,15 @@ def test_agefilter_caching(mocker, markets, whitelist_conf_3, tickers, ohlcv_his ), ({"method": "PriceFilter", "low_price_ratio": -0.001}, None, - "PriceFilter requires low_price_ratio be >= 0" + "PriceFilter requires low_price_ratio to be >= 0" ), # OperationalException expected ({"method": "PriceFilter", "min_price": -0.00000010}, None, - "PriceFilter requires min_price be >= 0" + "PriceFilter requires min_price to be >= 0" ), # OperationalException expected ({"method": "PriceFilter", "max_price": -1.00010000}, None, - "PriceFilter requires max_price be >= 0" + "PriceFilter requires max_price to be >= 0" ), # OperationalException expected ]) def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig, From cc91d5138910ce1d355a7eedb801274f05d0f7a0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 09:18:00 +0200 Subject: [PATCH 150/285] Fix wording in configuration.md --- docs/configuration.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 5fc28f3bf..a366cde12 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -683,7 +683,8 @@ Calculation example: Min price precision for SHITCOIN/BTC is 8 decimals. If its price is 0.00000011 - one price step above would be 0.00000012, which is ~9% higher than the previous price value. You may filter out this pair by using PriceFilter with `low_price_ratio` set to 0.09 (9%) or with `min_price` set to 0.00000011, correspondingly. -Low priced pairs are dangerous since they are often illiquid and it may also be impossible to place the desired stoploss, which can often result in high losses. Consider using PriceFilter with `low_price_ratio` set to a value which is less than the absolute value of your stoploss (for example, if your stoploss is -5% (-0.05), then the value for `low_price_ratio` can be 0.04 or even 0.02). +!!! Warning "Low priced pairs" + Low priced pairs with high "1 pip movements" are dangerous since they are often illiquid and it may also be impossible to place the desired stoploss, which can often result in high losses since price needs to be rounded to the next tradable price - so instead of having a stoploss of -5%, you could end up with a stoploss of -9% simply due to price rounding. #### ShuffleFilter From c2573c998b98fb295c2c29f6bc092a89c829b7c2 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 16:26:47 +0200 Subject: [PATCH 151/285] Remove Hyperopt note about windows --- docs/hyperopt.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 6330a1a5e..9acb606c3 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -370,9 +370,6 @@ By default, hyperopt prints colorized results -- epochs with positive profit are You can use the `--print-all` command line option if you would like to see all results in the hyperopt output, not only the best ones. When `--print-all` is used, current best results are also colorized by default -- they are printed in bold (bright) style. This can also be switched off with the `--no-color` command line option. -!!! Note "Windows and color output" - Windows does not support color-output nativly, therefore it is automatically disabled. To have color-output for hyperopt running under windows, please consider using WSL. - ### Understand Hyperopt ROI results If you are optimizing ROI (i.e. if optimization search-space contains 'all', 'default' or 'roi'), your result will look as follows and include a ROI table: From 56ca37fd8bb95e27baca7f396a4ea385e67d3638 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 15 Aug 2020 20:15:02 +0200 Subject: [PATCH 152/285] Also provide stacktrace via log endpoints --- freqtrade/rpc/rpc.py | 3 ++- freqtrade/rpc/telegram.py | 13 ++++++++----- tests/rpc/test_rpc_telegram.py | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 59c6acafa..b7a4f4f8c 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -640,7 +640,8 @@ class RPC: else: buffer = bufferHandler.buffer records = [[datetime.fromtimestamp(r.created).strftime("%Y-%m-%d %H:%M:%S"), - r.created, r.name, r.levelname, r.message] + r.created, r.name, r.levelname, + r.message + ('\n' + r.exc_text if r.exc_text else '')] for r in buffer] return {'log_count': len(records), 'logs': records} diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 23c3e3689..a095714a7 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -12,6 +12,7 @@ from tabulate import tabulate from telegram import ParseMode, ReplyKeyboardMarkup, Update from telegram.error import NetworkError, TelegramError from telegram.ext import CallbackContext, CommandHandler, Updater +from telegram.utils.helpers import escape_markdown from freqtrade.__init__ import __version__ from freqtrade.rpc import RPC, RPCException, RPCMessageType @@ -651,20 +652,22 @@ class Telegram(RPC): limit = 10 logs = self._rpc_get_logs(limit)['logs'] msgs = '' - msg_template = "*{}* {}: {} - `{}`" + msg_template = "*{}* {}: {} \\- `{}`" for logrec in logs: - msg = msg_template.format(logrec[0], logrec[2], logrec[3], logrec[4]) - + msg = msg_template.format(escape_markdown(logrec[0], version=2), + escape_markdown(logrec[2], version=2), + escape_markdown(logrec[3], version=2), + escape_markdown(logrec[4], version=2)) if len(msgs + msg) + 10 >= MAX_TELEGRAM_MESSAGE_LENGTH: # Send message immediately if it would become too long - self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN) + self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN_V2) msgs = msg + '\n' else: # Append message to messages to send msgs += msg + '\n' if msgs: - self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN) + self._send_msg(msgs, parse_mode=ParseMode.MARKDOWN_V2) 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 e0df31437..026a81ff8 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1124,8 +1124,8 @@ def test_telegram_logs(default_conf, update, mocker) -> None: context.args = [] telegram._logs(update=update, context=context) assert msg_mock.call_count == 1 - assert "freqtrade.rpc.telegram" in msg_mock.call_args_list[0][0][0] - assert "freqtrade.resolvers.iresolver" in msg_mock.call_args_list[0][0][0] + assert "freqtrade\\.rpc\\.telegram" in msg_mock.call_args_list[0][0][0] + assert "freqtrade\\.resolvers\\.iresolver" in msg_mock.call_args_list[0][0][0] msg_mock.reset_mock() context.args = ["1"] From b9e46a3c5a0d2f2ad4f8b18af9d31385fa73e325 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 03:02:10 +0200 Subject: [PATCH 153/285] Update stoploss.md Updated documentation to simplify examples --- docs/stoploss.md | 117 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 83 insertions(+), 34 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index bf7270dff..2945c18db 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -6,16 +6,10 @@ For example, value `-0.10` will cause immediate sell if the profit dips below -1 Most of the strategy files already include the optimal `stoploss` value. !!! Info - All stoploss properties mentioned in this file can be set in the Strategy, or in the configuration. Configuration values will override the strategy values. + All stoploss properties mentioned in this file can be set in the Strategy, or in the configuration. + Configuration values will override the strategy values. -## Stop Loss Types - -At this stage the bot contains the following stoploss support modes: - -1. Static stop loss. -2. Trailing stop loss. -3. Trailing stop loss, custom positive loss. -4. Trailing stop loss only once the trade has reached a certain offset. +## Stop Loss On-Exchange/Freqtrade Those stoploss modes can be *on exchange* or *off exchange*. If the stoploss is *on exchange* it means a stoploss limit order is placed on the exchange immediately after buy order happens successfully. This will protect you against sudden crashes in market as the order will be in the queue immediately and if market goes down then the order has more chance of being fulfilled. @@ -27,19 +21,58 @@ So this parameter will tell the bot how often it should update the stoploss orde This same logic will reapply a stoploss order on the exchange should you cancel it accidentally. !!! Note - Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. + Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. + Do not set too low stoploss value if using stop loss on exhange! -## Static Stop Loss +Stop loss on exchange is controlled with this value (default False): + +``` python + 'stoploss_on_exchange': False +``` + +Example from strategy file: + +``` python +order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': True +} +``` + +## Stop Loss Types + +At this stage the bot contains the following stoploss support modes: + +1. Static stop loss. +2. Trailing stop loss. +3. Trailing stop loss, custom positive loss. +4. Trailing stop loss only once the trade has reached a certain offset. + +### Static Stop Loss This is very simple, you define a stop loss of x (as a ratio of price, i.e. x * 100% of price). This will try to sell the asset once the loss exceeds the defined loss. -## Trailing Stop Loss +Example of stop loss: + +``` python + stoploss = -0.10 +``` + +For example, simplified math: +* the bot buys an asset at a price of 100$ +* the stop loss is defined at -10% +* the stop loss would get triggered once the asset dropps below 90$ + +### Trailing Stop Loss The initial value for this is `stoploss`, just as you would define your static Stop loss. To enable trailing stoploss: ``` python -trailing_stop = True + stoploss = -0.10 + trailing_stop = True ``` This will now activate an algorithm, which automatically moves the stop loss up every time the price of your asset increases. @@ -47,35 +80,40 @@ This will now activate an algorithm, which automatically moves the stop loss up For example, simplified math: * the bot buys an asset at a price of 100$ -* the stop loss is defined at 2% -* the stop loss would get triggered once the asset dropps below 98$ +* the stop loss is defined at -10% +* the stop loss would get triggered once the asset dropps below 90$ * assuming the asset now increases to 102$ -* the stop loss will now be 2% of 102$ or 99.96$ -* now the asset drops in value to 101$, the stop loss will still be 99.96$ and would trigger at 99.96$. +* the stop loss will now be -10% of 102$ = 91,8$ +* now the asset drops in value to 101$, the stop loss will still be 91,8$ and would trigger at 91,8$. In summary: The stoploss will be adjusted to be always be 2% of the highest observed price. -### Custom positive stoploss +### Trailing stop loss, custom positive loss -It is also possible to have a default stop loss, when you are in the red with your buy, but once your profit surpasses a certain percentage, the system will utilize a new stop loss, which can have a different value. -For example your default stop loss is 5%, but once you have 1.1% profit, it will be changed to be only a 1% stop loss, which trails the green candles until it goes below them. +It is also possible to have a default stop loss, when you are in the red with your buy (buy - fee), but once you hit possitive result the system will utilize a new stop loss, which can have a different value. +For example your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. -Both values require `trailing_stop` to be set to true. +Both values require `trailing_stop` to be set to true and trailing_stop_positive with a value. ``` python - trailing_stop_positive = 0.01 - trailing_stop_positive_offset = 0.011 + stoploss = -0.10 + trailing_stop = True + trailing_stop_positive = 0.02 ``` -The 0.01 would translate to a 1% stop loss, once you hit 1.1% profit. +For example, simplified math: + +* the bot buys an asset at a price of 100$ +* the stop loss is defined at -10% +* the stop loss would get triggered once the asset dropps below 90$ +* assuming the asset now increases to 102$ +* the stop loss will now be -2% of 102$ = 99,96$ +* now the asset drops in value to 101$, the stop loss will still be 99,96$ and would trigger at 99,96$ + +The 0.02 would translate to a -2% stop loss. Before this, `stoploss` is used for the trailing stoploss. -Read the [next section](#trailing-only-once-offset-is-reached) to keep stoploss at 5% of the entry point. - -!!! Tip - Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. - -### Trailing only once offset is reached +### Trailing stop loss only once the trade has reached a certain offset. It is also possible to use a static stoploss until the offset is reached, and then trail the trade to take profits once the market turns. @@ -87,17 +125,28 @@ This option can be used with or without `trailing_stop_positive`, but uses `trai trailing_only_offset_is_reached = True ``` -Simplified example: +Configuration (offset is buyprice + 3%): ``` python - stoploss = 0.05 + stoploss = -0.10 + trailing_stop = True + trailing_stop_positive = 0.02 trailing_stop_positive_offset = 0.03 trailing_only_offset_is_reached = True ``` +For example, simplified math: + * the bot buys an asset at a price of 100$ -* the stop loss is defined at 5% -* the stop loss will remain at 95% until profit reaches +3% +* the stop loss is defined at -10% +* the stop loss would get triggered once the asset dropps below 90$ +* stoploss will remain at 90$ unless asset increases to or above our configured offset +* assuming the asset now increases to 103$ (where we have the offset configured) +* the stop loss will now be -2% of 103$ = 100,94$ +* now the asset drops in value to 101$, the stop loss will still be 100,94$ and would trigger at 100,94$ + +!!! Tip + Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. ## Changing stoploss on open trades From bae8e5ed1a535435a580a2f39776929adc0046cd Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:03:56 +0200 Subject: [PATCH 154/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 2945c18db..32c304e60 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -63,7 +63,7 @@ Example of stop loss: For example, simplified math: * the bot buys an asset at a price of 100$ * the stop loss is defined at -10% -* the stop loss would get triggered once the asset dropps below 90$ +* the stop loss would get triggered once the asset drops below 90$ ### Trailing Stop Loss From c60192e4bdd5440c9f1c5ff2d039c269935a71f4 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:05:07 +0200 Subject: [PATCH 155/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 32c304e60..8bb68eb1d 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -81,7 +81,7 @@ For example, simplified math: * the bot buys an asset at a price of 100$ * the stop loss is defined at -10% -* the stop loss would get triggered once the asset dropps below 90$ +* the stop loss would get triggered once the asset drops below 90$ * assuming the asset now increases to 102$ * the stop loss will now be -10% of 102$ = 91,8$ * now the asset drops in value to 101$, the stop loss will still be 91,8$ and would trigger at 91,8$. From 1ce392f65208b9a1426d414eae4712ac72ed6ce1 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:05:38 +0200 Subject: [PATCH 156/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 8bb68eb1d..dbe839cab 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -37,7 +37,9 @@ order_types = { 'buy': 'limit', 'sell': 'limit', 'stoploss': 'market', - 'stoploss_on_exchange': True + 'stoploss_on_exchange': True, + 'stoploss_on_exchange_interval': 60, + 'stoploss_on_exchange_limit_ratio': 0.99 } ``` From 4ade3daa1ef1fd25e523314acd6b209a494e2c8f Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:09:19 +0200 Subject: [PATCH 157/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index dbe839cab..57d6c160e 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -85,8 +85,8 @@ For example, simplified math: * the stop loss is defined at -10% * the stop loss would get triggered once the asset drops below 90$ * assuming the asset now increases to 102$ -* the stop loss will now be -10% of 102$ = 91,8$ -* now the asset drops in value to 101$, the stop loss will still be 91,8$ and would trigger at 91,8$. +* the stop loss will now be -10% of 102$ = 91.8$ +* now the asset drops in value to 101$, the stop loss will still be 91.8$ and would trigger at 91,8$. In summary: The stoploss will be adjusted to be always be 2% of the highest observed price. From 902d40a32a7a9ed9992a4743e9a16cc7226cf28d Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:13:27 +0200 Subject: [PATCH 158/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 57d6c160e..7942b4c68 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -95,7 +95,7 @@ In summary: The stoploss will be adjusted to be always be 2% of the highest obse It is also possible to have a default stop loss, when you are in the red with your buy (buy - fee), but once you hit possitive result the system will utilize a new stop loss, which can have a different value. For example your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. -Both values require `trailing_stop` to be set to true and trailing_stop_positive with a value. +Both values require `trailing_stop` to be set to true and `trailing_stop_positive` with a value. ``` python stoploss = -0.10 From e30a38932f47406dde2cef8ec956358ff95bbf48 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:13:40 +0200 Subject: [PATCH 159/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 7942b4c68..e6cc59c83 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -107,7 +107,7 @@ For example, simplified math: * the bot buys an asset at a price of 100$ * the stop loss is defined at -10% -* the stop loss would get triggered once the asset dropps below 90$ +* the stop loss would get triggered once the asset drops below 90$ * assuming the asset now increases to 102$ * the stop loss will now be -2% of 102$ = 99,96$ * now the asset drops in value to 101$, the stop loss will still be 99,96$ and would trigger at 99,96$ From 4a0c988b678509cfe3fc61d87a015197b3d063a2 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:13:54 +0200 Subject: [PATCH 160/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index e6cc59c83..142dfd2c9 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -109,8 +109,8 @@ For example, simplified math: * the stop loss is defined at -10% * the stop loss would get triggered once the asset drops below 90$ * assuming the asset now increases to 102$ -* the stop loss will now be -2% of 102$ = 99,96$ -* now the asset drops in value to 101$, the stop loss will still be 99,96$ and would trigger at 99,96$ +* the stop loss will now be -2% of 102$ = 99.96$ +* now the asset drops in value to 101$, the stop loss will still be 99.96$ and would trigger at 99.96$ The 0.02 would translate to a -2% stop loss. Before this, `stoploss` is used for the trailing stoploss. From 67e9721274aa2bd1e23654b0befadce93ade8ce0 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:14:50 +0200 Subject: [PATCH 161/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 142dfd2c9..b866a3efa 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -115,7 +115,7 @@ For example, simplified math: The 0.02 would translate to a -2% stop loss. Before this, `stoploss` is used for the trailing stoploss. -### Trailing stop loss only once the trade has reached a certain offset. +### Trailing stop loss only once the trade has reached a certain offset It is also possible to use a static stoploss until the offset is reached, and then trail the trade to take profits once the market turns. From 8b348fc247416b04149d62a378c43bb6aa4dea89 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:16:35 +0200 Subject: [PATCH 162/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index b866a3efa..30d866fff 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -92,7 +92,7 @@ In summary: The stoploss will be adjusted to be always be 2% of the highest obse ### Trailing stop loss, custom positive loss -It is also possible to have a default stop loss, when you are in the red with your buy (buy - fee), but once you hit possitive result the system will utilize a new stop loss, which can have a different value. +It is also possible to have a default stop loss, when you are in the red with your buy (buy - fee), but once you hit positive result the system will utilize a new stop loss, which can have a different value. For example your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. Both values require `trailing_stop` to be set to true and `trailing_stop_positive` with a value. From 5091767276073528930d58b1f9d96b4d31da8133 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:17:01 +0200 Subject: [PATCH 163/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 30d866fff..ab3297ae9 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -141,7 +141,7 @@ For example, simplified math: * the bot buys an asset at a price of 100$ * the stop loss is defined at -10% -* the stop loss would get triggered once the asset dropps below 90$ +* the stop loss would get triggered once the asset drops below 90$ * stoploss will remain at 90$ unless asset increases to or above our configured offset * assuming the asset now increases to 103$ (where we have the offset configured) * the stop loss will now be -2% of 103$ = 100,94$ From 81a75c97cf6a17e7ff2683d9003696059993ba97 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:17:11 +0200 Subject: [PATCH 164/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index ab3297ae9..2cee88748 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -144,8 +144,8 @@ For example, simplified math: * the stop loss would get triggered once the asset drops below 90$ * stoploss will remain at 90$ unless asset increases to or above our configured offset * assuming the asset now increases to 103$ (where we have the offset configured) -* the stop loss will now be -2% of 103$ = 100,94$ -* now the asset drops in value to 101$, the stop loss will still be 100,94$ and would trigger at 100,94$ +* the stop loss will now be -2% of 103$ = 100.94$ +* now the asset drops in value to 101$, the stop loss will still be 100.94$ and would trigger at 100.94$ !!! Tip Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. From ddba999fe2a25befa5ad6705956a6c9bc1776eb8 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 13:44:32 +0200 Subject: [PATCH 165/285] Update stoploss.md --- docs/stoploss.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 2cee88748..283826708 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -16,13 +16,14 @@ Those stoploss modes can be *on exchange* or *off exchange*. If the stoploss is In case of stoploss on exchange there is another parameter called `stoploss_on_exchange_interval`. This configures the interval in seconds at which the bot will check the stoploss and update it if necessary. For example, assuming the stoploss is on exchange, and trailing stoploss is enabled, and the market is going up, then the bot automatically cancels the previous stoploss order and puts a new one with a stop value higher than the previous stoploss order. -The bot cannot do this every 5 seconds (at each iteration), otherwise it would get banned by the exchange. +The bot cannot do these every 5 seconds (at each iteration), otherwise it would get banned by the exchange. So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute). This same logic will reapply a stoploss order on the exchange should you cancel it accidentally. !!! Note Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. - Do not set too low stoploss value if using stop loss on exhange! + Do not set too low stoploss value if using stop loss on exhange! +* If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work Stop loss on exchange is controlled with this value (default False): @@ -88,12 +89,15 @@ For example, simplified math: * the stop loss will now be -10% of 102$ = 91.8$ * now the asset drops in value to 101$, the stop loss will still be 91.8$ and would trigger at 91,8$. -In summary: The stoploss will be adjusted to be always be 2% of the highest observed price. +In summary: The stoploss will be adjusted to be always be -10% of the highest observed price. ### Trailing stop loss, custom positive loss It is also possible to have a default stop loss, when you are in the red with your buy (buy - fee), but once you hit positive result the system will utilize a new stop loss, which can have a different value. -For example your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. +For example, your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. + +!!! Note + If you want the stoploss to only be changed when you break even of making a profit (what most users want) please refere to next section with [offset enabled](#Trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). Both values require `trailing_stop` to be set to true and `trailing_stop_positive` with a value. @@ -109,7 +113,7 @@ For example, simplified math: * the stop loss is defined at -10% * the stop loss would get triggered once the asset drops below 90$ * assuming the asset now increases to 102$ -* the stop loss will now be -2% of 102$ = 99.96$ +* the stop loss will now be -2% of 102$ = 99.96$ (99.96$ stop loss will be locked in and will follow asset price increasements with -2%) * now the asset drops in value to 101$, the stop loss will still be 99.96$ and would trigger at 99.96$ The 0.02 would translate to a -2% stop loss. From f8efb87a676d872e950a496e52ef0de88d32216c Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 14:57:53 +0200 Subject: [PATCH 166/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 283826708..5a8a553e7 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -87,7 +87,7 @@ For example, simplified math: * the stop loss would get triggered once the asset drops below 90$ * assuming the asset now increases to 102$ * the stop loss will now be -10% of 102$ = 91.8$ -* now the asset drops in value to 101$, the stop loss will still be 91.8$ and would trigger at 91,8$. +* now the asset drops in value to 101$, the stop loss will still be 91.8$ and would trigger at 91.8$. In summary: The stoploss will be adjusted to be always be -10% of the highest observed price. From bd308889fcb49ba4decb7dc969d6b3886e3e49fc Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Sun, 16 Aug 2020 14:58:06 +0200 Subject: [PATCH 167/285] Update docs/stoploss.md Co-authored-by: Matthias --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 5a8a553e7..d0b7f654d 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -97,7 +97,7 @@ It is also possible to have a default stop loss, when you are in the red with yo For example, your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. !!! Note - If you want the stoploss to only be changed when you break even of making a profit (what most users want) please refere to next section with [offset enabled](#Trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). + If you want the stoploss to only be changed when you break even of making a profit (what most users want) please refer to next section with [offset enabled](#Trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). Both values require `trailing_stop` to be set to true and `trailing_stop_positive` with a value. From 4619a50097074ff5686ecbff47594092fb169b5a Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Mon, 17 Aug 2020 02:07:25 +0200 Subject: [PATCH 168/285] Update configuration.md --- docs/configuration.md | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index a200d6411..ad18ac713 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -55,9 +55,9 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `process_only_new_candles` | Enable processing of indicators only when new candles arrive. If false each loop populates the indicators, this will mean the same candle is processed many times creating system load but can be useful of your strategy depends on tick data not only candle. [Strategy Override](#parameters-in-the-strategy).
    *Defaults to `false`.*
    **Datatype:** Boolean | `minimal_roi` | **Required.** Set the threshold as ratio the bot will use to sell a trade. [More information below](#understand-minimal_roi). [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Dict | `stoploss` | **Required.** Value as ratio of the stoploss used by the bot. More details in the [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Float (as ratio) -| `trailing_stop` | Enables trailing stoploss (based on `stoploss` in either configuration or strategy file). More details in the [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Boolean -| `trailing_stop_positive` | Changes stoploss once profit has been reached. More details in the [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Float -| `trailing_stop_positive_offset` | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. More details in the [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy).
    *Defaults to `0.0` (no offset).*
    **Datatype:** Float +| `trailing_stop` | Enables trailing stoploss (based on `stoploss` in either configuration or strategy file). More details in the [stoploss documentation](stoploss.md#trailing-stop-loss). [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Boolean +| `trailing_stop_positive` | Changes stoploss once profit has been reached. More details in the [stoploss documentation](stoploss.md#trailing-stop-loss-custom-positive-loss). [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Float +| `trailing_stop_positive_offset` | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. More details in the [stoploss documentation](stoploss.md#trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). [Strategy Override](#parameters-in-the-strategy).
    *Defaults to `0.0` (no offset).*
    **Datatype:** Float | `trailing_only_offset_is_reached` | Only apply trailing stoploss when the offset is reached. [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy).
    *Defaults to `false`.*
    **Datatype:** Boolean | `unfilledtimeout.buy` | **Required.** How long (in minutes) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled. [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Integer | `unfilledtimeout.sell` | **Required.** How long (in minutes) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled. [Strategy Override](#parameters-in-the-strategy).
    **Datatype:** Integer @@ -278,24 +278,13 @@ This allows to buy using limit orders, sell using limit-orders, and create stoplosses using market orders. It also allows to set the stoploss "on exchange" which means stoploss order would be placed immediately once the buy order is fulfilled. -If `stoploss_on_exchange` and `trailing_stop` are both set, then the bot will use `stoploss_on_exchange_interval` to check and update the stoploss on exchange periodically. -`order_types` can be set in the configuration file or in the strategy. + `order_types` set in the configuration file overwrites values set in the strategy as a whole, so you need to configure the whole `order_types` dictionary in one place. If this is configured, the following 4 values (`buy`, `sell`, `stoploss` and `stoploss_on_exchange`) need to be present, otherwise the bot will fail to start. -`emergencysell` is an optional value, which defaults to `market` and is used when creating stoploss on exchange orders fails. -The below is the default which is used if this is not configured in either strategy or configuration file. - -Not all Exchanges support `stoploss_on_exchange`. If an exchange supports both limit and market stoploss orders, then the value of `stoploss` will be used to determine the stoploss type. - -If `stoploss_on_exchange` uses limit orders, the exchange needs 2 prices, the stoploss_price and the Limit price. -`stoploss` defines the stop-price - and limit should be slightly below this. - -This defaults to 0.99 / 1% (configurable via `stoploss_on_exchange_limit_ratio`). -Calculation example: we bought the asset at 100$. -Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the stoploss will happen between 95$ and 94.05$. +For information on (`emergencysell`,`stoploss_on_exchange`,`stoploss_on_exchange_interval`,`stoploss_on_exchange_limit_ratio`) please see stop loss documentation [stop loss on exchange](stoploss.md) Syntax for Strategy: From 2a6faaae64f6e5e3a5d85a7cf60d4574031e7189 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Mon, 17 Aug 2020 02:07:32 +0200 Subject: [PATCH 169/285] Update stoploss.md --- docs/stoploss.md | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index d0b7f654d..ffa125fa5 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -11,25 +11,47 @@ Most of the strategy files already include the optimal `stoploss` value. ## Stop Loss On-Exchange/Freqtrade -Those stoploss modes can be *on exchange* or *off exchange*. If the stoploss is *on exchange* it means a stoploss limit order is placed on the exchange immediately after buy order happens successfully. This will protect you against sudden crashes in market as the order will be in the queue immediately and if market goes down then the order has more chance of being fulfilled. +Those stoploss modes can be *on exchange* or *off exchange*. -In case of stoploss on exchange there is another parameter called `stoploss_on_exchange_interval`. This configures the interval in seconds at which the bot will check the stoploss and update it if necessary. +These modes can be configured with these values: + +``` python + 'emergencysell': 'market', + 'stoploss_on_exchange': False + 'stoploss_on_exchange_interval': 60, + 'stoploss_on_exchange_limit_ratio': 0.99 +``` + +### stoploss_on_exchange +Enable or Disable stop loss on exchange. +If the stoploss is *on exchange* it means a stoploss limit order is placed on the exchange immediately after buy order happens successfully. This will protect you against sudden crashes in market as the order will be in the queue immediately and if market goes down then the order has more chance of being fulfilled. + +If `stoploss_on_exchange` uses limit orders, the exchange needs 2 prices, the stoploss_price and the Limit price. +`stoploss` defines the stop-price - and limit should be slightly below this. +If an exchange supports both limit and market stoploss orders, then the value of `stoploss` will be used to determine the stoploss type. For example, assuming the stoploss is on exchange, and trailing stoploss is enabled, and the market is going up, then the bot automatically cancels the previous stoploss order and puts a new one with a stop value higher than the previous stoploss order. + +### stoploss_on_exchange_interval +In case of stoploss on exchange there is another parameter called `stoploss_on_exchange_interval`. This configures the interval in seconds at which the bot will check the stoploss and update it if necessary. The bot cannot do these every 5 seconds (at each iteration), otherwise it would get banned by the exchange. So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute). This same logic will reapply a stoploss order on the exchange should you cancel it accidentally. +### emergencysell and stoploss_on_exchange_limit_ratio +`emergencysell` is an optional value, which defaults to `market` and is used when creating stop loss on exchange orders fails. +The below is the default which is used if this is not configured in either strategy or configuration file. + +This defaults to 0.99 / 1% (configurable via `stoploss_on_exchange_limit_ratio`). +Calculation example: we bought the asset at 100$. +Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the stoploss will happen between 95$ and 94.05$. + + !!! Note Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. Do not set too low stoploss value if using stop loss on exhange! * If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work -Stop loss on exchange is controlled with this value (default False): - -``` python - 'stoploss_on_exchange': False -``` Example from strategy file: @@ -37,6 +59,7 @@ Example from strategy file: order_types = { 'buy': 'limit', 'sell': 'limit', + 'emergencysell': 'market', 'stoploss': 'market', 'stoploss_on_exchange': True, 'stoploss_on_exchange_interval': 60, From d6ea442588a92493acaf9c9720e2f910028cc957 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Mon, 17 Aug 2020 02:10:56 +0200 Subject: [PATCH 170/285] Update stoploss.md --- docs/stoploss.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index ffa125fa5..bbb0be566 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -49,7 +49,7 @@ Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the stoploss wi !!! Note Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. - Do not set too low stoploss value if using stop loss on exhange! + Do not set too low stoploss value if using stop loss on exchange! * If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work From da6672841a1a5e5c118718e1165c9ed7e9ac1765 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:24:49 +0000 Subject: [PATCH 171/285] Bump mkdocs-material from 5.5.3 to 5.5.7 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 5.5.3 to 5.5.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/5.5.3...5.5.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 4068e364b..ab5aebb79 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,2 +1,2 @@ -mkdocs-material==5.5.3 +mkdocs-material==5.5.7 mdx_truly_sane_lists==1.2 From 7af7fb261b015522ac92b51f2eea5eb468e15675 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:24:50 +0000 Subject: [PATCH 172/285] Bump pytest-cov from 2.10.0 to 2.10.1 Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.10.0 to 2.10.1. - [Release notes](https://github.com/pytest-dev/pytest-cov/releases) - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.10.0...v2.10.1) 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 c02a439d3..e51713ceb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,7 +10,7 @@ flake8-tidy-imports==4.1.0 mypy==0.782 pytest==6.0.1 pytest-asyncio==0.14.0 -pytest-cov==2.10.0 +pytest-cov==2.10.1 pytest-mock==3.2.0 pytest-random-order==1.0.4 From 988bff9eaec92c3553d4997be3e8b79a02471164 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:24:54 +0000 Subject: [PATCH 173/285] Bump ccxt from 1.32.88 to 1.33.18 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.32.88 to 1.33.18. - [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.32.88...1.33.18) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index b7e71eada..df11ea3de 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.32.88 +ccxt==1.33.18 SQLAlchemy==1.3.18 python-telegram-bot==12.8 arrow==0.15.8 From c8ddd5654adee8d69ee9243855c3cf483e0f6039 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:25:04 +0000 Subject: [PATCH 174/285] Bump prompt-toolkit from 3.0.5 to 3.0.6 Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.5 to 3.0.6. - [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.5...3.0.6) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index b7e71eada..2d7e9be3e 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -32,4 +32,4 @@ flask-cors==3.0.8 colorama==0.4.3 # Building config files interactively questionary==1.5.2 -prompt-toolkit==3.0.5 +prompt-toolkit==3.0.6 From 30a2df14cbb09e30fb12059467e951b73ce888e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:25:10 +0000 Subject: [PATCH 175/285] Bump coveralls from 2.1.1 to 2.1.2 Bumps [coveralls](https://github.com/coveralls-clients/coveralls-python) from 2.1.1 to 2.1.2. - [Release notes](https://github.com/coveralls-clients/coveralls-python/releases) - [Changelog](https://github.com/coveralls-clients/coveralls-python/blob/master/CHANGELOG.md) - [Commits](https://github.com/coveralls-clients/coveralls-python/compare/2.1.1...2.1.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 c02a439d3..41500764c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,7 +3,7 @@ -r requirements-plot.txt -r requirements-hyperopt.txt -coveralls==2.1.1 +coveralls==2.1.2 flake8==3.8.3 flake8-type-annotations==0.1.0 flake8-tidy-imports==4.1.0 From ce15c55185f4c1e78ab084f26a3991c286062cd8 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 17 Aug 2020 20:24:30 +0200 Subject: [PATCH 176/285] Add libffi-dev to rpi image --- Dockerfile.armhf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.armhf b/Dockerfile.armhf index 45ed2dac9..5c5e4a885 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -1,7 +1,7 @@ FROM --platform=linux/arm/v7 python:3.7.7-slim-buster RUN apt-get update \ - && apt-get -y install curl build-essential libssl-dev libatlas3-base libgfortran5 sqlite3 \ + && apt-get -y install curl build-essential libssl-dev libffi-dev libatlas3-base libgfortran5 sqlite3 \ && apt-get clean \ && pip install --upgrade pip \ && echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > /etc/pip.conf From aa866294cd7fb93ff25c89007b288a9c4d5e767b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Aug 2020 14:02:22 +0200 Subject: [PATCH 177/285] Reformulate documentation --- docs/backtesting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index b1dcd5dba..149d1c104 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -213,7 +213,7 @@ Hence, keep in mind that your performance is an integral mix of all different el ### Sell reasons table The 2nd table contains a recap of sell reasons. -This table can tell you which area needs some additional work (e,g. all or many of the `sell_signal` trades are losses, so we should disable the sell-signal or work on improving that). +This table can tell you which area needs some additional work (e.g. all or many of the `sell_signal` trades are losses, so you should work on improving the sell signal, or consider disabling it). ### Left open trades table From 4eb17b4daf692041b7504a980edf84e0fd5b769a Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Aug 2020 15:20:37 +0200 Subject: [PATCH 178/285] Remove unneeded function --- freqtrade/data/btanalysis.py | 2 +- freqtrade/optimize/optimize_reports.py | 14 -------------- tests/optimize/test_optimize_reports.py | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index cf6e18e64..972961b36 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -179,7 +179,7 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF filters = [] if strategy: - filters = Trade.strategy == strategy + filters.append(Trade.strategy == strategy) trades = pd.DataFrame([(t.pair, t.open_date.replace(tzinfo=timezone.utc), diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 8e25d9d89..c69442d46 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -31,20 +31,6 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N file_dump_json(latest_filename, {'latest_backtest': str(filename.name)}) -def backtest_result_to_list(results: DataFrame) -> List[List]: - """ - Converts a list of Backtest-results to list - :param results: Dataframe containing results for one strategy - :return: List of Lists containing the trades - """ - # Return 0 as "index" for compatibility reasons (for now) - # TODO: Evaluate if we can remove this - return [[t.pair, t.profit_percent, t.open_date.timestamp(), - t.close_date.timestamp(), 0, t.trade_duration, - t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value] - for index, t in results.iterrows()] - - def _get_line_floatfmt() -> List[str]: """ Generate floatformat (goes in line with _generate_result_line()) diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index 2fab4578c..e5d98ca43 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -146,6 +146,25 @@ def test_generate_backtest_stats(default_conf, testdatadir): filename1.unlink() +def test_store_backtest_stats(testdatadir, mocker): + + dump_mock = mocker.patch('freqtrade.optimize.optimize_reports.file_dump_json') + + store_backtest_stats(testdatadir, {}) + + assert dump_mock.call_count == 2 + assert isinstance(dump_mock.call_args_list[0][0][0], Path) + assert str(dump_mock.call_args_list[0][0][0]).startswith(str(testdatadir/'backtest-result')) + + dump_mock.reset_mock() + filename = testdatadir / 'testresult.json' + store_backtest_stats(filename, {}) + assert dump_mock.call_count == 2 + assert isinstance(dump_mock.call_args_list[0][0][0], Path) + # result will be testdatadir / testresult-.json + assert str(dump_mock.call_args_list[0][0][0]).startswith(str(testdatadir / 'testresult')) + + def test_generate_pair_metrics(default_conf, mocker): results = pd.DataFrame( From 668d167adcb103309c44e8d87be97133fc7fbe87 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Aug 2020 16:15:24 +0200 Subject: [PATCH 179/285] Add docstring to store_backtest_stats --- freqtrade/optimize/optimize_reports.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index c69442d46..bf4e518ba 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -16,7 +16,13 @@ logger = logging.getLogger(__name__) def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> None: - + """ + Stores backtest results + :param recordfilename: Path object, which can either be a filename or a directory. + Filenames will be appended with a timestamp right before the suffix + while for diectories, /backtest-result-.json will be used as filename + :param stats: Dataframe containing the backtesting statistics + """ if recordfilename.is_dir(): filename = (recordfilename / f'backtest-result-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}.json') From 9982ad2f365b715f8bf2dd225bdcff509c6d8030 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Aug 2020 16:59:24 +0200 Subject: [PATCH 180/285] Add profit to backtest summary output --- docs/backtesting.md | 1 + freqtrade/optimize/optimize_reports.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/backtesting.md b/docs/backtesting.md index 149d1c104..20e69f52f 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -165,6 +165,7 @@ A backtesting result will look like that: | Total trades | 429 | | First trade | 2019-01-01 18:30:00 | | First trade Pair | EOS/USDT | +| Total Profit % | 152.41% | | Trades per day | 3.575 | | Best day | 25.27% | | Worst day | -30.67% | diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index bf4e518ba..0799ebb23 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -249,6 +249,9 @@ def generate_backtest_stats(config: Dict, 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(), + 'profit_total': results['profit_percent'].sum(), + 'profit_total_abs': results['profit_abs'].sum(), 'backtest_start': min_date.datetime, 'backtest_start_ts': min_date.timestamp * 1000, 'backtest_end': max_date.datetime, @@ -372,6 +375,7 @@ def text_table_add_metrics(strat_results: Dict) -> str: ('Total trades', strat_results['total_trades']), ('First trade', min_trade['open_date'].strftime(DATETIME_PRINT_FORMAT)), ('First trade Pair', min_trade['pair']), + ('Total Profit %', f"{round(strat_results['profit_total'] * 100, 2)}%"), ('Trades per day', strat_results['trades_per_day']), ('Best day', f"{round(strat_results['backtest_best_day'] * 100, 2)}%"), ('Worst day', f"{round(strat_results['backtest_worst_day'] * 100, 2)}%"), From d8e1f97465922f71128a4cffe37c582ea7721c00 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Aug 2020 19:44:44 +0200 Subject: [PATCH 181/285] Fix documentation typo --- docs/backtesting.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/backtesting.md b/docs/backtesting.md index 20e69f52f..84911568b 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -219,7 +219,7 @@ This table can tell you which area needs some additional work (e.g. all or many ### Left open trades table The 3rd table contains all trades the bot had to `forcesell` at the end of the backtesting period to present you the full picture. -This is necessary to simulate realistic behaviour, since the backtest period has to end at some point, while realistically, you could leave the bot running forever. +This is necessary to simulate realistic behavior, since the backtest period has to end at some point, while realistically, you could leave the bot running forever. These trades are also included in the first table, but are also shown separately in this table for clarity. ### Summary metrics @@ -236,6 +236,7 @@ It contains some useful key metrics about performance of your strategy on backte | Total trades | 429 | | First trade | 2019-01-01 18:30:00 | | First trade Pair | EOS/USDT | +| Total Profit % | 152.41% | | Trades per day | 3.575 | | Best day | 25.27% | | Worst day | -30.67% | @@ -254,11 +255,12 @@ It contains some useful key metrics about performance of your strategy on backte - `First trade`: First trade entered. - `First trade pair`: Which pair was part of the first trade. - `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option). +- `Total Profit %`: Total profit per stake amount. Aligned to the TOTAL column of 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 day` / `Worst day`: Best and worst day based on daily profit. - `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades. - `Max Drawdown`: Maximum drawdown experienced. For example, the value of 50% means that from highest to subsequent lowest point, a 50% drop was experienced). -- `Drawdown Start` / `Drawdown End`: Start and end datetimes for this largest drawdown (can also be visualized via the `plot-dataframe` subcommand). +- `Drawdown Start` / `Drawdown End`: Start and end datetimes for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command). - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. ### Assumptions made by backtesting From 375e671aafc508e91c0ab4fd9b33f74d2eba7400 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Aug 2020 20:12:14 +0200 Subject: [PATCH 182/285] Move formatting of /daily to telegram so /daily can return numbers in the API --- freqtrade/rpc/rpc.py | 10 ++++------ freqtrade/rpc/telegram.py | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index f4e20c16f..7be49b948 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -224,22 +224,20 @@ class RPC: ]).order_by(Trade.close_date).all() curdayprofit = sum(trade.close_profit_abs for trade in trades) profit_days[profitday] = { - 'amount': f'{curdayprofit:.8f}', + 'amount': curdayprofit, 'trades': len(trades) } data = [ { 'date': key, - 'abs_profit': f'{float(value["amount"]):.8f}', - 'fiat_value': '{value:.3f}'.format( - value=self._fiat_converter.convert_amount( + 'abs_profit': value["amount"], + 'fiat_value': self._fiat_converter.convert_amount( value['amount'], stake_currency, fiat_display_currency ) if self._fiat_converter else 0, - ), - 'trade_count': f'{value["trades"]}', + 'trade_count': value["trades"], } for key, value in profit_days.items() ] diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index f1d3cde21..809deb765 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -305,8 +305,8 @@ class Telegram(RPC): ) stats_tab = tabulate( [[day['date'], - f"{day['abs_profit']} {stats['stake_currency']}", - f"{day['fiat_value']} {stats['fiat_display_currency']}", + f"{day['abs_profit']:.8f} {stats['stake_currency']}", + f"{day['fiat_value']:.3f} {stats['fiat_display_currency']}", f"{day['trade_count']} trades"] for day in stats['data']], headers=[ 'Day', From e206cc9c216bbf7f140797c001692f41c0d7fd48 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 18 Aug 2020 20:15:41 +0200 Subject: [PATCH 183/285] Adjust tests --- tests/rpc/test_rpc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 9bbd34672..164c825ba 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -255,11 +255,11 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee, assert days['fiat_display_currency'] == default_conf['fiat_display_currency'] for day in days['data']: # [datetime.date(2018, 1, 11), '0.00000000 BTC', '0.000 USD'] - assert (day['abs_profit'] == '0.00000000' or - day['abs_profit'] == '0.00006217') + assert (day['abs_profit'] == 0.0 or + day['abs_profit'] == 0.00006217) - assert (day['fiat_value'] == '0.000' or - day['fiat_value'] == '0.767') + assert (day['fiat_value'] == 0.0 or + day['fiat_value'] == 0.76748865) # ensure first day is current date assert str(days['data'][0]['date']) == str(datetime.utcnow().date()) From 55c6e56762dc3d2523415641d1d25d903919de0c Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Wed, 19 Aug 2020 23:07:03 +0200 Subject: [PATCH 184/285] Update stoploss.md --- docs/stoploss.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index bbb0be566..2595a3f55 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -22,7 +22,7 @@ These modes can be configured with these values: 'stoploss_on_exchange_limit_ratio': 0.99 ``` -### stoploss_on_exchange +### stoploss_on_exchange and stoploss_on_exchange_limit_ratio Enable or Disable stop loss on exchange. If the stoploss is *on exchange* it means a stoploss limit order is placed on the exchange immediately after buy order happens successfully. This will protect you against sudden crashes in market as the order will be in the queue immediately and if market goes down then the order has more chance of being fulfilled. @@ -30,6 +30,10 @@ If `stoploss_on_exchange` uses limit orders, the exchange needs 2 prices, the st `stoploss` defines the stop-price - and limit should be slightly below this. If an exchange supports both limit and market stoploss orders, then the value of `stoploss` will be used to determine the stoploss type. +If `stoploss_on_exchange` fails to fill we can use `stoploss_on_exchange_limit_ratio` that defaults to 0.99 / 1% to perform an [emergency sell](#emergencysell). +Calculation example: we bought the asset at 100$. +Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the stoploss(emergency sell) will happen between 95$ and 94.05$. + For example, assuming the stoploss is on exchange, and trailing stoploss is enabled, and the market is going up, then the bot automatically cancels the previous stoploss order and puts a new one with a stop value higher than the previous stoploss order. ### stoploss_on_exchange_interval @@ -38,15 +42,10 @@ The bot cannot do these every 5 seconds (at each iteration), otherwise it would So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute). This same logic will reapply a stoploss order on the exchange should you cancel it accidentally. -### emergencysell and stoploss_on_exchange_limit_ratio +### emergencysell `emergencysell` is an optional value, which defaults to `market` and is used when creating stop loss on exchange orders fails. The below is the default which is used if this is not configured in either strategy or configuration file. -This defaults to 0.99 / 1% (configurable via `stoploss_on_exchange_limit_ratio`). -Calculation example: we bought the asset at 100$. -Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the stoploss will happen between 95$ and 94.05$. - - !!! Note Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. Do not set too low stoploss value if using stop loss on exchange! From bca24c8b6b584e012e573b8aeb393a1e8e54ab93 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 20 Aug 2020 19:35:40 +0200 Subject: [PATCH 185/285] Clarify hyperopt dataprovider usage --- docs/strategy-customization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 73d085abd..be08faa2d 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -366,8 +366,8 @@ All methods return `None` in case of failure (do not raise an exception). Please always check the mode of operation to select the correct method to get data (samples see below). !!! Warning "Hyperopt" - Dataprovider is available during hyperopt, however it can only be used in `populate_indicators()`. - It is not available in `populate_buy()` and `populate_sell()` methods. + Dataprovider is available during hyperopt, however it can only be used in `populate_indicators()` within a strategy. + It is not available in `populate_buy()` and `populate_sell()` methods, nor in `populate_indicators()`, if this method located in the hyperopt file. ### Possible options for DataProvider From f5a9001dc05effd378f07de663a30a88fa6201ec Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 20 Aug 2020 19:51:36 +0200 Subject: [PATCH 186/285] Handle backtest results without any trades --- freqtrade/optimize/optimize_reports.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 0799ebb23..0681eed7b 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -31,6 +31,7 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N recordfilename.parent, f'{recordfilename.stem}-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}' ).with_suffix(recordfilename.suffix) + print(stats) file_dump_json(filename, stats) latest_filename = Path.joinpath(filename.parent, LAST_BT_RESULT_FN) @@ -185,6 +186,16 @@ def generate_edge_table(results: dict) -> str: def generate_daily_stats(results: DataFrame) -> Dict[str, Any]: + if len(results) == 0: + return { + 'backtest_best_day': 0, + 'backtest_worst_day': 0, + 'winning_days': 0, + 'draw_days': 0, + 'losing_days': 0, + 'winner_holding_avg': timedelta(), + 'loser_holding_avg': timedelta(), + } daily_profit = results.resample('1d', on='close_date')['profit_percent'].sum() worst = min(daily_profit) best = max(daily_profit) @@ -249,7 +260,7 @@ def generate_backtest_stats(config: Dict, 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(), + 'profit_mean': results['profit_percent'].mean() if len(results) > 0 else 0, 'profit_total': results['profit_percent'].sum(), 'profit_total_abs': results['profit_abs'].sum(), 'backtest_start': min_date.datetime, @@ -258,7 +269,7 @@ def generate_backtest_stats(config: Dict, btdata: Dict[str, DataFrame], 'backtest_end_ts': max_date.timestamp * 1000, 'backtest_days': backtest_days, - 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else None, + 'trades_per_day': round(len(results) / backtest_days, 2) if backtest_days > 0 else 0, 'market_change': market_change, 'pairlist': list(btdata.keys()), 'stake_amount': config['stake_amount'], From 4f1179d85c3d3aa11a76768c8aaa6af922157e96 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 20 Aug 2020 19:56:41 +0200 Subject: [PATCH 187/285] Test for empty case --- freqtrade/optimize/optimize_reports.py | 1 - tests/optimize/test_optimize_reports.py | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 0681eed7b..94729b6a5 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -31,7 +31,6 @@ def store_backtest_stats(recordfilename: Path, stats: Dict[str, DataFrame]) -> N recordfilename.parent, f'{recordfilename.stem}-{datetime.now().strftime("%Y-%m-%d_%H-%M-%S")}' ).with_suffix(recordfilename.suffix) - print(stats) file_dump_json(filename, stats) latest_filename = Path.joinpath(filename.parent, LAST_BT_RESULT_FN) diff --git a/tests/optimize/test_optimize_reports.py b/tests/optimize/test_optimize_reports.py index e5d98ca43..4f62e2e23 100644 --- a/tests/optimize/test_optimize_reports.py +++ b/tests/optimize/test_optimize_reports.py @@ -204,6 +204,14 @@ def test_generate_daily_stats(testdatadir): assert res['winner_holding_avg'] == timedelta(seconds=1440) assert res['loser_holding_avg'] == timedelta(days=1, seconds=21420) + # Select empty dataframe! + res = generate_daily_stats(bt_data.loc[bt_data['open_date'] == '2000-01-01', :]) + assert isinstance(res, dict) + assert round(res['backtest_best_day'], 4) == 0.0 + assert res['winning_days'] == 0 + assert res['draw_days'] == 0 + assert res['losing_days'] == 0 + def test_text_table_sell_reason(default_conf): From fa0c8fa0b332e144556851cde5de218bca77f56d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 21 Aug 2020 14:26:23 +0200 Subject: [PATCH 188/285] Readd note about windows hyperopt color output --- docs/hyperopt.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 9acb606c3..6330a1a5e 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -370,6 +370,9 @@ By default, hyperopt prints colorized results -- epochs with positive profit are You can use the `--print-all` command line option if you would like to see all results in the hyperopt output, not only the best ones. When `--print-all` is used, current best results are also colorized by default -- they are printed in bold (bright) style. This can also be switched off with the `--no-color` command line option. +!!! Note "Windows and color output" + Windows does not support color-output nativly, therefore it is automatically disabled. To have color-output for hyperopt running under windows, please consider using WSL. + ### Understand Hyperopt ROI results If you are optimizing ROI (i.e. if optimization search-space contains 'all', 'default' or 'roi'), your result will look as follows and include a ROI table: From 3d93236709f93e0380659e074e2b44c518a1cc11 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 21 Aug 2020 14:55:47 +0200 Subject: [PATCH 189/285] Remove unused import --- freqtrade/optimize/hyperopt.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 3e7e2ca57..b9db3c09a 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -12,7 +12,6 @@ import warnings from collections import OrderedDict from math import ceil from operator import itemgetter -from os import path from pathlib import Path from pprint import pformat from typing import Any, Dict, List, Optional From 0e368b16aba83de72328b52f1e867d6ee5c9bcd1 Mon Sep 17 00:00:00 2001 From: Fredrik81 Date: Fri, 21 Aug 2020 18:25:45 +0200 Subject: [PATCH 190/285] Update stoploss.md --- docs/stoploss.md | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 2595a3f55..2518df846 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -6,8 +6,8 @@ For example, value `-0.10` will cause immediate sell if the profit dips below -1 Most of the strategy files already include the optimal `stoploss` value. !!! Info - All stoploss properties mentioned in this file can be set in the Strategy, or in the configuration. - Configuration values will override the strategy values. +* All stoploss properties mentioned in this file can be set in the Strategy, or in the configuration. +* Configuration values will override the strategy values. ## Stop Loss On-Exchange/Freqtrade @@ -22,35 +22,33 @@ These modes can be configured with these values: 'stoploss_on_exchange_limit_ratio': 0.99 ``` +!!! Note +* Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. +* Do not set too low stoploss value if using stop loss on exchange! +* If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work + ### stoploss_on_exchange and stoploss_on_exchange_limit_ratio Enable or Disable stop loss on exchange. If the stoploss is *on exchange* it means a stoploss limit order is placed on the exchange immediately after buy order happens successfully. This will protect you against sudden crashes in market as the order will be in the queue immediately and if market goes down then the order has more chance of being fulfilled. -If `stoploss_on_exchange` uses limit orders, the exchange needs 2 prices, the stoploss_price and the Limit price. -`stoploss` defines the stop-price - and limit should be slightly below this. -If an exchange supports both limit and market stoploss orders, then the value of `stoploss` will be used to determine the stoploss type. +If `stoploss_on_exchange` uses limit orders, the exchange needs 2 prices, the stoploss_price and the Limit price. +`stoploss` defines the stop-price where the limit order is placed - and limit should be slightly below this. +If an exchange supports both limit and market stoploss orders, then the value of `stoploss` will be used to determine the stoploss type. -If `stoploss_on_exchange` fails to fill we can use `stoploss_on_exchange_limit_ratio` that defaults to 0.99 / 1% to perform an [emergency sell](#emergencysell). -Calculation example: we bought the asset at 100$. -Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the stoploss(emergency sell) will happen between 95$ and 94.05$. +Calculation example: we bought the asset at 100$. +Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the limit order fill can happen between 95$ and 94.05$. For example, assuming the stoploss is on exchange, and trailing stoploss is enabled, and the market is going up, then the bot automatically cancels the previous stoploss order and puts a new one with a stop value higher than the previous stoploss order. ### stoploss_on_exchange_interval -In case of stoploss on exchange there is another parameter called `stoploss_on_exchange_interval`. This configures the interval in seconds at which the bot will check the stoploss and update it if necessary. +In case of stoploss on exchange there is another parameter called `stoploss_on_exchange_interval`. This configures the interval in seconds at which the bot will check the stoploss and update it if necessary. The bot cannot do these every 5 seconds (at each iteration), otherwise it would get banned by the exchange. So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute). This same logic will reapply a stoploss order on the exchange should you cancel it accidentally. ### emergencysell `emergencysell` is an optional value, which defaults to `market` and is used when creating stop loss on exchange orders fails. -The below is the default which is used if this is not configured in either strategy or configuration file. - -!!! Note - Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. - Do not set too low stoploss value if using stop loss on exchange! -* If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work - +The below is the default which is used if not changed in strategy or configuration file. Example from strategy file: @@ -119,7 +117,7 @@ It is also possible to have a default stop loss, when you are in the red with yo For example, your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. !!! Note - If you want the stoploss to only be changed when you break even of making a profit (what most users want) please refer to next section with [offset enabled](#Trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). +* If you want the stoploss to only be changed when you break even of making a profit (what most users want) please refer to next section with [offset enabled](#Trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). Both values require `trailing_stop` to be set to true and `trailing_stop_positive` with a value. @@ -174,7 +172,7 @@ For example, simplified math: * now the asset drops in value to 101$, the stop loss will still be 100.94$ and would trigger at 100.94$ !!! Tip - Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. +* Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. ## Changing stoploss on open trades From 637147f89c59a5fe431cd6d0f91f54345922c875 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 22 Aug 2020 09:33:35 +0200 Subject: [PATCH 191/285] Update sql cheatsheet parentheses --- docs/sql_cheatsheet.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index 748b16928..cf785ced6 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -110,7 +110,7 @@ SET is_open=0, close_date=, close_rate=, close_profit = close_rate / open_rate - 1, - close_profit_abs = (amount * * (1 - fee_close) - (amount * (open_rate * 1 - fee_open))), + close_profit_abs = (amount * * (1 - fee_close) - (amount * (open_rate * (1 - fee_open)))), sell_reason= WHERE id=; ``` @@ -123,7 +123,7 @@ SET is_open=0, close_date='2020-06-20 03:08:45.103418', close_rate=0.19638016, close_profit=0.0496, - close_profit_abs = (amount * 0.19638016 * (1 - fee_close) - (amount * open_rate * (1 - fee_open))), + close_profit_abs = (amount * 0.19638016 * (1 - fee_close) - (amount * (open_rate * (1 - fee_open)))), sell_reason='force_sell' WHERE id=31; ``` From d8a6410fd145d38a01f40b5cbc3757f76db2ea2c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 23 Aug 2020 09:00:57 +0200 Subject: [PATCH 192/285] Fix small bug when using max-open-trades -1 in backtesting --- freqtrade/optimize/optimize_reports.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 94729b6a5..b5e5da4af 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -273,7 +273,8 @@ def generate_backtest_stats(config: Dict, 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'], + 'max_open_trades': (config['max_open_trades'] + if config['max_open_trades'] != float('inf') else -1), 'timeframe': config['timeframe'], **daily_stats, } From 2701a7cb12ce57769ad79cd0b52a38cb27ad87df Mon Sep 17 00:00:00 2001 From: Martin Schultheiss Date: Sun, 23 Aug 2020 09:11:34 +0200 Subject: [PATCH 193/285] update bad exchanges --- freqtrade/exchange/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index 3bba9be72..7f6dfe0eb 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -16,6 +16,7 @@ BAD_EXCHANGES = { "Details in https://github.com/freqtrade/freqtrade/issues/1983", "hitbtc": "This API cannot be used with Freqtrade. " "Use `hitbtc2` exchange id to access this exchange.", + "phemex": "Does not provide history. ", **dict.fromkeys([ 'adara', 'anxpro', From 73417f11f1db843244ac321d91beaaf88ae30c83 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 23 Aug 2020 09:11:52 +0200 Subject: [PATCH 194/285] Fix rendering issue on readthedocs --- docs/stoploss.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/stoploss.md b/docs/stoploss.md index 2518df846..fa888cd47 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -6,8 +6,8 @@ For example, value `-0.10` will cause immediate sell if the profit dips below -1 Most of the strategy files already include the optimal `stoploss` value. !!! Info -* All stoploss properties mentioned in this file can be set in the Strategy, or in the configuration. -* Configuration values will override the strategy values. + All stoploss properties mentioned in this file can be set in the Strategy, or in the configuration. + Configuration values will override the strategy values. ## Stop Loss On-Exchange/Freqtrade @@ -23,9 +23,9 @@ These modes can be configured with these values: ``` !!! Note -* Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. -* Do not set too low stoploss value if using stop loss on exchange! -* If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work + Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. + Do not set too low stoploss value if using stop loss on exchange! + If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work ### stoploss_on_exchange and stoploss_on_exchange_limit_ratio Enable or Disable stop loss on exchange. @@ -117,7 +117,7 @@ It is also possible to have a default stop loss, when you are in the red with yo For example, your default stop loss is -10%, but once you have more than 0% profit (example 0.1%) a different trailing stoploss will be used. !!! Note -* If you want the stoploss to only be changed when you break even of making a profit (what most users want) please refer to next section with [offset enabled](#Trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). + If you want the stoploss to only be changed when you break even of making a profit (what most users want) please refer to next section with [offset enabled](#Trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). Both values require `trailing_stop` to be set to true and `trailing_stop_positive` with a value. @@ -172,7 +172,7 @@ For example, simplified math: * now the asset drops in value to 101$, the stop loss will still be 100.94$ and would trigger at 100.94$ !!! Tip -* Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. + Make sure to have this value (`trailing_stop_positive_offset`) lower than minimal ROI, otherwise minimal ROI will apply first and sell the trade. ## Changing stoploss on open trades From 05ec56d906b025f15032f513a1b68b4c2fec44fb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 23 Aug 2020 10:16:28 +0200 Subject: [PATCH 195/285] Dates should be changed to UTC to provide the correct timestamp --- freqtrade/persistence.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 28753ed48..9eebadd8d 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -2,7 +2,7 @@ This module contains the class to persist trades into SQLite """ import logging -from datetime import datetime +from datetime import datetime, timezone from decimal import Decimal from typing import Any, Dict, List, Optional @@ -274,7 +274,7 @@ class Trade(_DECL_BASE): 'open_date_hum': arrow.get(self.open_date).humanize(), 'open_date': self.open_date.strftime("%Y-%m-%d %H:%M:%S"), - 'open_timestamp': int(self.open_date.timestamp() * 1000), + 'open_timestamp': int(self.open_date.replace(tzinfo=timezone.utc).timestamp() * 1000), 'open_rate': self.open_rate, 'open_rate_requested': self.open_rate_requested, 'open_trade_price': round(self.open_trade_price, 8), @@ -283,7 +283,8 @@ class Trade(_DECL_BASE): if self.close_date else None), 'close_date': (self.close_date.strftime("%Y-%m-%d %H:%M:%S") if self.close_date else None), - 'close_timestamp': int(self.close_date.timestamp() * 1000) if self.close_date else None, + 'close_timestamp': int(self.close_date.replace( + tzinfo=timezone.utc).timestamp() * 1000) if self.close_date else None, 'close_rate': self.close_rate, 'close_rate_requested': self.close_rate_requested, 'close_profit': self.close_profit, @@ -298,8 +299,8 @@ class Trade(_DECL_BASE): 'stoploss_order_id': self.stoploss_order_id, 'stoploss_last_update': (self.stoploss_last_update.strftime("%Y-%m-%d %H:%M:%S") if self.stoploss_last_update else None), - 'stoploss_last_update_timestamp': (int(self.stoploss_last_update.timestamp() * 1000) - if self.stoploss_last_update else None), + 'stoploss_last_update_timestamp': int(self.stoploss_last_update.replace( + tzinfo=timezone.utc).timestamp() * 1000) if self.stoploss_last_update else None, 'initial_stop_loss': self.initial_stop_loss, # Deprecated - should not be used 'initial_stop_loss_abs': self.initial_stop_loss, 'initial_stop_loss_ratio': (self.initial_stop_loss_pct From ec949614374925d076febb3c140fc22aa4cedea9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 23 Aug 2020 19:14:28 +0200 Subject: [PATCH 196/285] Reduce loglevel of "using cached rate" --- freqtrade/freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 2a95f58fc..2fcb9f3f9 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -275,7 +275,7 @@ class FreqtradeBot: rate = self._buy_rate_cache.get(pair) # Check if cache has been invalidated if rate: - logger.info(f"Using cached buy rate for {pair}.") + logger.debug(f"Using cached buy rate for {pair}.") return rate bid_strategy = self.config.get('bid_strategy', {}) @@ -693,7 +693,7 @@ class FreqtradeBot: rate = self._sell_rate_cache.get(pair) # Check if cache has been invalidated if rate: - logger.info(f"Using cached sell rate for {pair}.") + logger.debug(f"Using cached sell rate for {pair}.") return rate ask_strategy = self.config.get('ask_strategy', {}) From a55dd8444df6c07fae14d467efc8006ae869b341 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 23 Aug 2020 19:31:35 +0200 Subject: [PATCH 197/285] Fix loglevel of using_cached-rate --- tests/test_freqtradebot.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index c6413cb5d..0d7968e26 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -953,6 +953,7 @@ def test_process_informative_pairs_added(default_conf, ticker, mocker) -> None: ]) def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid, last, last_ab, expected) -> None: + caplog.set_level(logging.DEBUG) default_conf['bid_strategy']['ask_last_balance'] = last_ab default_conf['bid_strategy']['price_side'] = side freqtrade = get_patched_freqtradebot(mocker, default_conf) @@ -3969,6 +3970,8 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order ('ask', 0.006, 1.0, 0.006), ]) def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask, expected) -> None: + caplog.set_level(logging.DEBUG) + default_conf['ask_strategy']['price_side'] = side mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'ask': ask, 'bid': bid}) pair = "ETH/BTC" @@ -3990,6 +3993,7 @@ def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask, expected) - ('ask', 0.043949), # Value from order_book_l2 fiture - asks side ]) def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, order_book_l2): + caplog.set_level(logging.DEBUG) # Test orderbook mode default_conf['ask_strategy']['price_side'] = side default_conf['ask_strategy']['use_order_book'] = True From 8940ba828f621963528578defe7c34f7cf48eb3c Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 23 Aug 2020 21:12:08 +0200 Subject: [PATCH 198/285] Update sandbox documentation --- docs/sandbox-testing.md | 150 ++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 99 deletions(-) diff --git a/docs/sandbox-testing.md b/docs/sandbox-testing.md index 7f3457d15..bb075217f 100644 --- a/docs/sandbox-testing.md +++ b/docs/sandbox-testing.md @@ -1,104 +1,59 @@ # Sandbox API testing -Where an exchange provides a sandbox for risk-free integration, or end-to-end, testing CCXT provides access to these. +Some exchanges provide sandboxes or testbeds for risk-free testing, while running the bot against a real exchange. +With some configuration, freqtrade (in combination with ccxt) provides access to these. -This document is a *light overview of configuring Freqtrade and GDAX sandbox. -This can be useful to developers and trader alike as Freqtrade is quite customisable. +This document is a light overview of configuring Freqtrade to be used with sandboxes. +This can be useful to developers and trader alike. + +## Exchanges known to have a sandbox / testnet + +* [binance](https://testnet.binance.vision/) +* [coinbasepro](https://public.sandbox.pro.coinbase.com) +* [gemini](https://exchange.sandbox.gemini.com/) +* [huobipro](https://www.testnet.huobi.pro/) +* [kucoin](https://sandbox.kucoin.com/) +* [phemex](https://testnet.phemex.com/) + +!!! Note + We did not test correct functioning of all of the above testnets. Please report your experiences with each sandbox. + +--- + +## Configure a Sandbox account When testing your API connectivity, make sure to use the following URLs. -***Website** -https://public.sandbox.gdax.com -***REST API** -https://api-public.sandbox.gdax.com ---- +In general, you should follow these steps to enable an exchange's sandbox: -# Configure a Sandbox account on Gdax +- Figure out if an exchange has a sandbox (most likely by using google or the exchange's support documents) +- Create a sandbox account (often the sandbox-account requires separate registration) +- [Add some test assets to account](#add-test-funds) +- Create API keys -Aim of this document section +### Add test funds -- An sanbox account -- create 2FA (needed to create an API) -- Add test 50BTC to account -- Create : -- - API-KEY -- - API-Secret -- - API Password +Usually, sandbox exchanges allow depositing funds directly via web-interface. +You should make sure to have a realistic amount of funds available to your test-account, so results are representable of your real account funds. -## Acccount +!!! Warning + Test exchanges will NEVER require your real credit card or banking details! -This link will redirect to the sandbox main page to login / create account dialogues: -https://public.sandbox.pro.coinbase.com/orders/ +## Configure freqtrade to use a exchange's sandbox -After registration and Email confimation you wil be redirected into your sanbox account. It is easy to verify you're in sandbox by checking the URL bar. -> https://public.sandbox.pro.coinbase.com/ - -## Enable 2Fa (a prerequisite to creating sandbox API Keys) - -From within sand box site select your profile, top right. ->Or as a direct link: https://public.sandbox.pro.coinbase.com/profile - -From the menu panel to the left of the screen select - -> Security: "*View or Update*" - -In the new site select "enable authenticator" as typical google Authenticator. - -- open Google Authenticator on your phone -- scan barcode -- enter your generated 2fa - -## Enable API Access - -From within sandbox select profile>api>create api-keys ->or as a direct link: https://public.sandbox.pro.coinbase.com/profile/api - -Click on "create one" and ensure **view** and **trade** are "checked" and sumbit your 2FA - -- **Copy and paste the Passphase** into a notepade this will be needed later -- **Copy and paste the API Secret** popup into a notepad this will needed later -- **Copy and paste the API Key** into a notepad this will needed later - -## Add 50 BTC test funds - -To add funds, use the web interface deposit and withdraw buttons. - -To begin select 'Wallets' from the top menu. -> Or as a direct link: https://public.sandbox.pro.coinbase.com/wallets - -- Deposits (bottom left of screen) -- - Deposit Funds Bitcoin -- - - Coinbase BTC Wallet -- - - - Max (50 BTC) -- - - - - Deposit - -*This process may be repeated for other currencies, ETH as example* - ---- - -# Configure Freqtrade to use Gax Sandbox - -The aim of this document section - -- Enable sandbox URLs in Freqtrade -- Configure API -- - secret -- - key -- - passphrase - -## Sandbox URLs +### Sandbox URLs Freqtrade makes use of CCXT which in turn provides a list of URLs to Freqtrade. These include `['test']` and `['api']`. -- `[Test]` if available will point to an Exchanges sandbox. -- `[Api]` normally used, and resolves to live API target on the exchange +- `[Test]` if available will point to an Exchanges sandbox. +- `[Api]` normally used, and resolves to live API target on the exchange. To make use of sandbox / test add "sandbox": true, to your config.json ```json "exchange": { - "name": "gdax", + "name": "coinbasepro", "sandbox": true, "key": "5wowfxemogxeowo;heiohgmd", "secret": "/ZMH1P62rCVmwefewrgcewX8nh4gob+lywxfwfxwwfxwfNsH1ySgvWCUR/w==", @@ -106,36 +61,33 @@ To make use of sandbox / test add "sandbox": true, to your config.json "outdated_offset": 5 "pair_whitelist": [ "BTC/USD" + ] + }, + "datadir": "user_data/data/coinbasepro_sandbox" ``` -Also insert your +Also the following information: -- api-key (noted earlier) +- api-key (created for the sandbox webpage) - api-secret (noted earlier) - password (the passphrase - noted earlier) +!!! Tip "Different data directory" + We also recommend to set `datadir` to something identifying downloaded data as sandbox data, to avoid having sandbox data mixed with data from the real exchange. + This can be done by adding the `"datadir"` key to the configuration. + Now, whenever you use this configuration, your data directory will be set to this directory. + --- ## You should now be ready to test your sandbox -Ensure Freqtrade logs show the sandbox URL, and trades made are shown in sandbox. -** Typically the BTC/USD has the most activity in sandbox to test against. +Ensure Freqtrade logs show the sandbox URL, and trades made are shown in sandbox. Also make sure to select a pair which shows at least some decent value (which very often is BTC/). -## GDAX - Old Candles problem +## Common problems with sandbox exchanges -It is my experience that GDAX sandbox candles may be 20+- minutes out of date. This can cause trades to fail as one of Freqtrades safety checks. +Sandbox exchange instances often have very low volume, which can cause some problems which usually are not seen on a real exchange instance. -To disable this check, add / change the `"outdated_offset"` parameter in the exchange section of your configuration to adjust for this delay. -Example based on the above configuration: +### Old Candles problem -```json - "exchange": { - "name": "gdax", - "sandbox": true, - "key": "5wowfxemogxeowo;heiohgmd", - "secret": "/ZMH1P62rCVmwefewrgcewX8nh4gob+lywxfwfxwwfxwfNsH1ySgvWCUR/w==", - "password": "1bkjfkhfhfu6sr", - "outdated_offset": 30 - "pair_whitelist": [ - "BTC/USD" -``` +Since Sandboxes often have low volume, candles can be quite old and show no volume. +To disable the error "Outdated history for pair ...", best increase the parameter `"outdated_offset"` to a number that seems realistic for the sandbox you're using. From 8478e083dc6e3e0ec40721c71c580500ef2484fb Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 23 Aug 2020 21:16:44 +0200 Subject: [PATCH 199/285] Improve wording of sandbox documentation --- docs/sandbox-testing.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/sandbox-testing.md b/docs/sandbox-testing.md index bb075217f..9556dd014 100644 --- a/docs/sandbox-testing.md +++ b/docs/sandbox-testing.md @@ -3,7 +3,7 @@ Some exchanges provide sandboxes or testbeds for risk-free testing, while running the bot against a real exchange. With some configuration, freqtrade (in combination with ccxt) provides access to these. -This document is a light overview of configuring Freqtrade to be used with sandboxes. +This document is an overview to configure Freqtrade to be used with sandboxes. This can be useful to developers and trader alike. ## Exchanges known to have a sandbox / testnet @@ -22,14 +22,14 @@ This can be useful to developers and trader alike. ## Configure a Sandbox account -When testing your API connectivity, make sure to use the following URLs. +When testing your API connectivity, make sure to use the appropriate sandbox / testnet URL. In general, you should follow these steps to enable an exchange's sandbox: -- Figure out if an exchange has a sandbox (most likely by using google or the exchange's support documents) -- Create a sandbox account (often the sandbox-account requires separate registration) -- [Add some test assets to account](#add-test-funds) -- Create API keys +* Figure out if an exchange has a sandbox (most likely by using google or the exchange's support documents) +* Create a sandbox account (often the sandbox-account requires separate registration) +* [Add some test assets to account](#add-test-funds) +* Create API keys ### Add test funds @@ -37,7 +37,7 @@ Usually, sandbox exchanges allow depositing funds directly via web-interface. You should make sure to have a realistic amount of funds available to your test-account, so results are representable of your real account funds. !!! Warning - Test exchanges will NEVER require your real credit card or banking details! + Test exchanges will **NEVER** require your real credit card or banking details! ## Configure freqtrade to use a exchange's sandbox @@ -46,8 +46,8 @@ You should make sure to have a realistic amount of funds available to your test- Freqtrade makes use of CCXT which in turn provides a list of URLs to Freqtrade. These include `['test']` and `['api']`. -- `[Test]` if available will point to an Exchanges sandbox. -- `[Api]` normally used, and resolves to live API target on the exchange. +* `[Test]` if available will point to an Exchanges sandbox. +* `[Api]` normally used, and resolves to live API target on the exchange. To make use of sandbox / test add "sandbox": true, to your config.json @@ -68,9 +68,9 @@ To make use of sandbox / test add "sandbox": true, to your config.json Also the following information: -- api-key (created for the sandbox webpage) -- api-secret (noted earlier) -- password (the passphrase - noted earlier) +* api-key (created for the sandbox webpage) +* api-secret (noted earlier) +* password (the passphrase - noted earlier) !!! Tip "Different data directory" We also recommend to set `datadir` to something identifying downloaded data as sandbox data, to avoid having sandbox data mixed with data from the real exchange. From 5799cc51f28bf06f9b7f208250b9169d454d3162 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 06:44:50 +0000 Subject: [PATCH 200/285] Bump mkdocs-material from 5.5.7 to 5.5.8 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 5.5.7 to 5.5.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/5.5.7...5.5.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 ab5aebb79..5226db750 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,2 +1,2 @@ -mkdocs-material==5.5.7 +mkdocs-material==5.5.8 mdx_truly_sane_lists==1.2 From 4c48fe96edbc1e2528f980e1a0cc8c3e73b0c24d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 06:44:52 +0000 Subject: [PATCH 201/285] Bump pytest-mock from 3.2.0 to 3.3.0 Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/pytest-dev/pytest-mock/releases) - [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.2.0...v3.3.0) 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 3c10fe445..1f5b68a73 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,7 +11,7 @@ mypy==0.782 pytest==6.0.1 pytest-asyncio==0.14.0 pytest-cov==2.10.1 -pytest-mock==3.2.0 +pytest-mock==3.3.0 pytest-random-order==1.0.4 # Convert jupyter notebooks to markdown documents From 74c97369d9f6a57e577672ab6a6ba6803432b6f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 06:44:54 +0000 Subject: [PATCH 202/285] Bump arrow from 0.15.8 to 0.16.0 Bumps [arrow](https://github.com/arrow-py/arrow) from 0.15.8 to 0.16.0. - [Release notes](https://github.com/arrow-py/arrow/releases) - [Changelog](https://github.com/arrow-py/arrow/blob/master/CHANGELOG.rst) - [Commits](https://github.com/arrow-py/arrow/compare/0.15.8...0.16.0) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 712cf820d..7f81d6265 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -3,7 +3,7 @@ ccxt==1.33.18 SQLAlchemy==1.3.18 python-telegram-bot==12.8 -arrow==0.15.8 +arrow==0.16.0 cachetools==4.1.1 requests==2.24.0 urllib3==1.25.10 From 0e20b8f530f3b93cfb2eb0e70a969aaf52b5dbec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 06:45:12 +0000 Subject: [PATCH 203/285] Bump ccxt from 1.33.18 to 1.33.52 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.33.18 to 1.33.52. - [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.33.18...1.33.52) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 712cf820d..3cd764693 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.33.18 +ccxt==1.33.52 SQLAlchemy==1.3.18 python-telegram-bot==12.8 arrow==0.15.8 From f22fc8ef3ee05e39c00aec8d84914fa2f487aa5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 06:45:20 +0000 Subject: [PATCH 204/285] Bump pandas from 1.1.0 to 1.1.1 Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.1.0 to 1.1.1. - [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.1.0...v1.1.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 d65f90325..66f4cbc5f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ -r requirements-common.txt numpy==1.19.1 -pandas==1.1.0 +pandas==1.1.1 From 7ece7294b2a0d7431cea91a674b785bc3bd0e7c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 07:18:00 +0000 Subject: [PATCH 205/285] Bump sqlalchemy from 1.3.18 to 1.3.19 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.3.18 to 1.3.19. - [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-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 27a233604..b6e2d329f 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,7 +1,7 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs ccxt==1.33.52 -SQLAlchemy==1.3.18 +SQLAlchemy==1.3.19 python-telegram-bot==12.8 arrow==0.16.0 cachetools==4.1.1 From c272944834b73f6705ab92d6eef1e956e3666cb0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 24 Aug 2020 11:09:09 +0200 Subject: [PATCH 206/285] Lock pair until a new candle arrives --- freqtrade/freqtradebot.py | 5 ++-- freqtrade/strategy/interface.py | 20 +++++++++------ tests/strategy/test_interface.py | 43 ++++++++++++++++++++------------ 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 2fcb9f3f9..eee60cc22 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -433,7 +433,9 @@ class FreqtradeBot: """ logger.debug(f"create_trade for pair {pair}") - if self.strategy.is_pair_locked(pair): + analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(pair, self.strategy.timeframe) + if self.strategy.is_pair_locked( + pair, analyzed_df.iloc[-1]['date'] if len(analyzed_df) > 0 else None): logger.info(f"Pair {pair} is currently locked.") return False @@ -444,7 +446,6 @@ class FreqtradeBot: return False # running get_signal on historical data fetched - analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(pair, self.strategy.timeframe) (buy, sell) = self.strategy.get_signal(pair, self.strategy.timeframe, analyzed_df) if buy and not sell: diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index efc4b8430..4a3a78c8f 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -2,6 +2,7 @@ IStrategy interface This module defines the interface to apply for strategies """ +from freqtrade.exchange.exchange import timeframe_to_next_date import logging import warnings from abc import ABC, abstractmethod @@ -297,13 +298,22 @@ class IStrategy(ABC): if pair in self._pair_locked_until: del self._pair_locked_until[pair] - def is_pair_locked(self, pair: str) -> bool: + def is_pair_locked(self, pair: str, candle_date: datetime = None) -> bool: """ Checks if a pair is currently locked """ if pair not in self._pair_locked_until: return False - return self._pair_locked_until[pair] >= datetime.now(timezone.utc) + if not candle_date: + return self._pair_locked_until[pair] >= datetime.now(timezone.utc) + else: + # Locking should happen until a new candle arrives + lock_time = timeframe_to_next_date(self.timeframe, candle_date) + # lock_time = candle_date + timedelta(minutes=timeframe_to_minutes(self.timeframe)) + res = self._pair_locked_until[pair] > lock_time + logger.debug(f"pair time = {lock_time} - pair_lock = {self._pair_locked_until[pair]} " + f"- res: {res}") + return res def analyze_ticker(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ @@ -438,12 +448,6 @@ class IStrategy(ABC): ) return False, False - # Check if dataframe has new candle - if (arrow.utcnow() - latest_date).total_seconds() // 60 >= timeframe_minutes: - logger.warning('Old candle for pair %s. Last candle is %s minutes old', - pair, int((arrow.utcnow() - latest_date).total_seconds() // 60)) - return False, False - (buy, sell) = latest[SignalType.BUY.value] == 1, latest[SignalType.SELL.value] == 1 logger.debug('trigger: %s (pair=%s) buy=%s sell=%s', latest['date'], pair, str(buy), str(sell)) diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index bca7cc0d9..f1b5d0244 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -1,6 +1,7 @@ # pragma pylint: disable=missing-docstring, C0103 import logging +from datetime import datetime, timedelta, timezone from unittest.mock import MagicMock import arrow @@ -8,12 +9,12 @@ import pytest from pandas import DataFrame from freqtrade.configuration import TimeRange +from freqtrade.data.dataprovider import DataProvider from freqtrade.data.history import load_data from freqtrade.exceptions import StrategyError from freqtrade.persistence import Trade from freqtrade.resolvers import StrategyResolver from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper -from freqtrade.data.dataprovider import DataProvider from tests.conftest import log_has, log_has_re from .strats.default_strategy import DefaultStrategy @@ -87,21 +88,6 @@ def test_get_signal_exception_valueerror(default_conf, mocker, caplog, ohlcv_his assert log_has_re(r'Strategy caused the following exception: xyz.*', caplog) -def test_get_signal_old_candle(default_conf, mocker, caplog, ohlcv_history): - caplog.set_level(logging.INFO) - # default_conf defines a 5m interval. we check interval of previous candle - # this is necessary as the last candle is removed (partial candles) by default - oldtime = arrow.utcnow().shift(minutes=-10) - ticks = DataFrame([{'buy': 1, 'date': oldtime}]) - mocker.patch.object( - _STRATEGY, '_analyze_ticker_internal', - return_value=DataFrame(ticks) - ) - assert (False, False) == _STRATEGY.get_signal('xyz', default_conf['timeframe'], - ohlcv_history) - assert log_has('Old candle for pair xyz. Last candle is 10 minutes old', caplog) - - def test_get_signal_old_dataframe(default_conf, mocker, caplog, ohlcv_history): # default_conf defines a 5m interval. we check interval * 2 + 5m # this is necessary as the last candle is removed (partial candles) by default @@ -402,6 +388,31 @@ def test_is_pair_locked(default_conf): strategy.unlock_pair(pair) assert not strategy.is_pair_locked(pair) + pair = 'BTC/USDT' + # Lock until 14:30 + lock_time = datetime(2020, 5, 1, 14, 30, 0, tzinfo=timezone.utc) + strategy.lock_pair(pair, lock_time) + # Lock is in the past ... + assert not strategy.is_pair_locked(pair) + # latest candle is from 14:20, lock goes to 14:30 + assert strategy.is_pair_locked(pair, lock_time + timedelta(minutes=-10)) + assert strategy.is_pair_locked(pair, lock_time + timedelta(minutes=-50)) + + # latest candle is from 14:25 (lock should be lifted) + # Since this is the "new candle" available at 14:30 + assert not strategy.is_pair_locked(pair, lock_time + timedelta(minutes=-4)) + + # Should not be locked after time expired + assert not strategy.is_pair_locked(pair, lock_time + timedelta(minutes=10)) + + # Change timeframe to 15m + strategy.timeframe = '15m' + # Candle from 14:14 - lock goes until 14:30 + assert strategy.is_pair_locked(pair, lock_time + timedelta(minutes=-16)) + assert strategy.is_pair_locked(pair, lock_time + timedelta(minutes=-15, seconds=-2)) + # Candle from 14:15 - lock goes until 14:30 + assert not strategy.is_pair_locked(pair, lock_time + timedelta(minutes=-15)) + def test_is_informative_pairs_callback(default_conf): default_conf.update({'strategy': 'TestStrategyLegacy'}) From 502e21b2cb6da649c97a00b0a484a2ab1b1ba408 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 24 Aug 2020 11:17:27 +0200 Subject: [PATCH 207/285] Add unfilled explanation for sandboxes --- docs/sandbox-testing.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/sandbox-testing.md b/docs/sandbox-testing.md index 9556dd014..9c14412de 100644 --- a/docs/sandbox-testing.md +++ b/docs/sandbox-testing.md @@ -91,3 +91,27 @@ Sandbox exchange instances often have very low volume, which can cause some prob Since Sandboxes often have low volume, candles can be quite old and show no volume. To disable the error "Outdated history for pair ...", best increase the parameter `"outdated_offset"` to a number that seems realistic for the sandbox you're using. + +### Unfilled orders + +Sandboxes often have very low volumes - which means that many trades can go unfilled, or can go unfilled for a very long time. + +To mitigate this, you can try to match the first order on the opposite orderbook side using the following configuration: + +``` jsonc + "order_types": { + "buy": "limit", + "sell": "limit" + // ... + }, + "bid_strategy": { + "price_side": "ask", + // ... + }, + "ask_strategy":{ + "price_side": "bid", + // ... + }, + ``` + + The configuration is similar to the suggested configuration for market orders - however by using limit-orders you can avoid moving the price too much, and you can set the worst price you might get. From 354a40624866645b191dde458c857588c17a211b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 24 Aug 2020 11:44:32 +0200 Subject: [PATCH 208/285] Sort imports in interface.py --- freqtrade/strategy/interface.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 4a3a78c8f..9673b0c68 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -2,7 +2,6 @@ IStrategy interface This module defines the interface to apply for strategies """ -from freqtrade.exchange.exchange import timeframe_to_next_date import logging import warnings from abc import ABC, abstractmethod @@ -15,8 +14,9 @@ from pandas import DataFrame from freqtrade.constants import ListPairsWithTimeframes from freqtrade.data.dataprovider import DataProvider -from freqtrade.exceptions import StrategyError, OperationalException +from freqtrade.exceptions import OperationalException, StrategyError from freqtrade.exchange import timeframe_to_minutes +from freqtrade.exchange.exchange import timeframe_to_next_date from freqtrade.persistence import Trade from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.wallets import Wallets @@ -310,10 +310,7 @@ class IStrategy(ABC): # Locking should happen until a new candle arrives lock_time = timeframe_to_next_date(self.timeframe, candle_date) # lock_time = candle_date + timedelta(minutes=timeframe_to_minutes(self.timeframe)) - res = self._pair_locked_until[pair] > lock_time - logger.debug(f"pair time = {lock_time} - pair_lock = {self._pair_locked_until[pair]} " - f"- res: {res}") - return res + return self._pair_locked_until[pair] > lock_time def analyze_ticker(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ From fca11160e443470aea767bb4e7d43c021fd5d149 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 24 Aug 2020 17:18:57 +0200 Subject: [PATCH 209/285] Improve docstring of is_pair_locked --- freqtrade/strategy/interface.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 9673b0c68..69d9333e2 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -301,6 +301,11 @@ class IStrategy(ABC): def is_pair_locked(self, pair: str, candle_date: datetime = None) -> bool: """ Checks if a pair is currently locked + The 2nd, optional parameter ensures that locks are applied until the new candle arrives, + and not stop at 14:00:00 - while the next candle arrives at 14:00:02 leaving a gap + of 2 seconds for a buy to happen on an old signal. + :param: pair: "Pair to check" + :param candle_date: Date of the last candle. Optional, defaults to current date """ if pair not in self._pair_locked_until: return False From 3bb69bc1bd5b78498a9c2d236a7f32a9779dc322 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 24 Aug 2020 17:31:00 +0200 Subject: [PATCH 210/285] Add returns statement to docstring --- freqtrade/strategy/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 69d9333e2..92d9f6c48 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -306,6 +306,7 @@ class IStrategy(ABC): of 2 seconds for a buy to happen on an old signal. :param: pair: "Pair to check" :param candle_date: Date of the last candle. Optional, defaults to current date + :returns: locking state of the pair in question. """ if pair not in self._pair_locked_until: return False From 9d4ecb625a004a45dc58c0f942394f0f4b80d277 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 07:16:29 +0200 Subject: [PATCH 211/285] Allow numpy numbers as comparisons, too --- freqtrade/vendor/qtpylib/indicators.py | 2 +- tests/test_indicators.py | 18 ++++++++++++++++++ tests/test_talib.py | 2 -- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 tests/test_indicators.py diff --git a/freqtrade/vendor/qtpylib/indicators.py b/freqtrade/vendor/qtpylib/indicators.py index bef140396..e5a404862 100644 --- a/freqtrade/vendor/qtpylib/indicators.py +++ b/freqtrade/vendor/qtpylib/indicators.py @@ -222,7 +222,7 @@ def crossed(series1, series2, direction=None): if isinstance(series1, np.ndarray): series1 = pd.Series(series1) - if isinstance(series2, (float, int, np.ndarray)): + if isinstance(series2, (float, int, np.ndarray, np.integer, np.floating)): series2 = pd.Series(index=series1.index, data=series2) if direction is None or direction == "above": diff --git a/tests/test_indicators.py b/tests/test_indicators.py new file mode 100644 index 000000000..2f9bdc0f9 --- /dev/null +++ b/tests/test_indicators.py @@ -0,0 +1,18 @@ +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy as np +import pandas as pd + + +def test_crossed_numpy_types(): + """ + This test is only present since this method currently diverges from the qtpylib implementation. + And we must ensure to not break this again once we update from the original source. + """ + series = pd.Series([56, 97, 19, 76, 65, 25, 87, 91, 79, 79]) + expected_result = pd.Series([False, True, False, True, False, False, True, False, False, False]) + + assert qtpylib.crossed_above(series, 60).equals(expected_result) + assert qtpylib.crossed_above(series, 60.0).equals(expected_result) + assert qtpylib.crossed_above(series, np.int32(60)).equals(expected_result) + assert qtpylib.crossed_above(series, np.int64(60)).equals(expected_result) + assert qtpylib.crossed_above(series, np.float64(60.0)).equals(expected_result) diff --git a/tests/test_talib.py b/tests/test_talib.py index 2c7f73eb1..4effc129b 100644 --- a/tests/test_talib.py +++ b/tests/test_talib.py @@ -1,5 +1,3 @@ - - import talib.abstract as ta import pandas as pd From 309ea1246aab34310aa9cf8aef32170bb5b3ccac Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 20:52:09 +0200 Subject: [PATCH 212/285] Update config to use single quotes --- freqtrade/commands/data_commands.py | 16 +-- freqtrade/commands/deploy_commands.py | 8 +- freqtrade/configuration/configuration.py | 40 +++---- freqtrade/data/btanalysis.py | 2 +- freqtrade/exchange/exchange.py | 4 +- freqtrade/plot/plotting.py | 22 ++-- scripts/rest_client.py | 10 +- tests/conftest.py | 2 +- tests/rpc/test_rpc_apiserver.py | 10 +- tests/test_arguments.py | 132 +++++++++++------------ tests/test_configuration.py | 2 +- tests/test_main.py | 14 +-- tests/test_plotting.py | 12 +-- 13 files changed, 137 insertions(+), 137 deletions(-) diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index aa0b826b5..da1eb0cf5 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -35,8 +35,8 @@ def start_download_data(args: Dict[str, Any]) -> None: "Downloading data requires a list of pairs. " "Please check the documentation on how to configure this.") - logger.info(f'About to download pairs: {config["pairs"]}, ' - f'intervals: {config["timeframes"]} to {config["datadir"]}') + logger.info(f"About to download pairs: {config['pairs']}, " + f"intervals: {config['timeframes']} to {config['datadir']}") pairs_not_available: List[str] = [] @@ -51,21 +51,21 @@ def start_download_data(args: Dict[str, Any]) -> None: if config.get('download_trades'): pairs_not_available = refresh_backtest_trades_data( - exchange, pairs=config["pairs"], datadir=config['datadir'], - timerange=timerange, erase=bool(config.get("erase")), + exchange, pairs=config['pairs'], datadir=config['datadir'], + timerange=timerange, erase=bool(config.get('erase')), data_format=config['dataformat_trades']) # Convert downloaded trade data to different timeframes convert_trades_to_ohlcv( - pairs=config["pairs"], timeframes=config["timeframes"], - datadir=config['datadir'], timerange=timerange, erase=bool(config.get("erase")), + pairs=config['pairs'], timeframes=config['timeframes'], + datadir=config['datadir'], timerange=timerange, erase=bool(config.get('erase')), data_format_ohlcv=config['dataformat_ohlcv'], data_format_trades=config['dataformat_trades'], ) else: pairs_not_available = refresh_backtest_ohlcv_data( - exchange, pairs=config["pairs"], timeframes=config["timeframes"], - datadir=config['datadir'], timerange=timerange, erase=bool(config.get("erase")), + exchange, pairs=config['pairs'], timeframes=config['timeframes'], + datadir=config['datadir'], timerange=timerange, erase=bool(config.get('erase')), data_format=config['dataformat_ohlcv']) except KeyboardInterrupt: diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index 86562fa7c..bfd68cb9b 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -75,7 +75,7 @@ def start_new_strategy(args: Dict[str, Any]) -> None: if args["strategy"] == "DefaultStrategy": raise OperationalException("DefaultStrategy is not allowed as name.") - new_path = config['user_data_dir'] / USERPATH_STRATEGIES / (args["strategy"] + ".py") + new_path = config['user_data_dir'] / USERPATH_STRATEGIES / (args['strategy'] + '.py') if new_path.exists(): raise OperationalException(f"`{new_path}` already exists. " @@ -125,11 +125,11 @@ def start_new_hyperopt(args: Dict[str, Any]) -> None: config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) - if "hyperopt" in args and args["hyperopt"]: - if args["hyperopt"] == "DefaultHyperopt": + if 'hyperopt' in args and args['hyperopt']: + if args['hyperopt'] == 'DefaultHyperopt': raise OperationalException("DefaultHyperopt is not allowed as name.") - new_path = config['user_data_dir'] / USERPATH_HYPEROPTS / (args["hyperopt"] + ".py") + new_path = config['user_data_dir'] / USERPATH_HYPEROPTS / (args['hyperopt'] + '.py') if new_path.exists(): raise OperationalException(f"`{new_path}` already exists. " diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 01e42144a..930917fae 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -54,7 +54,7 @@ class Configuration: :param files: List of file paths :return: configuration dictionary """ - c = Configuration({"config": files}, RunMode.OTHER) + c = Configuration({'config': files}, RunMode.OTHER) return c.get_config() def load_from_files(self, files: List[str]) -> Dict[str, Any]: @@ -123,10 +123,10 @@ class Configuration: the -v/--verbose, --logfile options """ # Log level - config.update({'verbosity': self.args.get("verbosity", 0)}) + config.update({'verbosity': self.args.get('verbosity', 0)}) - if 'logfile' in self.args and self.args["logfile"]: - config.update({'logfile': self.args["logfile"]}) + if 'logfile' in self.args and self.args['logfile']: + config.update({'logfile': self.args['logfile']}) setup_logging(config) @@ -149,22 +149,22 @@ class Configuration: def _process_common_options(self, config: Dict[str, Any]) -> None: # Set strategy if not specified in config and or if it's non default - if self.args.get("strategy") or not config.get('strategy'): - config.update({'strategy': self.args.get("strategy")}) + if self.args.get('strategy') or not config.get('strategy'): + config.update({'strategy': self.args.get('strategy')}) self._args_to_config(config, argname='strategy_path', logstring='Using additional Strategy lookup path: {}') - if ('db_url' in self.args and self.args["db_url"] and - self.args["db_url"] != constants.DEFAULT_DB_PROD_URL): - config.update({'db_url': self.args["db_url"]}) + if ('db_url' in self.args and self.args['db_url'] and + self.args['db_url'] != constants.DEFAULT_DB_PROD_URL): + config.update({'db_url': self.args['db_url']}) logger.info('Parameter --db-url detected ...') if config.get('forcebuy_enable', False): logger.warning('`forcebuy` RPC message enabled.') # Support for sd_notify - if 'sd_notify' in self.args and self.args["sd_notify"]: + if 'sd_notify' in self.args and self.args['sd_notify']: config['internals'].update({'sd_notify': True}) def _process_datadir_options(self, config: Dict[str, Any]) -> None: @@ -173,24 +173,24 @@ class Configuration: --user-data, --datadir """ # Check exchange parameter here - otherwise `datadir` might be wrong. - if "exchange" in self.args and self.args["exchange"]: - config['exchange']['name'] = self.args["exchange"] + if 'exchange' in self.args and self.args['exchange']: + config['exchange']['name'] = self.args['exchange'] logger.info(f"Using exchange {config['exchange']['name']}") if 'pair_whitelist' not in config['exchange']: config['exchange']['pair_whitelist'] = [] - if 'user_data_dir' in self.args and self.args["user_data_dir"]: - config.update({'user_data_dir': self.args["user_data_dir"]}) + if 'user_data_dir' in self.args and self.args['user_data_dir']: + config.update({'user_data_dir': self.args['user_data_dir']}) elif 'user_data_dir' not in config: # Default to cwd/user_data (legacy option ...) - config.update({'user_data_dir': str(Path.cwd() / "user_data")}) + config.update({'user_data_dir': str(Path.cwd() / 'user_data')}) # reset to user_data_dir so this contains the absolute path. config['user_data_dir'] = create_userdata_dir(config['user_data_dir'], create_dir=False) logger.info('Using user-data directory: %s ...', config['user_data_dir']) - config.update({'datadir': create_datadir(config, self.args.get("datadir", None))}) + config.update({'datadir': create_datadir(config, self.args.get('datadir', None))}) logger.info('Using data directory: %s ...', config.get('datadir')) if self.args.get('exportfilename'): @@ -219,8 +219,8 @@ class Configuration: config.update({'use_max_market_positions': False}) logger.info('Parameter --disable-max-market-positions detected ...') logger.info('max_open_trades set to unlimited ...') - elif 'max_open_trades' in self.args and self.args["max_open_trades"]: - config.update({'max_open_trades': self.args["max_open_trades"]}) + elif 'max_open_trades' in self.args and self.args['max_open_trades']: + config.update({'max_open_trades': self.args['max_open_trades']}) logger.info('Parameter --max-open-trades detected, ' 'overriding max_open_trades to: %s ...', config.get('max_open_trades')) elif config['runmode'] in NON_UTIL_MODES: @@ -447,12 +447,12 @@ class Configuration: config['pairs'].sort() return - if "config" in self.args and self.args["config"]: + if 'config' in self.args and self.args['config']: logger.info("Using pairlist from configuration.") config['pairs'] = config.get('exchange', {}).get('pair_whitelist') else: # Fall back to /dl_path/pairs.json - pairs_file = config['datadir'] / "pairs.json" + pairs_file = config['datadir'] / 'pairs.json' if pairs_file.exists(): with pairs_file.open('r') as f: config['pairs'] = json_load(f) diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 972961b36..2d45a7222 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -208,7 +208,7 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF def load_trades(source: str, db_url: str, exportfilename: Path, no_trades: bool = False, strategy: Optional[str] = None) -> pd.DataFrame: """ - Based on configuration option "trade_source": + Based on configuration option 'trade_source': * loads data from DB (using `db_url`) * loads data from backtestfile (using `exportfilename`) :param source: "DB" or "file" - specify source to load from diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index c9c5a0027..d84fe7b82 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -85,8 +85,8 @@ class Exchange: # Deep merge ft_has with default ft_has options self._ft_has = deep_merge_dicts(self._ft_has, deepcopy(self._ft_has_default)) - if exchange_config.get("_ft_has_params"): - self._ft_has = deep_merge_dicts(exchange_config.get("_ft_has_params"), + if exchange_config.get('_ft_has_params'): + self._ft_has = deep_merge_dicts(exchange_config.get('_ft_has_params'), self._ft_has) logger.info("Overriding exchange._ft_has with config params, result: %s", self._ft_has) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index b420db770..270fe615b 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -38,15 +38,15 @@ def init_plotscript(config): """ if "pairs" in config: - pairs = config["pairs"] + pairs = config['pairs'] else: - pairs = config["exchange"]["pair_whitelist"] + pairs = config['exchange']['pair_whitelist'] # Set timerange to use - timerange = TimeRange.parse_timerange(config.get("timerange")) + timerange = TimeRange.parse_timerange(config.get('timerange')) data = load_data( - datadir=config.get("datadir"), + datadir=config.get('datadir'), pairs=pairs, timeframe=config.get('timeframe', '5m'), timerange=timerange, @@ -67,7 +67,7 @@ def init_plotscript(config): db_url=config.get('db_url'), exportfilename=filename, no_trades=no_trades, - strategy=config.get("strategy"), + strategy=config.get('strategy'), ) trades = trim_dataframe(trades, timerange, 'open_date') @@ -491,13 +491,13 @@ def load_and_plot_trades(config: Dict[str, Any]): pair=pair, data=df_analyzed, trades=trades_pair, - indicators1=config.get("indicators1", []), - indicators2=config.get("indicators2", []), + indicators1=config.get('indicators1', []), + indicators2=config.get('indicators2', []), plot_config=strategy.plot_config if hasattr(strategy, 'plot_config') else {} ) store_plot_file(fig, filename=generate_plot_filename(pair, config['timeframe']), - directory=config['user_data_dir'] / "plot") + directory=config['user_data_dir'] / 'plot') logger.info('End of plotting process. %s plots generated', pair_counter) @@ -514,7 +514,7 @@ def plot_profit(config: Dict[str, Any]) -> None: # Filter trades to relevant pairs # Remove open pairs - we don't know the profit yet so can't calculate profit for these. # Also, If only one open pair is left, then the profit-generation would fail. - trades = trades[(trades['pair'].isin(plot_elements["pairs"])) + trades = trades[(trades['pair'].isin(plot_elements['pairs'])) & (~trades['close_date'].isnull()) ] if len(trades) == 0: @@ -523,7 +523,7 @@ def plot_profit(config: Dict[str, Any]) -> None: # Create an average close price of all the pairs that were involved. # this could be useful to gauge the overall market trend - fig = generate_profit_graph(plot_elements["pairs"], plot_elements["ohlcv"], + fig = generate_profit_graph(plot_elements['pairs'], plot_elements['ohlcv'], trades, config.get('timeframe', '5m')) store_plot_file(fig, filename='freqtrade-profit-plot.html', - directory=config['user_data_dir'] / "plot", auto_open=True) + directory=config['user_data_dir'] / 'plot', auto_open=True) diff --git a/scripts/rest_client.py b/scripts/rest_client.py index 51ea596f6..598a82040 100755 --- a/scripts/rest_client.py +++ b/scripts/rest_client.py @@ -276,11 +276,11 @@ def main(args): print_commands() sys.exit() - config = load_config(args["config"]) - url = config.get("api_server", {}).get("server_url", "127.0.0.1") - port = config.get("api_server", {}).get("listen_port", "8080") - username = config.get("api_server", {}).get("username") - password = config.get("api_server", {}).get("password") + config = load_config(args['config']) + url = config.get('api_server', {}).get('server_url', '127.0.0.1') + port = config.get('api_server', {}).get('listen_port', '8080') + username = config.get('api_server', {}).get('username') + password = config.get('api_server', {}).get('password') server_url = f"http://{url}:{port}" client = FtRestClient(server_url, username, password) diff --git a/tests/conftest.py b/tests/conftest.py index a40bfbc6c..dbed08ec5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -78,7 +78,7 @@ def patch_exchange(mocker, api_mock=None, id='bittrex', mock_markets=True) -> No def get_patched_exchange(mocker, config, api_mock=None, id='bittrex', mock_markets=True) -> Exchange: patch_exchange(mocker, api_mock, id, mock_markets) - config["exchange"]["name"] = id + config['exchange']['name'] = id try: exchange = ExchangeResolver.load_exchange(id, config) except ImportError: diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index a3a2c9a1f..2513f751b 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -87,20 +87,20 @@ def test_api_unauthorized(botclient): assert rc.json == {'error': 'Unauthorized'} # Change only username - ftbot.config['api_server']['username'] = "Ftrader" + ftbot.config['api_server']['username'] = 'Ftrader' rc = client_get(client, f"{BASE_URI}/version") assert_response(rc, 401) assert rc.json == {'error': 'Unauthorized'} # Change only password ftbot.config['api_server']['username'] = _TEST_USER - ftbot.config['api_server']['password'] = "WrongPassword" + ftbot.config['api_server']['password'] = 'WrongPassword' rc = client_get(client, f"{BASE_URI}/version") assert_response(rc, 401) assert rc.json == {'error': 'Unauthorized'} - ftbot.config['api_server']['username'] = "Ftrader" - ftbot.config['api_server']['password'] = "WrongPassword" + ftbot.config['api_server']['username'] = 'Ftrader' + ftbot.config['api_server']['password'] = 'WrongPassword' rc = client_get(client, f"{BASE_URI}/version") assert_response(rc, 401) @@ -677,7 +677,7 @@ def test_api_forcebuy(botclient, mocker, fee): assert rc.json == {"error": "Error querying _forcebuy: Forcebuy not enabled."} # enable forcebuy - ftbot.config["forcebuy_enable"] = True + ftbot.config['forcebuy_enable'] = True fbuy_mock = MagicMock(return_value=None) mocker.patch("freqtrade.rpc.RPC._rpc_forcebuy", fbuy_mock) diff --git a/tests/test_arguments.py b/tests/test_arguments.py index 457683598..2af36277b 100644 --- a/tests/test_arguments.py +++ b/tests/test_arguments.py @@ -19,64 +19,64 @@ def test_parse_args_none() -> None: def test_parse_args_defaults(mocker) -> None: - mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True])) + mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[False, True])) args = Arguments(['trade']).get_parsed_arg() - assert args["config"] == ['config.json'] - assert args["strategy_path"] is None - assert args["datadir"] is None - assert args["verbosity"] == 0 + assert args['config'] == ['config.json'] + assert args['strategy_path'] is None + assert args['datadir'] is None + assert args['verbosity'] == 0 def test_parse_args_default_userdatadir(mocker) -> None: - mocker.patch.object(Path, "is_file", MagicMock(return_value=True)) + mocker.patch.object(Path, 'is_file', MagicMock(return_value=True)) args = Arguments(['trade']).get_parsed_arg() # configuration defaults to user_data if that is available. - assert args["config"] == [str(Path('user_data/config.json'))] - assert args["strategy_path"] is None - assert args["datadir"] is None - assert args["verbosity"] == 0 + assert args['config'] == [str(Path('user_data/config.json'))] + assert args['strategy_path'] is None + assert args['datadir'] is None + assert args['verbosity'] == 0 def test_parse_args_userdatadir(mocker) -> None: - mocker.patch.object(Path, "is_file", MagicMock(return_value=True)) + mocker.patch.object(Path, 'is_file', MagicMock(return_value=True)) args = Arguments(['trade', '--user-data-dir', 'user_data']).get_parsed_arg() # configuration defaults to user_data if that is available. - assert args["config"] == [str(Path('user_data/config.json'))] - assert args["strategy_path"] is None - assert args["datadir"] is None - assert args["verbosity"] == 0 + assert args['config'] == [str(Path('user_data/config.json'))] + assert args['strategy_path'] is None + assert args['datadir'] is None + assert args['verbosity'] == 0 def test_parse_args_config() -> None: args = Arguments(['trade', '-c', '/dev/null']).get_parsed_arg() - assert args["config"] == ['/dev/null'] + assert args['config'] == ['/dev/null'] args = Arguments(['trade', '--config', '/dev/null']).get_parsed_arg() - assert args["config"] == ['/dev/null'] + assert args['config'] == ['/dev/null'] args = Arguments(['trade', '--config', '/dev/null', '--config', '/dev/zero'],).get_parsed_arg() - assert args["config"] == ['/dev/null', '/dev/zero'] + assert args['config'] == ['/dev/null', '/dev/zero'] def test_parse_args_db_url() -> None: args = Arguments(['trade', '--db-url', 'sqlite:///test.sqlite']).get_parsed_arg() - assert args["db_url"] == 'sqlite:///test.sqlite' + assert args['db_url'] == 'sqlite:///test.sqlite' def test_parse_args_verbose() -> None: args = Arguments(['trade', '-v']).get_parsed_arg() - assert args["verbosity"] == 1 + assert args['verbosity'] == 1 args = Arguments(['trade', '--verbose']).get_parsed_arg() - assert args["verbosity"] == 1 + assert args['verbosity'] == 1 def test_common_scripts_options() -> None: args = Arguments(['download-data', '-p', 'ETH/BTC', 'XRP/BTC']).get_parsed_arg() - assert args["pairs"] == ['ETH/BTC', 'XRP/BTC'] - assert "func" in args + assert args['pairs'] == ['ETH/BTC', 'XRP/BTC'] + assert 'func' in args def test_parse_args_version() -> None: @@ -91,7 +91,7 @@ def test_parse_args_invalid() -> None: def test_parse_args_strategy() -> None: args = Arguments(['trade', '--strategy', 'SomeStrategy']).get_parsed_arg() - assert args["strategy"] == 'SomeStrategy' + assert args['strategy'] == 'SomeStrategy' def test_parse_args_strategy_invalid() -> None: @@ -101,7 +101,7 @@ def test_parse_args_strategy_invalid() -> None: def test_parse_args_strategy_path() -> None: args = Arguments(['trade', '--strategy-path', '/some/path']).get_parsed_arg() - assert args["strategy_path"] == '/some/path' + assert args['strategy_path'] == '/some/path' def test_parse_args_strategy_path_invalid() -> None: @@ -127,13 +127,13 @@ def test_parse_args_backtesting_custom() -> None: 'SampleStrategy' ] call_args = Arguments(args).get_parsed_arg() - assert call_args["config"] == ['test_conf.json'] - assert call_args["verbosity"] == 0 - assert call_args["command"] == 'backtesting' - assert call_args["func"] is not None - assert call_args["timeframe"] == '1m' - assert type(call_args["strategy_list"]) is list - assert len(call_args["strategy_list"]) == 2 + assert call_args['config'] == ['test_conf.json'] + assert call_args['verbosity'] == 0 + assert call_args['command'] == 'backtesting' + assert call_args['func'] is not None + assert call_args['timeframe'] == '1m' + assert type(call_args['strategy_list']) is list + assert len(call_args['strategy_list']) == 2 def test_parse_args_hyperopt_custom() -> None: @@ -144,13 +144,13 @@ def test_parse_args_hyperopt_custom() -> None: '--spaces', 'buy' ] call_args = Arguments(args).get_parsed_arg() - assert call_args["config"] == ['test_conf.json'] - assert call_args["epochs"] == 20 - assert call_args["verbosity"] == 0 - assert call_args["command"] == 'hyperopt' - assert call_args["spaces"] == ['buy'] - assert call_args["func"] is not None - assert callable(call_args["func"]) + assert call_args['config'] == ['test_conf.json'] + assert call_args['epochs'] == 20 + assert call_args['verbosity'] == 0 + assert call_args['command'] == 'hyperopt' + assert call_args['spaces'] == ['buy'] + assert call_args['func'] is not None + assert callable(call_args['func']) def test_download_data_options() -> None: @@ -163,10 +163,10 @@ def test_download_data_options() -> None: ] pargs = Arguments(args).get_parsed_arg() - assert pargs["pairs_file"] == 'file_with_pairs' - assert pargs["datadir"] == 'datadir/directory' - assert pargs["days"] == 30 - assert pargs["exchange"] == 'binance' + assert pargs['pairs_file'] == 'file_with_pairs' + assert pargs['datadir'] == 'datadir/directory' + assert pargs['days'] == 30 + assert pargs['exchange'] == 'binance' def test_plot_dataframe_options() -> None: @@ -180,10 +180,10 @@ def test_plot_dataframe_options() -> None: ] pargs = Arguments(args).get_parsed_arg() - assert pargs["indicators1"] == ["sma10", "sma100"] - assert pargs["indicators2"] == ["macd", "fastd", "fastk"] - assert pargs["plot_limit"] == 30 - assert pargs["pairs"] == ["UNITTEST/BTC"] + assert pargs['indicators1'] == ['sma10', 'sma100'] + assert pargs['indicators2'] == ['macd', 'fastd', 'fastk'] + assert pargs['plot_limit'] == 30 + assert pargs['pairs'] == ['UNITTEST/BTC'] def test_plot_profit_options() -> None: @@ -191,66 +191,66 @@ def test_plot_profit_options() -> None: 'plot-profit', '-p', 'UNITTEST/BTC', '--trade-source', 'DB', - "--db-url", "sqlite:///whatever.sqlite", + '--db-url', 'sqlite:///whatever.sqlite', ] pargs = Arguments(args).get_parsed_arg() - assert pargs["trade_source"] == "DB" - assert pargs["pairs"] == ["UNITTEST/BTC"] - assert pargs["db_url"] == "sqlite:///whatever.sqlite" + assert pargs['trade_source'] == 'DB' + assert pargs['pairs'] == ['UNITTEST/BTC'] + assert pargs['db_url'] == 'sqlite:///whatever.sqlite' def test_config_notallowed(mocker) -> None: - mocker.patch.object(Path, "is_file", MagicMock(return_value=False)) + mocker.patch.object(Path, 'is_file', MagicMock(return_value=False)) args = [ 'create-userdir', ] pargs = Arguments(args).get_parsed_arg() - assert "config" not in pargs + assert 'config' not in pargs # When file exists: - mocker.patch.object(Path, "is_file", MagicMock(return_value=True)) + mocker.patch.object(Path, 'is_file', MagicMock(return_value=True)) args = [ 'create-userdir', ] pargs = Arguments(args).get_parsed_arg() # config is not added even if it exists, since create-userdir is in the notallowed list - assert "config" not in pargs + assert 'config' not in pargs def test_config_notrequired(mocker) -> None: - mocker.patch.object(Path, "is_file", MagicMock(return_value=False)) + mocker.patch.object(Path, 'is_file', MagicMock(return_value=False)) args = [ 'download-data', ] pargs = Arguments(args).get_parsed_arg() - assert pargs["config"] is None + assert pargs['config'] is None # When file exists: - mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True])) + mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[False, True])) args = [ 'download-data', ] pargs = Arguments(args).get_parsed_arg() # config is added if it exists - assert pargs["config"] == ['config.json'] + assert pargs['config'] == ['config.json'] def test_check_int_positive() -> None: - assert check_int_positive("3") == 3 - assert check_int_positive("1") == 1 - assert check_int_positive("100") == 100 + assert check_int_positive('3') == 3 + assert check_int_positive('1') == 1 + assert check_int_positive('100') == 100 with pytest.raises(argparse.ArgumentTypeError): - check_int_positive("-2") + check_int_positive('-2') with pytest.raises(argparse.ArgumentTypeError): - check_int_positive("0") + check_int_positive('0') with pytest.raises(argparse.ArgumentTypeError): - check_int_positive("3.5") + check_int_positive('3.5') with pytest.raises(argparse.ArgumentTypeError): - check_int_positive("DeadBeef") + check_int_positive('DeadBeef') diff --git a/tests/test_configuration.py b/tests/test_configuration.py index ca5d6eadc..8549f00c9 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -1005,7 +1005,7 @@ def test_pairlist_resolving_fallback(mocker): args = Arguments(arglist).get_parsed_arg() # Fix flaky tests if config.json exists - args["config"] = None + args['config'] = None configuration = Configuration(args, RunMode.OTHER) config = configuration.get_config() diff --git a/tests/test_main.py b/tests/test_main.py index d5309ae3f..dd0c877e8 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -44,19 +44,19 @@ def test_parse_args_backtesting(mocker) -> None: def test_main_start_hyperopt(mocker) -> None: - mocker.patch.object(Path, "is_file", MagicMock(side_effect=[False, True])) + mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[False, True])) hyperopt_mock = mocker.patch('freqtrade.commands.start_hyperopt', MagicMock()) - hyperopt_mock.__name__ = PropertyMock("start_hyperopt") + hyperopt_mock.__name__ = PropertyMock('start_hyperopt') # it's sys.exit(0) at the end of hyperopt with pytest.raises(SystemExit): main(['hyperopt']) assert hyperopt_mock.call_count == 1 call_args = hyperopt_mock.call_args[0][0] - assert call_args["config"] == ['config.json'] - assert call_args["verbosity"] == 0 - assert call_args["command"] == 'hyperopt' - assert call_args["func"] is not None - assert callable(call_args["func"]) + assert call_args['config'] == ['config.json'] + assert call_args['verbosity'] == 0 + assert call_args['command'] == 'hyperopt' + assert call_args['func'] is not None + assert callable(call_args['func']) def test_main_fatal_exception(mocker, default_conf, caplog) -> None: diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 28c486877..bcababbf1 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -362,22 +362,22 @@ def test_start_plot_profit(mocker): def test_start_plot_profit_error(mocker): args = [ - "plot-profit", - "--pairs", "ETH/BTC" + 'plot-profit', + '--pairs', 'ETH/BTC' ] argsp = get_args(args) # Make sure we use no config. Details: #2241 # not resetting config causes random failures if config.json exists - argsp["config"] = [] + argsp['config'] = [] with pytest.raises(OperationalException): start_plot_profit(argsp) def test_plot_profit(default_conf, mocker, testdatadir, caplog): default_conf['trade_source'] = 'file' - default_conf["datadir"] = testdatadir - default_conf['exportfilename'] = testdatadir / "backtest-result_test_nofile.json" - default_conf['pairs'] = ["ETH/BTC", "LTC/BTC"] + default_conf['datadir'] = testdatadir + default_conf['exportfilename'] = testdatadir / 'backtest-result_test_nofile.json' + default_conf['pairs'] = ['ETH/BTC', 'LTC/BTC'] profit_mock = MagicMock() store_mock = MagicMock() From d161b94d7241e9f5c5bc873a8e8f1282aba1738e Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 21:22:36 +0200 Subject: [PATCH 213/285] Allow simulating cancelled orders in dry-run --- freqtrade/exchange/exchange.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index d84fe7b82..b89da14eb 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -973,7 +973,12 @@ class Exchange: @retrier def cancel_order(self, order_id: str, pair: str) -> Dict: if self._config['dry_run']: - return {} + order = self._dry_run_open_orders.get(order_id) + if order: + order.update({'status': 'canceled', 'filled': 0.0, 'remaining': order['amount']}) + return order + else: + return {} try: return self._api.cancel_order(order_id, pair) From add78414e4c9aa1d1b3a9847d3ae0a20fb332e1d Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 21:24:47 +0200 Subject: [PATCH 214/285] Don't overwrite cancel_reason --- freqtrade/constants.py | 1 + freqtrade/freqtradebot.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 1f8cebd0d..f44be220e 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -341,6 +341,7 @@ CANCEL_REASON = { "PARTIALLY_FILLED": "partially filled - keeping order open", "ALL_CANCELLED": "cancelled (all unfilled and partially filled open orders cancelled)", "CANCELLED_ON_EXCHANGE": "cancelled on exchange", + "FORCE_SELL": "forcesold", } # List of pairs with their timeframes diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index eee60cc22..917bb356f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -974,7 +974,8 @@ class FreqtradeBot: # Cancelled orders may have the status of 'canceled' or 'closed' if order['status'] not in ('canceled', 'closed'): - reason = constants.CANCEL_REASON['TIMEOUT'] + # TODO: this reason will overwrite the input in all cases + # reason = constants.CANCEL_REASON['TIMEOUT'] corder = self.exchange.cancel_order_with_result(trade.open_order_id, trade.pair, trade.amount) # Avoid race condition where the order could not be cancelled coz its already filled. From 85e71275d3c555b04a7ab8bb15269c0a6711830f Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 21:27:09 +0200 Subject: [PATCH 215/285] Simplify forcesell method by using freqtrade methods --- freqtrade/rpc/rpc.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 12e79d35b..25a85ac02 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -11,6 +11,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union import arrow from numpy import NAN, mean +from freqtrade.constants import CANCEL_REASON from freqtrade.exceptions import (ExchangeError, PricingError) from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs @@ -453,29 +454,22 @@ class RPC: """ def _exec_forcesell(trade: Trade) -> None: # Check if there is there is an open order + fully_canceled = False if trade.open_order_id: order = self._freqtrade.exchange.fetch_order(trade.open_order_id, trade.pair) - # Cancel open LIMIT_BUY orders and close trade - if order and order['status'] == 'open' \ - and order['type'] == 'limit' \ - and order['side'] == 'buy': - self._freqtrade.exchange.cancel_order(trade.open_order_id, trade.pair) - trade.close(order.get('price') or trade.open_rate) - # Do the best effort, if we don't know 'filled' amount, don't try selling - if order['filled'] is None: - return - trade.amount = order['filled'] + if order['side'] == 'buy': + fully_canceled = self._freqtrade.handle_cancel_buy( + trade, order, CANCEL_REASON['FORCE_SELL']) - # Ignore trades with an attached LIMIT_SELL order - if order and order['status'] == 'open' \ - and order['type'] == 'limit' \ - and order['side'] == 'sell': - return + if order['side'] == 'sell': + # Cancel order - so it is placed anew with a fresh price. + self._freqtrade.handle_cancel_sell(trade, order, CANCEL_REASON['FORCE_SELL']) - # Get current rate and execute sell - current_rate = self._freqtrade.get_sell_rate(trade.pair, False) - self._freqtrade.execute_sell(trade, current_rate, SellType.FORCE_SELL) + if not fully_canceled: + # Get current rate and execute sell + current_rate = self._freqtrade.get_sell_rate(trade.pair, False) + self._freqtrade.execute_sell(trade, current_rate, SellType.FORCE_SELL) # ---- EOF def _exec_forcesell ---- if self._freqtrade.state != State.RUNNING: From 5e75caa91778908abd14bbd8bcfc4c59e2d0c2ec Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 21:37:52 +0200 Subject: [PATCH 216/285] Adjust tests to new forcesell --- tests/rpc/test_rpc.py | 33 +++++++++++++++++++++++++++------ tests/rpc/test_rpc_telegram.py | 10 ++++++---- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index c370dce8f..102ed12fe 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -669,7 +669,8 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: return_value={ 'status': 'closed', 'type': 'limit', - 'side': 'buy' + 'side': 'buy', + 'filled': 0.0, } ), get_fee=fee, @@ -695,6 +696,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: msg = rpc._rpc_forcesell('all') assert msg == {'result': 'Created sell orders for all open trades.'} + freqtradebot.enter_positions() msg = rpc._rpc_forcesell('1') assert msg == {'result': 'Created sell order for trade 1.'} @@ -707,17 +709,24 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: freqtradebot.state = State.RUNNING assert cancel_order_mock.call_count == 0 + freqtradebot.enter_positions() # make an limit-buy open trade trade = Trade.query.filter(Trade.id == '1').first() filled_amount = trade.amount / 2 + # Fetch order - it's open first, and closed after cancel_order is called. mocker.patch( 'freqtrade.exchange.Exchange.fetch_order', - return_value={ + side_effect=[{ 'status': 'open', 'type': 'limit', 'side': 'buy', 'filled': filled_amount - } + }, { + 'status': 'closed', + 'type': 'limit', + 'side': 'buy', + 'filled': filled_amount + }] ) # check that the trade is called, which is done by ensuring exchange.cancel_order is called # and trade amount is updated @@ -725,6 +734,16 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: assert cancel_order_mock.call_count == 1 assert trade.amount == filled_amount + mocker.patch( + 'freqtrade.exchange.Exchange.fetch_order', + return_value={ + 'status': 'open', + 'type': 'limit', + 'side': 'buy', + 'filled': filled_amount + }) + + freqtradebot.config['max_open_trades'] = 3 freqtradebot.enter_positions() trade = Trade.query.filter(Trade.id == '2').first() amount = trade.amount @@ -744,20 +763,22 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker) -> None: assert cancel_order_mock.call_count == 2 assert trade.amount == amount - freqtradebot.enter_positions() # make an limit-sell open trade mocker.patch( 'freqtrade.exchange.Exchange.fetch_order', return_value={ 'status': 'open', 'type': 'limit', - 'side': 'sell' + 'side': 'sell', + 'amount': amount, + 'remaining': amount, + 'filled': 0.0 } ) msg = rpc._rpc_forcesell('3') assert msg == {'result': 'Created sell order for trade 3.'} # status quo, no exchange calls - assert cancel_order_mock.call_count == 2 + assert cancel_order_mock.call_count == 3 def test_performance_handle(default_conf, ticker, limit_buy_order, fee, diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 10738ada3..b11409767 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -724,7 +724,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee, context.args = ["1"] telegram._forcesell(update=update, context=context) - assert rpc_mock.call_count == 2 + assert rpc_mock.call_count == 4 last_msg = rpc_mock.call_args_list[-1][0][0] assert { 'type': RPCMessageType.SELL_NOTIFICATION, @@ -783,7 +783,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee, context.args = ["1"] telegram._forcesell(update=update, context=context) - assert rpc_mock.call_count == 2 + assert rpc_mock.call_count == 4 last_msg = rpc_mock.call_args_list[-1][0][0] assert { @@ -833,8 +833,10 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None context.args = ["all"] telegram._forcesell(update=update, context=context) - assert rpc_mock.call_count == 4 - msg = rpc_mock.call_args_list[0][0][0] + # Called for all trades 3 times + # cancel notification (wtf??), sell notification, buy_cancel + assert rpc_mock.call_count == 12 + msg = rpc_mock.call_args_list[2][0][0] assert { 'type': RPCMessageType.SELL_NOTIFICATION, 'trade_id': 1, From 9c0a3fffd733dc22f0498ea9cb72758d61ff0738 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 22:17:43 +0200 Subject: [PATCH 217/285] Avoid double notifications in case of partially filled buy orders --- freqtrade/constants.py | 4 +++- freqtrade/freqtradebot.py | 15 +++++++-------- freqtrade/rpc/telegram.py | 2 +- tests/rpc/test_rpc_telegram.py | 6 ++++-- tests/test_freqtradebot.py | 6 +++--- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index f44be220e..b92ab3eeb 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -338,7 +338,9 @@ SCHEMA_MINIMAL_REQUIRED = [ CANCEL_REASON = { "TIMEOUT": "cancelled due to timeout", - "PARTIALLY_FILLED": "partially filled - keeping order open", + "PARTIALLY_FILLED_KEEP_OPEN": "partially filled - keeping order open", + "PARTIALLY_FILLED": "partially filled", + "FULLY_CANCELLED": "fully cancelled", "ALL_CANCELLED": "cancelled (all unfilled and partially filled open orders cancelled)", "CANCELLED_ON_EXCHANGE": "cancelled on exchange", "FORCE_SELL": "forcesold", diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 917bb356f..d53902633 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -618,7 +618,7 @@ class FreqtradeBot: # Send the message self.rpc.send_msg(msg) - def _notify_buy_cancel(self, trade: Trade, order_type: str) -> None: + def _notify_buy_cancel(self, trade: Trade, order_type: str, reason: str) -> None: """ Sends rpc notification when a buy cancel occured. """ @@ -637,6 +637,7 @@ class FreqtradeBot: 'amount': trade.amount, 'open_date': trade.open_date, 'current_rate': current_rate, + 'reason': reason, } # Send the message @@ -993,13 +994,13 @@ class FreqtradeBot: # Using filled to determine the filled amount filled_amount = safe_value_fallback2(corder, order, 'filled', 'filled') - if isclose(filled_amount, 0.0, abs_tol=constants.MATH_CLOSE_PREC): logger.info('Buy order fully cancelled. Removing %s from database.', trade) # if trade is not partially completed, just delete the trade Trade.session.delete(trade) Trade.session.flush() was_trade_fully_canceled = True + reason += f", {constants.CANCEL_REASON['FULLY_CANCELLED']}" else: # if trade is partially complete, edit the stake details for the trade # and close the order @@ -1012,13 +1013,11 @@ class FreqtradeBot: trade.open_order_id = None logger.info('Partial buy order timeout for %s.', trade) - self.rpc.send_msg({ - 'type': RPCMessageType.STATUS_NOTIFICATION, - 'status': f'Remaining buy order for {trade.pair} cancelled due to timeout' - }) + reason += f", {constants.CANCEL_REASON['PARTIALLY_FILLED']}" self.wallets.update() - self._notify_buy_cancel(trade, order_type=self.strategy.order_types['buy']) + self._notify_buy_cancel(trade, order_type=self.strategy.order_types['buy'], + reason=reason) return was_trade_fully_canceled def handle_cancel_sell(self, trade: Trade, order: Dict, reason: str) -> str: @@ -1049,7 +1048,7 @@ class FreqtradeBot: trade.open_order_id = None else: # TODO: figure out how to handle partially complete sell orders - reason = constants.CANCEL_REASON['PARTIALLY_FILLED'] + reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] self.wallets.update() self._notify_sell_cancel( diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 458007c04..ecf907f54 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -149,7 +149,7 @@ class Telegram(RPC): elif msg['type'] == RPCMessageType.BUY_CANCEL_NOTIFICATION: message = ("\N{WARNING SIGN} *{exchange}:* " - "Cancelling Open Buy Order for {pair}".format(**msg)) + "Cancelling open buy Order for {pair}. Reason: {reason}.".format(**msg)) elif msg['type'] == RPCMessageType.SELL_NOTIFICATION: msg['amount'] = round(msg['amount'], 8) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index b11409767..145df9ed7 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -14,6 +14,7 @@ from telegram import Chat, Message, Update from telegram.error import NetworkError from freqtrade import __version__ +from freqtrade.constants import CANCEL_REASON from freqtrade.edge import PairInfo from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade @@ -1310,9 +1311,10 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None: 'type': RPCMessageType.BUY_CANCEL_NOTIFICATION, 'exchange': 'Bittrex', 'pair': 'ETH/BTC', + 'reason': CANCEL_REASON['TIMEOUT'] }) - assert msg_mock.call_args[0][0] \ - == ('\N{WARNING SIGN} *Bittrex:* Cancelling Open Buy Order for ETH/BTC') + assert (msg_mock.call_args[0][0] == '\N{WARNING SIGN} *Bittrex:* ' + 'Cancelling open buy Order for ETH/BTC. Reason: cancelled due to timeout.') def test_send_msg_sell_notification(default_conf, mocker) -> None: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 0d7968e26..7b4ed47f1 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2527,13 +2527,13 @@ def test_handle_cancel_sell_limit(mocker, default_conf, fee) -> None: send_msg_mock.reset_mock() order['amount'] = 2 - assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED'] + assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] # Assert cancel_order was not called (callcount remains unchanged) assert cancel_order_mock.call_count == 1 assert send_msg_mock.call_count == 1 - assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED'] + assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] # Message should not be iterated again - assert trade.sell_order_status == CANCEL_REASON['PARTIALLY_FILLED'] + assert trade.sell_order_status == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] assert send_msg_mock.call_count == 1 From b2373fccfd8a5441c4639f8934d344a40a921e2b Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 26 Aug 2020 22:24:45 +0200 Subject: [PATCH 218/285] Adjust tests as send_msg is only called once --- freqtrade/freqtradebot.py | 2 -- tests/rpc/test_rpc_telegram.py | 10 +++++----- tests/test_freqtradebot.py | 12 +++++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d53902633..66d687536 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -975,8 +975,6 @@ class FreqtradeBot: # Cancelled orders may have the status of 'canceled' or 'closed' if order['status'] not in ('canceled', 'closed'): - # TODO: this reason will overwrite the input in all cases - # reason = constants.CANCEL_REASON['TIMEOUT'] corder = self.exchange.cancel_order_with_result(trade.open_order_id, trade.pair, trade.amount) # Avoid race condition where the order could not be cancelled coz its already filled. diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 145df9ed7..a5e501390 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -725,7 +725,7 @@ def test_telegram_forcesell_handle(default_conf, update, ticker, fee, context.args = ["1"] telegram._forcesell(update=update, context=context) - assert rpc_mock.call_count == 4 + assert rpc_mock.call_count == 3 last_msg = rpc_mock.call_args_list[-1][0][0] assert { 'type': RPCMessageType.SELL_NOTIFICATION, @@ -784,7 +784,7 @@ def test_telegram_forcesell_down_handle(default_conf, update, ticker, fee, context.args = ["1"] telegram._forcesell(update=update, context=context) - assert rpc_mock.call_count == 4 + assert rpc_mock.call_count == 3 last_msg = rpc_mock.call_args_list[-1][0][0] assert { @@ -836,8 +836,8 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None # Called for all trades 3 times # cancel notification (wtf??), sell notification, buy_cancel - assert rpc_mock.call_count == 12 - msg = rpc_mock.call_args_list[2][0][0] + assert rpc_mock.call_count == 8 + msg = rpc_mock.call_args_list[1][0][0] assert { 'type': RPCMessageType.SELL_NOTIFICATION, 'trade_id': 1, @@ -1314,7 +1314,7 @@ def test_send_msg_buy_cancel_notification(default_conf, mocker) -> None: 'reason': CANCEL_REASON['TIMEOUT'] }) assert (msg_mock.call_args[0][0] == '\N{WARNING SIGN} *Bittrex:* ' - 'Cancelling open buy Order for ETH/BTC. Reason: cancelled due to timeout.') + 'Cancelling open buy Order for ETH/BTC. Reason: cancelled due to timeout.') def test_send_msg_sell_notification(default_conf, mocker) -> None: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 7b4ed47f1..ac6d3791a 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2289,7 +2289,7 @@ def test_check_handle_timedout_partial(default_conf, ticker, limit_buy_order_old # note this is for a partially-complete buy order freqtrade.check_handle_timedout() assert cancel_order_mock.call_count == 1 - assert rpc_mock.call_count == 2 + assert rpc_mock.call_count == 1 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() assert len(trades) == 1 assert trades[0].amount == 23.0 @@ -2324,7 +2324,7 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap assert log_has_re(r"Applying fee on amount for Trade.*", caplog) assert cancel_order_mock.call_count == 1 - assert rpc_mock.call_count == 2 + assert rpc_mock.call_count == 1 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() assert len(trades) == 1 # Verify that trade has been updated @@ -2364,7 +2364,7 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, assert log_has_re(r"Could not update trade amount: .*", caplog) assert cancel_order_mock.call_count == 1 - assert rpc_mock.call_count == 2 + assert rpc_mock.call_count == 1 trades = Trade.query.filter(Trade.open_order_id.is_(open_trade.open_order_id)).all() assert len(trades) == 1 # Verify that trade has been updated @@ -2527,11 +2527,13 @@ def test_handle_cancel_sell_limit(mocker, default_conf, fee) -> None: send_msg_mock.reset_mock() order['amount'] = 2 - assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] + assert freqtrade.handle_cancel_sell(trade, order, reason + ) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] # Assert cancel_order was not called (callcount remains unchanged) assert cancel_order_mock.call_count == 1 assert send_msg_mock.call_count == 1 - assert freqtrade.handle_cancel_sell(trade, order, reason) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] + assert freqtrade.handle_cancel_sell(trade, order, reason + ) == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] # Message should not be iterated again assert trade.sell_order_status == CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] assert send_msg_mock.call_count == 1 From bf5a082358f93adfd2bbe771b76d7ab7928fc3cf Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 27 Aug 2020 11:37:20 +0200 Subject: [PATCH 219/285] bufferhandler should log right from the beginning --- freqtrade/loggers.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/freqtrade/loggers.py b/freqtrade/loggers.py index 263f97ce1..8f5da9bee 100644 --- a/freqtrade/loggers.py +++ b/freqtrade/loggers.py @@ -41,13 +41,14 @@ def setup_logging_pre() -> None: """ Early setup for logging. Uses INFO loglevel and only the Streamhandler. - Early messages (before proper logging setup) will therefore only be available - after the proper logging setup. + Early messages (before proper logging setup) will therefore only be sent to additional + logging handlers after the real initialization, because we don't know which + ones the user desires beforehand. """ logging.basicConfig( level=logging.INFO, format=LOGFORMAT, - handlers=[logging.StreamHandler(sys.stderr)] + handlers=[logging.StreamHandler(sys.stderr), bufferHandler] ) From cf719bc5d32a53aea394e8a2473812dff1412340 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 27 Aug 2020 12:04:55 +0200 Subject: [PATCH 220/285] Fix logformat to use epoch timestamp in ms --- freqtrade/rpc/rpc.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index b7a4f4f8c..fed170001 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -640,10 +640,15 @@ class RPC: else: buffer = bufferHandler.buffer records = [[datetime.fromtimestamp(r.created).strftime("%Y-%m-%d %H:%M:%S"), - r.created, r.name, r.levelname, + r.created * 1000, r.name, r.levelname, r.message + ('\n' + r.exc_text if r.exc_text else '')] for r in buffer] + # Logs format: + # [logtime-formatted, logepoch, logger-name, loglevel, message \n + exception] + # e.g. ["2020-08-27 11:35:01", 1598520901097.9397, + # "freqtrade.worker", "INFO", "Starting worker develop"] + return {'log_count': len(records), 'logs': records} def _rpc_edge(self) -> List[Dict[str, Any]]: From dc6d71f651cc087ba943efe2e9e73d399f75bce5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 27 Aug 2020 14:41:31 +0200 Subject: [PATCH 221/285] Improve comment formatting --- freqtrade/rpc/rpc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index fed170001..13a799ef2 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -644,10 +644,10 @@ class RPC: r.message + ('\n' + r.exc_text if r.exc_text else '')] for r in buffer] - # Logs format: + # Log format: # [logtime-formatted, logepoch, logger-name, loglevel, message \n + exception] # e.g. ["2020-08-27 11:35:01", 1598520901097.9397, - # "freqtrade.worker", "INFO", "Starting worker develop"] + # "freqtrade.worker", "INFO", "Starting worker develop"] return {'log_count': len(records), 'logs': records} From 289425a434e5e7b3f010beca8639623a5e6982a3 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 29 Aug 2020 10:07:02 +0200 Subject: [PATCH 222/285] Add test for dry-run-cancel order --- tests/exchange/test_exchange.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 571053b44..c254d6a09 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1761,6 +1761,14 @@ def test_cancel_order_dry_run(default_conf, mocker, exchange_name): assert exchange.cancel_order(order_id='123', pair='TKN/BTC') == {} assert exchange.cancel_stoploss_order(order_id='123', pair='TKN/BTC') == {} + order = exchange.buy('ETH/BTC', 'limit', 5, 0.55, 'gtc') + + cancel_order = exchange.cancel_order(order_id=order['id'], pair='ETH/BTC') + assert order['id'] == cancel_order['id'] + assert order['amount'] == cancel_order['amount'] + assert order['pair'] == cancel_order['pair'] + assert cancel_order['status'] == 'canceled' + @pytest.mark.parametrize("exchange_name", EXCHANGES) @pytest.mark.parametrize("order,result", [ From a595d23bf16b7488ac5c5c0e3d16ac7c2fa96411 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 29 Aug 2020 10:14:49 +0200 Subject: [PATCH 223/285] Improve comment in test --- tests/rpc/test_rpc_telegram.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index bce20a043..51298d8f3 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -835,8 +835,7 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, mocker) -> None context.args = ["all"] telegram._forcesell(update=update, context=context) - # Called for all trades 3 times - # cancel notification (wtf??), sell notification, buy_cancel + # Called for each trade 3 times assert rpc_mock.call_count == 8 msg = rpc_mock.call_args_list[1][0][0] assert { From 2ae04af6946097b555d28addecd771bb44ca707d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 29 Aug 2020 10:26:26 +0200 Subject: [PATCH 224/285] Improve some doc wording --- README.md | 1 - docs/deprecated.md | 11 +++++------ tests/rpc/test_rpc_telegram.py | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7e0acde46..90f303c6d 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,6 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor - `/help`: Show help message - `/version`: Show version - ## Development branches The project is currently setup in two main branches: diff --git a/docs/deprecated.md b/docs/deprecated.md index a7b57b10e..44f0b686a 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -9,21 +9,20 @@ and are no longer supported. Please avoid their usage in your configuration. ### the `--refresh-pairs-cached` command line option `--refresh-pairs-cached` in the context of backtesting, hyperopt and edge allows to refresh candle data for backtesting. -Since this leads to much confusion, and slows down backtesting (while not being part of backtesting) this has been singled out -as a seperate freqtrade subcommand `freqtrade download-data`. +Since this leads to much confusion, and slows down backtesting (while not being part of backtesting) this has been singled out as a separate freqtrade sub-command `freqtrade download-data`. -This command line option was deprecated in 2019.7-dev (develop branch) and removed in 2019.9 (master branch). +This command line option was deprecated in 2019.7-dev (develop branch) and removed in 2019.9. ### The **--dynamic-whitelist** command line option This command line option was deprecated in 2018 and removed freqtrade 2019.6-dev (develop branch) -and in freqtrade 2019.7 (master branch). +and in freqtrade 2019.7. ### the `--live` command line option `--live` in the context of backtesting allowed to download the latest tick data for backtesting. Did only download the latest 500 candles, so was ineffective in getting good backtest data. -Removed in 2019-7-dev (develop branch) and in freqtrade 2019-8 (master branch) +Removed in 2019-7-dev (develop branch) and in freqtrade 2019.8. ### Allow running multiple pairlists in sequence @@ -31,6 +30,6 @@ The former `"pairlist"` section in the configuration has been removed, and is re The old section of configuration parameters (`"pairlist"`) has been deprecated in 2019.11 and has been removed in 2020.4. -### deprecation of bidVolume and askVolume from volumepairlist +### deprecation of bidVolume and askVolume from volume-pairlist Since only quoteVolume can be compared between assets, the other options (bidVolume, askVolume) have been deprecated in 2020.4. diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index bb63f283a..c962f68db 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1127,7 +1127,6 @@ def test_telegram_logs(default_conf, update, mocker) -> None: telegram._logs(update=update, context=context) assert msg_mock.call_count == 1 assert "freqtrade\\.rpc\\.telegram" in msg_mock.call_args_list[0][0][0] - assert "freqtrade\\.resolvers\\.iresolver" in msg_mock.call_args_list[0][0][0] msg_mock.reset_mock() context.args = ["1"] From 284d39930fc6b94912cdb4d45bc8e8df7307feb0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 30 Aug 2020 10:07:28 +0200 Subject: [PATCH 225/285] Allow using pairlists through dataprovider in backtesting --- freqtrade/data/dataprovider.py | 6 ++++++ freqtrade/optimize/backtesting.py | 1 + 2 files changed, 7 insertions(+) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 3b4de823f..ccb6cbf56 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -39,6 +39,12 @@ class DataProvider: """ self.__cached_pairs[(pair, timeframe)] = (dataframe, Arrow.utcnow().datetime) + def add_pairlisthandler(self, pairlists) -> None: + """ + Allow adding pairlisthandler after initialization + """ + self._pairlists = pairlists + def refresh(self, pairlist: ListPairsWithTimeframes, helping_pairs: ListPairsWithTimeframes = None) -> None: diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 3bd75f61a..005ec9fb8 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -96,6 +96,7 @@ class Backtesting: "PrecisionFilter not allowed for backtesting multiple strategies." ) + dataprovider.add_pairlisthandler(self.pairlists) self.pairlists.refresh_pairlist() if len(self.pairlists.whitelist) == 0: From 842eff95eba81ddaa34e71ac1d4082ed163d6630 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 30 Aug 2020 10:07:58 +0200 Subject: [PATCH 226/285] Add simple verification to ensure pairlists is iitialized --- tests/optimize/test_backtesting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 52d8f217c..f5c313520 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -359,6 +359,7 @@ def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: ] for line in exists: assert log_has(line, caplog) + assert backtesting.strategy.dp._pairlists is not None def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> None: From 3d39f05c8fabe2d237a9207aab026dcbc6878fbe Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 30 Aug 2020 10:23:14 +0200 Subject: [PATCH 227/285] Improve release documetation --- docs/developer.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/developer.md b/docs/developer.md index f09ae2c76..8bee1fd8e 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -52,6 +52,7 @@ The fastest and easiest way to start up is to use docker-compose.develop which g * [docker-compose](https://docs.docker.com/compose/install/) #### Starting the bot + ##### Use the develop dockerfile ``` bash @@ -74,7 +75,7 @@ docker-compose up docker-compose build ``` -##### Execing (effectively SSH into the container) +##### Executing (effectively SSH into the container) The `exec` command requires that the container already be running, if you want to start it that can be effected by `docker-compose up` or `docker-compose run freqtrade_develop` @@ -127,7 +128,7 @@ First of all, have a look at the [VolumePairList](https://github.com/freqtrade/f This is a simple Handler, which however serves as a good example on how to start developing. -Next, modify the classname of the Handler (ideally align this with the module filename). +Next, modify the class-name of the Handler (ideally align this with the module filename). The base-class provides an instance of the exchange (`self._exchange`) the pairlist manager (`self._pairlistmanager`), as well as the main configuration (`self._config`), the pairlist dedicated configuration (`self._pairlistconfig`) and the absolute position within the list of pairlists. @@ -147,7 +148,7 @@ Configuration for the chain of Pairlist Handlers is done in the bot configuratio By convention, `"number_assets"` is used to specify the maximum number of pairs to keep in the pairlist. Please follow this to ensure a consistent user experience. -Additional parameters can be configured as needed. For instance, `VolumePairList` uses `"sort_key"` to specify the sorting value - however feel free to specify whatever is necessary for your great algorithm to be successfull and dynamic. +Additional parameters can be configured as needed. For instance, `VolumePairList` uses `"sort_key"` to specify the sorting value - however feel free to specify whatever is necessary for your great algorithm to be successful and dynamic. #### short_desc @@ -163,7 +164,7 @@ This is called with each iteration of the bot (only if the Pairlist Handler is a It must return the resulting pairlist (which may then be passed into the chain of Pairlist Handlers). -Validations are optional, the parent class exposes a `_verify_blacklist(pairlist)` and `_whitelist_for_active_markets(pairlist)` to do default filtering. Use this if you limit your result to a certain number of pairs - so the endresult is not shorter than expected. +Validations are optional, the parent class exposes a `_verify_blacklist(pairlist)` and `_whitelist_for_active_markets(pairlist)` to do default filtering. Use this if you limit your result to a certain number of pairs - so the end-result is not shorter than expected. #### filter_pairlist @@ -171,13 +172,13 @@ This method is called for each Pairlist Handler in the chain by the pairlist man This is called with each iteration of the bot - so consider implementing caching for compute/network heavy calculations. -It get's passed a pairlist (which can be the result of previous pairlists) as well as `tickers`, a pre-fetched version of `get_tickers()`. +It gets passed a pairlist (which can be the result of previous pairlists) as well as `tickers`, a pre-fetched version of `get_tickers()`. The default implementation in the base class simply calls the `_validate_pair()` method for each pair in the pairlist, but you may override it. So you should either implement the `_validate_pair()` in your Pairlist Handler or override `filter_pairlist()` to do something else. If overridden, it must return the resulting pairlist (which may then be passed into the next Pairlist Handler in the chain). -Validations are optional, the parent class exposes a `_verify_blacklist(pairlist)` and `_whitelist_for_active_markets(pairlist)` to do default filters. Use this if you limit your result to a certain number of pairs - so the endresult is not shorter than expected. +Validations are optional, the parent class exposes a `_verify_blacklist(pairlist)` and `_whitelist_for_active_markets(pairlist)` to do default filters. Use this if you limit your result to a certain number of pairs - so the end result is not shorter than expected. In `VolumePairList`, this implements different methods of sorting, does early validation so only the expected number of pairs is returned. @@ -201,7 +202,7 @@ Most exchanges supported by CCXT should work out of the box. Check if the new exchange supports Stoploss on Exchange orders through their API. -Since CCXT does not provide unification for Stoploss On Exchange yet, we'll need to implement the exchange-specific parameters ourselfs. Best look at `binance.py` for an example implementation of this. You'll need to dig through the documentation of the Exchange's API on how exactly this can be done. [CCXT Issues](https://github.com/ccxt/ccxt/issues) may also provide great help, since others may have implemented something similar for their projects. +Since CCXT does not provide unification for Stoploss On Exchange yet, we'll need to implement the exchange-specific parameters ourselves. Best look at `binance.py` for an example implementation of this. You'll need to dig through the documentation of the Exchange's API on how exactly this can be done. [CCXT Issues](https://github.com/ccxt/ccxt/issues) may also provide great help, since others may have implemented something similar for their projects. ### Incomplete candles @@ -274,6 +275,7 @@ git checkout -b new_release Determine if crucial bugfixes have been made between this commit and the current state, and eventually cherry-pick these. +* Merge the release branch (master) into this branch. * Edit `freqtrade/__init__.py` and add the version matching the current date (for example `2019.7` for July 2019). Minor versions can be `2019.7.1` should we need to do a second release that month. Version numbers must follow allowed versions from PEP0440 to avoid failures pushing to pypi. * Commit this part * push that branch to the remote and create a PR against the master branch @@ -281,14 +283,14 @@ Determine if crucial bugfixes have been made between this commit and the current ### Create changelog from git commits !!! Note - Make sure that the master branch is uptodate! + Make sure that the master branch is up-to-date! ``` bash # Needs to be done before merging / pulling that branch. git log --oneline --no-decorate --no-merges master..new_release ``` -To keep the release-log short, best wrap the full git changelog into a collapsible details secction. +To keep the release-log short, best wrap the full git changelog into a collapsible details section. ```markdown
    @@ -312,6 +314,9 @@ Once the PR against master is merged (best right after merging): ### pypi +!!! Note + This process is now automated as part of Github Actions. + To create a pypi release, please run the following commands: Additional requirement: `wheel`, `twine` (for uploading), account on pypi with proper permissions. From 7f74ff53b12c5baff8c497227b8dd49ddcc4d499 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 31 Aug 2020 07:34:43 +0200 Subject: [PATCH 228/285] Move clock warning to installation pages --- docs/bot-usage.md | 3 +++ docs/docker.md | 3 +++ docs/index.md | 6 +----- docs/installation.md | 3 +++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/bot-usage.md b/docs/bot-usage.md index 40ff3d82b..4a4496bbc 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -5,6 +5,9 @@ This page explains the different parameters of the bot and how to run it. !!! Note If you've used `setup.sh`, don't forget to activate your virtual environment (`source .env/bin/activate`) before running freqtrade commands. +!!! 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. + ## Bot commands ``` diff --git a/docs/docker.md b/docs/docker.md index 92478088a..b9508648b 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -12,6 +12,9 @@ Optionally, [docker-compose](https://docs.docker.com/compose/install/) should be Once you have Docker installed, simply prepare the config file (e.g. `config.json`) and run the image for `freqtrade` as explained below. +!!! 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 with docker-compose Freqtrade provides an official Docker image on [Dockerhub](https://hub.docker.com/r/freqtradeorg/freqtrade/), as well as a [docker-compose file](https://github.com/freqtrade/freqtrade/blob/develop/docker-compose.yml) ready for usage. diff --git a/docs/index.md b/docs/index.md index adc661300..397c549aa 100644 --- a/docs/index.md +++ b/docs/index.md @@ -37,13 +37,9 @@ Freqtrade is a crypto-currency algorithmic trading software developed in python ## Requirements -### 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. - ### Hardware requirements -To run this bot we recommend you a cloud instance with a minimum of: +To run this bot we recommend you a linux cloud instance with a minimum of: - 2GB RAM - 1GB disk space diff --git a/docs/installation.md b/docs/installation.md index c03be55d1..ec5e40965 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -18,6 +18,9 @@ Click each one for install guide: 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. + ## Quick start Freqtrade provides the Linux/MacOS Easy Installation script to install all dependencies and help you configure the bot. From f83633ff4e9ded4689ccc70a0af9b7efe0ea26fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2020 06:38:24 +0000 Subject: [PATCH 229/285] Bump prompt-toolkit from 3.0.6 to 3.0.7 Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.6 to 3.0.7. - [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.6...3.0.7) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index b6e2d329f..9e1dbf86f 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -32,4 +32,4 @@ flask-cors==3.0.8 colorama==0.4.3 # Building config files interactively questionary==1.5.2 -prompt-toolkit==3.0.6 +prompt-toolkit==3.0.7 From 4adf012ee68f200ab185a49a0b9c437e22ee2f8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2020 06:38:35 +0000 Subject: [PATCH 230/285] Bump flask-cors from 3.0.8 to 3.0.9 Bumps [flask-cors](https://github.com/corydolphin/flask-cors) from 3.0.8 to 3.0.9. - [Release notes](https://github.com/corydolphin/flask-cors/releases) - [Changelog](https://github.com/corydolphin/flask-cors/blob/master/CHANGELOG.md) - [Commits](https://github.com/corydolphin/flask-cors/compare/3.0.8...3.0.9) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index b6e2d329f..d543f206d 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -26,7 +26,7 @@ sdnotify==0.3.2 # Api server flask==1.1.2 flask-jwt-extended==3.24.1 -flask-cors==3.0.8 +flask-cors==3.0.9 # Support for colorized terminal output colorama==0.4.3 From 821af9be9e36ff5a5c4f632c309409034467c8a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2020 06:38:36 +0000 Subject: [PATCH 231/285] Bump mkdocs-material from 5.5.8 to 5.5.11 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 5.5.8 to 5.5.11. - [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/5.5.8...5.5.11) 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 5226db750..c8f08d12a 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,2 +1,2 @@ -mkdocs-material==5.5.8 +mkdocs-material==5.5.11 mdx_truly_sane_lists==1.2 From 55a49bfc5325364a0c5da7190e723b2a3c261089 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2020 06:38:38 +0000 Subject: [PATCH 232/285] Bump progressbar2 from 3.51.4 to 3.52.1 Bumps [progressbar2](https://github.com/WoLpH/python-progressbar) from 3.51.4 to 3.52.1. - [Release notes](https://github.com/WoLpH/python-progressbar/releases) - [Changelog](https://github.com/WoLpH/python-progressbar/blob/develop/CHANGES.rst) - [Commits](https://github.com/WoLpH/python-progressbar/compare/v3.51.4...v3.52.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 ce08f08e0..fbc679eaa 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -7,4 +7,4 @@ scikit-learn==0.23.1 scikit-optimize==0.7.4 filelock==3.0.12 joblib==0.16.0 -progressbar2==3.51.4 +progressbar2==3.52.1 From 8969ab4aa3026f3536980a34d6612bdb0a9dde38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2020 06:38:55 +0000 Subject: [PATCH 233/285] Bump pytest-mock from 3.3.0 to 3.3.1 Bumps [pytest-mock](https://github.com/pytest-dev/pytest-mock) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/pytest-dev/pytest-mock/releases) - [Changelog](https://github.com/pytest-dev/pytest-mock/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-mock/compare/v3.3.0...v3.3.1) 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 1f5b68a73..44f0c7265 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,7 +11,7 @@ mypy==0.782 pytest==6.0.1 pytest-asyncio==0.14.0 pytest-cov==2.10.1 -pytest-mock==3.3.0 +pytest-mock==3.3.1 pytest-random-order==1.0.4 # Convert jupyter notebooks to markdown documents From c5b8993e9d061e7f839be9c40bc54769ec997991 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2020 06:38:56 +0000 Subject: [PATCH 234/285] Bump ccxt from 1.33.52 to 1.33.72 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.33.52 to 1.33.72. - [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.33.52...1.33.72) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index b6e2d329f..6f4ae45b3 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.33.52 +ccxt==1.33.72 SQLAlchemy==1.3.19 python-telegram-bot==12.8 arrow==0.16.0 From 24df8d6bf5c81c3bfc9127b0d3cd1c01b4a99780 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 31 Aug 2020 15:46:31 +0200 Subject: [PATCH 235/285] Sort imports --- tests/data/test_history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data/test_history.py b/tests/data/test_history.py index c89156f4c..2d6aed8f6 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -1,6 +1,5 @@ # pragma pylint: disable=missing-docstring, protected-access, C0103 -from freqtrade.data.history.hdf5datahandler import HDF5DataHandler import json import uuid from pathlib import Path @@ -15,6 +14,7 @@ from pandas.testing import assert_frame_equal from freqtrade.configuration import TimeRange from freqtrade.constants import AVAILABLE_DATAHANDLERS from freqtrade.data.converter import ohlcv_to_dataframe +from freqtrade.data.history.hdf5datahandler import HDF5DataHandler from freqtrade.data.history.history_utils import ( _download_pair_history, _download_trades_history, _load_cached_data_for_updating, convert_trades_to_ohlcv, get_timerange, From a4e3edbcc597fc05f9be1eec2aa827593e1d33e7 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 1 Sep 2020 07:10:48 +0200 Subject: [PATCH 236/285] Fix stoploss_last_update beein updated with date object in wrong timezone --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index eee60cc22..768f283ab 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -835,7 +835,7 @@ class FreqtradeBot: stop_price = trade.open_rate * (1 + stoploss) if self.create_stoploss_order(trade=trade, stop_price=stop_price): - trade.stoploss_last_update = datetime.now() + trade.stoploss_last_update = datetime.utcnow() return False # If stoploss order is canceled for some reason we add it From 3bc6cb36c60155a8de4e25cfd1879d1b260a4348 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 1 Sep 2020 08:00:20 +0200 Subject: [PATCH 237/285] Remove deprectead volumepairlist options --- docs/deprecated.md | 2 +- freqtrade/pairlist/VolumePairList.py | 7 +------ tests/pairlist/test_pairlist.py | 13 ------------- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/docs/deprecated.md b/docs/deprecated.md index 44f0b686a..312f2c74f 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -32,4 +32,4 @@ The old section of configuration parameters (`"pairlist"`) has been deprecated i ### deprecation of bidVolume and askVolume from volume-pairlist -Since only quoteVolume can be compared between assets, the other options (bidVolume, askVolume) have been deprecated in 2020.4. +Since only quoteVolume can be compared between assets, the other options (bidVolume, askVolume) have been deprecated in 2020.4, and have been removed in 2020.9. diff --git a/freqtrade/pairlist/VolumePairList.py b/freqtrade/pairlist/VolumePairList.py index 35dce93eb..44e5c52d7 100644 --- a/freqtrade/pairlist/VolumePairList.py +++ b/freqtrade/pairlist/VolumePairList.py @@ -14,7 +14,7 @@ from freqtrade.pairlist.IPairList import IPairList logger = logging.getLogger(__name__) -SORT_VALUES = ['askVolume', 'bidVolume', 'quoteVolume'] +SORT_VALUES = ['quoteVolume'] class VolumePairList(IPairList): @@ -45,11 +45,6 @@ class VolumePairList(IPairList): raise OperationalException( f'key {self._sort_key} not in {SORT_VALUES}') - if self._sort_key != 'quoteVolume': - logger.warning( - "DEPRECATED: using any key other than quoteVolume for VolumePairList is deprecated." - ) - @property def needstickers(self) -> bool: """ diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index 9217abc46..a5e479912 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -231,9 +231,6 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): # VolumePairList only ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC', 'HOT/BTC']), - # Different sorting depending on quote or bid volume - ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}], - "BTC", ['HOT/BTC', 'FUEL/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']), ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}], "USDT", ['ETH/USDT', 'NANO/USDT', 'ADAHALF/USDT', 'ADADOUBLE/USDT']), # No pair for ETH, VolumePairList @@ -263,10 +260,6 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}, {"method": "PrecisionFilter"}], "BTC", ['ETH/BTC', 'TKN/BTC', 'LTC/BTC', 'XRP/BTC']), - # Precisionfilter bid - ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}, - {"method": "PrecisionFilter"}], - "BTC", ['FUEL/BTC', 'XRP/BTC', 'LTC/BTC', 'TKN/BTC']), # PriceFilter and VolumePairList ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}, {"method": "PriceFilter", "low_price_ratio": 0.03}], @@ -293,9 +286,6 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): ([{"method": "StaticPairList"}], "BTC", ['ETH/BTC', 'TKN/BTC', 'HOT/BTC']), # Static Pairlist before VolumePairList - sorting changes - ([{"method": "StaticPairList"}, - {"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}], - "BTC", ['HOT/BTC', 'TKN/BTC', 'ETH/BTC']), # SpreadFilter ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}, {"method": "SpreadFilter", "max_spread_ratio": 0.005}], @@ -344,9 +334,6 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): ([{"method": "SpreadFilter", "max_spread_ratio": 0.005}], "BTC", 'filter_at_the_beginning'), # OperationalException expected # Static Pairlist after VolumePairList, on a non-first position - ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "bidVolume"}, - {"method": "StaticPairList"}], - "BTC", 'static_in_the_middle'), ([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"}, {"method": "PriceFilter", "low_price_ratio": 0.02}], "USDT", ['ETH/USDT', 'NANO/USDT']), From d44418282935c97eb17181fa4e564bc2abf10d61 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 1 Sep 2020 10:31:11 +0200 Subject: [PATCH 238/285] Reinstate wrongly removed pairlist test --- tests/pairlist/test_pairlist.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/pairlist/test_pairlist.py b/tests/pairlist/test_pairlist.py index a5e479912..1f05bef1e 100644 --- a/tests/pairlist/test_pairlist.py +++ b/tests/pairlist/test_pairlist.py @@ -334,6 +334,9 @@ def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): ([{"method": "SpreadFilter", "max_spread_ratio": 0.005}], "BTC", 'filter_at_the_beginning'), # OperationalException expected # Static Pairlist after VolumePairList, on a non-first position + ([{"method": "VolumePairList", "number_assets": 5, "sort_key": "quoteVolume"}, + {"method": "StaticPairList"}], + "BTC", 'static_in_the_middle'), ([{"method": "VolumePairList", "number_assets": 20, "sort_key": "quoteVolume"}, {"method": "PriceFilter", "low_price_ratio": 0.02}], "USDT", ['ETH/USDT', 'NANO/USDT']), From dff0ac276803e480c03ba6fb33620b7179307824 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 1 Sep 2020 19:16:11 +0200 Subject: [PATCH 239/285] Remove trailing_stop from default config example - it'll be misleading --- config.json.example | 1 - config_binance.json.example | 1 - config_kraken.json.example | 1 - 3 files changed, 3 deletions(-) diff --git a/config.json.example b/config.json.example index 77a147d0c..ab517b77c 100644 --- a/config.json.example +++ b/config.json.example @@ -7,7 +7,6 @@ "timeframe": "5m", "dry_run": false, "cancel_open_orders_on_exit": false, - "trailing_stop": false, "unfilledtimeout": { "buy": 10, "sell": 30 diff --git a/config_binance.json.example b/config_binance.json.example index 82943749d..f3f8eb659 100644 --- a/config_binance.json.example +++ b/config_binance.json.example @@ -7,7 +7,6 @@ "timeframe": "5m", "dry_run": true, "cancel_open_orders_on_exit": false, - "trailing_stop": false, "unfilledtimeout": { "buy": 10, "sell": 30 diff --git a/config_kraken.json.example b/config_kraken.json.example index fb983a4a3..fd0b2b95d 100644 --- a/config_kraken.json.example +++ b/config_kraken.json.example @@ -7,7 +7,6 @@ "timeframe": "5m", "dry_run": true, "cancel_open_orders_on_exit": false, - "trailing_stop": false, "unfilledtimeout": { "buy": 10, "sell": 30 From f54fecaebaaa009dd4a5da2c83dcb85516be8a6a Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 2 Sep 2020 19:58:26 +0200 Subject: [PATCH 240/285] Expose helpermethods thorugh freqtrade.strategy --- freqtrade/strategy/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/strategy/__init__.py b/freqtrade/strategy/__init__.py index 40a4a0bea..91ea0e075 100644 --- a/freqtrade/strategy/__init__.py +++ b/freqtrade/strategy/__init__.py @@ -1 +1,4 @@ -from freqtrade.strategy.interface import IStrategy # noqa: F401 +# flake8: noqa: F401 +from freqtrade.exchange import (timeframe_to_minutes, timeframe_to_prev_date, + timeframe_to_seconds, timeframe_to_next_date, timeframe_to_msecs) +from freqtrade.strategy.interface import IStrategy From e268bd192e85868cb4da9e74dceb652d249ffbe6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 2 Sep 2020 19:59:04 +0200 Subject: [PATCH 241/285] Fix informative sample documentation --- docs/strategy-customization.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index be08faa2d..4362c251f 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -483,6 +483,10 @@ if self.dp: ### Complete Data-provider sample ```python +from freqtrade.strategy import IStrategy, timeframe_to_minutes +from pandas import DataFrame +import pandas as pd + class SampleStrategy(IStrategy): # strategy init stuff... @@ -518,9 +522,15 @@ class SampleStrategy(IStrategy): # Assuming inf_tf = '1d' - then the columns will now be: # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d + # Shift date by 1 Frequency unit + # This is necessary since the data is always the "open date" + # and a 15m candle starting at 12:15 should not know the close of the 1h candle from 12:00 to 13:00 + minutes = timeframe_to_minutes(inf_tf) + informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') + # Combine the 2 dataframes # all indicators on the informative sample MUST be calculated before this point - dataframe = pd.merge(dataframe, informative, left_on='date', right_on=f'date_{inf_tf}', how='left') + dataframe = pd.merge(dataframe, informative, left_on='date', right_on=f'date_merge_{inf_tf}', how='left') # FFill to have the 1d value available in every row throughout the day. # Without this, comparisons would only work once per day. dataframe = dataframe.ffill() From 79ea8cf7719879e942d4c49dddd63cafd2d38cfe Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 2 Sep 2020 20:02:41 +0200 Subject: [PATCH 242/285] Improve wording --- docs/strategy-customization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 4362c251f..e2548e510 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -522,7 +522,7 @@ class SampleStrategy(IStrategy): # Assuming inf_tf = '1d' - then the columns will now be: # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d - # Shift date by 1 Frequency unit + # Shift date by 1 candle # This is necessary since the data is always the "open date" # and a 15m candle starting at 12:15 should not know the close of the 1h candle from 12:00 to 13:00 minutes = timeframe_to_minutes(inf_tf) From 295ecaa9b20e688a4735a7a9fe1cd9bbbea2f7d0 Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Wed, 2 Sep 2020 16:58:54 -0600 Subject: [PATCH 243/285] Updating Edge Positioning Doc. Integrated MathJax Included worked out examples Changed Language to achieve a middle ground. Minor formatting improvements --- docs/edge.md | 204 +++++++++++++++++++++++-------------- docs/javascripts/config.js | 12 +++ mkdocs.yml | 8 +- 3 files changed, 149 insertions(+), 75 deletions(-) create mode 100644 docs/javascripts/config.js diff --git a/docs/edge.md b/docs/edge.md index dcb559f96..182c47651 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -1,92 +1,141 @@ # Edge positioning -This page explains how to use Edge Positioning module in your bot in order to enter into a trade only if the trade has a reasonable win rate and risk reward ratio, and consequently adjust your position size and stoploss. +The `Edge Positioning` module uses probability to calculate your win rate and risk reward ration. It will use these statistics to control your strategy trade entry points, position side and, stoploss. !!! Warning - Edge positioning is not compatible with dynamic (volume-based) whitelist. + `Edge positioning` is not compatible with dynamic (volume-based) whitelist. !!! Note - Edge does not consider anything other than *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file. - Therefore, it is important to understand that Edge can improve the performance of some trading strategies but *decrease* the performance of others. + `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 is all about probability. No one can claim that he has a strategy working all the time. You have to assume that sometimes you lose. +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. -But it doesn't mean there is no rule, it only means rules should work "most of the time". Let's play a game: we toss a coin, heads: I give you 10$, tails: you give me 10$. Is it an interesting game? No, it's quite boring, isn't it? +To obtain an edge in the market, a strategy has to make more money than it loses. Marking money in trading is not only about *how often* the strategy makes or loses money. -But let's say the probability that we have heads is 80% (because our coin has the displaced distribution of mass or other defect), and the probability that we have tails is 20%. Now it is becoming interesting... +!!! tip "It doesn't matter how often, but how much!" + A bad strategy might make 1 penny in *ten* transactions but lose 1 dollar in *one* transaction. If one only checks the number of winning trades, it would be misleading to think that the strategy is actually making a profit. -That means 10$ X 80% versus 10$ X 20%. 8$ versus 2$. That means over time you will win 8$ risking only 2$ on each toss of coin. +The Edge Positioning module seeks to improve a strategy's winning probability and the money that the strategy will make *on the long run*. -Let's complicate it more: you win 80% of the time but only 2$, I win 20% of the time but 8$. The calculation is: 80% X 2$ versus 20% X 8$. It is becoming boring again because overtime you win $1.6$ (80% X 2$) and me $1.6 (20% X 8$) too. +We raise the following question[^1]: -The question is: How do you calculate that? How do you know if you wanna play? +!!! Question "Which trade is a better option?" + a) A trade with 80% of chance of losing $100 and 20% chance of winning $200
    + b) A trade with 100% of chance of losing $30 -The answer comes to two factors: +??? Info "Answer" + The expected value of *a)* is smaller than the expected value of *b)*.
    + Hence, *b*) represents a smaller loss in the long run.
    + However, the answer is: *it depends* -- Win Rate -- Risk Reward Ratio +Another way to look at it is to ask a similar question: -### Win Rate +!!! Question "Which trade is a better option?" + a) A trade with 80% of chance of winning 100 and 20% chance of losing $200
    + b) A trade with 100% of chance of winning $30 -Win Rate (*W*) is is the mean over some amount of trades (*N*) what is the percentage of winning trades to total number of trades (note that we don't consider how much you gained but only if you won or not). +Edge positioning tries to answer the hard questions about risk/reward and position size automatically, seeking to minimizes the chances of losing of a given strategy. -``` -W = (Number of winning trades) / (Total number of trades) = (Number of winning trades) / N -``` +### Trading, winning and losing -Complementary Loss Rate (*L*) is defined as +Let's call $o$ the return of a single transaction $o$ where $o \in \mathbb{R}$. The collection $O = \{o_1, o_2, ..., o_N\}$ is the set of all returns of transactions made during a trading session. We say that $N$ is the cardinality of $O$, or, in lay terms, it is the number of transactions made in a trading session. -``` -L = (Number of losing trades) / (Total number of trades) = (Number of losing trades) / N -``` +!!! Example + In a session where a strategy made three transactions we can say that $O = \{3.5, -1, 15\}$. That means that $N = 3$ and $o_1 = 3.5$, $o_2 = -1$, $o = 15$. -or, which is the same, as +A winning trade is a trade where a strategy *made* money. Making money means that the strategy closed the position in a value that returned a profit, after all deducted fees. Formally, a winning trade will have a return $o_i > 0$. Similarly, a losing trade will have a return $o_j \leq 0$. With that, we can discover the set of all winning trades, $T_{win}$, as follows: -``` -L = 1 – W -``` +$$ T_{win} = \{ o \in O | o > 0 \} $$ + +Similarly, we can discover the set of losing trades $T_{lose}$ as follows: + +$$ T_{lose} = \{o \in O | o \leq 0\} $$ + +!!! Example + In a section where a strategy made three transactions $O = \{3.5, -1, 15, 0\}$:
    + $T_{win} = \{3.5, 15\}$
    + $T_{lose} = \{-1, 0\}$
    + +### Win Rate and Lose Rate + +The win rate $W$ is the proportion of winning trades with respect to all the trades made by a strategy. We use the following function to compute the win rate: + +$$W = \frac{\sum^{o \in T_{win}} o}{N}$$ + +Where $W$ is the win rate, $N$ is the number of trades and, $T_{win}$ is the set of all trades where the strategy made money. + +Similarly, we can compute the rate of losing trades: + +$$ + L = \frac{\sum^{o \in T_{lose}} o}{N} +$$ + +Where $L$ is the lose rate, $N$ is the amount of trades made and, $T_{lose}$ is the set of all trades where the strategy lost money. Note that the above formula is the same as calculating $L = 1 – W$ or $W = 1 – L$ ### Risk Reward Ratio -Risk Reward Ratio (*R*) is a formula used to measure the expected gains of a given investment against the risk of loss. It is basically what you potentially win divided by what you potentially lose: +Risk Reward Ratio (*R*) is a formula used to measure the expected gains of a given investment against the risk of loss. It is basically what you potentially win divided by what you potentially lose. Formally: -``` -R = Profit / Loss -``` +$$ R = \frac{\text{potential_profit}}{\text{potential_loss}} $$ -Over time, on many trades, you can calculate your risk reward by dividing your average profit on winning trades by your average loss on losing trades: +??? Example "Worked example of $R$ calculation" + Let's say that you think that the price of *stonecoin* today is $10.0. You believe that, because they will start mining stonecoin it will go up to $15.0 tomorrow. There is the risk that the stone is too hard, and the GPUs can't mine it, so the price might go to $0 tomorrow. You are planning to invest $100.
    + Your potential profit is calculated as:
    + $\begin{aligned} + \text{potential_profit} &= (\text{potential_price} - \text{cost_per_unit}) * \frac{\text{investment}}{\text{cost_per_unit}} \\ + &= (15 - 10) * \frac{100}{15}\\ + &= 33.33 + \end{aligned}$
    + Since the price might go to $0, the $100 dolars invested could turn into 0. We can compute the Risk Reward Ratio as follows:
    + $\begin{aligned} + R &= \frac{\text{potential_profit}}{\text{potential_loss}}\\ + &= \frac{33.33}{100}\\ + &= 0.333... + \end{aligned}$
    + What it effectivelly means is that the strategy have the potential to make $0.33 for each $1 invested. -``` -Average profit = (Sum of profits) / (Number of winning trades) +On a long horizonte, that is, on many trades, we can calculate the risk reward by dividing the strategy' average profit on winning trades by the strategy' average loss on losing trades. We can calculate the average profit, $\mu_{win}$, as follows: -Average loss = (Sum of losses) / (Number of losing trades) +$$ \text{average_profit} = \mu_{win} = \frac{\text{sum_of_profits}}{\text{count_winning_trades}} = \frac{\sum^{o \in T_{win}} o}{|T_{win}|} $$ -R = (Average profit) / (Average loss) -``` +Similarly, we can calculate the average loss, $\mu_{lose}$, as follows: + +$$ \text{average_loss} = \mu_{lose} = \frac{\text{sum_of_losses}}{\text{count_losing_trades}} = \frac{\sum^{o \in T_{lose}} o}{|T_{lose}|} $$ + +Finally, we can calculate the Risk Reward ratio as follows: + +$$ R = \frac{\text{average_profit}}{\text{average_loss}} = \frac{\mu_{win}}{\mu_{lose}}\\ $$ + + +??? Example "Worked example of $R$ calculation using mean profit/loss" + Let's say the strategy that we are using makes an average win $\mu_{win} = 2.06$ and an average loss $\mu_{loss} = 4.11$.
    + We calculate the risk reward ratio as follows:
    + $R = \frac{\mu_{win}}{\mu_{loss}} = \frac{2.06}{4.11} = 0.5012...$ + ### Expectancy -At this point we can combine *W* and *R* to create an expectancy ratio. This is a simple process of multiplying the risk reward ratio by the percentage of winning trades and subtracting the percentage of losing trades, which is calculated as follows: +By combining the Win Rate $W$ and and the Risk Reward ratio $R$ to create an expectancy ratio $E$. A expectance ratio is the expected return of the investment made in a trade. We can compute the value of $E$ as follows: -``` -Expectancy Ratio = (Risk Reward Ratio X Win Rate) – Loss Rate = (R X W) – L -``` +$$E = R * W - L$$ -So lets say your Win rate is 28% and your Risk Reward Ratio is 5: +!!! Example "Calculating $E$" + Let's say that a strategy has a win rate $W = 0.28$ and a risk reward ratio $R = 5$. What this means is that the strategy is expected to make 5 times the investment around on 28% of the trades it makes. Working out the example:
    + $E = R * W - L = 5 * 0.28 - 0.72 = 0.68$ +
    -``` -Expectancy = (5 X 0.28) – 0.72 = 0.68 -``` +The expectancy worked out in the example above means that, on average, this strategy' trades will return 1.68 times the size of its losses. Said another way, the strategy makes $1.68 for every $1 it loses, on average. -Superficially, this means that on average you expect this strategy’s trades to return 1.68 times the size of your loses. Said another way, you can expect to win $1.68 for every $1 you lose. This is important for two reasons: First, it may seem obvious, but you know right away that you have a positive return. Second, you now have a number you can compare to other candidate systems to make decisions about which ones you employ. +You canThis is important for two reasons: First, it may seem obvious, but you know right away that you have a positive return. Second, you now have a number you can compare to other candidate systems to make decisions about which ones you employ. It is important to remember that any system with an expectancy greater than 0 is profitable using past data. The key is finding one that will be profitable in the future. You can also use this value to evaluate the effectiveness of modifications to this system. -**NOTICE:** It's important to keep in mind that Edge is testing your expectancy using historical data, there's no guarantee that you will have a similar edge in the future. It's still vital to do this testing in order to build confidence in your methodology, but be wary of "curve-fitting" your approach to the historical data as things are unlikely to play out the exact same way for future trades. +**NOTICE:** It's important to keep in mind that Edge is testing your expectancy using historical data, there's no guarantee that you will have a similar edge in the future. It's still vital to do this testing in order to build confidence in your methodology but be wary of "curve-fitting" your approach to the historical data as things are unlikely to play out the exact same way for future trades. ## How does it work? @@ -99,13 +148,13 @@ Edge combines dynamic stoploss, dynamic positions, and whitelist generation into | XZC/ETH | -0.03 | 0.52 |1.359670 | 0.228 | | XZC/ETH | -0.04 | 0.51 |1.234539 | 0.117 | -The goal here is to find the best stoploss for the strategy in order to have the maximum expectancy. In the above example stoploss at 3% leads to the maximum expectancy according to historical data. +The goal here is to find the best stoploss for the strategy in order to have the maximum expectancy. In the above example stoploss at $3% $leads to the maximum expectancy according to historical data. Edge module then forces stoploss value it evaluated to your strategy dynamically. ### Position size -Edge also dictates the stake amount for each trade to the bot according to the following factors: +Edge dictates the amount at stake for each trade to the bot according to the following factors: - Allowed capital at risk - Stoploss @@ -116,9 +165,9 @@ Allowed capital at risk is calculated as follows: Allowed capital at risk = (Capital available_percentage) X (Allowed risk per trade) ``` -Stoploss is calculated as described above against historical data. +Stoploss is calculated as described above with respect to historical data. -Your position size then will be: +The position size is calculated as follows: ``` Position size = (Allowed capital at risk) / Stoploss @@ -126,19 +175,23 @@ Position size = (Allowed capital at risk) / Stoploss Example: -Let's say the stake currency is ETH and you have 10 ETH on the exchange, your capital available percentage is 50% and you would allow 1% of risk for each trade. thus your available capital for trading is **10 x 0.5 = 5 ETH** and allowed capital at risk would be **5 x 0.01 = 0.05 ETH**. +Let's say the stake currency is **ETH** and there is $10$ **ETH** on the wallet. The capital available percentage is $50%$ and the allowed risk per trade is $1\%$. Thus, the available capital for trading is $10 * 0.5 = 5$ **ETH** and the allowed capital at risk would be $5 * 0.01 = 0.05$ **ETH**. -Let's assume Edge has calculated that for **XLM/ETH** market your stoploss should be at 2%. So your position size will be **0.05 / 0.02 = 2.5 ETH**. +- **Trade 1:** The strategy detects a new buy signal in the **XLM/ETH** market. `Edge Positioning` calculates a stoploss of $2\%$ and a position of $0.05 / 0.02 = 2.5$ **ETH**. The bot takes a position of $2.5$ **ETH** in the **XLM/ETH** market. -Bot takes a position of 2.5 ETH on XLM/ETH (call it trade 1). Up next, you receive another buy signal while trade 1 is still open. This time on **BTC/ETH** market. Edge calculated stoploss for this market at 4%. So your position size would be 0.05 / 0.04 = 1.25 ETH (call it trade 2). +- **Trade 2:** The strategy detects a buy signal on the **BTC/ETH** market while **Trade 1** is still open. `Edge Positioning` calculates the stoploss of $4\%$ on this market. Thus, **Trade 2** position size is $0.05 / 0.04 = 1.25$ **ETH**. -Note that available capital for trading didn’t change for trade 2 even if you had already trade 1. The available capital doesn’t mean the free amount on your wallet. +!!! Tip "Available Capital $\neq$ Available in wallet" + The available capital for trading didn't change in **Trade 2** even with **Trade 1** still open. The available capital **is not** the free amount in the wallet. -Now you have two trades open. The bot receives yet another buy signal for another market: **ADA/ETH**. This time the stoploss is calculated at 1%. So your position size is **0.05 / 0.01 = 5 ETH**. But there are already 3.75 ETH blocked in two previous trades. So the position size for this third trade would be **5 – 3.75 = 1.25 ETH**. +- **Trade 3:** The strategy detects a buy signal in the **ADA/ETH** market. `Edge Positioning` calculates a stoploss of $1\%$ and a position of $0.05 / 0.01 = 5$ **ETH**. Since **Trade 1** has $2.5$ **ETH** blocked and **Trade 2** has $1.25$ **ETH** blocked, there is only $5 - 1.25 - 2.5 = 1.25$ **ETH** available. Hence, the position size of **Trade 3** is $1.25$ **ETH**. -Available capital doesn’t change before a position is sold. Let’s assume that trade 1 receives a sell signal and it is sold with a profit of 1 ETH. Your total capital on exchange would be 11 ETH and the available capital for trading becomes 5.5 ETH. +!!! Tip "Available Capital Updates" + The available capital does not change before a position is sold. After a trade is closed the Available Capital goes up if the trade was profitable or goes down if the trade was a loss. -So the Bot receives another buy signal for trade 4 with a stoploss at 2% then your position size would be **0.055 / 0.02 = 2.75 ETH**. +- The strategy detects a sell signal in the **XLM/ETH** market. The bot exits **Trade 1** for a profit of $1$ **ETH**. The total capital in the wallet becomes $11$ **ETH** and the available capital for trading becomes $5.5$ **ETH**. + +- **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**. ## Configurations @@ -169,23 +222,23 @@ freqtrade edge An example of its output: -| pair | stoploss | win rate | risk reward ratio | required risk reward | expectancy | total number of trades | average duration (min) | -|:----------|-----------:|-----------:|--------------------:|-----------------------:|-------------:|-------------------------:|-------------------------:| -| AGI/BTC | -0.02 | 0.64 | 5.86 | 0.56 | 3.41 | 14 | 54 | -| NXS/BTC | -0.03 | 0.64 | 2.99 | 0.57 | 1.54 | 11 | 26 | -| LEND/BTC | -0.02 | 0.82 | 2.05 | 0.22 | 1.50 | 11 | 36 | -| VIA/BTC | -0.01 | 0.55 | 3.01 | 0.83 | 1.19 | 11 | 48 | -| MTH/BTC | -0.09 | 0.56 | 2.82 | 0.80 | 1.12 | 18 | 52 | -| ARDR/BTC | -0.04 | 0.42 | 3.14 | 1.40 | 0.73 | 12 | 42 | -| BCPT/BTC | -0.01 | 0.71 | 1.34 | 0.40 | 0.67 | 14 | 30 | -| WINGS/BTC | -0.02 | 0.56 | 1.97 | 0.80 | 0.65 | 27 | 42 | -| VIBE/BTC | -0.02 | 0.83 | 0.91 | 0.20 | 0.59 | 12 | 35 | -| MCO/BTC | -0.02 | 0.79 | 0.97 | 0.27 | 0.55 | 14 | 31 | -| GNT/BTC | -0.02 | 0.50 | 2.06 | 1.00 | 0.53 | 18 | 24 | -| HOT/BTC | -0.01 | 0.17 | 7.72 | 4.81 | 0.50 | 209 | 7 | -| SNM/BTC | -0.03 | 0.71 | 1.06 | 0.42 | 0.45 | 17 | 38 | -| APPC/BTC | -0.02 | 0.44 | 2.28 | 1.27 | 0.44 | 25 | 43 | -| NEBL/BTC | -0.03 | 0.63 | 1.29 | 0.58 | 0.44 | 19 | 59 | +| **pair** | **stoploss** | **win rate** | **risk reward ratio** | **required risk reward** | **expectancy** | **total number of trades** | **average duration (min)** | +|:----------|-----------:|-----------:|--------------------:|-----------------------:|-------------:|-----------------:|---------------:| +| **AGI/BTC** | -0.02 | 0.64 | 5.86 | 0.56 | 3.41 | 14 | 54 | +| **NXS/BTC** | -0.03 | 0.64 | 2.99 | 0.57 | 1.54 | 11 | 26 | +| **LEND/BTC** | -0.02 | 0.82 | 2.05 | 0.22 | 1.50 | 11 | 36 | +| **VIA/BTC** | -0.01 | 0.55 | 3.01 | 0.83 | 1.19 | 11 | 48 | +| **MTH/BTC** | -0.09 | 0.56 | 2.82 | 0.80 | 1.12 | 18 | 52 | +| **ARDR/BTC** | -0.04 | 0.42 | 3.14 | 1.40 | 0.73 | 12 | 42 | +| **BCPT/BTC** | -0.01 | 0.71 | 1.34 | 0.40 | 0.67 | 14 | 30 | +| **WINGS/BTC** | -0.02 | 0.56 | 1.97 | 0.80 | 0.65 | 27 | 42 | +| **VIBE/BTC** | -0.02 | 0.83 | 0.91 | 0.20 | 0.59 | 12 | 35 | +| **MCO/BTC** | -0.02 | 0.79 | 0.97 | 0.27 | 0.55 | 14 | 31 | +| **GNT/BTC** | -0.02 | 0.50 | 2.06 | 1.00 | 0.53 | 18 | 24 | +| **HOT/BTC** | -0.01 | 0.17 | 7.72 | 4.81 | 0.50 | 209 | 7 | +| **SNM/BTC** | -0.03 | 0.71 | 1.06 | 0.42 | 0.45 | 17 | 38 | +| **APPC/BTC** | -0.02 | 0.44 | 2.28 | 1.27 | 0.44 | 25 | 43 | +| **NEBL/BTC** | -0.03 | 0.63 | 1.29 | 0.58 | 0.44 | 19 | 59 | Edge produced the above table by comparing `calculate_since_number_of_days` to `minimum_expectancy` to find `min_trade_number` historical information based on the config file. The timerange Edge uses for its comparisons can be further limited by using the `--timerange` switch. @@ -218,3 +271,6 @@ The full timerange specification: * Use tickframes since 2018/01/31: `--timerange=20180131-` * Use tickframes since 2018/01/31 till 2018/03/01 : `--timerange=20180131-20180301` * Use tickframes between POSIX timestamps 1527595200 1527618600: `--timerange=1527595200-1527618600` + + +[^1]: Question extracted from MIT Opencourseware S096 - Mathematics with applications in Finance: https://ocw.mit.edu/courses/mathematics/18-s096-topics-in-mathematics-with-applications-in-finance-fall-2013/ diff --git a/docs/javascripts/config.js b/docs/javascripts/config.js new file mode 100644 index 000000000..95d619efc --- /dev/null +++ b/docs/javascripts/config.js @@ -0,0 +1,12 @@ +window.MathJax = { + tex: { + inlineMath: [["\\(", "\\)"]], + displayMath: [["\\[", "\\]"]], + processEscapes: true, + processEnvironments: true + }, + options: { + ignoreHtmlClass: ".*|", + processHtmlClass: "arithmatex" + } +}; \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index ebd32b3c1..324dc46db 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -39,13 +39,19 @@ theme: accent: 'tear' extra_css: - 'stylesheets/ft.extra.css' +extra_javascript: + - javascripts/config.js + - https://polyfill.io/v3/polyfill.min.js?features=es6 + - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js markdown_extensions: - admonition + - footnotes - codehilite: guess_lang: false - toc: permalink: true - - pymdownx.arithmatex + - pymdownx.arithmatex: + generic: true - pymdownx.caret - pymdownx.critic - pymdownx.details From 47352e17215731b02748ee05aedfd08fd7fc9c71 Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Wed, 2 Sep 2020 20:37:45 -0600 Subject: [PATCH 244/285] Address issue #2487 Breakdown insllation instructions Make installation instructions shorter Separate Windows from the remainder Use tabs for better navigation Minor language improvements --- docs/docker.md | 349 ++++++--------------------------- docs/docker_compose.md | 44 +++++ docs/installation.md | 146 ++++---------- docs/windows_installation.md | 49 +++++ docs/without_docker_compose.md | 201 +++++++++++++++++++ mkdocs.yml | 10 +- 6 files changed, 405 insertions(+), 394 deletions(-) create mode 100644 docs/docker_compose.md create mode 100644 docs/windows_installation.md create mode 100644 docs/without_docker_compose.md diff --git a/docs/docker.md b/docs/docker.md index 92478088a..83f2d06e3 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -8,7 +8,7 @@ Start by downloading and installing Docker CE for your platform: * [Windows](https://docs.docker.com/docker-for-windows/install/) * [Linux](https://docs.docker.com/install/) -Optionally, [docker-compose](https://docs.docker.com/compose/install/) should be installed and available to follow the [docker quick start guide](#docker-quick-start). +Optionally, [`docker-compose`](https://docs.docker.com/compose/install/) should be installed and available to follow the [docker quick start guide](#docker-quick-start). Once you have Docker installed, simply prepare the config file (e.g. `config.json`) and run the image for `freqtrade` as explained below. @@ -17,325 +17,96 @@ Once you have Docker installed, simply prepare the config file (e.g. `config.jso Freqtrade provides an official Docker image on [Dockerhub](https://hub.docker.com/r/freqtradeorg/freqtrade/), as well as a [docker-compose file](https://github.com/freqtrade/freqtrade/blob/develop/docker-compose.yml) ready for usage. !!! Note - The following section assumes that docker and docker-compose is installed and available to the logged in user. - -!!! Note - All below comands use relative directories and will have to be executed from the directory containing the `docker-compose.yml` file. - -!!! Note "Docker on Raspberry" - If you're running freqtrade on a Raspberry PI, you must change the image from `freqtradeorg/freqtrade:master` to `freqtradeorg/freqtrade:master_pi` or `freqtradeorg/freqtrade:develop_pi`, otherwise the image will not work. + - The following section assumes that `docker` and `docker-compose` are installed and available to the logged in user. + - All below comands use relative directories and will have to be executed from the directory containing the `docker-compose.yml` file. + ### Docker quick start Create a new directory and place the [docker-compose file](https://github.com/freqtrade/freqtrade/blob/develop/docker-compose.yml) in this directory. -``` bash -mkdir ft_userdata -cd ft_userdata/ -# Download the docker-compose file from the repository -curl https://raw.githubusercontent.com/freqtrade/freqtrade/develop/docker-compose.yml -o docker-compose.yml +=== "PC/MAC/Linux" + ``` bash + mkdir ft_userdata + cd ft_userdata/ + # Download the docker-compose file from the repository + curl https://raw.githubusercontent.com/freqtrade/freqtrade/master/docker-compose.yml -o docker-compose.yml -# Pull the freqtrade image -docker-compose pull + # Pull the freqtrade image + docker-compose pull -# Create user directory structure -docker-compose run --rm freqtrade create-userdir --userdir user_data + # Create user directory structure + docker-compose run --rm freqtrade create-userdir --userdir user_data -# Create configuration - Requires answering interactive questions -docker-compose run --rm freqtrade new-config --config user_data/config.json -``` + # Create configuration - Requires answering interactive questions + docker-compose run --rm freqtrade new-config --config user_data/config.json + ``` -The above snippet creates a new directory called "ft_userdata", downloads the latest compose file and pulls the freqtrade image. -The last 2 steps in the snippet create the directory with user-data, as well as (interactively) the default configuration based on your selections. +=== "RaspberryPi" + ``` bash + mkdir ft_userdata + cd ft_userdata/ + # Download the docker-compose file from the repository + curl https://raw.githubusercontent.com/freqtrade/freqtrade/master_pi/docker-compose.yml -o docker-compose.yml -!!! Note + # Pull the freqtrade image + docker-compose pull + + # Create user directory structure + docker-compose run --rm freqtrade create-userdir --userdir user_data + + # Create configuration - Requires answering interactive questions + docker-compose run --rm freqtrade new-config --config user_data/config.json + ``` + +The above snippet creates a new directory called `ft_userdata`, downloads the latest compose file and pulls the freqtrade image. +The last 2 steps in the snippet create the directory with `user_data`, as well as (interactively) the default configuration based on your selections. + +!!! Question "How to edit the bot configuration?" You can edit the configuration at any time, which is available as `user_data/config.json` (within the directory `ft_userdata`) when using the above configuration. -#### Adding your strategy +#### Adding a custom strategy -The configuration is now available as `user_data/config.json`. -You should now copy your strategy to `user_data/strategies/` - and add the Strategy class name to the `docker-compose.yml` file, replacing `SampleStrategy`. If you wish to run the bot with the SampleStrategy, just leave it as it is. +1. The configuration is now available as `user_data/config.json` +2. Copy a custom strategy to the directory `user_data/strategies/` +3. add the Strategy' class name to the `docker-compose.yml` file -!!! Warning +The `SampleStrategy` is run by default. + +!!! Warning "`SampleStrategy` is just a demo!" The `SampleStrategy` is there for your reference and give you ideas for your own strategy. Please always backtest the strategy and use dry-run for some time before risking real money! Once this is done, you're ready to launch the bot in trading mode (Dry-run or Live-trading, depending on your answer to the corresponding question you made above). -``` bash -docker-compose up -d -``` +=== "Docker Compose" + ``` bash + docker-compose up -d + ``` #### Docker-compose logs -Logs will be written to `user_data/logs/freqtrade.log`. -Alternatively, you can check the latest logs using `docker-compose logs -f`. +Logs will be located at: `user_data/logs/freqtrade.log`. +You can check the latest log with the command `docker-compose logs -f`. #### Database -The database will be in the user_data directory as well, and will be called `user_data/tradesv3.sqlite`. +The database will be at: `user_data/tradesv3.sqlite` #### Updating freqtrade with docker-compose -To update freqtrade when using docker-compose is as simple as running the following 2 commands: +To update freqtrade when using `docker-compose` is as simple as running the following 2 commands: -``` bash -# Download the latest image -docker-compose pull -# Restart the image -docker-compose up -d -``` +=== "Docker Compose" + ``` bash + # Download the latest image + docker-compose pull + # Restart the image + docker-compose up -d + ``` This will first pull the latest image, and will then restart the container with the just pulled version. -!!! Note +!!! Warning "Check the Changelog" You should always check the changelog for breaking changes / manual interventions required and make sure the bot starts correctly after the update. -#### Going from here - -Advanced users may edit the docker-compose file further to include all possible options or arguments. - -All possible freqtrade arguments will be available by running `docker-compose run --rm freqtrade `. - -!!! Note "`docker-compose run --rm`" - Including `--rm` will clean up the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command). - -##### Example: Download data with docker-compose - -Download backtesting data for 5 days for the pair ETH/BTC and 1h timeframe from Binance. The data will be stored in the directory `user_data/data/` on the host. - -``` bash -docker-compose run --rm freqtrade download-data --pairs ETH/BTC --exchange binance --days 5 -t 1h -``` - -Head over to the [Data Downloading Documentation](data-download.md) for more details on downloading data. - -##### Example: Backtest with docker-compose - -Run backtesting in docker-containers for SampleStrategy and specified timerange of historical data, on 5m timeframe: - -``` bash -docker-compose run --rm freqtrade backtesting --config user_data/config.json --strategy SampleStrategy --timerange 20190801-20191001 -i 5m -``` - -Head over to the [Backtesting Documentation](backtesting.md) to learn more. - -#### Additional dependencies with docker-compose - -If your strategy requires dependencies not included in the default image (like [technical](https://github.com/freqtrade/technical)) - it will be necessary to build the image on your host. -For this, please create a Dockerfile containing installation steps for the additional dependencies (have a look at [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) for an example). - -You'll then also need to modify the `docker-compose.yml` file and uncomment the build step, as well as rename the image to avoid naming collisions. - -``` yaml - image: freqtrade_custom - build: - context: . - dockerfile: "./Dockerfile." -``` - -You can then run `docker-compose build` to build the docker image, and run it using the commands described above. - -## Freqtrade with docker without docker-compose - -!!! Warning - The below documentation is provided for completeness and assumes that you are somewhat familiar with running docker containers. If you're just starting out with docker, we recommend to follow the [Freqtrade with docker-compose](#freqtrade-with-docker-compose) instructions. - -### Download the official Freqtrade docker image - -Pull the image from docker hub. - -Branches / tags available can be checked out on [Dockerhub tags page](https://hub.docker.com/r/freqtradeorg/freqtrade/tags/). - -```bash -docker pull freqtradeorg/freqtrade:develop -# Optionally tag the repository so the run-commands remain shorter -docker tag freqtradeorg/freqtrade:develop freqtrade -``` - -To update the image, simply run the above commands again and restart your running container. - -Should you require additional libraries, please [build the image yourself](#build-your-own-docker-image). - -!!! Note "Docker image update frequency" - The official docker images with tags `master`, `develop` and `latest` are automatically rebuild once a week to keep the base image uptodate. - In addition to that, every merge to `develop` will trigger a rebuild for `develop` and `latest`. - -### Prepare the configuration files - -Even though you will use docker, you'll still need some files from the github repository. - -#### Clone the git repository - -Linux/Mac/Windows with WSL - -```bash -git clone https://github.com/freqtrade/freqtrade.git -``` - -Windows with docker - -```bash -git clone --config core.autocrlf=input https://github.com/freqtrade/freqtrade.git -``` - -#### Copy `config.json.example` to `config.json` - -```bash -cd freqtrade -cp -n config.json.example config.json -``` - -> To understand the configuration options, please refer to the [Bot Configuration](configuration.md) page. - -#### Create your database file - -Production - -```bash -touch tradesv3.sqlite -```` - -Dry-Run - -```bash -touch tradesv3.dryrun.sqlite -``` - -!!! Note - Make sure to use the path to this file when starting the bot in docker. - -### Build your own Docker image - -Best start by pulling the official docker image from dockerhub as explained [here](#download-the-official-docker-image) to speed up building. - -To add additional libraries to your docker image, best check out [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) which adds the [technical](https://github.com/freqtrade/technical) module to the image. - -```bash -docker build -t freqtrade -f Dockerfile.technical . -``` - -If you are developing using Docker, use `Dockerfile.develop` to build a dev Docker image, which will also set up develop dependencies: - -```bash -docker build -f Dockerfile.develop -t freqtrade-dev . -``` - -!!! Note - For security reasons, your configuration file will not be included in the image, you will need to bind mount it. It is also advised to bind mount an SQLite database file (see the "5. Run a restartable docker image" section) to keep it between updates. - -#### Verify the Docker image - -After the build process you can verify that the image was created with: - -```bash -docker images -``` - -The output should contain the freqtrade image. - -### Run the Docker image - -You can run a one-off container that is immediately deleted upon exiting with the following command (`config.json` must be in the current working directory): - -```bash -docker run --rm -v `pwd`/config.json:/freqtrade/config.json -it freqtrade -``` - -!!! Warning - In this example, the database will be created inside the docker instance and will be lost when you will refresh your image. - -#### Adjust timezone - -By default, the container will use UTC timezone. -Should you find this irritating please add the following to your docker commands: - -##### Linux - -``` bash --v /etc/timezone:/etc/timezone:ro - -# Complete command: -docker run --rm -v /etc/timezone:/etc/timezone:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade -``` - -##### MacOS - -There is known issue in OSX Docker versions after 17.09.1, whereby `/etc/localtime` cannot be shared causing Docker to not start. A work-around for this is to start with the following cmd. - -```bash -docker run --rm -e TZ=`ls -la /etc/localtime | cut -d/ -f8-9` -v `pwd`/config.json:/freqtrade/config.json -it freqtrade -``` - -More information on this docker issue and work-around can be read [here](https://github.com/docker/for-mac/issues/2396). - -### Run a restartable docker image - -To run a restartable instance in the background (feel free to place your configuration and database files wherever it feels comfortable on your filesystem). - -#### Move your config file and database - -The following will assume that you place your configuration / database files to `~/.freqtrade`, which is a hidden directory in your home directory. Feel free to use a different directory and replace the directory in the upcomming commands. - -```bash -mkdir ~/.freqtrade -mv config.json ~/.freqtrade -mv tradesv3.sqlite ~/.freqtrade -``` - -#### Run the docker image - -```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 \ - freqtrade trade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy -``` - -!!! Note - When using docker, it's best to specify `--db-url` explicitly to ensure that the database URL and the mounted database file match. - -!!! Note - All available bot command line parameters can be added to the end of the `docker run` command. - -!!! Note - You can define a [restart policy](https://docs.docker.com/config/containers/start-containers-automatically/) in docker. It can be useful in some cases to use the `--restart unless-stopped` flag (crash of freqtrade or reboot of your system). - -### Monitor your Docker instance - -You can use the following commands to monitor and manage your container: - -```bash -docker logs freqtrade -docker logs -f freqtrade -docker restart freqtrade -docker stop freqtrade -docker start freqtrade -``` - -For more information on how to operate Docker, please refer to the [official Docker documentation](https://docs.docker.com/). - -!!! Note - You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. - -### Backtest with docker - -The following assumes that the download/setup of the docker image have been completed successfully. -Also, backtest-data should be available at `~/.freqtrade/user_data/`. - -```bash -docker run -d \ - --name freqtrade \ - -v /etc/localtime:/etc/localtime:ro \ - -v ~/.freqtrade/config.json:/freqtrade/config.json \ - -v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \ - -v ~/.freqtrade/user_data/:/freqtrade/user_data/ \ - freqtrade backtesting --strategy AwsomelyProfitableStrategy -``` - -Head over to the [Backtesting Documentation](backtesting.md) for more details. - -!!! Note - Additional bot command line parameters can be appended after the image name (`freqtrade` in the above example). diff --git a/docs/docker_compose.md b/docs/docker_compose.md new file mode 100644 index 000000000..302d3b358 --- /dev/null +++ b/docs/docker_compose.md @@ -0,0 +1,44 @@ +#### Editing the docker-compose file + +Advanced users may edit the docker-compose file further to include all possible options or arguments. + +All possible freqtrade arguments will be available by running `docker-compose run --rm freqtrade `. + +!!! Note "`docker-compose run --rm`" + Including `--rm` will clean up the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command). + +##### Example: Download data with docker-compose + +Download backtesting data for 5 days for the pair ETH/BTC and 1h timeframe from Binance. The data will be stored in the directory `user_data/data/` on the host. + +``` bash +docker-compose run --rm freqtrade download-data --pairs ETH/BTC --exchange binance --days 5 -t 1h +``` + +Head over to the [Data Downloading Documentation](data-download.md) for more details on downloading data. + +##### Example: Backtest with docker-compose + +Run backtesting in docker-containers for SampleStrategy and specified timerange of historical data, on 5m timeframe: + +``` bash +docker-compose run --rm freqtrade backtesting --config user_data/config.json --strategy SampleStrategy --timerange 20190801-20191001 -i 5m +``` + +Head over to the [Backtesting Documentation](backtesting.md) to learn more. + +#### Additional dependencies with docker-compose + +If your strategy requires dependencies not included in the default image (like [technical](https://github.com/freqtrade/technical)) - it will be necessary to build the image on your host. +For this, please create a Dockerfile containing installation steps for the additional dependencies (have a look at [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) for an example). + +You'll then also need to modify the `docker-compose.yml` file and uncomment the build step, as well as rename the image to avoid naming collisions. + +``` yaml + image: freqtrade_custom + build: + context: . + dockerfile: "./Dockerfile." +``` + +You can then run `docker-compose build` to build the docker image, and run it using the commands described above. \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md index c03be55d1..979679c9f 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -79,6 +79,20 @@ This option will hard reset your branch (only if you are on either `master` or ` DEPRECATED - use `freqtrade new-config -c config.json` instead. +### MacOS installation error + +Newer versions of MacOS may have installation failed with errors like `error: command 'g++' failed with exit status 1`. + +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 +open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg +``` + +If this file is inexistant, then you're probably on a different version of MacOS, so you may need to consult the internet for specific resolution details. + + ------ ## Custom Installation @@ -89,36 +103,44 @@ OS Specific steps are listed first, the [Common](#common) section below is neces !!! Note Python3.6 or higher and the corresponding pip are assumed to be available. -### Linux - Ubuntu 16.04 +=== "Ubuntu 16.04" + #### Install necessary dependencies -#### Install necessary dependencies + ```bash + sudo apt-get update + sudo apt-get install build-essential git + ``` -```bash -sudo apt-get update -sudo apt-get install build-essential git -``` +=== "RaspberryPi/Raspbian" + The following assumes the latest [Raspbian Buster lite image](https://www.raspberrypi.org/downloads/raspbian/) from at least September 2019. + This image comes with python3.7 preinstalled, making it easy to get freqtrade up and running. -### Raspberry Pi / Raspbian + Tested using a Raspberry Pi 3 with the Raspbian Buster lite image, all updates applied. -The following assumes the latest [Raspbian Buster lite image](https://www.raspberrypi.org/downloads/raspbian/) from at least September 2019. -This image comes with python3.7 preinstalled, making it easy to get freqtrade up and running. + ``` bash + sudo apt-get install python3-venv libatlas-base-dev + git clone https://github.com/freqtrade/freqtrade.git + cd freqtrade -Tested using a Raspberry Pi 3 with the Raspbian Buster lite image, all updates applied. + bash setup.sh -i + ``` -``` bash -sudo apt-get install python3-venv libatlas-base-dev -git clone https://github.com/freqtrade/freqtrade.git -cd freqtrade + !!! Note "Installation duration" + Depending on your internet speed and the Raspberry Pi version, installation can take multiple hours to complete. -bash setup.sh -i -``` + !!! 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. -!!! Note "Installation duration" - Depending on your internet speed and the Raspberry Pi version, installation can take multiple hours to complete. +=== "Anaconda" + Freqtrade can also be installed using Anaconda (or Miniconda). -!!! 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. + !!! Note + This requires the [ta-lib](#1-install-ta-lib) C-library to be installed first. See below. + + ``` bash + conda env create -f environment.yml + ``` ### Common @@ -169,11 +191,6 @@ Clone the git repository: ```bash git clone https://github.com/freqtrade/freqtrade.git cd freqtrade -``` - -Optionally checkout the master branch to get the latest stable release: - -```bash git checkout master ``` @@ -212,83 +229,6 @@ On Linux, as an optional post-installation task, you may wish to setup the bot t ------ -## Using Conda - -Freqtrade can also be installed using Anaconda (or Miniconda). - -``` bash -conda env create -f environment.yml -``` - -!!! Note - This requires the [ta-lib](#1-install-ta-lib) C-library to be installed first. - -## Windows - -We recommend that Windows users use [Docker](docker.md) as this will work much easier and smoother (also more secure). - -If that is not possible, try using the Windows Linux subsystem (WSL) - for which the Ubuntu instructions should work. -If that is not available on your system, feel free to try the instructions below, which led to success for some. - -### Install freqtrade manually - -!!! Note - Make sure to use 64bit Windows and 64bit Python to avoid problems with backtesting or hyperopt due to the memory constraints 32bit applications have under Windows. - -!!! Hint - Using the [Anaconda Distribution](https://www.anaconda.com/distribution/) under Windows can greatly help with installation problems. Check out the [Conda section](#using-conda) in this document for more information. - -#### Clone the git repository - -```bash -git clone https://github.com/freqtrade/freqtrade.git -``` - -#### Install ta-lib - -Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7/ta-lib#windows). - -As compiling from source on windows has heavy dependencies (requires a partial visual studio installation), there is also a repository of unofficial precompiled windows Wheels [here](https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib), which needs to be downloaded and installed using `pip install TA_Lib‑0.4.18‑cp38‑cp38‑win_amd64.whl` (make sure to use the version matching your python version) - -```cmd ->cd \path\freqtrade-develop ->python -m venv .env ->.env\Scripts\activate.bat -REM optionally install ta-lib from wheel -REM >pip install TA_Lib‑0.4.18‑cp38‑cp38‑win_amd64.whl ->pip install -r requirements.txt ->pip install -e . ->freqtrade -``` - -> Thanks [Owdr](https://github.com/Owdr) for the commands. Source: [Issue #222](https://github.com/freqtrade/freqtrade/issues/222) - -#### Error during installation under Windows - -``` bash -error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools -``` - -Unfortunately, many packages requiring compilation don't provide a pre-build wheel. It is therefore mandatory to have a C/C++ compiler installed and available for your python environment to use. - -The easiest way is to download install Microsoft Visual Studio Community [here](https://visualstudio.microsoft.com/downloads/) and make sure to install "Common Tools for Visual C++" to enable building c code on Windows. Unfortunately, this is a heavy download / dependency (~4Gb) so you might want to consider WSL or [docker](docker.md) first. - ---- - Now you have an environment ready, the next step is [Bot Configuration](configuration.md). -## Troubleshooting - -### MacOS installation error - -Newer versions of MacOS may have installation failed with errors like `error: command 'g++' failed with exit status 1`. - -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 -open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -``` - -If this file is inexistant, then you're probably on a different version of MacOS, so you may need to consult the internet for specific resolution details. diff --git a/docs/windows_installation.md b/docs/windows_installation.md new file mode 100644 index 000000000..1cdb3d613 --- /dev/null +++ b/docs/windows_installation.md @@ -0,0 +1,49 @@ +We **strongly** recommend that Windows users use [Docker](docker.md) as this will work much easier and smoother (also more secure). + +If that is not possible, try using the Windows Linux subsystem (WSL) - for which the Ubuntu instructions should work. +Otherwise, try the instructions below. + +## Install freqtrade manually + +!!! Note + Make sure to use 64bit Windows and 64bit Python to avoid problems with backtesting or hyperopt due to the memory constraints 32bit applications have under Windows. + +!!! Hint + Using the [Anaconda Distribution](https://www.anaconda.com/distribution/) under Windows can greatly help with installation problems. Check out the [Conda section](#using-conda) in this document for more information. + +### 1. Clone the git repository + +```bash +git clone https://github.com/freqtrade/freqtrade.git +``` + +### 2. Install ta-lib + +Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7/ta-lib#windows). + +As compiling from source on windows has heavy dependencies (requires a partial visual studio installation), there is also a repository of unofficial precompiled windows Wheels [here](https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib), which needs to be downloaded and installed using `pip install TA_Lib‑0.4.18‑cp38‑cp38‑win_amd64.whl` (make sure to use the version matching your python version) + +```cmd +>cd \path\freqtrade-develop +>python -m venv .env +>.env\Scripts\activate.bat +REM optionally install ta-lib from wheel +REM >pip install TA_Lib‑0.4.18‑cp38‑cp38‑win_amd64.whl +>pip install -r requirements.txt +>pip install -e . +>freqtrade +``` + +> Thanks [Owdr](https://github.com/Owdr) for the commands. Source: [Issue #222](https://github.com/freqtrade/freqtrade/issues/222) + +### Error during installation on Windows + +``` bash +error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools +``` + +Unfortunately, many packages requiring compilation don't provide a pre-build wheel. It is therefore mandatory to have a C/C++ compiler installed and available for your python environment to use. + +The easiest way is to download install Microsoft Visual Studio Community [here](https://visualstudio.microsoft.com/downloads/) and make sure to install "Common Tools for Visual C++" to enable building c code on Windows. Unfortunately, this is a heavy download / dependency (~4Gb) so you might want to consider WSL or [docker](docker.md) first. + +--- diff --git a/docs/without_docker_compose.md b/docs/without_docker_compose.md new file mode 100644 index 000000000..23994f38f --- /dev/null +++ b/docs/without_docker_compose.md @@ -0,0 +1,201 @@ +## Freqtrade with docker without docker-compose + +!!! Warning + The below documentation is provided for completeness and assumes that you are familiar with running docker containers. If you're just starting out with Docker, we recommend to follow the [Quickstart](docker.md) instructions. + +### Download the official Freqtrade docker image + +Pull the image from docker hub. + +Branches / tags available can be checked out on [Dockerhub tags page](https://hub.docker.com/r/freqtradeorg/freqtrade/tags/). + +```bash +docker pull freqtradeorg/freqtrade:master +# Optionally tag the repository so the run-commands remain shorter +docker tag freqtradeorg/freqtrade:master freqtrade +``` + +To update the image, simply run the above commands again and restart your running container. + +Should you require additional libraries, please [build the image yourself](#build-your-own-docker-image). + +!!! Note "Docker image update frequency" + The official docker images with tags `master`, `develop` and `latest` are automatically rebuild once a week to keep the base image uptodate. + In addition to that, every merge to `develop` will trigger a rebuild for `develop` and `latest`. + +### Prepare the configuration files + +Even though you will use docker, you'll still need some files from the github repository. + +#### Clone the git repository + +Linux/Mac/Windows with WSL + +```bash +git clone https://github.com/freqtrade/freqtrade.git +``` + +Windows with docker + +```bash +git clone --config core.autocrlf=input https://github.com/freqtrade/freqtrade.git +``` + +#### Copy `config.json.example` to `config.json` + +```bash +cd freqtrade +cp -n config.json.example config.json +``` + +> To understand the configuration options, please refer to the [Bot Configuration](configuration.md) page. + +#### Create your database file + +=== "Dry-Run" + ``` bash + touch tradesv3.dryrun.sqlite + ``` + +=== "Production" + ``` bash + touch tradesv3.sqlite + ``` + + +!!! Warning Database File Path + Make sure to use the path to the correct database file when starting the bot in Docker. + +### Build your own Docker image + +Best start by pulling the official docker image from dockerhub as explained [here](#download-the-official-docker-image) to speed up building. + +To add additional libraries to your docker image, best check out [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) which adds the [technical](https://github.com/freqtrade/technical) module to the image. + +```bash +docker build -t freqtrade -f Dockerfile.technical . +``` + +If you are developing using Docker, use `Dockerfile.develop` to build a dev Docker image, which will also set up develop dependencies: + +```bash +docker build -f Dockerfile.develop -t freqtrade-dev . +``` + +!!! Warning Include your config file manually + For security reasons, your configuration file will not be included in the image, you will need to bind mount it. It is also advised to bind mount an SQLite database file (see [5. Run a restartable docker image](#run-a-restartable-docker-image)") to keep it between updates. + +#### Verify the Docker image + +After the build process you can verify that the image was created with: + +```bash +docker images +``` + +The output should contain the freqtrade image. + +### Run the Docker image + +You can run a one-off container that is immediately deleted upon exiting with the following command (`config.json` must be in the current working directory): + +```bash +docker run --rm -v `pwd`/config.json:/freqtrade/config.json -it freqtrade +``` + +!!! Warning + In this example, the database will be created inside the docker instance and will be lost when you refresh your image. + +#### Adjust timezone + +By default, the container will use UTC timezone. +If you would like to change the timezone use the following commands: + +=== "Linux" + ``` bash + -v /etc/timezone:/etc/timezone:ro + + # Complete command: + docker run --rm -v /etc/timezone:/etc/timezone:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade + ``` + +=== "MacOS" + ```bash + docker run --rm -e TZ=`ls -la /etc/localtime | cut -d/ -f8-9` -v `pwd`/config.json:/freqtrade/config.json -it freqtrade + ``` + +!!! Note MacOS Issues + The OSX Docker versions after 17.09.1 have a known issue whereby `/etc/localtime` cannot be shared causing Docker to not start.
    + A work-around for this is to start with the MacOS command above + More information on this docker issue and work-around can be read [here](https://github.com/docker/for-mac/issues/2396). + +### Run a restartable docker image + +To run a restartable instance in the background (feel free to place your configuration and database files wherever it feels comfortable on your filesystem). + +#### 1. Move your config file and database + +The following will assume that you place your configuration / database files to `~/.freqtrade`, which is a hidden directory in your home directory. Feel free to use a different directory and replace the directory in the upcomming commands. + +```bash +mkdir ~/.freqtrade +mv config.json ~/.freqtrade +mv tradesv3.sqlite ~/.freqtrade +``` + +#### 2. Run the docker image + +```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 \ + freqtrade trade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy +``` + +!!! Note + When using docker, it's best to specify `--db-url` explicitly to ensure that the database URL and the mounted database file match. + +!!! Note + All available bot command line parameters can be added to the end of the `docker run` command. + +!!! Note + You can define a [restart policy](https://docs.docker.com/config/containers/start-containers-automatically/) in docker. It can be useful in some cases to use the `--restart unless-stopped` flag (crash of freqtrade or reboot of your system). + +### Monitor your Docker instance + +You can use the following commands to monitor and manage your container: + +```bash +docker logs freqtrade +docker logs -f freqtrade +docker restart freqtrade +docker stop freqtrade +docker start freqtrade +``` + +For more information on how to operate Docker, please refer to the [official Docker documentation](https://docs.docker.com/). + +!!! Note + You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. + +### Backtest with docker + +The following assumes that the download/setup of the docker image have been completed successfully. +Also, backtest-data should be available at `~/.freqtrade/user_data/`. + +```bash +docker run -d \ + --name freqtrade \ + -v /etc/localtime:/etc/localtime:ro \ + -v ~/.freqtrade/config.json:/freqtrade/config.json \ + -v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \ + -v ~/.freqtrade/user_data/:/freqtrade/user_data/ \ + freqtrade backtesting --strategy AwsomelyProfitableStrategy +``` + +Head over to the [Backtesting Documentation](backtesting.md) for more details. + +!!! Note + Additional bot command line parameters can be appended after the image name (`freqtrade` in the above example). diff --git a/mkdocs.yml b/mkdocs.yml index 324dc46db..2750ed3a5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,8 +1,13 @@ site_name: Freqtrade nav: - Home: index.md - - Installation Docker: docker.md - - Installation: installation.md + - Installation Docker: + - Quickstart: docker.md + - Freqtrade with Docker Compose (Advanced): docker_compose.md + - Freqtrade without docker-compose: without_docker_compose.md + - Installation: + - Linux/MacOS/Raspberry: installation.md + - Windows: windows_installation.md - Freqtrade Basics: bot-basics.md - Configuration: configuration.md - Strategy Customization: strategy-customization.md @@ -59,6 +64,7 @@ markdown_extensions: - pymdownx.magiclink - pymdownx.mark - pymdownx.smartsymbols + - pymdownx.tabbed - pymdownx.superfences - pymdownx.tasklist: custom_checkbox: true From 5c5cf782f53597f27bf0c361f86268d1c07a8ebf Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 3 Sep 2020 19:29:48 +0200 Subject: [PATCH 245/285] Fix small bug with /daily if close_profit_abs is not yet filled --- 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 802c8372b..b89a95ee8 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -224,7 +224,8 @@ class RPC: Trade.close_date >= profitday, Trade.close_date < (profitday + timedelta(days=1)) ]).order_by(Trade.close_date).all() - curdayprofit = sum(trade.close_profit_abs for trade in trades) + curdayprofit = sum( + trade.close_profit_abs for trade in trades if trade.close_profit_abs is not None) profit_days[profitday] = { 'amount': curdayprofit, 'trades': len(trades) From 27362046d474744da563d74bd370da70eb82cd3b Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 3 Sep 2020 19:33:34 +0200 Subject: [PATCH 246/285] Add documentation section about running docs locally --- docs/developer.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/developer.md b/docs/developer.md index 8bee1fd8e..111c7a96f 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -10,6 +10,15 @@ Documentation is available at [https://freqtrade.io](https://www.freqtrade.io/) Special fields for the documentation (like Note boxes, ...) can be found [here](https://squidfunk.github.io/mkdocs-material/extensions/admonition/). +To test the documentation locally use the following commands. + +``` bash +pip install -r docs/requirements-docs.txt +mkdocs serve +``` + +This will spin up a local server (usually on port 8000) so you can see if everything looks as you'd like it to. + ## Developer setup To configure a development environment, best use the `setup.sh` script and answer "y" when asked "Do you want to install dependencies for dev [y/N]? ". From ec9b51d60a49feda0ab4d8dbb477780ffe149bca Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:49:32 -0600 Subject: [PATCH 247/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 182c47651..6d43b0ea9 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -13,7 +13,7 @@ The `Edge Positioning` module uses probability to calculate your win rate and ri 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. -To obtain an edge in the market, a strategy has to make more money than it loses. Marking money in trading is not only about *how often* the strategy makes or loses money. +To obtain an edge in the market, a strategy has to make more money than it loses. Making money in trading is not only about *how often* the strategy makes or loses money. !!! tip "It doesn't matter how often, but how much!" A bad strategy might make 1 penny in *ten* transactions but lose 1 dollar in *one* transaction. If one only checks the number of winning trades, it would be misleading to think that the strategy is actually making a profit. From 69349a9d8d047c762e567723637a68259a478bd2 Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:49:54 -0600 Subject: [PATCH 248/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 6d43b0ea9..8fae683a5 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -82,7 +82,7 @@ Risk Reward Ratio (*R*) is a formula used to measure the expected gains of a giv $$ R = \frac{\text{potential_profit}}{\text{potential_loss}} $$ ??? Example "Worked example of $R$ calculation" - Let's say that you think that the price of *stonecoin* today is $10.0. You believe that, because they will start mining stonecoin it will go up to $15.0 tomorrow. There is the risk that the stone is too hard, and the GPUs can't mine it, so the price might go to $0 tomorrow. You are planning to invest $100.
    + Let's say that you think that the price of *stonecoin* today is $10.0. You believe that, because they will start mining stonecoin, it will go up to $15.0 tomorrow. There is the risk that the stone is too hard, and the GPUs can't mine it, so the price might go to $0 tomorrow. You are planning to invest $100.
    Your potential profit is calculated as:
    $\begin{aligned} \text{potential_profit} &= (\text{potential_price} - \text{cost_per_unit}) * \frac{\text{investment}}{\text{cost_per_unit}} \\ From 70eaf971cd55c45c9e27c8420f23e5c41a875ecc Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:50:23 -0600 Subject: [PATCH 249/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 8fae683a5..7634718ae 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -77,7 +77,7 @@ Where $L$ is the lose rate, $N$ is the amount of trades made and, $T_{lose}$ is ### Risk Reward Ratio -Risk Reward Ratio (*R*) is a formula used to measure the expected gains of a given investment against the risk of loss. It is basically what you potentially win divided by what you potentially lose. Formally: +Risk Reward Ratio ($R$) is a formula used to measure the expected gains of a given investment against the risk of loss. It is basically what you potentially win divided by what you potentially lose. Formally: $$ R = \frac{\text{potential_profit}}{\text{potential_loss}} $$ From 5f9c449d8eecd8a1af79c2a1e7a3f5b897ea5eb6 Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:53:33 -0600 Subject: [PATCH 250/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 7634718ae..e6b27a340 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -97,7 +97,7 @@ $$ R = \frac{\text{potential_profit}}{\text{potential_loss}} $$ \end{aligned}$
    What it effectivelly means is that the strategy have the potential to make $0.33 for each $1 invested. -On a long horizonte, that is, on many trades, we can calculate the risk reward by dividing the strategy' average profit on winning trades by the strategy' average loss on losing trades. We can calculate the average profit, $\mu_{win}$, as follows: +On a long horizon, that is, on many trades, we can calculate the risk reward by dividing the strategy' average profit on winning trades by the strategy' average loss on losing trades. We can calculate the average profit, $\mu_{win}$, as follows: $$ \text{average_profit} = \mu_{win} = \frac{\text{sum_of_profits}}{\text{count_winning_trades}} = \frac{\sum^{o \in T_{win}} o}{|T_{win}|} $$ From 08e35461209d47ab0b57b838da55add33d8a5575 Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:55:07 -0600 Subject: [PATCH 251/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index e6b27a340..8c8b230c9 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -105,7 +105,7 @@ Similarly, we can calculate the average loss, $\mu_{lose}$, as follows: $$ \text{average_loss} = \mu_{lose} = \frac{\text{sum_of_losses}}{\text{count_losing_trades}} = \frac{\sum^{o \in T_{lose}} o}{|T_{lose}|} $$ -Finally, we can calculate the Risk Reward ratio as follows: +Finally, we can calculate the Risk Reward ratio, $R$, as follows: $$ R = \frac{\text{average_profit}}{\text{average_loss}} = \frac{\mu_{win}}{\mu_{lose}}\\ $$ From 1f13a8b91d28d5f25579b2010e9b4246bece4a90 Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:55:49 -0600 Subject: [PATCH 252/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 8c8b230c9..a5df45901 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -129,7 +129,7 @@ $$E = R * W - L$$ The expectancy worked out in the example above means that, on average, this strategy' trades will return 1.68 times the size of its losses. Said another way, the strategy makes $1.68 for every $1 it loses, on average. -You canThis is important for two reasons: First, it may seem obvious, but you know right away that you have a positive return. Second, you now have a number you can compare to other candidate systems to make decisions about which ones you employ. +This is important for two reasons: First, it may seem obvious, but you know right away that you have a positive return. Second, you now have a number you can compare to other candidate systems to make decisions about which ones you employ. It is important to remember that any system with an expectancy greater than 0 is profitable using past data. The key is finding one that will be profitable in the future. From 93d1ad5ed9569072a51678e3a3b2634be41bc8fd Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:56:54 -0600 Subject: [PATCH 253/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index a5df45901..f7870ac1a 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -135,7 +135,8 @@ It is important to remember that any system with an expectancy greater than 0 is You can also use this value to evaluate the effectiveness of modifications to this system. -**NOTICE:** It's important to keep in mind that Edge is testing your expectancy using historical data, there's no guarantee that you will have a similar edge in the future. It's still vital to do this testing in order to build confidence in your methodology but be wary of "curve-fitting" your approach to the historical data as things are unlikely to play out the exact same way for future trades. +!!! Note + It's important to keep in mind that Edge is testing your expectancy using historical data, there's no guarantee that you will have a similar edge in the future. It's still vital to do this testing in order to build confidence in your methodology but be wary of "curve-fitting" your approach to the historical data as things are unlikely to play out the exact same way for future trades. ## How does it work? From 47f0e69072975469acabe808304f1a9491086db2 Mon Sep 17 00:00:00 2001 From: Victor Silva <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 12:57:15 -0600 Subject: [PATCH 254/285] Update docs/edge.md Co-authored-by: Matthias --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index f7870ac1a..593137c8d 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -149,7 +149,7 @@ Edge combines dynamic stoploss, dynamic positions, and whitelist generation into | XZC/ETH | -0.03 | 0.52 |1.359670 | 0.228 | | XZC/ETH | -0.04 | 0.51 |1.234539 | 0.117 | -The goal here is to find the best stoploss for the strategy in order to have the maximum expectancy. In the above example stoploss at $3% $leads to the maximum expectancy according to historical data. +The goal here is to find the best stoploss for the strategy in order to have the maximum expectancy. In the above example stoploss at $3%$ leads to the maximum expectancy according to historical data. Edge module then forces stoploss value it evaluated to your strategy dynamically. From 714264701c5bcc338ebee9b1dd8286e3d7cb90cd Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:11:04 -0600 Subject: [PATCH 255/285] Fixes typos --- docs/without_docker_compose.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/without_docker_compose.md b/docs/without_docker_compose.md index 23994f38f..3fe335cf0 100644 --- a/docs/without_docker_compose.md +++ b/docs/without_docker_compose.md @@ -63,7 +63,7 @@ cp -n config.json.example config.json ``` -!!! Warning Database File Path +!!! Warning "Database File Path" Make sure to use the path to the correct database file when starting the bot in Docker. ### Build your own Docker image @@ -82,7 +82,7 @@ If you are developing using Docker, use `Dockerfile.develop` to build a dev Dock docker build -f Dockerfile.develop -t freqtrade-dev . ``` -!!! Warning Include your config file manually +!!! Warning "Include your config file manually" For security reasons, your configuration file will not be included in the image, you will need to bind mount it. It is also advised to bind mount an SQLite database file (see [5. Run a restartable docker image](#run-a-restartable-docker-image)") to keep it between updates. #### Verify the Docker image @@ -124,7 +124,7 @@ If you would like to change the timezone use the following commands: docker run --rm -e TZ=`ls -la /etc/localtime | cut -d/ -f8-9` -v `pwd`/config.json:/freqtrade/config.json -it freqtrade ``` -!!! Note MacOS Issues +!!! Note "MacOS Issues" The OSX Docker versions after 17.09.1 have a known issue whereby `/etc/localtime` cannot be shared causing Docker to not start.
    A work-around for this is to start with the MacOS command above More information on this docker issue and work-around can be read [here](https://github.com/docker/for-mac/issues/2396). From f6a8dda8e5600ca8a95108013cb1903240085bec Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:12:43 -0600 Subject: [PATCH 256/285] Reorganize structure - Quickstart moved out of installation - Installation now contains only advanced modes. - Joined quickstart with Docker --- mkdocs.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 2750ed3a5..5d936687f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,11 +1,9 @@ site_name: Freqtrade nav: - Home: index.md - - Installation Docker: - - Quickstart: docker.md - - Freqtrade with Docker Compose (Advanced): docker_compose.md - - Freqtrade without docker-compose: without_docker_compose.md + - Quickstart with Docker: docker.md - Installation: + - Freqtrade without docker-compose: without_docker_compose.md - Linux/MacOS/Raspberry: installation.md - Windows: windows_installation.md - Freqtrade Basics: bot-basics.md From 66505bd9bf2f281417044b5259db345b4621b6c8 Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:18:15 -0600 Subject: [PATCH 257/285] Fixes Raspberri Pi Image config --- docs/docker.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/docker.md b/docs/docker.md index 83f2d06e3..9c8cc1683 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -47,7 +47,7 @@ Create a new directory and place the [docker-compose file](https://github.com/fr mkdir ft_userdata cd ft_userdata/ # Download the docker-compose file from the repository - curl https://raw.githubusercontent.com/freqtrade/freqtrade/master_pi/docker-compose.yml -o docker-compose.yml + curl https://raw.githubusercontent.com/freqtrade/freqtrade/master/docker-compose.yml -o docker-compose.yml # Pull the freqtrade image docker-compose pull @@ -59,6 +59,13 @@ Create a new directory and place the [docker-compose file](https://github.com/fr docker-compose run --rm freqtrade new-config --config user_data/config.json ``` + !!! Note "Change your docker Image" + You should change the docker image in your config file for your Raspeberry build to work properly. + ``` bash + image: freqtradeorg/freqtrade:master_pi + # image: freqtradeorg/freqtrade:develop_pi + ``` + The above snippet creates a new directory called `ft_userdata`, downloads the latest compose file and pulls the freqtrade image. The last 2 steps in the snippet create the directory with `user_data`, as well as (interactively) the default configuration based on your selections. From e6058b716b1be8711d54d9274b0509700fdda5dd Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:19:05 -0600 Subject: [PATCH 258/285] removes prolixity docker-compose --- docs/docker.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/docker.md b/docs/docker.md index 9c8cc1683..9f90502bf 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -104,13 +104,13 @@ The database will be at: `user_data/tradesv3.sqlite` To update freqtrade when using `docker-compose` is as simple as running the following 2 commands: -=== "Docker Compose" - ``` bash - # Download the latest image - docker-compose pull - # Restart the image - docker-compose up -d - ``` + +``` bash +# Download the latest image +docker-compose pull +# Restart the image +docker-compose up -d +``` This will first pull the latest image, and will then restart the container with the just pulled version. From 29fe2ffff74de8f1ee2f3ce1f53f1da4f6cbf960 Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:22:22 -0600 Subject: [PATCH 259/285] Added that the user can edit docker-compose.yml --- docs/docker.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/docker.md b/docs/docker.md index 9f90502bf..ae16fe922 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -60,7 +60,7 @@ Create a new directory and place the [docker-compose file](https://github.com/fr ``` !!! Note "Change your docker Image" - You should change the docker image in your config file for your Raspeberry build to work properly. + You should change the docker image in your config file for your Raspberry build to work properly. ``` bash image: freqtradeorg/freqtrade:master_pi # image: freqtradeorg/freqtrade:develop_pi @@ -72,6 +72,8 @@ The last 2 steps in the snippet create the directory with `user_data`, as well a !!! Question "How to edit the bot configuration?" You can edit the configuration at any time, which is available as `user_data/config.json` (within the directory `ft_userdata`) when using the above configuration. + You can also change the both Strategy and commands by editing the `docker-compose.yml` file. + #### Adding a custom strategy 1. The configuration is now available as `user_data/config.json` From 34b27d2f96808846e64430a9c19724519cfb5309 Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:32:07 -0600 Subject: [PATCH 260/285] Moving stuff around - Mac troubleshooting to the end - optional master checkout - Anaconda moved to the end --- docs/installation.md | 50 +++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 979679c9f..83dd2938c 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -38,7 +38,7 @@ This can be achieved with the following commands: ```bash git clone https://github.com/freqtrade/freqtrade.git cd freqtrade -git checkout master # Optional, see (1) +# git checkout master # Optional, see (1) ./setup.sh --install ``` @@ -79,18 +79,7 @@ This option will hard reset your branch (only if you are on either `master` or ` DEPRECATED - use `freqtrade new-config -c config.json` instead. -### MacOS installation error -Newer versions of MacOS may have installation failed with errors like `error: command 'g++' failed with exit status 1`. - -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 -open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -``` - -If this file is inexistant, then you're probably on a different version of MacOS, so you may need to consult the internet for specific resolution details. ------ @@ -132,16 +121,6 @@ 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. -=== "Anaconda" - Freqtrade can also be installed using Anaconda (or Miniconda). - - !!! Note - This requires the [ta-lib](#1-install-ta-lib) C-library to be installed first. See below. - - ``` bash - conda env create -f environment.yml - ``` - ### Common #### 1. Install TA-Lib @@ -229,6 +208,33 @@ On Linux, as an optional post-installation task, you may wish to setup the bot t ------ +### Anaconda + +Freqtrade can also be installed using Anaconda (or Miniconda). + +!!! Note + This requires the [ta-lib](#1-install-ta-lib) C-library to be installed first. See below. + +``` bash +conda env create -f environment.yml +``` + +----- + Now you have an environment ready, the next step is [Bot Configuration](configuration.md). +----- + +### MacOS installation error + +Newer versions of MacOS may have installation failed with errors like `error: command 'g++' failed with exit status 1`. + +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 +open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg +``` + +If this file is inexistant, then you're probably on a different version of MacOS, so you may need to consult the internet for specific resolution details. \ No newline at end of file From 275d8534323129124a1a5ed369fe7a38576e7251 Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:38:46 -0600 Subject: [PATCH 261/285] Updated W, L Formulas --- docs/edge.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/edge.md b/docs/edge.md index 593137c8d..e147cc15e 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -26,7 +26,7 @@ We raise the following question[^1]: a) A trade with 80% of chance of losing $100 and 20% chance of winning $200
    b) A trade with 100% of chance of losing $30 -??? Info "Answer" +???+ Info "Answer" The expected value of *a)* is smaller than the expected value of *b)*.
    Hence, *b*) represents a smaller loss in the long run.
    However, the answer is: *it depends* @@ -63,14 +63,14 @@ $$ T_{lose} = \{o \in O | o \leq 0\} $$ The win rate $W$ is the proportion of winning trades with respect to all the trades made by a strategy. We use the following function to compute the win rate: -$$W = \frac{\sum^{o \in T_{win}} o}{N}$$ +$$W = \frac{|T_{win}|}{N}$$ Where $W$ is the win rate, $N$ is the number of trades and, $T_{win}$ is the set of all trades where the strategy made money. Similarly, we can compute the rate of losing trades: $$ - L = \frac{\sum^{o \in T_{lose}} o}{N} + L = \frac{|T_{lose}|}{N} $$ Where $L$ is the lose rate, $N$ is the amount of trades made and, $T_{lose}$ is the set of all trades where the strategy lost money. Note that the above formula is the same as calculating $L = 1 – W$ or $W = 1 – L$ @@ -81,7 +81,7 @@ Risk Reward Ratio ($R$) is a formula used to measure the expected gains of a giv $$ R = \frac{\text{potential_profit}}{\text{potential_loss}} $$ -??? Example "Worked example of $R$ calculation" +???+ Example "Worked example of $R$ calculation" Let's say that you think that the price of *stonecoin* today is $10.0. You believe that, because they will start mining stonecoin, it will go up to $15.0 tomorrow. There is the risk that the stone is too hard, and the GPUs can't mine it, so the price might go to $0 tomorrow. You are planning to invest $100.
    Your potential profit is calculated as:
    $\begin{aligned} @@ -110,7 +110,7 @@ Finally, we can calculate the Risk Reward ratio, $R$, as follows: $$ R = \frac{\text{average_profit}}{\text{average_loss}} = \frac{\mu_{win}}{\mu_{lose}}\\ $$ -??? Example "Worked example of $R$ calculation using mean profit/loss" +???+ Example "Worked example of $R$ calculation using mean profit/loss" Let's say the strategy that we are using makes an average win $\mu_{win} = 2.06$ and an average loss $\mu_{loss} = 4.11$.
    We calculate the risk reward ratio as follows:
    $R = \frac{\mu_{win}}{\mu_{loss}} = \frac{2.06}{4.11} = 0.5012...$ From 32005b886a9cc5916e015cb1308ce3e78572db7b Mon Sep 17 00:00:00 2001 From: silvavn <37382997+silvavn@users.noreply.github.com> Date: Thu, 3 Sep 2020 13:39:38 -0600 Subject: [PATCH 262/285] small typo --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index e147cc15e..500c3c833 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -44,7 +44,7 @@ Edge positioning tries to answer the hard questions about risk/reward and positi Let's call $o$ the return of a single transaction $o$ where $o \in \mathbb{R}$. The collection $O = \{o_1, o_2, ..., o_N\}$ is the set of all returns of transactions made during a trading session. We say that $N$ is the cardinality of $O$, or, in lay terms, it is the number of transactions made in a trading session. !!! Example - In a session where a strategy made three transactions we can say that $O = \{3.5, -1, 15\}$. That means that $N = 3$ and $o_1 = 3.5$, $o_2 = -1$, $o = 15$. + In a session where a strategy made three transactions we can say that $O = \{3.5, -1, 15\}$. That means that $N = 3$ and $o_1 = 3.5$, $o_2 = -1$, $o_3 = 15$. A winning trade is a trade where a strategy *made* money. Making money means that the strategy closed the position in a value that returned a profit, after all deducted fees. Formally, a winning trade will have a return $o_i > 0$. Similarly, a losing trade will have a return $o_j \leq 0$. With that, we can discover the set of all winning trades, $T_{win}$, as follows: From 1406691945511db6c1de8f69b89f03fd1a09af75 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 4 Sep 2020 07:12:08 +0200 Subject: [PATCH 263/285] Rename files to have clearer paths --- docs/docker.md | 304 +++++++++++++++++++++------------ docs/docker_compose.md | 44 ----- docs/docker_quickstart.md | 162 ++++++++++++++++++ docs/installation.md | 13 +- docs/without_docker_compose.md | 201 ---------------------- mkdocs.yml | 6 +- 6 files changed, 364 insertions(+), 366 deletions(-) delete mode 100644 docs/docker_compose.md create mode 100644 docs/docker_quickstart.md delete mode 100644 docs/without_docker_compose.md diff --git a/docs/docker.md b/docs/docker.md index ae16fe922..3fe335cf0 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -1,121 +1,201 @@ -# Using Freqtrade with Docker +## Freqtrade with docker without docker-compose -## Install Docker +!!! Warning + The below documentation is provided for completeness and assumes that you are familiar with running docker containers. If you're just starting out with Docker, we recommend to follow the [Quickstart](docker.md) instructions. -Start by downloading and installing Docker CE for your platform: +### Download the official Freqtrade docker image -* [Mac](https://docs.docker.com/docker-for-mac/install/) -* [Windows](https://docs.docker.com/docker-for-windows/install/) -* [Linux](https://docs.docker.com/install/) +Pull the image from docker hub. -Optionally, [`docker-compose`](https://docs.docker.com/compose/install/) should be installed and available to follow the [docker quick start guide](#docker-quick-start). +Branches / tags available can be checked out on [Dockerhub tags page](https://hub.docker.com/r/freqtradeorg/freqtrade/tags/). -Once you have Docker installed, simply prepare the config file (e.g. `config.json`) and run the image for `freqtrade` as explained below. - -## Freqtrade with docker-compose - -Freqtrade provides an official Docker image on [Dockerhub](https://hub.docker.com/r/freqtradeorg/freqtrade/), as well as a [docker-compose file](https://github.com/freqtrade/freqtrade/blob/develop/docker-compose.yml) ready for usage. - -!!! Note - - The following section assumes that `docker` and `docker-compose` are installed and available to the logged in user. - - All below comands use relative directories and will have to be executed from the directory containing the `docker-compose.yml` file. - - -### Docker quick start - -Create a new directory and place the [docker-compose file](https://github.com/freqtrade/freqtrade/blob/develop/docker-compose.yml) in this directory. - -=== "PC/MAC/Linux" - ``` bash - mkdir ft_userdata - cd ft_userdata/ - # Download the docker-compose file from the repository - curl https://raw.githubusercontent.com/freqtrade/freqtrade/master/docker-compose.yml -o docker-compose.yml - - # Pull the freqtrade image - docker-compose pull - - # Create user directory structure - docker-compose run --rm freqtrade create-userdir --userdir user_data - - # Create configuration - Requires answering interactive questions - docker-compose run --rm freqtrade new-config --config user_data/config.json - ``` - -=== "RaspberryPi" - ``` bash - mkdir ft_userdata - cd ft_userdata/ - # Download the docker-compose file from the repository - curl https://raw.githubusercontent.com/freqtrade/freqtrade/master/docker-compose.yml -o docker-compose.yml - - # Pull the freqtrade image - docker-compose pull - - # Create user directory structure - docker-compose run --rm freqtrade create-userdir --userdir user_data - - # Create configuration - Requires answering interactive questions - docker-compose run --rm freqtrade new-config --config user_data/config.json - ``` - - !!! Note "Change your docker Image" - You should change the docker image in your config file for your Raspberry build to work properly. - ``` bash - image: freqtradeorg/freqtrade:master_pi - # image: freqtradeorg/freqtrade:develop_pi - ``` - -The above snippet creates a new directory called `ft_userdata`, downloads the latest compose file and pulls the freqtrade image. -The last 2 steps in the snippet create the directory with `user_data`, as well as (interactively) the default configuration based on your selections. - -!!! Question "How to edit the bot configuration?" - You can edit the configuration at any time, which is available as `user_data/config.json` (within the directory `ft_userdata`) when using the above configuration. - - You can also change the both Strategy and commands by editing the `docker-compose.yml` file. - -#### Adding a custom strategy - -1. The configuration is now available as `user_data/config.json` -2. Copy a custom strategy to the directory `user_data/strategies/` -3. add the Strategy' class name to the `docker-compose.yml` file - -The `SampleStrategy` is run by default. - -!!! Warning "`SampleStrategy` is just a demo!" - The `SampleStrategy` is there for your reference and give you ideas for your own strategy. - Please always backtest the strategy and use dry-run for some time before risking real money! - -Once this is done, you're ready to launch the bot in trading mode (Dry-run or Live-trading, depending on your answer to the corresponding question you made above). - -=== "Docker Compose" - ``` bash - docker-compose up -d - ``` - -#### Docker-compose logs - -Logs will be located at: `user_data/logs/freqtrade.log`. -You can check the latest log with the command `docker-compose logs -f`. - -#### Database - -The database will be at: `user_data/tradesv3.sqlite` - -#### Updating freqtrade with docker-compose - -To update freqtrade when using `docker-compose` is as simple as running the following 2 commands: - - -``` bash -# Download the latest image -docker-compose pull -# Restart the image -docker-compose up -d +```bash +docker pull freqtradeorg/freqtrade:master +# Optionally tag the repository so the run-commands remain shorter +docker tag freqtradeorg/freqtrade:master freqtrade ``` -This will first pull the latest image, and will then restart the container with the just pulled version. +To update the image, simply run the above commands again and restart your running container. -!!! Warning "Check the Changelog" - You should always check the changelog for breaking changes / manual interventions required and make sure the bot starts correctly after the update. +Should you require additional libraries, please [build the image yourself](#build-your-own-docker-image). +!!! Note "Docker image update frequency" + The official docker images with tags `master`, `develop` and `latest` are automatically rebuild once a week to keep the base image uptodate. + In addition to that, every merge to `develop` will trigger a rebuild for `develop` and `latest`. + +### Prepare the configuration files + +Even though you will use docker, you'll still need some files from the github repository. + +#### Clone the git repository + +Linux/Mac/Windows with WSL + +```bash +git clone https://github.com/freqtrade/freqtrade.git +``` + +Windows with docker + +```bash +git clone --config core.autocrlf=input https://github.com/freqtrade/freqtrade.git +``` + +#### Copy `config.json.example` to `config.json` + +```bash +cd freqtrade +cp -n config.json.example config.json +``` + +> To understand the configuration options, please refer to the [Bot Configuration](configuration.md) page. + +#### Create your database file + +=== "Dry-Run" + ``` bash + touch tradesv3.dryrun.sqlite + ``` + +=== "Production" + ``` bash + touch tradesv3.sqlite + ``` + + +!!! Warning "Database File Path" + Make sure to use the path to the correct database file when starting the bot in Docker. + +### Build your own Docker image + +Best start by pulling the official docker image from dockerhub as explained [here](#download-the-official-docker-image) to speed up building. + +To add additional libraries to your docker image, best check out [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) which adds the [technical](https://github.com/freqtrade/technical) module to the image. + +```bash +docker build -t freqtrade -f Dockerfile.technical . +``` + +If you are developing using Docker, use `Dockerfile.develop` to build a dev Docker image, which will also set up develop dependencies: + +```bash +docker build -f Dockerfile.develop -t freqtrade-dev . +``` + +!!! Warning "Include your config file manually" + For security reasons, your configuration file will not be included in the image, you will need to bind mount it. It is also advised to bind mount an SQLite database file (see [5. Run a restartable docker image](#run-a-restartable-docker-image)") to keep it between updates. + +#### Verify the Docker image + +After the build process you can verify that the image was created with: + +```bash +docker images +``` + +The output should contain the freqtrade image. + +### Run the Docker image + +You can run a one-off container that is immediately deleted upon exiting with the following command (`config.json` must be in the current working directory): + +```bash +docker run --rm -v `pwd`/config.json:/freqtrade/config.json -it freqtrade +``` + +!!! Warning + In this example, the database will be created inside the docker instance and will be lost when you refresh your image. + +#### Adjust timezone + +By default, the container will use UTC timezone. +If you would like to change the timezone use the following commands: + +=== "Linux" + ``` bash + -v /etc/timezone:/etc/timezone:ro + + # Complete command: + docker run --rm -v /etc/timezone:/etc/timezone:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade + ``` + +=== "MacOS" + ```bash + docker run --rm -e TZ=`ls -la /etc/localtime | cut -d/ -f8-9` -v `pwd`/config.json:/freqtrade/config.json -it freqtrade + ``` + +!!! Note "MacOS Issues" + The OSX Docker versions after 17.09.1 have a known issue whereby `/etc/localtime` cannot be shared causing Docker to not start.
    + A work-around for this is to start with the MacOS command above + More information on this docker issue and work-around can be read [here](https://github.com/docker/for-mac/issues/2396). + +### Run a restartable docker image + +To run a restartable instance in the background (feel free to place your configuration and database files wherever it feels comfortable on your filesystem). + +#### 1. Move your config file and database + +The following will assume that you place your configuration / database files to `~/.freqtrade`, which is a hidden directory in your home directory. Feel free to use a different directory and replace the directory in the upcomming commands. + +```bash +mkdir ~/.freqtrade +mv config.json ~/.freqtrade +mv tradesv3.sqlite ~/.freqtrade +``` + +#### 2. Run the docker image + +```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 \ + freqtrade trade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy +``` + +!!! Note + When using docker, it's best to specify `--db-url` explicitly to ensure that the database URL and the mounted database file match. + +!!! Note + All available bot command line parameters can be added to the end of the `docker run` command. + +!!! Note + You can define a [restart policy](https://docs.docker.com/config/containers/start-containers-automatically/) in docker. It can be useful in some cases to use the `--restart unless-stopped` flag (crash of freqtrade or reboot of your system). + +### Monitor your Docker instance + +You can use the following commands to monitor and manage your container: + +```bash +docker logs freqtrade +docker logs -f freqtrade +docker restart freqtrade +docker stop freqtrade +docker start freqtrade +``` + +For more information on how to operate Docker, please refer to the [official Docker documentation](https://docs.docker.com/). + +!!! Note + You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. + +### Backtest with docker + +The following assumes that the download/setup of the docker image have been completed successfully. +Also, backtest-data should be available at `~/.freqtrade/user_data/`. + +```bash +docker run -d \ + --name freqtrade \ + -v /etc/localtime:/etc/localtime:ro \ + -v ~/.freqtrade/config.json:/freqtrade/config.json \ + -v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \ + -v ~/.freqtrade/user_data/:/freqtrade/user_data/ \ + freqtrade backtesting --strategy AwsomelyProfitableStrategy +``` + +Head over to the [Backtesting Documentation](backtesting.md) for more details. + +!!! Note + Additional bot command line parameters can be appended after the image name (`freqtrade` in the above example). diff --git a/docs/docker_compose.md b/docs/docker_compose.md deleted file mode 100644 index 302d3b358..000000000 --- a/docs/docker_compose.md +++ /dev/null @@ -1,44 +0,0 @@ -#### Editing the docker-compose file - -Advanced users may edit the docker-compose file further to include all possible options or arguments. - -All possible freqtrade arguments will be available by running `docker-compose run --rm freqtrade `. - -!!! Note "`docker-compose run --rm`" - Including `--rm` will clean up the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command). - -##### Example: Download data with docker-compose - -Download backtesting data for 5 days for the pair ETH/BTC and 1h timeframe from Binance. The data will be stored in the directory `user_data/data/` on the host. - -``` bash -docker-compose run --rm freqtrade download-data --pairs ETH/BTC --exchange binance --days 5 -t 1h -``` - -Head over to the [Data Downloading Documentation](data-download.md) for more details on downloading data. - -##### Example: Backtest with docker-compose - -Run backtesting in docker-containers for SampleStrategy and specified timerange of historical data, on 5m timeframe: - -``` bash -docker-compose run --rm freqtrade backtesting --config user_data/config.json --strategy SampleStrategy --timerange 20190801-20191001 -i 5m -``` - -Head over to the [Backtesting Documentation](backtesting.md) to learn more. - -#### Additional dependencies with docker-compose - -If your strategy requires dependencies not included in the default image (like [technical](https://github.com/freqtrade/technical)) - it will be necessary to build the image on your host. -For this, please create a Dockerfile containing installation steps for the additional dependencies (have a look at [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) for an example). - -You'll then also need to modify the `docker-compose.yml` file and uncomment the build step, as well as rename the image to avoid naming collisions. - -``` yaml - image: freqtrade_custom - build: - context: . - dockerfile: "./Dockerfile." -``` - -You can then run `docker-compose build` to build the docker image, and run it using the commands described above. \ No newline at end of file diff --git a/docs/docker_quickstart.md b/docs/docker_quickstart.md new file mode 100644 index 000000000..c033e827b --- /dev/null +++ b/docs/docker_quickstart.md @@ -0,0 +1,162 @@ +# Using Freqtrade with Docker + +## Install Docker + +Start by downloading and installing Docker CE for your platform: + +* [Mac](https://docs.docker.com/docker-for-mac/install/) +* [Windows](https://docs.docker.com/docker-for-windows/install/) +* [Linux](https://docs.docker.com/install/) + +Optionally, [`docker-compose`](https://docs.docker.com/compose/install/) should be installed and available to follow the [docker quick start guide](#docker-quick-start). + +Once you have Docker installed, simply prepare the config file (e.g. `config.json`) and run the image for `freqtrade` as explained below. + +## Freqtrade with docker-compose + +Freqtrade provides an official Docker image on [Dockerhub](https://hub.docker.com/r/freqtradeorg/freqtrade/), as well as a [docker-compose file](https://github.com/freqtrade/freqtrade/blob/develop/docker-compose.yml) ready for usage. + +!!! Note + - The following section assumes that `docker` and `docker-compose` are installed and available to the logged in user. + - All below commands use relative directories and will have to be executed from the directory containing the `docker-compose.yml` file. + +### Docker quick start + +Create a new directory and place the [docker-compose file](https://github.com/freqtrade/freqtrade/blob/develop/docker-compose.yml) in this directory. + +=== "PC/MAC/Linux" + ``` bash + mkdir ft_userdata + cd ft_userdata/ + # Download the docker-compose file from the repository + curl https://raw.githubusercontent.com/freqtrade/freqtrade/master/docker-compose.yml -o docker-compose.yml + + # Pull the freqtrade image + docker-compose pull + + # Create user directory structure + docker-compose run --rm freqtrade create-userdir --userdir user_data + + # Create configuration - Requires answering interactive questions + docker-compose run --rm freqtrade new-config --config user_data/config.json + ``` + +=== "RaspberryPi" + ``` bash + mkdir ft_userdata + cd ft_userdata/ + # Download the docker-compose file from the repository + curl https://raw.githubusercontent.com/freqtrade/freqtrade/master/docker-compose.yml -o docker-compose.yml + + # Pull the freqtrade image + docker-compose pull + + # Create user directory structure + docker-compose run --rm freqtrade create-userdir --userdir user_data + + # Create configuration - Requires answering interactive questions + docker-compose run --rm freqtrade new-config --config user_data/config.json + ``` + + !!! Note "Change your docker Image" + You have to change the docker image in the docker-compose file for your Raspberry build to work properly. + ``` yml + image: freqtradeorg/freqtrade:master_pi + # image: freqtradeorg/freqtrade:develop_pi + ``` + +The above snippet creates a new directory called `ft_userdata`, downloads the latest compose file and pulls the freqtrade image. +The last 2 steps in the snippet create the directory with `user_data`, as well as (interactively) the default configuration based on your selections. + +!!! Question "How to edit the bot configuration?" + You can edit the configuration at any time, which is available as `user_data/config.json` (within the directory `ft_userdata`) when using the above configuration. + + You can also change the both Strategy and commands by editing the `docker-compose.yml` file. + +#### Adding a custom strategy + +1. The configuration is now available as `user_data/config.json` +2. Copy a custom strategy to the directory `user_data/strategies/` +3. add the Strategy' class name to the `docker-compose.yml` file + +The `SampleStrategy` is run by default. + +!!! Warning "`SampleStrategy` is just a demo!" + The `SampleStrategy` is there for your reference and give you ideas for your own strategy. + Please always backtest the strategy and use dry-run for some time before risking real money! + +Once this is done, you're ready to launch the bot in trading mode (Dry-run or Live-trading, depending on your answer to the corresponding question you made above). + +``` bash +docker-compose up -d +``` + +#### Docker-compose logs + +Logs will be located at: `user_data/logs/freqtrade.log`. +You can check the latest log with the command `docker-compose logs -f`. + +#### Database + +The database will be at: `user_data/tradesv3.sqlite` + +#### Updating freqtrade with docker-compose + +To update freqtrade when using `docker-compose` is as simple as running the following 2 commands: + +``` bash +# Download the latest image +docker-compose pull +# Restart the image +docker-compose up -d +``` + +This will first pull the latest image, and will then restart the container with the just pulled version. + +!!! Warning "Check the Changelog" + You should always check the changelog for breaking changes / manual interventions required and make sure the bot starts correctly after the update. + +### Editing the docker-compose file + +Advanced users may edit the docker-compose file further to include all possible options or arguments. + +All possible freqtrade arguments will be available by running `docker-compose run --rm freqtrade `. + +!!! Note "`docker-compose run --rm`" + Including `--rm` will clean up the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command). + +#### Example: Download data with docker-compose + +Download backtesting data for 5 days for the pair ETH/BTC and 1h timeframe from Binance. The data will be stored in the directory `user_data/data/` on the host. + +``` bash +docker-compose run --rm freqtrade download-data --pairs ETH/BTC --exchange binance --days 5 -t 1h +``` + +Head over to the [Data Downloading Documentation](data-download.md) for more details on downloading data. + +#### Example: Backtest with docker-compose + +Run backtesting in docker-containers for SampleStrategy and specified timerange of historical data, on 5m timeframe: + +``` bash +docker-compose run --rm freqtrade backtesting --config user_data/config.json --strategy SampleStrategy --timerange 20190801-20191001 -i 5m +``` + +Head over to the [Backtesting Documentation](backtesting.md) to learn more. + +### Additional dependencies with docker-compose + +If your strategy requires dependencies not included in the default image (like [technical](https://github.com/freqtrade/technical)) - it will be necessary to build the image on your host. +For this, please create a Dockerfile containing installation steps for the additional dependencies (have a look at [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) for an example). + +You'll then also need to modify the `docker-compose.yml` file and uncomment the build step, as well as rename the image to avoid naming collisions. + +``` yaml + image: freqtrade_custom + build: + context: . + dockerfile: "./Dockerfile." +``` + +You can then run `docker-compose build` to build the docker image, and run it using the commands described above. diff --git a/docs/installation.md b/docs/installation.md index 83dd2938c..baa4a64d7 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -220,11 +220,7 @@ conda env create -f environment.yml ``` ----- - -Now you have an environment ready, the next step is -[Bot Configuration](configuration.md). - ------ +## Troubleshooting ### MacOS installation error @@ -237,4 +233,9 @@ For MacOS 10.14, this can be accomplished with the below command. open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg ``` -If this file is inexistant, then you're probably on a different version of MacOS, so you may need to consult the internet for specific resolution details. \ No newline at end of file +If this file is inexistent, then you're probably on a different version of MacOS, so you may need to consult the internet for specific resolution details. + +----- + +Now you have an environment ready, the next step is +[Bot Configuration](configuration.md). diff --git a/docs/without_docker_compose.md b/docs/without_docker_compose.md deleted file mode 100644 index 3fe335cf0..000000000 --- a/docs/without_docker_compose.md +++ /dev/null @@ -1,201 +0,0 @@ -## Freqtrade with docker without docker-compose - -!!! Warning - The below documentation is provided for completeness and assumes that you are familiar with running docker containers. If you're just starting out with Docker, we recommend to follow the [Quickstart](docker.md) instructions. - -### Download the official Freqtrade docker image - -Pull the image from docker hub. - -Branches / tags available can be checked out on [Dockerhub tags page](https://hub.docker.com/r/freqtradeorg/freqtrade/tags/). - -```bash -docker pull freqtradeorg/freqtrade:master -# Optionally tag the repository so the run-commands remain shorter -docker tag freqtradeorg/freqtrade:master freqtrade -``` - -To update the image, simply run the above commands again and restart your running container. - -Should you require additional libraries, please [build the image yourself](#build-your-own-docker-image). - -!!! Note "Docker image update frequency" - The official docker images with tags `master`, `develop` and `latest` are automatically rebuild once a week to keep the base image uptodate. - In addition to that, every merge to `develop` will trigger a rebuild for `develop` and `latest`. - -### Prepare the configuration files - -Even though you will use docker, you'll still need some files from the github repository. - -#### Clone the git repository - -Linux/Mac/Windows with WSL - -```bash -git clone https://github.com/freqtrade/freqtrade.git -``` - -Windows with docker - -```bash -git clone --config core.autocrlf=input https://github.com/freqtrade/freqtrade.git -``` - -#### Copy `config.json.example` to `config.json` - -```bash -cd freqtrade -cp -n config.json.example config.json -``` - -> To understand the configuration options, please refer to the [Bot Configuration](configuration.md) page. - -#### Create your database file - -=== "Dry-Run" - ``` bash - touch tradesv3.dryrun.sqlite - ``` - -=== "Production" - ``` bash - touch tradesv3.sqlite - ``` - - -!!! Warning "Database File Path" - Make sure to use the path to the correct database file when starting the bot in Docker. - -### Build your own Docker image - -Best start by pulling the official docker image from dockerhub as explained [here](#download-the-official-docker-image) to speed up building. - -To add additional libraries to your docker image, best check out [Dockerfile.technical](https://github.com/freqtrade/freqtrade/blob/develop/Dockerfile.technical) which adds the [technical](https://github.com/freqtrade/technical) module to the image. - -```bash -docker build -t freqtrade -f Dockerfile.technical . -``` - -If you are developing using Docker, use `Dockerfile.develop` to build a dev Docker image, which will also set up develop dependencies: - -```bash -docker build -f Dockerfile.develop -t freqtrade-dev . -``` - -!!! Warning "Include your config file manually" - For security reasons, your configuration file will not be included in the image, you will need to bind mount it. It is also advised to bind mount an SQLite database file (see [5. Run a restartable docker image](#run-a-restartable-docker-image)") to keep it between updates. - -#### Verify the Docker image - -After the build process you can verify that the image was created with: - -```bash -docker images -``` - -The output should contain the freqtrade image. - -### Run the Docker image - -You can run a one-off container that is immediately deleted upon exiting with the following command (`config.json` must be in the current working directory): - -```bash -docker run --rm -v `pwd`/config.json:/freqtrade/config.json -it freqtrade -``` - -!!! Warning - In this example, the database will be created inside the docker instance and will be lost when you refresh your image. - -#### Adjust timezone - -By default, the container will use UTC timezone. -If you would like to change the timezone use the following commands: - -=== "Linux" - ``` bash - -v /etc/timezone:/etc/timezone:ro - - # Complete command: - docker run --rm -v /etc/timezone:/etc/timezone:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade - ``` - -=== "MacOS" - ```bash - docker run --rm -e TZ=`ls -la /etc/localtime | cut -d/ -f8-9` -v `pwd`/config.json:/freqtrade/config.json -it freqtrade - ``` - -!!! Note "MacOS Issues" - The OSX Docker versions after 17.09.1 have a known issue whereby `/etc/localtime` cannot be shared causing Docker to not start.
    - A work-around for this is to start with the MacOS command above - More information on this docker issue and work-around can be read [here](https://github.com/docker/for-mac/issues/2396). - -### Run a restartable docker image - -To run a restartable instance in the background (feel free to place your configuration and database files wherever it feels comfortable on your filesystem). - -#### 1. Move your config file and database - -The following will assume that you place your configuration / database files to `~/.freqtrade`, which is a hidden directory in your home directory. Feel free to use a different directory and replace the directory in the upcomming commands. - -```bash -mkdir ~/.freqtrade -mv config.json ~/.freqtrade -mv tradesv3.sqlite ~/.freqtrade -``` - -#### 2. Run the docker image - -```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 \ - freqtrade trade --db-url sqlite:///tradesv3.sqlite --strategy MyAwesomeStrategy -``` - -!!! Note - When using docker, it's best to specify `--db-url` explicitly to ensure that the database URL and the mounted database file match. - -!!! Note - All available bot command line parameters can be added to the end of the `docker run` command. - -!!! Note - You can define a [restart policy](https://docs.docker.com/config/containers/start-containers-automatically/) in docker. It can be useful in some cases to use the `--restart unless-stopped` flag (crash of freqtrade or reboot of your system). - -### Monitor your Docker instance - -You can use the following commands to monitor and manage your container: - -```bash -docker logs freqtrade -docker logs -f freqtrade -docker restart freqtrade -docker stop freqtrade -docker start freqtrade -``` - -For more information on how to operate Docker, please refer to the [official Docker documentation](https://docs.docker.com/). - -!!! Note - You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. - -### Backtest with docker - -The following assumes that the download/setup of the docker image have been completed successfully. -Also, backtest-data should be available at `~/.freqtrade/user_data/`. - -```bash -docker run -d \ - --name freqtrade \ - -v /etc/localtime:/etc/localtime:ro \ - -v ~/.freqtrade/config.json:/freqtrade/config.json \ - -v ~/.freqtrade/tradesv3.sqlite:/freqtrade/tradesv3.sqlite \ - -v ~/.freqtrade/user_data/:/freqtrade/user_data/ \ - freqtrade backtesting --strategy AwsomelyProfitableStrategy -``` - -Head over to the [Backtesting Documentation](backtesting.md) for more details. - -!!! Note - Additional bot command line parameters can be appended after the image name (`freqtrade` in the above example). diff --git a/mkdocs.yml b/mkdocs.yml index 5d936687f..26494ae45 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,9 +1,9 @@ site_name: Freqtrade nav: - Home: index.md - - Quickstart with Docker: docker.md - - Installation: - - Freqtrade without docker-compose: without_docker_compose.md + - Quickstart with Docker: docker_quickstart.md + - Installation: + - Docker without docker-compose: docker.md - Linux/MacOS/Raspberry: installation.md - Windows: windows_installation.md - Freqtrade Basics: bot-basics.md From bc5cc48f67ddb494ad320e93817e7f8f7e44606b Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 4 Sep 2020 07:28:21 +0200 Subject: [PATCH 264/285] Adjust windows docs, fix failing doc-test --- docs/windows_installation.md | 28 ++++++++++++++++++---------- tests/test_docs.sh | 3 +-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/windows_installation.md b/docs/windows_installation.md index 1cdb3d613..f7900d85a 100644 --- a/docs/windows_installation.md +++ b/docs/windows_installation.md @@ -9,7 +9,7 @@ Otherwise, try the instructions below. Make sure to use 64bit Windows and 64bit Python to avoid problems with backtesting or hyperopt due to the memory constraints 32bit applications have under Windows. !!! Hint - Using the [Anaconda Distribution](https://www.anaconda.com/distribution/) under Windows can greatly help with installation problems. Check out the [Conda section](#using-conda) in this document for more information. + Using the [Anaconda Distribution](https://www.anaconda.com/distribution/) under Windows can greatly help with installation problems. Check out the [Anaconda installation section](installation.md#Anaconda) in this document for more information. ### 1. Clone the git repository @@ -23,17 +23,25 @@ Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7 As compiling from source on windows has heavy dependencies (requires a partial visual studio installation), there is also a repository of unofficial precompiled windows Wheels [here](https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib), which needs to be downloaded and installed using `pip install TA_Lib‑0.4.18‑cp38‑cp38‑win_amd64.whl` (make sure to use the version matching your python version) -```cmd ->cd \path\freqtrade-develop ->python -m venv .env ->.env\Scripts\activate.bat -REM optionally install ta-lib from wheel -REM >pip install TA_Lib‑0.4.18‑cp38‑cp38‑win_amd64.whl ->pip install -r requirements.txt ->pip install -e . ->freqtrade +Freqtrade provides these dependencies for the latest 2 Python versions (3.7 and 3.8) and for 64bit Windows. +Other versions must be downloaded from the above link. + +``` powershell +cd \path\freqtrade +python -m venv .env +.env\Scripts\activate.ps1 +# optionally install ta-lib from wheel +# Eventually adjust the below filename to match the downloaded wheel +pip install build_helpes/TA_Lib‑0.4.18‑cp38‑cp38‑win_amd64.whl +pip install -r requirements.txt +pip install -e . +freqtrade ``` +!!! Note "Use Powershell" + The above installation script assumes you're using powershell on a 64bit windows. + Commands for the legacy CMD windows console may differ. + > Thanks [Owdr](https://github.com/Owdr) for the commands. Source: [Issue #222](https://github.com/freqtrade/freqtrade/issues/222) ### Error during installation on Windows diff --git a/tests/test_docs.sh b/tests/test_docs.sh index 8a354daad..09e142b99 100755 --- a/tests/test_docs.sh +++ b/tests/test_docs.sh @@ -2,8 +2,7 @@ # Test Documentation boxes - # !!! : is not allowed! # !!! "title" - Title needs to be quoted! -# !!! Spaces at the beginning are not allowed -grep -Er '^!{3}\s\S+:|^!{3}\s\S+\s[^"]|^\s+!{3}\s\S+' docs/* +grep -Er '^!{3}\s\S+:|^!{3}\s\S+\s[^"]' docs/* if [ $? -ne 0 ]; then echo "Docs test success." From bd4f3d838ab959c3c8ff9f0e39daaeb62c3bddce Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 4 Sep 2020 19:44:35 +0200 Subject: [PATCH 265/285] Implement merge_informative_pairs helper --- freqtrade/strategy/__init__.py | 1 + freqtrade/strategy/strategy_helper.py | 39 ++++++++++++++++ tests/strategy/test_strategy_helpers.py | 61 +++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 freqtrade/strategy/strategy_helper.py create mode 100644 tests/strategy/test_strategy_helpers.py diff --git a/freqtrade/strategy/__init__.py b/freqtrade/strategy/__init__.py index 91ea0e075..5758bbbcc 100644 --- a/freqtrade/strategy/__init__.py +++ b/freqtrade/strategy/__init__.py @@ -2,3 +2,4 @@ from freqtrade.exchange import (timeframe_to_minutes, timeframe_to_prev_date, timeframe_to_seconds, timeframe_to_next_date, timeframe_to_msecs) from freqtrade.strategy.interface import IStrategy +from freqtrade.strategy.strategy_helper import merge_informative_pairs diff --git a/freqtrade/strategy/strategy_helper.py b/freqtrade/strategy/strategy_helper.py new file mode 100644 index 000000000..ce98cccba --- /dev/null +++ b/freqtrade/strategy/strategy_helper.py @@ -0,0 +1,39 @@ +import pandas as pd +from freqtrade.exchange import timeframe_to_minutes + + +def merge_informative_pairs(dataframe: pd.DataFrame, informative: pd.DataFrame, + timeframe_inf: str, ffill: bool = True) -> pd.DataFrame: + """ + Correctly merge informative samples to the original dataframe, avoiding lookahead bias. + + Since dates are candle open dates, merging a 15m candle that starts at 15:00, and a + 1h candle that starts at 15:00 will result in all candles to know the close at 16:00 + which they should not know. + + Moves the date of the informative pair by 1 time interval forward. + This way, the 14:00 1h candle is merged to 15:00 15m candle, since the 14:00 1h candle is the + last candle that's closed at 15:00, 15:15, 15:30 or 15:45. + + :param dataframe: Original dataframe + :param informative: Informative pair, most likely loaded via dp.get_pair_dataframe + :param timeframe_inf: Timeframe of the informative pair sample. + :param ffill: Forwardfill missing values - optional but usually required + """ + # Rename columns to be unique + + minutes = timeframe_to_minutes(timeframe_inf) + informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') + + informative.columns = [f"{col}_{timeframe_inf}" for col in informative.columns] + + # Combine the 2 dataframes + # all indicators on the informative sample MUST be calculated before this point + dataframe = pd.merge(dataframe, informative, left_on='date', + right_on=f'date_merge_{timeframe_inf}', how='left') + dataframe = dataframe.drop(f'date_merge_{timeframe_inf}', axis=1) + + if ffill: + dataframe = dataframe.ffill() + + return dataframe diff --git a/tests/strategy/test_strategy_helpers.py b/tests/strategy/test_strategy_helpers.py new file mode 100644 index 000000000..89bbba2c1 --- /dev/null +++ b/tests/strategy/test_strategy_helpers.py @@ -0,0 +1,61 @@ +import pandas as pd +import numpy as np + +from freqtrade.strategy import merge_informative_pairs, timeframe_to_minutes + + +def generate_test_data(timeframe: str, size: int): + np.random.seed(42) + tf_mins = timeframe_to_minutes(timeframe) + + base = np.random.normal(20, 2, size=size) + + date = pd.period_range('2020-07-05', periods=size, freq=f'{tf_mins}min').to_timestamp() + df = pd.DataFrame({ + 'date': date, + 'open': base, + 'high': base + np.random.normal(2, 1, size=size), + 'low': base - np.random.normal(2, 1, size=size), + 'close': base + np.random.normal(0, 1, size=size), + 'volume': np.random.normal(200, size=size) + } + ) + df = df.dropna() + return df + + +def test_merge_informative_pairs(): + data = generate_test_data('15m', 40) + informative = generate_test_data('1h', 40) + + result = merge_informative_pairs(data, informative, '1h', ffill=True) + assert isinstance(result, pd.DataFrame) + assert len(result) == len(data) + assert 'date' in result.columns + assert result['date'].equals(data['date']) + assert 'date_1h' in result.columns + + assert 'open' in result.columns + assert 'open_1h' in result.columns + assert result['open'].equals(data['open']) + + assert 'close' in result.columns + assert 'close_1h' in result.columns + assert result['close'].equals(data['close']) + + assert 'volume' in result.columns + assert 'volume_1h' in result.columns + assert result['volume'].equals(data['volume']) + + # First 4 rows are empty + assert result.iloc[0]['date_1h'] is pd.NaT + assert result.iloc[1]['date_1h'] is pd.NaT + assert result.iloc[2]['date_1h'] is pd.NaT + assert result.iloc[3]['date_1h'] is pd.NaT + # Next 4 rows contain the starting date (0:00) + assert result.iloc[4]['date_1h'] == result.iloc[0]['date'] + assert result.iloc[5]['date_1h'] == result.iloc[0]['date'] + assert result.iloc[6]['date_1h'] == result.iloc[0]['date'] + assert result.iloc[7]['date_1h'] == result.iloc[0]['date'] + # Next 4 rows contain the next Hourly date original date row 4 + assert result.iloc[8]['date_1h'] == result.iloc[4]['date'] From 7bc89279148872e43d4f6f6233ffbc864bc1f436 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 4 Sep 2020 20:02:31 +0200 Subject: [PATCH 266/285] Add documentation for merge_informative_pair helper --- docs/strategy-customization.md | 79 +++++++++++++++++++------ freqtrade/strategy/__init__.py | 2 +- freqtrade/strategy/strategy_helper.py | 7 ++- tests/strategy/test_strategy_helpers.py | 6 +- 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index e2548e510..c791be615 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -483,9 +483,8 @@ if self.dp: ### Complete Data-provider sample ```python -from freqtrade.strategy import IStrategy, timeframe_to_minutes +from freqtrade.strategy import IStrategy, merge_informative_pairs from pandas import DataFrame -import pandas as pd class SampleStrategy(IStrategy): # strategy init stuff... @@ -517,23 +516,12 @@ class SampleStrategy(IStrategy): # Get the 14 day rsi informative['rsi'] = ta.RSI(informative, timeperiod=14) - # Rename columns to be unique - informative.columns = [f"{col}_{inf_tf}" for col in informative.columns] - # Assuming inf_tf = '1d' - then the columns will now be: - # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d - - # Shift date by 1 candle - # This is necessary since the data is always the "open date" - # and a 15m candle starting at 12:15 should not know the close of the 1h candle from 12:00 to 13:00 - minutes = timeframe_to_minutes(inf_tf) - informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') - - # Combine the 2 dataframes - # all indicators on the informative sample MUST be calculated before this point - dataframe = pd.merge(dataframe, informative, left_on='date', right_on=f'date_merge_{inf_tf}', how='left') + # Use the helper function merge_informative_pair to safely merge the pair + # Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair # FFill to have the 1d value available in every row throughout the day. # Without this, comparisons would only work once per day. - dataframe = dataframe.ffill() + # Full documentation of this method, see below + dataframe = merge_informative_pair(dataframe, informative_pairs, inf_tf, ffill=True) # Calculate rsi of the original dataframe (5m timeframe) dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) @@ -557,6 +545,63 @@ class SampleStrategy(IStrategy): *** +## Helper functions + +### *merge_informative_pair()* + +This method helps you merge an informative pair to a regular dataframe without lookahead bias. +It's there to help you merge the dataframe in a safe and consistent way. + +Options: + +- Rename the columns for you to create unique columns +- Merge the dataframe without lookahead bias +- Forward-fill (optional) + +All columns of the informative dataframe will be available on the returning dataframe in a renamed fashion: + +!!! Example "Column renaming" + Assuming `inf_tf = '1d'` the resulting columns will be: + + ``` python + 'date', 'open', 'high', 'low', 'close', 'rsi' # from the original dataframe + 'date_1d', 'open_1d', 'high_1d', 'low_1d', 'close_1d', 'rsi_1d' # from the informative dataframe + ``` + +??? Example "Column renaming - 1h" + Assuming `inf_tf = '1h'` the resulting columns will be: + + ``` python + 'date', 'open', 'high', 'low', 'close', 'rsi' # from the original dataframe + 'date_1h', 'open_1h', 'high_1h', 'low_1h', 'close_1h', 'rsi_1h' # from the informative dataframe + ``` + +??? Example "Custom implementation" + A custom implementation for this is possible, and can be done as follows: + + ``` python + # Rename columns to be unique + informative.columns = [f"{col}_{inf_tf}" for col in informative.columns] + # Assuming inf_tf = '1d' - then the columns will now be: + # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d + + # Shift date by 1 candle + # This is necessary since the data is always the "open date" + # and a 15m candle starting at 12:15 should not know the close of the 1h candle from 12:00 to 13:00 + minutes = timeframe_to_minutes(inf_tf) + informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') + + # Combine the 2 dataframes + # all indicators on the informative sample MUST be calculated before this point + dataframe = pd.merge(dataframe, informative, left_on='date', right_on=f'date_merge_{inf_tf}', how='left') + # FFill to have the 1d value available in every row throughout the day. + # Without this, comparisons would only work once per day. + dataframe = dataframe.ffill() + + ``` + +*** + ## Additional data (Wallets) The strategy provides access to the `Wallets` object. This contains the current balances on the exchange. diff --git a/freqtrade/strategy/__init__.py b/freqtrade/strategy/__init__.py index 5758bbbcc..d1510489e 100644 --- a/freqtrade/strategy/__init__.py +++ b/freqtrade/strategy/__init__.py @@ -2,4 +2,4 @@ from freqtrade.exchange import (timeframe_to_minutes, timeframe_to_prev_date, timeframe_to_seconds, timeframe_to_next_date, timeframe_to_msecs) from freqtrade.strategy.interface import IStrategy -from freqtrade.strategy.strategy_helper import merge_informative_pairs +from freqtrade.strategy.strategy_helper import merge_informative_pair diff --git a/freqtrade/strategy/strategy_helper.py b/freqtrade/strategy/strategy_helper.py index ce98cccba..2684e7b03 100644 --- a/freqtrade/strategy/strategy_helper.py +++ b/freqtrade/strategy/strategy_helper.py @@ -2,8 +2,8 @@ import pandas as pd from freqtrade.exchange import timeframe_to_minutes -def merge_informative_pairs(dataframe: pd.DataFrame, informative: pd.DataFrame, - timeframe_inf: str, ffill: bool = True) -> pd.DataFrame: +def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, + timeframe_inf: str, ffill: bool = True) -> pd.DataFrame: """ Correctly merge informative samples to the original dataframe, avoiding lookahead bias. @@ -15,6 +15,9 @@ def merge_informative_pairs(dataframe: pd.DataFrame, informative: pd.DataFrame, This way, the 14:00 1h candle is merged to 15:00 15m candle, since the 14:00 1h candle is the last candle that's closed at 15:00, 15:15, 15:30 or 15:45. + Assuming inf_tf = '1d' - then the resulting columns will be: + date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d + :param dataframe: Original dataframe :param informative: Informative pair, most likely loaded via dp.get_pair_dataframe :param timeframe_inf: Timeframe of the informative pair sample. diff --git a/tests/strategy/test_strategy_helpers.py b/tests/strategy/test_strategy_helpers.py index 89bbba2c1..9201d91e1 100644 --- a/tests/strategy/test_strategy_helpers.py +++ b/tests/strategy/test_strategy_helpers.py @@ -1,7 +1,7 @@ import pandas as pd import numpy as np -from freqtrade.strategy import merge_informative_pairs, timeframe_to_minutes +from freqtrade.strategy import merge_informative_pair, timeframe_to_minutes def generate_test_data(timeframe: str, size: int): @@ -24,11 +24,11 @@ def generate_test_data(timeframe: str, size: int): return df -def test_merge_informative_pairs(): +def test_merge_informative_pair(): data = generate_test_data('15m', 40) informative = generate_test_data('1h', 40) - result = merge_informative_pairs(data, informative, '1h', ffill=True) + result = merge_informative_pair(data, informative, '1h', ffill=True) assert isinstance(result, pd.DataFrame) assert len(result) == len(data) assert 'date' in result.columns From cc684c51415afd7e1b682242ecd8c76f594e8c1d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 4 Sep 2020 20:09:02 +0200 Subject: [PATCH 267/285] Correctly handle identical timerame merges --- docs/strategy-customization.md | 7 +++--- freqtrade/strategy/strategy_helper.py | 11 +++++++--- tests/strategy/test_strategy_helpers.py | 29 ++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index c791be615..7396f2a89 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -518,10 +518,10 @@ class SampleStrategy(IStrategy): # Use the helper function merge_informative_pair to safely merge the pair # Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair - # FFill to have the 1d value available in every row throughout the day. - # Without this, comparisons would only work once per day. + # use ffill to have the 1d value available in every row throughout the day. + # Without this, comparisons between columns of the original and the informative pair would only work once per day. # Full documentation of this method, see below - dataframe = merge_informative_pair(dataframe, informative_pairs, inf_tf, ffill=True) + dataframe = merge_informative_pair(dataframe, informative_pairs, self.timeframe, inf_tf, ffill=True) # Calculate rsi of the original dataframe (5m timeframe) dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) @@ -589,6 +589,7 @@ All columns of the informative dataframe will be available on the returning data # This is necessary since the data is always the "open date" # and a 15m candle starting at 12:15 should not know the close of the 1h candle from 12:00 to 13:00 minutes = timeframe_to_minutes(inf_tf) + # Only do this if the timeframes are different: informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') # Combine the 2 dataframes diff --git a/freqtrade/strategy/strategy_helper.py b/freqtrade/strategy/strategy_helper.py index 2684e7b03..0fa7f4258 100644 --- a/freqtrade/strategy/strategy_helper.py +++ b/freqtrade/strategy/strategy_helper.py @@ -3,7 +3,7 @@ from freqtrade.exchange import timeframe_to_minutes def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, - timeframe_inf: str, ffill: bool = True) -> pd.DataFrame: + timeframe: str, timeframe_inf: str, ffill: bool = True) -> pd.DataFrame: """ Correctly merge informative samples to the original dataframe, avoiding lookahead bias. @@ -20,13 +20,18 @@ def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, :param dataframe: Original dataframe :param informative: Informative pair, most likely loaded via dp.get_pair_dataframe + :param timeframe: Timeframe of the original pair sample. :param timeframe_inf: Timeframe of the informative pair sample. :param ffill: Forwardfill missing values - optional but usually required """ # Rename columns to be unique - minutes = timeframe_to_minutes(timeframe_inf) - informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') + minutes_inf = timeframe_to_minutes(timeframe_inf) + if timeframe == timeframe_inf: + # No need to forwardshift if the timeframes are identical + informative['date_merge'] = informative["date"] + else: + informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes_inf, 'm') informative.columns = [f"{col}_{timeframe_inf}" for col in informative.columns] diff --git a/tests/strategy/test_strategy_helpers.py b/tests/strategy/test_strategy_helpers.py index 9201d91e1..4b29bf304 100644 --- a/tests/strategy/test_strategy_helpers.py +++ b/tests/strategy/test_strategy_helpers.py @@ -28,7 +28,7 @@ def test_merge_informative_pair(): data = generate_test_data('15m', 40) informative = generate_test_data('1h', 40) - result = merge_informative_pair(data, informative, '1h', ffill=True) + result = merge_informative_pair(data, informative, '15m', '1h', ffill=True) assert isinstance(result, pd.DataFrame) assert len(result) == len(data) assert 'date' in result.columns @@ -59,3 +59,30 @@ def test_merge_informative_pair(): assert result.iloc[7]['date_1h'] == result.iloc[0]['date'] # Next 4 rows contain the next Hourly date original date row 4 assert result.iloc[8]['date_1h'] == result.iloc[4]['date'] + + +def test_merge_informative_pair_same(): + data = generate_test_data('15m', 40) + informative = generate_test_data('15m', 40) + + result = merge_informative_pair(data, informative, '15m', '15m', ffill=True) + assert isinstance(result, pd.DataFrame) + assert len(result) == len(data) + assert 'date' in result.columns + assert result['date'].equals(data['date']) + assert 'date_15m' in result.columns + + assert 'open' in result.columns + assert 'open_15m' in result.columns + assert result['open'].equals(data['open']) + + assert 'close' in result.columns + assert 'close_15m' in result.columns + assert result['close'].equals(data['close']) + + assert 'volume' in result.columns + assert 'volume_15m' in result.columns + assert result['volume'].equals(data['volume']) + + # Dates match 1:1 + assert result['date_15m'].equals(result['date']) From 71af64af94ba07a19181618e58f0dbfa8480709f Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 4 Sep 2020 20:10:43 +0200 Subject: [PATCH 268/285] Move comment to the right place --- freqtrade/strategy/strategy_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/strategy/strategy_helper.py b/freqtrade/strategy/strategy_helper.py index 0fa7f4258..1fbf618bd 100644 --- a/freqtrade/strategy/strategy_helper.py +++ b/freqtrade/strategy/strategy_helper.py @@ -24,7 +24,6 @@ def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, :param timeframe_inf: Timeframe of the informative pair sample. :param ffill: Forwardfill missing values - optional but usually required """ - # Rename columns to be unique minutes_inf = timeframe_to_minutes(timeframe_inf) if timeframe == timeframe_inf: @@ -33,6 +32,7 @@ def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, else: informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes_inf, 'm') + # Rename columns to be unique informative.columns = [f"{col}_{timeframe_inf}" for col in informative.columns] # Combine the 2 dataframes From c18441f36fe5fa25012f0b363153d41df93c4955 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Sep 2020 16:44:23 +0200 Subject: [PATCH 269/285] Fix typo in reloading_conf --- freqtrade/rpc/rpc.py | 2 +- tests/rpc/test_rpc_apiserver.py | 2 +- tests/rpc/test_rpc_telegram.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index b89a95ee8..0b9196f2e 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -436,7 +436,7 @@ class RPC: def _rpc_reload_config(self) -> Dict[str, str]: """ Handler for reload_config. """ self._freqtrade.state = State.RELOAD_CONFIG - return {'status': 'reloading config ...'} + return {'status': 'Reloading config ...'} def _rpc_stopbuy(self) -> Dict[str, str]: """ diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index d2b69ee4f..d9f5bf781 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -266,7 +266,7 @@ def test_api_reloadconf(botclient): rc = client_post(client, f"{BASE_URI}/reload_config") assert_response(rc) - assert rc.json == {'status': 'reloading config ...'} + assert rc.json == {'status': 'Reloading config ...'} assert ftbot.state == State.RELOAD_CONFIG diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 71898db8c..762780111 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -692,7 +692,7 @@ def test_reload_config_handle(default_conf, update, mocker) -> None: telegram._reload_config(update=update, context=MagicMock()) assert freqtradebot.state == State.RELOAD_CONFIG assert msg_mock.call_count == 1 - assert 'reloading config' in msg_mock.call_args_list[0][0][0] + assert 'Reloading config' in msg_mock.call_args_list[0][0][0] def test_telegram_forcesell_handle(default_conf, update, ticker, fee, From 8c9297e1f0effeccd5490652f83b91a0a3105507 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Sep 2020 16:51:19 +0200 Subject: [PATCH 270/285] Don't crash if a strategy imports something wrongly --- freqtrade/resolvers/iresolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/resolvers/iresolver.py b/freqtrade/resolvers/iresolver.py index 52d944f2c..b7d25ef2c 100644 --- a/freqtrade/resolvers/iresolver.py +++ b/freqtrade/resolvers/iresolver.py @@ -59,7 +59,7 @@ class IResolver: module = importlib.util.module_from_spec(spec) try: spec.loader.exec_module(module) # type: ignore # importlib does not use typehints - except (ModuleNotFoundError, SyntaxError) as err: + except (ModuleNotFoundError, SyntaxError, ImportError) as err: # Catch errors in case a specific module is not installed logger.warning(f"Could not import {module_path} due to '{err}'") if enum_failed: From 7852feab0566ecdda19e705cd88c7c7bd61cd52b Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 7 Sep 2020 09:06:43 +0200 Subject: [PATCH 271/285] support smaller timeframes --- docs/strategy-customization.md | 6 +++++- freqtrade/strategy/strategy_helper.py | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 7396f2a89..a1de1044c 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -521,7 +521,7 @@ class SampleStrategy(IStrategy): # use ffill to have the 1d value available in every row throughout the day. # Without this, comparisons between columns of the original and the informative pair would only work once per day. # Full documentation of this method, see below - dataframe = merge_informative_pair(dataframe, informative_pairs, self.timeframe, inf_tf, ffill=True) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, inf_tf, ffill=True) # Calculate rsi of the original dataframe (5m timeframe) dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) @@ -601,6 +601,10 @@ All columns of the informative dataframe will be available on the returning data ``` +!!! Warning "Informative timeframe < timeframe" + Using informative timeframes smaller than the dataframe timeframe is not recommended with this method, as it will not use any of the additional information this would provide. + To use the more detailed information properly, more advanced methods should be applied (which are out of scope for freqtrade documentation, as it'll depend on the respective need). + *** ## Additional data (Wallets) diff --git a/freqtrade/strategy/strategy_helper.py b/freqtrade/strategy/strategy_helper.py index 1fbf618bd..1a5b2d0f8 100644 --- a/freqtrade/strategy/strategy_helper.py +++ b/freqtrade/strategy/strategy_helper.py @@ -26,7 +26,8 @@ def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame, """ minutes_inf = timeframe_to_minutes(timeframe_inf) - if timeframe == timeframe_inf: + minutes = timeframe_to_minutes(timeframe) + if minutes >= minutes_inf: # No need to forwardshift if the timeframes are identical informative['date_merge'] = informative["date"] else: From 014fcb36f4e6b3da535dcc7ebaa604ea47f9e2d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2020 07:09:07 +0000 Subject: [PATCH 272/285] Bump mkdocs-material from 5.5.11 to 5.5.12 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 5.5.11 to 5.5.12. - [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/5.5.11...5.5.12) 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 c8f08d12a..6408616a0 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,2 +1,2 @@ -mkdocs-material==5.5.11 +mkdocs-material==5.5.12 mdx_truly_sane_lists==1.2 From 534404c284a3de1b8bc9b6cb4f8e9603c32f81c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2020 07:09:22 +0000 Subject: [PATCH 273/285] Bump ccxt from 1.33.72 to 1.34.3 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.33.72 to 1.34.3. - [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.33.72...1.34.3) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index f305d8793..58912bc0c 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.33.72 +ccxt==1.34.3 SQLAlchemy==1.3.19 python-telegram-bot==12.8 arrow==0.16.0 From ff0e73a9e592e4c61eca8fce97b0c84d5b886844 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2020 07:09:23 +0000 Subject: [PATCH 274/285] Bump scikit-optimize from 0.7.4 to 0.8.1 Bumps [scikit-optimize](https://github.com/scikit-optimize/scikit-optimize) from 0.7.4 to 0.8.1. - [Release notes](https://github.com/scikit-optimize/scikit-optimize/releases) - [Changelog](https://github.com/scikit-optimize/scikit-optimize/blob/master/CHANGELOG.md) - [Commits](https://github.com/scikit-optimize/scikit-optimize/compare/v0.7.4...v0.8.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 fbc679eaa..ea24196b9 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -4,7 +4,7 @@ # Required for hyperopt scipy==1.5.2 scikit-learn==0.23.1 -scikit-optimize==0.7.4 +scikit-optimize==0.8.1 filelock==3.0.12 joblib==0.16.0 progressbar2==3.52.1 From f20318fad1b27039c8269984f4ea78cecb1aab90 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2020 07:37:12 +0000 Subject: [PATCH 275/285] Bump scikit-learn from 0.23.1 to 0.23.2 Bumps [scikit-learn](https://github.com/scikit-learn/scikit-learn) from 0.23.1 to 0.23.2. - [Release notes](https://github.com/scikit-learn/scikit-learn/releases) - [Commits](https://github.com/scikit-learn/scikit-learn/compare/0.23.1...0.23.2) 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 ea24196b9..4d884b4fe 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -3,7 +3,7 @@ # Required for hyperopt scipy==1.5.2 -scikit-learn==0.23.1 +scikit-learn==0.23.2 scikit-optimize==0.8.1 filelock==3.0.12 joblib==0.16.0 From 4cf66e2fba76d3aab734bffe94063ca906c74bbc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:29:22 +0000 Subject: [PATCH 276/285] Bump progressbar2 from 3.52.1 to 3.53.1 Bumps [progressbar2](https://github.com/WoLpH/python-progressbar) from 3.52.1 to 3.53.1. - [Release notes](https://github.com/WoLpH/python-progressbar/releases) - [Changelog](https://github.com/WoLpH/python-progressbar/blob/develop/CHANGES.rst) - [Commits](https://github.com/WoLpH/python-progressbar/compare/v3.52.1...v3.53.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 4d884b4fe..b47331aa3 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -7,4 +7,4 @@ scikit-learn==0.23.2 scikit-optimize==0.8.1 filelock==3.0.12 joblib==0.16.0 -progressbar2==3.52.1 +progressbar2==3.53.1 From 986e767d6c4ec460cc35b95db178e19bbef9de2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:29:27 +0000 Subject: [PATCH 277/285] Bump blosc from 1.9.1 to 1.9.2 Bumps [blosc](https://github.com/blosc/python-blosc) from 1.9.1 to 1.9.2. - [Release notes](https://github.com/blosc/python-blosc/releases) - [Changelog](https://github.com/Blosc/python-blosc/blob/master/RELEASE_NOTES.rst) - [Commits](https://github.com/blosc/python-blosc/compare/v1.9.1...v1.9.2) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 58912bc0c..5efc6a2ee 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -14,7 +14,7 @@ tabulate==0.8.7 pycoingecko==1.3.0 jinja2==2.11.2 tables==3.6.1 -blosc==1.9.1 +blosc==1.9.2 # find first, C search in arrays py_find_1st==1.1.4 From d8dae46544987a2f5d672d1128851d47d5f6d9bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:29:31 +0000 Subject: [PATCH 278/285] Bump ccxt from 1.34.3 to 1.34.11 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.34.3 to 1.34.11. - [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.34.3...1.34.11) Signed-off-by: dependabot[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 58912bc0c..faa022c4c 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.34.3 +ccxt==1.34.11 SQLAlchemy==1.3.19 python-telegram-bot==12.8 arrow==0.16.0 From 8c97b83b8c44de9f7b921cba6bec3bdeb39e5527 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2020 13:29:36 +0000 Subject: [PATCH 279/285] Bump pandas from 1.1.1 to 1.1.2 Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.1.1 to 1.1.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.1.1...v1.1.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 66f4cbc5f..a1a1fb250 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,4 @@ -r requirements-common.txt numpy==1.19.1 -pandas==1.1.1 +pandas==1.1.2 From 4480b3b39374439296407128b816a797749865c9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 9 Sep 2020 15:39:35 +0200 Subject: [PATCH 280/285] Fix error in documentation (wrong sequence of steps) --- docs/strategy-customization.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index a1de1044c..615be0247 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -580,10 +580,6 @@ All columns of the informative dataframe will be available on the returning data A custom implementation for this is possible, and can be done as follows: ``` python - # Rename columns to be unique - informative.columns = [f"{col}_{inf_tf}" for col in informative.columns] - # Assuming inf_tf = '1d' - then the columns will now be: - # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d # Shift date by 1 candle # This is necessary since the data is always the "open date" @@ -592,6 +588,11 @@ All columns of the informative dataframe will be available on the returning data # Only do this if the timeframes are different: informative['date_merge'] = informative["date"] + pd.to_timedelta(minutes, 'm') + # Rename columns to be unique + informative.columns = [f"{col}_{inf_tf}" for col in informative.columns] + # Assuming inf_tf = '1d' - then the columns will now be: + # date_1d, open_1d, high_1d, low_1d, close_1d, rsi_1d + # Combine the 2 dataframes # all indicators on the informative sample MUST be calculated before this point dataframe = pd.merge(dataframe, informative, left_on='date', right_on=f'date_merge_{inf_tf}', how='left') From 6a08fee25b88b8f4824bcc5f76f2dc3ee7c96529 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 10 Sep 2020 08:04:04 +0200 Subject: [PATCH 281/285] Fix wrong import in documentation --- docs/strategy-customization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index 615be0247..14d5fcd84 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -483,7 +483,7 @@ if self.dp: ### Complete Data-provider sample ```python -from freqtrade.strategy import IStrategy, merge_informative_pairs +from freqtrade.strategy import IStrategy, merge_informative_pair from pandas import DataFrame class SampleStrategy(IStrategy): From b8773de5b0d39163c9ded61e312578791ad9bb98 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 11 Sep 2020 06:44:20 +0200 Subject: [PATCH 282/285] scoped sessions should be closed after requests --- freqtrade/rpc/api_server.py | 10 +++++++++- tests/rpc/test_rpc_apiserver.py | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/freqtrade/rpc/api_server.py b/freqtrade/rpc/api_server.py index 4bbc8a1dc..0ae0698cd 100644 --- a/freqtrade/rpc/api_server.py +++ b/freqtrade/rpc/api_server.py @@ -17,8 +17,9 @@ from werkzeug.serving import make_server from freqtrade.__init__ import __version__ from freqtrade.constants import DATETIME_PRINT_FORMAT -from freqtrade.rpc.rpc import RPC, RPCException +from freqtrade.persistence import Trade from freqtrade.rpc.fiat_convert import CryptoToFiatConverter +from freqtrade.rpc.rpc import RPC, RPCException logger = logging.getLogger(__name__) @@ -70,6 +71,11 @@ def rpc_catch_errors(func: Callable[..., Any]): return func_wrapper +def shutdown_session(exception=None): + # Remove scoped session + Trade.session.remove() + + class ApiServer(RPC): """ This class runs api server and provides rpc.rpc functionality to it @@ -104,6 +110,8 @@ class ApiServer(RPC): self.jwt = JWTManager(self.app) self.app.json_encoder = ArrowJSONEncoder + self.app.teardown_appcontext(shutdown_session) + # Register application handling self.register_rest_rpc_urls() diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index d9f5bf781..f8256f1ba 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -471,6 +471,7 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): assert rc.json == {"error": "Error querying _edge: Edge is not enabled."} +@pytest.mark.usefixtures("init_persistence") def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, limit_sell_order): ftbot, client = botclient patch_get_signal(ftbot, (True, False)) @@ -498,6 +499,7 @@ def test_api_profit(botclient, mocker, ticker, fee, markets, limit_buy_order, li assert rc.json['best_pair'] == '' assert rc.json['best_rate'] == 0 + trade = Trade.query.first() trade.update(limit_sell_order) trade.close_date = datetime.utcnow() From 0c9301e74a313a40e3829aed1ab701e04858d262 Mon Sep 17 00:00:00 2001 From: caudurodev Date: Fri, 11 Sep 2020 08:41:33 +0200 Subject: [PATCH 283/285] FIX: added missing ) for SQLite insert --- docs/sql_cheatsheet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index cf785ced6..249e935ef 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -47,6 +47,7 @@ sqlite3 ```sql CREATE TABLE trades +( id INTEGER NOT NULL, exchange VARCHAR NOT NULL, pair VARCHAR NOT NULL, From 90d97c536d5b0a8ad7d863304023e418fe6f766e Mon Sep 17 00:00:00 2001 From: caudurodev Date: Fri, 11 Sep 2020 08:42:42 +0200 Subject: [PATCH 284/285] FIX: added missing ) for SQLite insert --- docs/sql_cheatsheet.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/sql_cheatsheet.md b/docs/sql_cheatsheet.md index 249e935ef..168d416ab 100644 --- a/docs/sql_cheatsheet.md +++ b/docs/sql_cheatsheet.md @@ -46,8 +46,7 @@ sqlite3 ### Trade table structure ```sql -CREATE TABLE trades -( +CREATE TABLE trades( id INTEGER NOT NULL, exchange VARCHAR NOT NULL, pair VARCHAR NOT NULL, From 50f0483d9aab4a0c73b6f7eb65d7babd3946817d Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 11 Sep 2020 20:00:36 +0200 Subject: [PATCH 285/285] FIx fluky test in test_api_logs --- 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 f8256f1ba..626586a4a 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -435,7 +435,7 @@ def test_api_logs(botclient): assert len(rc.json) == 2 assert 'logs' in rc.json # Using a fixed comparison here would make this test fail! - assert rc.json['log_count'] > 10 + assert rc.json['log_count'] > 1 assert len(rc.json['logs']) == rc.json['log_count'] assert isinstance(rc.json['logs'][0], list)