diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 7adb7a154..80f74bfb6 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -7,7 +7,6 @@ from abc import ABC, abstractmethod from datetime import datetime, timedelta, timezone from typing import Dict, List, Optional, Tuple, Union -import arrow from pandas import DataFrame from freqtrade.constants import CUSTOM_TAG_MAX_LENGTH, Config, IntOrInf, ListPairsWithTimeframes @@ -23,6 +22,7 @@ from freqtrade.strategy.informative_decorator import (InformativeData, PopulateI _create_and_merge_informative_pair, _format_pair_name) from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper +from freqtrade.util import dt_now from freqtrade.wallets import Wallets @@ -938,7 +938,7 @@ class IStrategy(ABC, HyperStrategyMixin): pair: str, timeframe: str, dataframe: DataFrame, - ) -> Tuple[Optional[DataFrame], Optional[arrow.Arrow]]: + ) -> Tuple[Optional[DataFrame], Optional[datetime]]: """ Calculates current signal based based on the entry order or exit order columns of the dataframe. @@ -955,15 +955,15 @@ class IStrategy(ABC, HyperStrategyMixin): latest_date = dataframe['date'].max() latest = dataframe.loc[dataframe['date'] == latest_date].iloc[-1] # Explicitly convert to arrow object to ensure the below comparison does not fail - latest_date = arrow.get(latest_date) + latest_date = latest_date.to_pydatetime() # Check if dataframe is out of date timeframe_minutes = timeframe_to_minutes(timeframe) offset = self.config.get('exchange', {}).get('outdated_offset', 5) - if latest_date < (arrow.utcnow().shift(minutes=-(timeframe_minutes * 2 + offset))): + if latest_date < (dt_now() - timedelta(minutes=timeframe_minutes * 2 + offset)): logger.warning( 'Outdated history for pair %s. Last tick is %s minutes old', - pair, int((arrow.utcnow() - latest_date).total_seconds() // 60) + pair, int((dt_now() - latest_date).total_seconds() // 60) ) return None, None return latest, latest_date @@ -1046,8 +1046,8 @@ class IStrategy(ABC, HyperStrategyMixin): timeframe_seconds = timeframe_to_seconds(timeframe) if self.ignore_expired_candle( - latest_date=latest_date.datetime, - current_time=datetime.now(timezone.utc), + latest_date=latest_date, + current_time=dt_now(), timeframe_seconds=timeframe_seconds, enter=bool(enter_signal) ): diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 204fa996d..ef8fd0be9 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -22,6 +22,7 @@ from freqtrade.strategy.hyper import detect_parameters from freqtrade.strategy.parameters import (BaseParameter, BooleanParameter, CategoricalParameter, DecimalParameter, IntParameter, RealParameter) from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper +from freqtrade.util import dt_now from tests.conftest import (CURRENT_TEST_STRATEGY, TRADE_SIDES, create_mock_trades, log_has, log_has_re) @@ -34,7 +35,7 @@ _STRATEGY.dp = DataProvider({}, None, None) def test_returns_latest_signal(ohlcv_history): - ohlcv_history.loc[1, 'date'] = arrow.utcnow() + ohlcv_history.loc[1, 'date'] = dt_now() # Take a copy to correctly modify the call mocked_history = ohlcv_history.copy() mocked_history['enter_long'] = 0 @@ -159,7 +160,7 @@ def test_get_signal_exception_valueerror(mocker, caplog, ohlcv_history): 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 - ohlcv_history.loc[1, 'date'] = arrow.utcnow().shift(minutes=-16) + ohlcv_history.loc[1, 'date'] = dt_now() - timedelta(minutes=16) # Take a copy to correctly modify the call mocked_history = ohlcv_history.copy() mocked_history['exit_long'] = 0 @@ -180,7 +181,7 @@ def test_get_signal_old_dataframe(default_conf, mocker, caplog, ohlcv_history): def test_get_signal_no_sell_column(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 - ohlcv_history.loc[1, 'date'] = arrow.utcnow() + ohlcv_history.loc[1, 'date'] = dt_now() # Take a copy to correctly modify the call mocked_history = ohlcv_history.copy() # Intentionally don't set sell column @@ -224,7 +225,7 @@ def test_ignore_expired_candle(default_conf): def test_assert_df_raise(mocker, caplog, ohlcv_history): - ohlcv_history.loc[1, 'date'] = arrow.utcnow().shift(minutes=-16) + ohlcv_history.loc[1, 'date'] = dt_now() - timedelta(minutes=16) # Take a copy to correctly modify the call mocked_history = ohlcv_history.copy() mocked_history['sell'] = 0 @@ -323,7 +324,7 @@ def test_min_roi_reached(default_conf, fee) -> None: pair='ETH/BTC', stake_amount=0.001, amount=5, - open_date=arrow.utcnow().shift(hours=-1).datetime, + open_date=dt_now() - timedelta(hours=1), fee_open=fee.return_value, fee_close=fee.return_value, exchange='binance',