From 4a8c8f296a0e53553d2e47c692bbdf1926fcf752 Mon Sep 17 00:00:00 2001 From: Joe Schr <8218910+TheJoeSchr@users.noreply.github.com> Date: Mon, 26 Feb 2024 14:47:08 +0100 Subject: [PATCH 1/2] chore: extract `timeframe_to_*` functions into `exchange_utils_timeframe.py` --- freqtrade/exchange/exchange_utils.py | 87 +++---------------- .../exchange/exchange_utils_timeframe.py | 81 +++++++++++++++++ 2 files changed, 95 insertions(+), 73 deletions(-) create mode 100644 freqtrade/exchange/exchange_utils_timeframe.py diff --git a/freqtrade/exchange/exchange_utils.py b/freqtrade/exchange/exchange_utils.py index f4dc3a721..4427ad060 100644 --- a/freqtrade/exchange/exchange_utils.py +++ b/freqtrade/exchange/exchange_utils.py @@ -11,13 +11,26 @@ from ccxt import (DECIMAL_PLACES, ROUND, ROUND_DOWN, ROUND_UP, SIGNIFICANT_DIGIT from freqtrade.exchange.common import (BAD_EXCHANGES, EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED, SUPPORTED_EXCHANGES) +from freqtrade.exchange.exchange_utils_timeframe import (timeframe_to_minutes, timeframe_to_msecs, + timeframe_to_next_date, + timeframe_to_prev_date, + timeframe_to_resample_freq, + timeframe_to_seconds) from freqtrade.types import ValidExchangesType from freqtrade.util import FtPrecise -from freqtrade.util.datetime_helpers import dt_from_ts, dt_ts CcxtModuleType = Any +__all__ = [ + 'timeframe_to_minutes', + 'timeframe_to_msecs', + 'timeframe_to_next_date', + 'timeframe_to_prev_date', + 'timeframe_to_resample_freq', + 'timeframe_to_seconds' +] + def is_exchange_known_ccxt( exchange_name: str, ccxt_module: Optional[CcxtModuleType] = None) -> bool: @@ -108,78 +121,6 @@ def list_available_exchanges(all_exchanges: bool) -> List[ValidExchangesType]: return exchanges_valid -def timeframe_to_seconds(timeframe: str) -> int: - """ - Translates the timeframe interval value written in the human readable - form ('1m', '5m', '1h', '1d', '1w', etc.) to the number - of seconds for one timeframe interval. - """ - return ccxt.Exchange.parse_timeframe(timeframe) - - -def timeframe_to_minutes(timeframe: str) -> int: - """ - Same as timeframe_to_seconds, but returns minutes. - """ - return ccxt.Exchange.parse_timeframe(timeframe) // 60 - - -def timeframe_to_msecs(timeframe: str) -> int: - """ - Same as timeframe_to_seconds, but returns milliseconds. - """ - return ccxt.Exchange.parse_timeframe(timeframe) * 1000 - - -def timeframe_to_resample_freq(timeframe: str) -> str: - """ - Translates the timeframe interval value written in the human readable - form ('1m', '5m', '1h', '1d', '1w', etc.) to the resample frequency - used by pandas ('1T', '5T', '1H', '1D', '1W', etc.) - """ - if timeframe == '1y': - return '1YS' - timeframe_seconds = timeframe_to_seconds(timeframe) - timeframe_minutes = timeframe_seconds // 60 - resample_interval = f'{timeframe_seconds}s' - if 10000 < timeframe_minutes < 43200: - resample_interval = '1W-MON' - elif timeframe_minutes >= 43200 and timeframe_minutes < 525600: - # Monthly candles need special treatment to stick to the 1st of the month - resample_interval = f'{timeframe}S' - elif timeframe_minutes > 43200: - resample_interval = timeframe - return resample_interval - - -def timeframe_to_prev_date(timeframe: str, date: Optional[datetime] = None) -> datetime: - """ - Use Timeframe and determine the candle start date for this date. - Does not round when given a candle start date. - :param timeframe: timeframe in string format (e.g. "5m") - :param date: date to use. Defaults to now(utc) - :returns: date of previous candle (with utc timezone) - """ - if not date: - date = datetime.now(timezone.utc) - - new_timestamp = ccxt.Exchange.round_timeframe(timeframe, dt_ts(date), ROUND_DOWN) // 1000 - return dt_from_ts(new_timestamp) - - -def timeframe_to_next_date(timeframe: str, date: Optional[datetime] = None) -> datetime: - """ - Use Timeframe and determine next candle. - :param timeframe: timeframe in string format (e.g. "5m") - :param date: date to use. Defaults to now(utc) - :returns: date of next candle (with utc timezone) - """ - if not date: - date = datetime.now(timezone.utc) - new_timestamp = ccxt.Exchange.round_timeframe(timeframe, dt_ts(date), ROUND_UP) // 1000 - return dt_from_ts(new_timestamp) - - def date_minus_candles( timeframe: str, candle_count: int, date: Optional[datetime] = None) -> datetime: """ diff --git a/freqtrade/exchange/exchange_utils_timeframe.py b/freqtrade/exchange/exchange_utils_timeframe.py new file mode 100644 index 000000000..9366bc7a1 --- /dev/null +++ b/freqtrade/exchange/exchange_utils_timeframe.py @@ -0,0 +1,81 @@ +from datetime import datetime, timezone +from typing import Optional + +import ccxt +from ccxt import ROUND_DOWN, ROUND_UP + +from freqtrade.util.datetime_helpers import dt_from_ts, dt_ts + + +def timeframe_to_seconds(timeframe: str) -> int: + """ + Translates the timeframe interval value written in the human readable + form ('1m', '5m', '1h', '1d', '1w', etc.) to the number + of seconds for one timeframe interval. + """ + return ccxt.Exchange.parse_timeframe(timeframe) + + +def timeframe_to_minutes(timeframe: str) -> int: + """ + Same as timeframe_to_seconds, but returns minutes. + """ + return ccxt.Exchange.parse_timeframe(timeframe) // 60 + + +def timeframe_to_msecs(timeframe: str) -> int: + """ + Same as timeframe_to_seconds, but returns milliseconds. + """ + return ccxt.Exchange.parse_timeframe(timeframe) * 1000 + + +def timeframe_to_resample_freq(timeframe: str) -> str: + """ + Translates the timeframe interval value written in the human readable + form ('1m', '5m', '1h', '1d', '1w', etc.) to the resample frequency + used by pandas ('1T', '5T', '1H', '1D', '1W', etc.) + """ + if timeframe == '1y': + return '1YS' + timeframe_seconds = timeframe_to_seconds(timeframe) + timeframe_minutes = timeframe_seconds // 60 + resample_interval = f'{timeframe_seconds}s' + if 10000 < timeframe_minutes < 43200: + resample_interval = '1W-MON' + elif timeframe_minutes >= 43200 and timeframe_minutes < 525600: + # Monthly candles need special treatment to stick to the 1st of the month + resample_interval = f'{timeframe}S' + elif timeframe_minutes > 43200: + resample_interval = timeframe + return resample_interval + + +def timeframe_to_prev_date(timeframe: str, date: Optional[datetime] = None) -> datetime: + """ + Use Timeframe and determine the candle start date for this date. + Does not round when given a candle start date. + :param timeframe: timeframe in string format (e.g. "5m") + :param date: date to use. Defaults to now(utc) + :returns: date of previous candle (with utc timezone) + """ + if not date: + date = datetime.now(timezone.utc) + + new_timestamp = ccxt.Exchange.round_timeframe( + timeframe, dt_ts(date), ROUND_DOWN) // 1000 + return dt_from_ts(new_timestamp) + + +def timeframe_to_next_date(timeframe: str, date: Optional[datetime] = None) -> datetime: + """ + Use Timeframe and determine next candle. + :param timeframe: timeframe in string format (e.g. "5m") + :param date: date to use. Defaults to now(utc) + :returns: date of next candle (with utc timezone) + """ + if not date: + date = datetime.now(timezone.utc) + new_timestamp = ccxt.Exchange.round_timeframe( + timeframe, dt_ts(date), ROUND_UP) // 1000 + return dt_from_ts(new_timestamp) From b55105ec829694b5c051df8d7f06358ec3c9fc95 Mon Sep 17 00:00:00 2001 From: Joe Schr <8218910+TheJoeSchr@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:37:31 +0100 Subject: [PATCH 2/2] chore: adjust `timeframe_to_*` imports accordingly --- freqtrade/exchange/__init__.py | 8 +++++--- freqtrade/exchange/exchange.py | 9 +++++---- freqtrade/exchange/exchange_utils.py | 15 +-------------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 145332a33..1c6ba9cbd 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -15,10 +15,12 @@ from freqtrade.exchange.exchange_utils import (ROUND_DOWN, ROUND_UP, amount_to_c contracts_to_amount, date_minus_candles, is_exchange_known_ccxt, list_available_exchanges, market_is_active, price_to_precision, - timeframe_to_minutes, timeframe_to_msecs, - timeframe_to_next_date, timeframe_to_prev_date, - timeframe_to_resample_freq, timeframe_to_seconds, validate_exchange) +from freqtrade.exchange.exchange_utils_timeframe import (timeframe_to_minutes, timeframe_to_msecs, + timeframe_to_next_date, + timeframe_to_prev_date, + timeframe_to_resample_freq, + timeframe_to_seconds) from freqtrade.exchange.gate import Gate from freqtrade.exchange.hitbtc import Hitbtc from freqtrade.exchange.htx import Htx diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 7f7fccca8..b55bb9845 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -33,10 +33,11 @@ from freqtrade.exchange.exchange_utils import (ROUND, ROUND_DOWN, ROUND_UP, Ccxt amount_to_contract_precision, amount_to_contracts, amount_to_precision, contracts_to_amount, date_minus_candles, is_exchange_known_ccxt, - market_is_active, price_to_precision, - timeframe_to_minutes, timeframe_to_msecs, - timeframe_to_next_date, timeframe_to_prev_date, - timeframe_to_seconds) + market_is_active, price_to_precision) +from freqtrade.exchange.exchange_utils_timeframe import (timeframe_to_minutes, timeframe_to_msecs, + timeframe_to_next_date, + timeframe_to_prev_date, + timeframe_to_seconds) from freqtrade.exchange.types import OHLCVResponse, OrderBook, Ticker, Tickers from freqtrade.misc import (chunks, deep_merge_dicts, file_dump_json, file_load_json, safe_value_fallback2) diff --git a/freqtrade/exchange/exchange_utils.py b/freqtrade/exchange/exchange_utils.py index 4427ad060..73f61f256 100644 --- a/freqtrade/exchange/exchange_utils.py +++ b/freqtrade/exchange/exchange_utils.py @@ -11,26 +11,13 @@ from ccxt import (DECIMAL_PLACES, ROUND, ROUND_DOWN, ROUND_UP, SIGNIFICANT_DIGIT from freqtrade.exchange.common import (BAD_EXCHANGES, EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED, SUPPORTED_EXCHANGES) -from freqtrade.exchange.exchange_utils_timeframe import (timeframe_to_minutes, timeframe_to_msecs, - timeframe_to_next_date, - timeframe_to_prev_date, - timeframe_to_resample_freq, - timeframe_to_seconds) +from freqtrade.exchange.exchange_utils_timeframe import timeframe_to_minutes, timeframe_to_prev_date from freqtrade.types import ValidExchangesType from freqtrade.util import FtPrecise CcxtModuleType = Any -__all__ = [ - 'timeframe_to_minutes', - 'timeframe_to_msecs', - 'timeframe_to_next_date', - 'timeframe_to_prev_date', - 'timeframe_to_resample_freq', - 'timeframe_to_seconds' -] - def is_exchange_known_ccxt( exchange_name: str, ccxt_module: Optional[CcxtModuleType] = None) -> bool: