From 35580b135a1ab2fa04bc046b93ba6aa28edf0bb2 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 10 Sep 2019 10:42:45 +0300 Subject: [PATCH 01/13] Improve backtesting logs --- freqtrade/optimize/backtesting.py | 44 +++++++++++++++----------- freqtrade/persistence.py | 52 +++++++++++++------------------ freqtrade/strategy/interface.py | 39 +++++++++++++---------- 3 files changed, 69 insertions(+), 66 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 708b60144..752a83d2d 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -239,14 +239,16 @@ class Backtesting(object): stake_amount: float, max_open_trades: int) -> Optional[BacktestResult]: trade = Trade( + pair=pair, open_rate=buy_row.open, open_date=buy_row.date, stake_amount=stake_amount, amount=stake_amount / buy_row.open, fee_open=self.fee, - fee_close=self.fee + fee_close=self.fee, + is_open=True, ) - + logger.debug(f"'{pair}' - Backtesting emulates creation of new trade: {trade}.") # calculate win/lose forwards from buy point for sell_row in partial_ticker: if max_open_trades > 0: @@ -289,23 +291,25 @@ class Backtesting(object): if partial_ticker: # no sell condition found - trade stil open at end of backtest period sell_row = partial_ticker[-1] - btr = BacktestResult(pair=pair, - profit_percent=trade.calc_profit_percent(rate=sell_row.open), - profit_abs=trade.calc_profit(rate=sell_row.open), - open_time=buy_row.date, - close_time=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, - sell_reason=SellType.FORCE_SELL - ) - logger.debug('Force_selling still open trade %s with %s perc - %s', btr.pair, - btr.profit_percent, btr.profit_abs) - return btr + bt_res = BacktestResult(pair=pair, + profit_percent=trade.calc_profit_percent(rate=sell_row.open), + profit_abs=trade.calc_profit(rate=sell_row.open), + open_time=buy_row.date, + close_time=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, + sell_reason=SellType.FORCE_SELL + ) + logger.debug(f"'{pair}' - Force selling still open trade, " + f"profit percent: {bt_res.profit_percent}, " + f"profit abs: {bt_res.profit_abs}") + + return bt_res return None def backtest(self, args: Dict) -> DataFrame: @@ -384,6 +388,8 @@ class Backtesting(object): max_open_trades) 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 trades.append(trade_entry) else: diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index dff7e4ff6..608243d54 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -1,7 +1,6 @@ """ This module contains the class to persist trades into SQLite """ - import logging from datetime import datetime from decimal import Decimal @@ -19,8 +18,10 @@ from sqlalchemy.pool import StaticPool from freqtrade import OperationalException + logger = logging.getLogger(__name__) + _DECL_BASE: Any = declarative_base() _SQL_DOCS_URL = 'http://docs.sqlalchemy.org/en/latest/core/engines.html#database-urls' @@ -209,7 +210,8 @@ class Trade(_DECL_BASE): ticker_interval = Column(Integer, nullable=True) def __repr__(self): - open_since = arrow.get(self.open_date).humanize() if self.is_open else 'closed' + open_since = (f"{arrow.get(self.open_date).strftime('%Y-%m-%d %H:%M:%S')} " + f"({arrow.get(self.open_date).humanize()})" ) if self.is_open else 'closed' return (f'Trade(id={self.id}, pair={self.pair}, amount={self.amount:.8f}, ' f'open_rate={self.open_rate:.8f}, open_since={open_since})') @@ -250,7 +252,6 @@ class Trade(_DECL_BASE): :param initial: Called to initiate stop_loss. Skips everything if self.stop_loss is already set. """ - if initial and not (self.stop_loss is None or self.stop_loss == 0): # Don't modify if called with initial and nothing to do return @@ -259,7 +260,7 @@ class Trade(_DECL_BASE): # no stop loss assigned yet if not self.stop_loss: - logger.debug("assigning new stop loss") + logger.debug(f"'{self.pair}' - Assigning new stoploss...") self.stop_loss = new_loss self.stop_loss_pct = -1 * abs(stoploss) self.initial_stop_loss = new_loss @@ -269,21 +270,21 @@ class Trade(_DECL_BASE): # evaluate if the stop loss needs to be updated else: if new_loss > self.stop_loss: # stop losses only walk up, never down! + logger.debug(f"'{self.pair}' - Adjusting stoploss...") self.stop_loss = new_loss self.stop_loss_pct = -1 * abs(stoploss) self.stoploss_last_update = datetime.utcnow() - logger.debug("adjusted stop loss") else: - logger.debug("keeping current stop loss") + logger.debug(f"'{self.pair}' - Keeping current stoploss...") logger.debug( - f"{self.pair} - current price {current_price:.8f}, " + f"'{self.pair}' - Stoploss adjusted. Current price {current_price:.8f}, " f"bought at {self.open_rate:.8f} and calculated " - f"stop loss is at: {self.initial_stop_loss:.8f} initial " - f"stop at {self.stop_loss:.8f}. " - f"trailing stop loss saved us: " + f"stoploss is at: {self.initial_stop_loss:.8f}, " + f"initial stop at {self.stop_loss:.8f}. " + f"Trailing stoploss saved us: " f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f} " - f"and max observed rate was {self.max_rate:.8f}") + f"and max observed rate was {self.max_rate:.8f}.") def update(self, order: Dict) -> None: """ @@ -331,24 +332,19 @@ class Trade(_DECL_BASE): self ) - def calc_open_trade_price( - self, - fee: Optional[float] = None) -> float: + def calc_open_trade_price(self, fee: Optional[float] = None) -> float: """ Calculate the open_rate including fee. :param fee: fee to use on the open rate (optional). If rate is not set self.fee will be used :return: Price in of the open trade incl. Fees """ - buy_trade = (Decimal(self.amount) * Decimal(self.open_rate)) fees = buy_trade * Decimal(fee or self.fee_open) return float(buy_trade + fees) - def calc_close_trade_price( - self, - rate: Optional[float] = None, - fee: Optional[float] = None) -> float: + def calc_close_trade_price(self, rate: Optional[float] = None, + fee: Optional[float] = None) -> float: """ Calculate the close_rate including fee :param fee: fee to use on the close rate (optional). @@ -357,7 +353,6 @@ class Trade(_DECL_BASE): If rate is not set self.close_rate will be used :return: Price in BTC of the open trade """ - if rate is None and not self.close_rate: return 0.0 @@ -365,10 +360,8 @@ class Trade(_DECL_BASE): fees = sell_trade * Decimal(fee or self.fee_close) return float(sell_trade - fees) - def calc_profit( - self, - rate: Optional[float] = None, - fee: Optional[float] = None) -> float: + def calc_profit(self, rate: Optional[float] = None, + fee: Optional[float] = None) -> float: """ Calculate the absolute profit in stake currency between Close and Open trade :param fee: fee to use on the close rate (optional). @@ -385,10 +378,8 @@ class Trade(_DECL_BASE): profit = close_trade_price - open_trade_price return float(f"{profit:.8f}") - def calc_profit_percent( - self, - rate: Optional[float] = None, - fee: Optional[float] = None) -> float: + def calc_profit_percent(self, rate: Optional[float] = None, + fee: Optional[float] = None) -> float: """ Calculates the profit in percentage (including fee). :param rate: rate to compare with (optional). @@ -396,7 +387,6 @@ class Trade(_DECL_BASE): :param fee: fee to use on the close rate (optional). :return: profit in percentage as float """ - open_trade_price = self.calc_open_trade_price() close_trade_price = self.calc_close_trade_price( rate=(rate or self.close_rate), @@ -436,8 +426,8 @@ class Trade(_DECL_BASE): and trade.initial_stop_loss_pct != desired_stoploss): # Stoploss value got changed - logger.info(f"Stoploss for {trade} needs adjustment.") + logger.info(f"Stoploss for {trade} needs adjustment...") # Force reset of stoploss trade.stop_loss = None trade.adjust_stop_loss(trade.open_rate, desired_stoploss) - logger.info(f"new stoploss: {trade.stop_loss}, ") + logger.info(f"New stoploss: {trade.stop_loss}.") diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 6c6593a53..d4b89a3ae 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -202,7 +202,6 @@ class IStrategy(ABC): :param metadata: Metadata dictionary with additional data (e.g. 'pair') :return: DataFrame with ticker data and indicator data """ - pair = str(metadata.get('pair')) # Test if seen this pair and last candle before. @@ -292,7 +291,6 @@ class IStrategy(ABC): :param force_stoploss: Externally provided stoploss :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_percent(current_rate) @@ -304,6 +302,8 @@ class IStrategy(ABC): force_stoploss=force_stoploss, high=high) if stoplossflag.sell_flag: + logger.debug(f"'{trade.pair}' - Stoploss hit. Selling " + f"(sell_type={stoplossflag.sell_type})...") return stoplossflag # Set current rate to high for backtesting sell @@ -312,22 +312,30 @@ class IStrategy(ABC): experimental = self.config.get('experimental', {}) if buy and experimental.get('ignore_roi_if_buy_signal', False): - logger.debug('Buy signal still active - not selling.') + logger.debug(f"'{trade.pair}' - Buy signal still active. Not selling " + f"(sell_type=SellType.NONE)...") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) # Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee) if self.min_roi_reached(trade=trade, current_profit=current_profit, current_time=date): - logger.debug('Required profit reached. Selling..') + logger.debug(f"'{trade.pair}' - Required profit reached. Selling " + f"(sell_type=SellType.ROI)...") return SellCheckTuple(sell_flag=True, sell_type=SellType.ROI) if experimental.get('sell_profit_only', False): - logger.debug('Checking if trade is profitable..') + logger.debug(f"'{trade.pair}' - Checking if trade is profitable...") if trade.calc_profit(rate=rate) <= 0: + logger.debug(f"'{trade.pair}' - Trade is not profitable. Not selling " + f"(sell_type=SellType.NONE)...") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) + if sell and not buy and experimental.get('use_sell_signal', False): - logger.debug('Sell signal received. Selling..') + logger.debug(f"'{trade.pair}' - Sell signal received. Selling " + f"(sell_type=SellType.SELL_SIGNAL)...") return SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL) + # This one is noisy, commented out... +# logger.debug(f"'{trade.pair}' - Not selling (sell_type=SellType.NONE)...") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) def stop_loss_reached(self, current_rate: float, trade: Trade, @@ -338,7 +346,6 @@ class IStrategy(ABC): decides to sell or not :param current_profit: current profit in percent """ - trailing_stop = self.config.get('trailing_stop', False) stop_loss_value = force_stoploss if force_stoploss else self.stoploss @@ -359,7 +366,7 @@ class IStrategy(ABC): if 'trailing_stop_positive' in self.config and high_profit > sl_offset: # Ignore mypy error check in configuration that this is a float stop_loss_value = self.config.get('trailing_stop_positive') # type: ignore - logger.debug(f"using positive stop loss: {stop_loss_value} " + logger.debug(f"'{trade.pair}' - Using positive stoploss: {stop_loss_value} " f"offset: {sl_offset:.4g} profit: {current_profit:.4f}%") trade.adjust_stop_loss(high or current_rate, stop_loss_value) @@ -369,20 +376,20 @@ class IStrategy(ABC): (trade.stop_loss >= current_rate) and (not self.order_types.get('stoploss_on_exchange'))): - selltype = 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: - selltype = SellType.TRAILING_STOP_LOSS + sell_type = SellType.TRAILING_STOP_LOSS logger.debug( - f"HIT STOP: current price at {current_rate:.6f}, " - f"stop loss is {trade.stop_loss:.6f}, " - f"initial stop loss was at {trade.initial_stop_loss:.6f}, " + f"'{trade.pair}' - HIT STOP: current price at {current_rate:.6f}, " + f"stoploss is {trade.stop_loss:.6f}, " + f"initial stoploss was at {trade.initial_stop_loss:.6f}, " f"trade opened at {trade.open_rate:.6f}") - logger.debug(f"trailing stop saved {trade.stop_loss - trade.initial_stop_loss:.6f}") + logger.debug(f"'{trade.pair}' - Trailing stop saved " + f"{trade.stop_loss - trade.initial_stop_loss:.6f}") - logger.debug('Stop loss hit.') - return SellCheckTuple(sell_flag=True, sell_type=selltype) + return SellCheckTuple(sell_flag=True, sell_type=sell_type) return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) From e298e773198150a0ec9fdd4d36b4f16001b87f65 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 10 Sep 2019 10:43:15 +0300 Subject: [PATCH 02/13] Adjust tests --- tests/test_freqtradebot.py | 44 ++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a67659d8c..388553dc5 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1823,7 +1823,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, # if ROI is reached we must sell patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has('Required profit reached. Selling..', caplog) + assert log_has("'ETH/BTC' - Required profit reached. Selling (sell_type=SellType.ROI)...", caplog) def test_handle_trade_experimental( @@ -1853,7 +1853,7 @@ def test_handle_trade_experimental( patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has('Sell signal received. Selling..', caplog) + assert log_has("'ETH/BTC' - Sell signal received. Selling (sell_type=SellType.SELL_SIGNAL)...", caplog) def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, @@ -2132,6 +2132,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) - ) freqtrade = FreqtradeBot(default_conf) + open_date = arrow.utcnow().shift(minutes=-601) trade_buy = Trade( pair='ETH/BTC', open_rate=0.00001099, @@ -2141,16 +2142,16 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) - fee_open=0.0, fee_close=0.0, stake_amount=1, - open_date=arrow.utcnow().shift(minutes=-601).datetime, + open_date=open_date.datetime, is_open=True ) Trade.session.add(trade_buy) freqtrade.check_handle_timedout() - assert log_has_re(r'Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, ' - r'open_rate=0.00001099, open_since=10 hours ago\) due to Traceback \(most ' - r'recent call last\):\n.*', caplog) + assert log_has_re(f"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, " + f"open_rate=0.00001099, open_since={open_date.strftime('%Y-%m-%d %H:%M:%S')} " + f"\(10 hours ago\)\) due to Traceback \(most recent call last\):\n*", caplog) def test_handle_timedout_limit_buy(mocker, default_conf) -> None: @@ -2793,8 +2794,9 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog, # Sell as trailing-stop is reached assert freqtrade.handle_trade(trade) is True assert log_has( - f'HIT STOP: current price at 0.000012, stop loss is 0.000015, ' - f'initial stop loss was at 0.000010, trade opened at 0.000011', caplog) + f"'ETH/BTC' - HIT STOP: current price at 0.000012, " + f"stoploss is 0.000015, " + f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value @@ -2836,8 +2838,8 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - assert log_has(f'using positive stop loss: 0.01 offset: 0 profit: 0.2666%', caplog) - assert log_has(f'adjusted stop loss', caplog) + assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.01 offset: 0 profit: 0.2666%", caplog) + assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 mocker.patch('freqtrade.exchange.Exchange.get_ticker', @@ -2849,9 +2851,9 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets # Lower price again (but still positive) assert freqtrade.handle_trade(trade) is True assert log_has( - f'HIT STOP: current price at {buy_price + 0.000002:.6f}, ' - f'stop loss is {trade.stop_loss:.6f}, ' - f'initial stop loss was at 0.000010, trade opened at 0.000011', caplog) + f"'ETH/BTC' - HIT STOP: current price at {buy_price + 0.000002:.6f}, " + f"stoploss is {trade.stop_loss:.6f}, " + f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, @@ -2894,8 +2896,8 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - assert log_has(f'using positive stop loss: 0.01 offset: 0.011 profit: 0.2666%', caplog) - assert log_has(f'adjusted stop loss', caplog) + assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", caplog) + assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 mocker.patch('freqtrade.exchange.Exchange.get_ticker', @@ -2907,9 +2909,9 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, # Lower price again (but still positive) assert freqtrade.handle_trade(trade) is True assert log_has( - f'HIT STOP: current price at {buy_price + 0.000002:.6f}, ' - f'stop loss is {trade.stop_loss:.6f}, ' - f'initial stop loss was at 0.000010, trade opened at 0.000011', caplog) + f"'ETH/BTC' - HIT STOP: current price at {buy_price + 0.000002:.6f}, " + f"stoploss is {trade.stop_loss:.6f}, " + f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value @@ -2960,7 +2962,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, # stop-loss should not be adjusted as offset is not reached yet assert freqtrade.handle_trade(trade) is False - assert not log_has(f'adjusted stop loss', caplog) + assert not log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000098910 # price rises above the offset (rises 12% when the offset is 5.5%) @@ -2972,8 +2974,8 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, })) assert freqtrade.handle_trade(trade) is False - assert log_has(f'using positive stop loss: 0.05 offset: 0.055 profit: 0.1218%', caplog) - assert log_has(f'adjusted stop loss', caplog) + assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", caplog) + assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000117705 From 2081d7552f9b92dd2ec2f8d996d6a8c645965381 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Tue, 10 Sep 2019 12:37:15 +0300 Subject: [PATCH 03/13] Make flake happy --- freqtrade/persistence.py | 2 +- tests/test_freqtradebot.py | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 608243d54..be9374ebe 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -211,7 +211,7 @@ class Trade(_DECL_BASE): def __repr__(self): open_since = (f"{arrow.get(self.open_date).strftime('%Y-%m-%d %H:%M:%S')} " - f"({arrow.get(self.open_date).humanize()})" ) if self.is_open else 'closed' + f"({arrow.get(self.open_date).humanize()})") if self.is_open else 'closed' return (f'Trade(id={self.id}, pair={self.pair}, amount={self.amount:.8f}, ' f'open_rate={self.open_rate:.8f}, open_since={open_since})') diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 388553dc5..cb6259c22 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1823,7 +1823,8 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, # if ROI is reached we must sell patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has("'ETH/BTC' - Required profit reached. Selling (sell_type=SellType.ROI)...", caplog) + assert log_has("'ETH/BTC' - Required profit reached. Selling (sell_type=SellType.ROI)...", + caplog) def test_handle_trade_experimental( @@ -1853,7 +1854,8 @@ def test_handle_trade_experimental( patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has("'ETH/BTC' - Sell signal received. Selling (sell_type=SellType.SELL_SIGNAL)...", caplog) + assert log_has("'ETH/BTC' - Sell signal received. Selling (sell_type=SellType.SELL_SIGNAL)...", + caplog) def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order, @@ -2149,9 +2151,11 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) - Trade.session.add(trade_buy) freqtrade.check_handle_timedout() - assert log_has_re(f"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, " - f"open_rate=0.00001099, open_since={open_date.strftime('%Y-%m-%d %H:%M:%S')} " - f"\(10 hours ago\)\) due to Traceback \(most recent call last\):\n*", caplog) + assert log_has_re(f"Cannot query order for Trade\\(id=1, pair=ETH/BTC, amount=90.99181073, " + f"open_rate=0.00001099, open_since=" + f"{open_date.strftime('%Y-%m-%d %H:%M:%S')} " + f"\\(10 hours ago\\)\\) due to Traceback \\(most recent call last\\):\n*", + caplog) def test_handle_timedout_limit_buy(mocker, default_conf) -> None: @@ -2896,7 +2900,8 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", caplog) + assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", + caplog) assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 @@ -2974,7 +2979,8 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, })) assert freqtrade.handle_trade(trade) is False - assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", caplog) + assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", + caplog) assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000117705 From 2bd59de00243bb30ebbf24692963c002f5b566eb Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 11 Sep 2019 10:56:02 +0300 Subject: [PATCH 04/13] Cleanup log_has_re regexp string --- tests/test_freqtradebot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index cb6259c22..ac2014cd5 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2151,10 +2151,10 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) - Trade.session.add(trade_buy) freqtrade.check_handle_timedout() - assert log_has_re(f"Cannot query order for Trade\\(id=1, pair=ETH/BTC, amount=90.99181073, " - f"open_rate=0.00001099, open_since=" + assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, " + r"open_rate=0.00001099, open_since=" f"{open_date.strftime('%Y-%m-%d %H:%M:%S')} " - f"\\(10 hours ago\\)\\) due to Traceback \\(most recent call last\\):\n*", + r"\(10 hours ago\)\) due to Traceback \(most recent call last\):\n*", caplog) From 9bdfaf3803f17588bcb1546770da3bbac0cafd79 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Wed, 11 Sep 2019 23:32:08 +0300 Subject: [PATCH 05/13] Remove quotes around the pairs --- freqtrade/optimize/backtesting.py | 6 +++--- freqtrade/persistence.py | 8 ++++---- freqtrade/strategy/interface.py | 20 ++++++++++---------- tests/test_freqtradebot.py | 28 ++++++++++++++-------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 752a83d2d..acfe8392a 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -248,7 +248,7 @@ class Backtesting(object): fee_close=self.fee, is_open=True, ) - logger.debug(f"'{pair}' - Backtesting emulates creation of new trade: {trade}.") + logger.debug(f"{pair} - Backtesting emulates creation of new trade: {trade}.") # calculate win/lose forwards from buy point for sell_row in partial_ticker: if max_open_trades > 0: @@ -305,7 +305,7 @@ class Backtesting(object): close_rate=sell_row.open, sell_reason=SellType.FORCE_SELL ) - logger.debug(f"'{pair}' - Force selling still open trade, " + logger.debug(f"{pair} - Force selling still open trade, " f"profit percent: {bt_res.profit_percent}, " f"profit abs: {bt_res.profit_abs}") @@ -388,7 +388,7 @@ class Backtesting(object): max_open_trades) if trade_entry: - logger.debug(f"'{pair}' - Locking pair till " + logger.debug(f"{pair} - Locking pair till " f"close_time={trade_entry.close_time}") lock_pair_until[pair] = trade_entry.close_time trades.append(trade_entry) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index be9374ebe..ea5188e0c 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -260,7 +260,7 @@ class Trade(_DECL_BASE): # no stop loss assigned yet if not self.stop_loss: - logger.debug(f"'{self.pair}' - Assigning new stoploss...") + logger.debug(f"{self.pair} - Assigning new stoploss...") self.stop_loss = new_loss self.stop_loss_pct = -1 * abs(stoploss) self.initial_stop_loss = new_loss @@ -270,15 +270,15 @@ class Trade(_DECL_BASE): # evaluate if the stop loss needs to be updated else: if new_loss > self.stop_loss: # stop losses only walk up, never down! - logger.debug(f"'{self.pair}' - Adjusting stoploss...") + logger.debug(f"{self.pair} - Adjusting stoploss...") self.stop_loss = new_loss self.stop_loss_pct = -1 * abs(stoploss) self.stoploss_last_update = datetime.utcnow() else: - logger.debug(f"'{self.pair}' - Keeping current stoploss...") + logger.debug(f"{self.pair} - Keeping current stoploss...") logger.debug( - f"'{self.pair}' - Stoploss adjusted. Current price {current_price:.8f}, " + f"{self.pair} - Stoploss adjusted. Current price {current_price:.8f}, " f"bought at {self.open_rate:.8f} and calculated " f"stoploss is at: {self.initial_stop_loss:.8f}, " f"initial stop at {self.stop_loss:.8f}. " diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index d4b89a3ae..1c4b8e669 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -302,7 +302,7 @@ class IStrategy(ABC): force_stoploss=force_stoploss, high=high) if stoplossflag.sell_flag: - logger.debug(f"'{trade.pair}' - Stoploss hit. Selling " + logger.debug(f"{trade.pair} - Stoploss hit. Selling " f"(sell_type={stoplossflag.sell_type})...") return stoplossflag @@ -312,30 +312,30 @@ class IStrategy(ABC): experimental = self.config.get('experimental', {}) if buy and experimental.get('ignore_roi_if_buy_signal', False): - logger.debug(f"'{trade.pair}' - Buy signal still active. Not selling " + logger.debug(f"{trade.pair} - Buy signal still active. Not selling " f"(sell_type=SellType.NONE)...") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) # Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee) if self.min_roi_reached(trade=trade, current_profit=current_profit, current_time=date): - logger.debug(f"'{trade.pair}' - Required profit reached. Selling " + logger.debug(f"{trade.pair} - Required profit reached. Selling " f"(sell_type=SellType.ROI)...") return SellCheckTuple(sell_flag=True, sell_type=SellType.ROI) if experimental.get('sell_profit_only', False): - logger.debug(f"'{trade.pair}' - Checking if trade is profitable...") + logger.debug(f"{trade.pair} - Checking if trade is profitable...") if trade.calc_profit(rate=rate) <= 0: - logger.debug(f"'{trade.pair}' - Trade is not profitable. Not selling " + logger.debug(f"{trade.pair} - Trade is not profitable. Not selling " f"(sell_type=SellType.NONE)...") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) if sell and not buy and experimental.get('use_sell_signal', False): - logger.debug(f"'{trade.pair}' - Sell signal received. Selling " + logger.debug(f"{trade.pair} - Sell signal received. Selling " f"(sell_type=SellType.SELL_SIGNAL)...") return SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL) # This one is noisy, commented out... -# logger.debug(f"'{trade.pair}' - Not selling (sell_type=SellType.NONE)...") +# logger.debug(f"{trade.pair} - Not selling (sell_type=SellType.NONE)...") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) def stop_loss_reached(self, current_rate: float, trade: Trade, @@ -366,7 +366,7 @@ class IStrategy(ABC): if 'trailing_stop_positive' in self.config and high_profit > sl_offset: # Ignore mypy error check in configuration that this is a float stop_loss_value = self.config.get('trailing_stop_positive') # type: ignore - logger.debug(f"'{trade.pair}' - Using positive stoploss: {stop_loss_value} " + logger.debug(f"{trade.pair} - Using positive stoploss: {stop_loss_value} " f"offset: {sl_offset:.4g} profit: {current_profit:.4f}%") trade.adjust_stop_loss(high or current_rate, stop_loss_value) @@ -382,11 +382,11 @@ class IStrategy(ABC): if trade.initial_stop_loss != trade.stop_loss: sell_type = SellType.TRAILING_STOP_LOSS logger.debug( - f"'{trade.pair}' - HIT STOP: current price at {current_rate:.6f}, " + f"{trade.pair} - HIT STOP: current price at {current_rate:.6f}, " f"stoploss is {trade.stop_loss:.6f}, " f"initial stoploss was at {trade.initial_stop_loss:.6f}, " f"trade opened at {trade.open_rate:.6f}") - logger.debug(f"'{trade.pair}' - Trailing stop saved " + logger.debug(f"{trade.pair} - Trailing stop saved " f"{trade.stop_loss - trade.initial_stop_loss:.6f}") return SellCheckTuple(sell_flag=True, sell_type=sell_type) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index ac2014cd5..7a74fc333 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1823,7 +1823,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, # if ROI is reached we must sell patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has("'ETH/BTC' - Required profit reached. Selling (sell_type=SellType.ROI)...", + assert log_has("ETH/BTC - Required profit reached. Selling (sell_type=SellType.ROI)...", caplog) @@ -1854,7 +1854,7 @@ def test_handle_trade_experimental( patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has("'ETH/BTC' - Sell signal received. Selling (sell_type=SellType.SELL_SIGNAL)...", + assert log_has("ETH/BTC - Sell signal received. Selling (sell_type=SellType.SELL_SIGNAL)...", caplog) @@ -2798,7 +2798,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog, # Sell as trailing-stop is reached assert freqtrade.handle_trade(trade) is True assert log_has( - f"'ETH/BTC' - HIT STOP: current price at 0.000012, " + f"ETH/BTC - HIT STOP: current price at 0.000012, " f"stoploss is 0.000015, " f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value @@ -2842,8 +2842,8 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.01 offset: 0 profit: 0.2666%", caplog) - assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) + assert log_has(f"ETH/BTC - Using positive stoploss: 0.01 offset: 0 profit: 0.2666%", caplog) + assert log_has(f"ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 mocker.patch('freqtrade.exchange.Exchange.get_ticker', @@ -2855,7 +2855,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets # Lower price again (but still positive) assert freqtrade.handle_trade(trade) is True assert log_has( - f"'ETH/BTC' - HIT STOP: current price at {buy_price + 0.000002:.6f}, " + f"ETH/BTC - HIT STOP: current price at {buy_price + 0.000002:.6f}, " f"stoploss is {trade.stop_loss:.6f}, " f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) @@ -2900,9 +2900,9 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", + assert log_has(f"ETH/BTC - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", caplog) - assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) + assert log_has(f"ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 mocker.patch('freqtrade.exchange.Exchange.get_ticker', @@ -2914,7 +2914,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, # Lower price again (but still positive) assert freqtrade.handle_trade(trade) is True assert log_has( - f"'ETH/BTC' - HIT STOP: current price at {buy_price + 0.000002:.6f}, " + f"ETH/BTC - HIT STOP: current price at {buy_price + 0.000002:.6f}, " f"stoploss is {trade.stop_loss:.6f}, " f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value @@ -2967,7 +2967,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, # stop-loss should not be adjusted as offset is not reached yet assert freqtrade.handle_trade(trade) is False - assert not log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) + assert not log_has(f"ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000098910 # price rises above the offset (rises 12% when the offset is 5.5%) @@ -2979,9 +2979,9 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, })) assert freqtrade.handle_trade(trade) is False - assert log_has(f"'ETH/BTC' - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", + assert log_has(f"ETH/BTC - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", caplog) - assert log_has(f"'ETH/BTC' - Adjusting stoploss...", caplog) + assert log_has(f"ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000117705 @@ -3350,8 +3350,8 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets) default_conf['telegram']['enabled'] = False freqtrade = FreqtradeBot(default_conf) - # ordrebook shall be used even if tickers would be lower. - assert freqtrade.get_target_bid('ETH/BTC', ) != 0.042 + # orderbook shall be used even if tickers would be lower. + assert freqtrade.get_target_bid('ETH/BTC') != 0.042 assert ticker_mock.call_count == 0 From acf3b751f01e6d76722c31ed3d94c5d1140a5b24 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Thu, 12 Sep 2019 01:21:14 +0300 Subject: [PATCH 06/13] Log sell_flag, do not log sell_type=SellType.NONE --- freqtrade/strategy/interface.py | 20 +++++++++----------- tests/test_freqtradebot.py | 4 ++-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 1c4b8e669..3c1df276c 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -302,8 +302,8 @@ class IStrategy(ABC): force_stoploss=force_stoploss, high=high) if stoplossflag.sell_flag: - logger.debug(f"{trade.pair} - Stoploss hit. Selling " - f"(sell_type={stoplossflag.sell_type})...") + logger.debug(f"{trade.pair} - Stoploss hit. sell_flag=True, " + f"sell_type={stoplossflag.sell_type}") return stoplossflag # Set current rate to high for backtesting sell @@ -312,30 +312,28 @@ class IStrategy(ABC): experimental = self.config.get('experimental', {}) if buy and experimental.get('ignore_roi_if_buy_signal', False): - logger.debug(f"{trade.pair} - Buy signal still active. Not selling " - f"(sell_type=SellType.NONE)...") + logger.debug(f"{trade.pair} - Buy signal still active. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) # Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee) if self.min_roi_reached(trade=trade, current_profit=current_profit, current_time=date): - logger.debug(f"{trade.pair} - Required profit reached. Selling " - f"(sell_type=SellType.ROI)...") + logger.debug(f"{trade.pair} - Required profit reached. sell_flag=True, " + f"sell_type=SellType.ROI") return SellCheckTuple(sell_flag=True, sell_type=SellType.ROI) if experimental.get('sell_profit_only', False): logger.debug(f"{trade.pair} - Checking if trade is profitable...") if trade.calc_profit(rate=rate) <= 0: - logger.debug(f"{trade.pair} - Trade is not profitable. Not selling " - f"(sell_type=SellType.NONE)...") + logger.debug(f"{trade.pair} - Trade is not profitable. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) if sell and not buy and experimental.get('use_sell_signal', False): - logger.debug(f"{trade.pair} - Sell signal received. Selling " - f"(sell_type=SellType.SELL_SIGNAL)...") + logger.debug(f"{trade.pair} - Sell signal received. sell_flag=True, " + f"sell_type=SellType.SELL_SIGNAL") return SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL) # This one is noisy, commented out... -# logger.debug(f"{trade.pair} - Not selling (sell_type=SellType.NONE)...") +# logger.debug(f"{trade.pair} - No sell signal. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) def stop_loss_reached(self, current_rate: float, trade: Trade, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 7a74fc333..d34197519 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1823,7 +1823,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, # if ROI is reached we must sell patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has("ETH/BTC - Required profit reached. Selling (sell_type=SellType.ROI)...", + assert log_has("ETH/BTC - Required profit reached. sell_flag=True, sell_type=SellType.ROI", caplog) @@ -1854,7 +1854,7 @@ def test_handle_trade_experimental( patch_get_signal(freqtrade, value=(False, True)) assert freqtrade.handle_trade(trade) - assert log_has("ETH/BTC - Sell signal received. Selling (sell_type=SellType.SELL_SIGNAL)...", + assert log_has("ETH/BTC - Sell signal received. sell_flag=True, sell_type=SellType.SELL_SIGNAL", caplog) From 1d781ea9e0591f3589e11c42612380681119bb77 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Thu, 12 Sep 2019 02:29:47 +0300 Subject: [PATCH 07/13] Refine 'stoploss adjusted' log message --- freqtrade/persistence.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index ea5188e0c..e497a16c7 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -278,13 +278,12 @@ class Trade(_DECL_BASE): logger.debug(f"{self.pair} - Keeping current stoploss...") logger.debug( - f"{self.pair} - Stoploss adjusted. Current price {current_price:.8f}, " - f"bought at {self.open_rate:.8f} and calculated " - f"stoploss is at: {self.initial_stop_loss:.8f}, " - f"initial stop at {self.stop_loss:.8f}. " + f"{self.pair} - Stoploss adjusted. current_price={current_price:.8f}, " + f"open_rate={self.open_rate:.8f}, max_rate={self.max_rate:.8f}, " + f"initial_stop_loss={self.initial_stop_loss:.8f}, " + f"stop_loss={self.stop_loss:.8f}. " f"Trailing stoploss saved us: " - f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f} " - f"and max observed rate was {self.max_rate:.8f}.") + f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f}.") def update(self, order: Dict) -> None: """ From 045ca8739dc5c35101e06906632d54865f79c7a3 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Thu, 12 Sep 2019 20:56:00 +0300 Subject: [PATCH 08/13] Do not print humanized datetime in the log message --- freqtrade/persistence.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index e497a16c7..1850aafd9 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -210,8 +210,7 @@ class Trade(_DECL_BASE): ticker_interval = Column(Integer, nullable=True) def __repr__(self): - open_since = (f"{arrow.get(self.open_date).strftime('%Y-%m-%d %H:%M:%S')} " - f"({arrow.get(self.open_date).humanize()})") if self.is_open else 'closed' + open_since = self.open_date.strftime('%Y-%m-%d %H:%M:%S') if self.is_open else 'closed' return (f'Trade(id={self.id}, pair={self.pair}, amount={self.amount:.8f}, ' f'open_rate={self.open_rate:.8f}, open_since={open_since})') From 67ff48ce3e9dbca1fac36109d5cbb2ab66c03f7f Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Thu, 12 Sep 2019 20:58:10 +0300 Subject: [PATCH 09/13] Comment out noisy log messages --- freqtrade/strategy/interface.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 3c1df276c..17246ecf7 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -312,7 +312,8 @@ class IStrategy(ABC): experimental = self.config.get('experimental', {}) if buy and experimental.get('ignore_roi_if_buy_signal', False): - logger.debug(f"{trade.pair} - Buy signal still active. sell_flag=False") + # This one is noisy, commented out + # logger.debug(f"{trade.pair} - Buy signal still active. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) # Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee) @@ -322,9 +323,11 @@ class IStrategy(ABC): return SellCheckTuple(sell_flag=True, sell_type=SellType.ROI) if experimental.get('sell_profit_only', False): - logger.debug(f"{trade.pair} - Checking if trade is profitable...") + # This one is noisy, commented out + # logger.debug(f"{trade.pair} - Checking if trade is profitable...") if trade.calc_profit(rate=rate) <= 0: - logger.debug(f"{trade.pair} - Trade is not profitable. sell_flag=False") + # This one is noisy, commented out + # logger.debug(f"{trade.pair} - Trade is not profitable. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) if sell and not buy and experimental.get('use_sell_signal', False): @@ -333,7 +336,7 @@ class IStrategy(ABC): return SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL) # This one is noisy, commented out... -# logger.debug(f"{trade.pair} - No sell signal. sell_flag=False") + # logger.debug(f"{trade.pair} - No sell signal. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) def stop_loss_reached(self, current_rate: float, trade: Trade, From e6ec8f9f30138e5eb63666dd0cad5d73c48a6324 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Thu, 12 Sep 2019 21:28:51 +0300 Subject: [PATCH 10/13] Fix tests: Change condition for printing 'close' --- freqtrade/persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 1850aafd9..bccbce931 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -210,7 +210,7 @@ class Trade(_DECL_BASE): ticker_interval = Column(Integer, nullable=True) def __repr__(self): - open_since = self.open_date.strftime('%Y-%m-%d %H:%M:%S') if self.is_open else 'closed' + open_since = self.open_date.strftime('%Y-%m-%d %H:%M:%S') if self.open_date else 'closed' return (f'Trade(id={self.id}, pair={self.pair}, amount={self.amount:.8f}, ' f'open_rate={self.open_rate:.8f}, open_since={open_since})') From c8d191a5c9ca63661276e1c6585e2b29be3bf71f Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Thu, 12 Sep 2019 22:53:54 +0300 Subject: [PATCH 11/13] Adjust test --- tests/test_freqtradebot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index d34197519..d39c9aaef 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -2153,8 +2153,8 @@ def test_check_handle_timedout_exception(default_conf, ticker, mocker, caplog) - freqtrade.check_handle_timedout() assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, " r"open_rate=0.00001099, open_since=" - f"{open_date.strftime('%Y-%m-%d %H:%M:%S')} " - r"\(10 hours ago\)\) due to Traceback \(most recent call last\):\n*", + f"{open_date.strftime('%Y-%m-%d %H:%M:%S')}" + r"\) due to Traceback \(most recent call last\):\n*", caplog) From eda1ec652f99f8210916c19f678df441db01921b Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Fri, 13 Sep 2019 23:00:09 +0300 Subject: [PATCH 12/13] Revert back condition for open_since in Trade.__repr__ --- freqtrade/persistence.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index bccbce931..1850aafd9 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -210,7 +210,7 @@ class Trade(_DECL_BASE): ticker_interval = Column(Integer, nullable=True) def __repr__(self): - open_since = self.open_date.strftime('%Y-%m-%d %H:%M:%S') if self.open_date else 'closed' + open_since = self.open_date.strftime('%Y-%m-%d %H:%M:%S') if self.is_open else 'closed' return (f'Trade(id={self.id}, pair={self.pair}, amount={self.amount:.8f}, ' f'open_rate={self.open_rate:.8f}, open_since={open_since})') From b00467c8efaa61c2556d6e88c446c3dcd3230dd6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 14 Sep 2019 10:07:23 +0200 Subject: [PATCH 13/13] Fix test failure --- tests/test_freqtradebot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index d39c9aaef..a595e0ce6 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1590,6 +1590,8 @@ def test_update_trade_state(mocker, default_conf, limit_buy_order, caplog) -> No Trade.session = MagicMock() trade.open_order_id = '123' trade.open_fee = 0.001 + # Add datetime explicitly since sqlalchemy defaults apply only once written to database + trade.open_date = arrow.utcnow().datetime freqtrade.update_trade_state(trade) # Test amount not modified by fee-logic assert not log_has_re(r'Applying fee to .*', caplog)