refactor: Update timezone.utc to UTC

This commit is contained in:
Matthias
2025-07-04 08:58:03 +02:00
parent 37cc949d94
commit a7ee45a0ba
13 changed files with 50 additions and 51 deletions
@@ -3,7 +3,7 @@ import importlib
import logging import logging
from abc import abstractmethod from abc import abstractmethod
from collections.abc import Callable from collections.abc import Callable
from datetime import datetime, timezone from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@@ -239,7 +239,7 @@ class BaseReinforcementLearningModel(IFreqaiModel):
pair, refresh=False, side="exit", is_short=trade.is_short pair, refresh=False, side="exit", is_short=trade.is_short
) )
now = datetime.now(timezone.utc).timestamp() now = datetime.now(UTC).timestamp()
trade_duration = int((now - trade.open_date_utc.timestamp()) / self.base_tf_seconds) trade_duration = int((now - trade.open_date_utc.timestamp()) / self.base_tf_seconds)
current_profit = trade.calc_profit_ratio(current_rate) current_profit = trade.calc_profit_ratio(current_rate)
if trade.is_short: if trade.is_short:
+2 -2
View File
@@ -1,8 +1,8 @@
from datetime import datetime from datetime import datetime
from typing import Literal from typing import Literal, Required
from pydantic import TypeAdapter from pydantic import TypeAdapter
from typing_extensions import Required, TypedDict from typing_extensions import TypedDict
class AnnotationType(TypedDict, total=False): class AnnotationType(TypedDict, total=False):
+4 -4
View File
@@ -1,6 +1,6 @@
import logging import logging
from copy import deepcopy from copy import deepcopy
from datetime import datetime, timezone from datetime import UTC, datetime
from typing import Any from typing import Any
from pandas import DataFrame from pandas import DataFrame
@@ -38,7 +38,7 @@ class BaseAnalysis:
@staticmethod @staticmethod
def dt_to_timestamp(dt: datetime): def dt_to_timestamp(dt: datetime):
timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp()) timestamp = int(dt.replace(tzinfo=UTC).timestamp())
return timestamp return timestamp
def fill_full_varholder(self): def fill_full_varholder(self):
@@ -48,12 +48,12 @@ class BaseAnalysis:
parsed_timerange = TimeRange.parse_timerange(self.local_config["timerange"]) parsed_timerange = TimeRange.parse_timerange(self.local_config["timerange"])
if parsed_timerange.startdt is None: if parsed_timerange.startdt is None:
self.full_varHolder.from_dt = datetime.fromtimestamp(0, tz=timezone.utc) self.full_varHolder.from_dt = datetime.fromtimestamp(0, tz=UTC)
else: else:
self.full_varHolder.from_dt = parsed_timerange.startdt self.full_varHolder.from_dt = parsed_timerange.startdt
if parsed_timerange.stopdt is None: if parsed_timerange.stopdt is None:
self.full_varHolder.to_dt = datetime.now(timezone.utc) self.full_varHolder.to_dt = datetime.now(UTC)
else: else:
self.full_varHolder.to_dt = parsed_timerange.stopdt self.full_varHolder.to_dt = parsed_timerange.stopdt
@@ -6,7 +6,7 @@ and will be sent to the hyperopt worker processes.
import logging import logging
import sys import sys
import warnings import warnings
from datetime import datetime, timezone from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@@ -273,7 +273,7 @@ class HyperOptimizer:
Keep this function as optimized as possible! Keep this function as optimized as possible!
""" """
HyperoptStateContainer.set_state(HyperoptState.OPTIMIZE) HyperoptStateContainer.set_state(HyperoptState.OPTIMIZE)
backtest_start_time = datetime.now(timezone.utc) backtest_start_time = datetime.now(UTC)
# Apply parameters # Apply parameters
if HyperoptTools.has_space(self.config, "buy"): if HyperoptTools.has_space(self.config, "buy"):
@@ -330,7 +330,7 @@ class HyperOptimizer:
bt_results = self.backtesting.backtest( bt_results = self.backtesting.backtest(
processed=processed, start_date=self.min_date, end_date=self.max_date processed=processed, start_date=self.min_date, end_date=self.max_date
) )
backtest_end_time = datetime.now(timezone.utc) backtest_end_time = datetime.now(UTC)
bt_results.update( bt_results.update(
{ {
"backtest_start_time": int(backtest_start_time.timestamp()), "backtest_start_time": int(backtest_start_time.timestamp()),
+2 -2
View File
@@ -1,7 +1,7 @@
import logging import logging
from collections.abc import Iterator from collections.abc import Iterator
from copy import deepcopy from copy import deepcopy
from datetime import datetime, timezone from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@@ -71,7 +71,7 @@ class HyperoptTools:
"strategy_name": strategy_name, "strategy_name": strategy_name,
"params": final_params, "params": final_params,
"ft_stratparam_v": 1, "ft_stratparam_v": 1,
"export_time": datetime.now(timezone.utc), "export_time": datetime.now(UTC),
} }
logger.info(f"Dumping parameters to {filename}") logger.info(f"Dumping parameters to {filename}")
with filename.open("w") as f: with filename.open("w") as f:
@@ -1,6 +1,6 @@
import logging import logging
from copy import deepcopy from copy import deepcopy
from datetime import datetime, timedelta, timezone from datetime import UTC, datetime, timedelta
from typing import Any, Literal from typing import Any, Literal
import numpy as np import numpy as np
@@ -652,9 +652,9 @@ def generate_strategy_stats(
"max_drawdown_abs": 0.0, "max_drawdown_abs": 0.0,
"max_drawdown_low": 0.0, "max_drawdown_low": 0.0,
"max_drawdown_high": 0.0, "max_drawdown_high": 0.0,
"drawdown_start": datetime(1970, 1, 1, tzinfo=timezone.utc), "drawdown_start": datetime(1970, 1, 1, tzinfo=UTC),
"drawdown_start_ts": 0, "drawdown_start_ts": 0,
"drawdown_end": datetime(1970, 1, 1, tzinfo=timezone.utc), "drawdown_end": datetime(1970, 1, 1, tzinfo=UTC),
"drawdown_end_ts": 0, "drawdown_end_ts": 0,
"csum_min": 0, "csum_min": 0,
"csum_max": 0, "csum_max": 0,
+5 -5
View File
@@ -1,4 +1,4 @@
from datetime import datetime, timezone from datetime import UTC, datetime
from enum import Enum from enum import Enum
from typing import ClassVar, Literal from typing import ClassVar, Literal
@@ -114,7 +114,7 @@ class KeyValueStore:
if kv.value_type == ValueTypesEnum.STRING: if kv.value_type == ValueTypesEnum.STRING:
return kv.string_value return kv.string_value
if kv.value_type == ValueTypesEnum.DATETIME and kv.datetime_value is not None: if kv.value_type == ValueTypesEnum.DATETIME and kv.datetime_value is not None:
return kv.datetime_value.replace(tzinfo=timezone.utc) return kv.datetime_value.replace(tzinfo=UTC)
if kv.value_type == ValueTypesEnum.FLOAT: if kv.value_type == ValueTypesEnum.FLOAT:
return kv.float_value return kv.float_value
if kv.value_type == ValueTypesEnum.INT: if kv.value_type == ValueTypesEnum.INT:
@@ -156,7 +156,7 @@ class KeyValueStore:
) )
if kv is None or kv.datetime_value is None: if kv is None or kv.datetime_value is None:
return None return None
return kv.datetime_value.replace(tzinfo=timezone.utc) return kv.datetime_value.replace(tzinfo=UTC)
@staticmethod @staticmethod
def get_float_value(key: KeyStoreKeys) -> float | None: def get_float_value(key: KeyStoreKeys) -> float | None:
@@ -207,5 +207,5 @@ def set_startup_time() -> None:
if t is not None: if t is not None:
KeyValueStore.store_value("bot_start_time", t.open_date_utc) KeyValueStore.store_value("bot_start_time", t.open_date_utc)
else: else:
KeyValueStore.store_value("bot_start_time", datetime.now(timezone.utc)) KeyValueStore.store_value("bot_start_time", datetime.now(UTC))
KeyValueStore.store_value("startup_time", datetime.now(timezone.utc)) KeyValueStore.store_value("startup_time", datetime.now(UTC))
+3 -3
View File
@@ -1,4 +1,4 @@
from datetime import datetime, timezone from datetime import UTC, datetime
from typing import Any, ClassVar from typing import Any, ClassVar
from sqlalchemy import ScalarResult, String, or_, select from sqlalchemy import ScalarResult, String, or_, select
@@ -69,10 +69,10 @@ class PairLock(ModelBase):
"id": self.id, "id": self.id,
"pair": self.pair, "pair": self.pair,
"lock_time": self.lock_time.strftime(DATETIME_PRINT_FORMAT), "lock_time": self.lock_time.strftime(DATETIME_PRINT_FORMAT),
"lock_timestamp": int(self.lock_time.replace(tzinfo=timezone.utc).timestamp() * 1000), "lock_timestamp": int(self.lock_time.replace(tzinfo=UTC).timestamp() * 1000),
"lock_end_time": self.lock_end_time.strftime(DATETIME_PRINT_FORMAT), "lock_end_time": self.lock_end_time.strftime(DATETIME_PRINT_FORMAT),
"lock_end_timestamp": int( "lock_end_timestamp": int(
self.lock_end_time.replace(tzinfo=timezone.utc).timestamp() * 1000 self.lock_end_time.replace(tzinfo=UTC).timestamp() * 1000
), ),
"reason": self.reason, "reason": self.reason,
"side": self.side, "side": self.side,
+7 -7
View File
@@ -1,6 +1,6 @@
import logging import logging
from collections.abc import Sequence from collections.abc import Sequence
from datetime import datetime, timezone from datetime import UTC, datetime
from sqlalchemy import select from sqlalchemy import select
@@ -52,7 +52,7 @@ class PairLocks:
""" """
lock = PairLock( lock = PairLock(
pair=pair, pair=pair,
lock_time=now or datetime.now(timezone.utc), lock_time=now or datetime.now(UTC),
lock_end_time=timeframe_to_next_date(PairLocks.timeframe, until), lock_end_time=timeframe_to_next_date(PairLocks.timeframe, until),
reason=reason, reason=reason,
side=side, side=side,
@@ -77,7 +77,7 @@ class PairLocks:
:param side: Side get locks for, can be 'long', 'short', '*' or None :param side: Side get locks for, can be 'long', 'short', '*' or None
""" """
if not now: if not now:
now = datetime.now(timezone.utc) now = datetime.now(UTC)
if PairLocks.use_db: if PairLocks.use_db:
return PairLock.query_pair_locks(pair, now, side).all() return PairLock.query_pair_locks(pair, now, side).all()
@@ -114,7 +114,7 @@ class PairLocks:
defaults to datetime.now(timezone.utc) defaults to datetime.now(timezone.utc)
""" """
if not now: if not now:
now = datetime.now(timezone.utc) now = datetime.now(UTC)
logger.info(f"Releasing all locks for {pair}.") logger.info(f"Releasing all locks for {pair}.")
locks = PairLocks.get_pair_locks(pair, now, side=side) locks = PairLocks.get_pair_locks(pair, now, side=side)
@@ -132,7 +132,7 @@ class PairLocks:
defaults to datetime.now(timezone.utc) defaults to datetime.now(timezone.utc)
""" """
if not now: if not now:
now = datetime.now(timezone.utc) now = datetime.now(UTC)
if PairLocks.use_db: if PairLocks.use_db:
# used in live modes # used in live modes
@@ -161,7 +161,7 @@ class PairLocks:
defaults to datetime.now(timezone.utc) defaults to datetime.now(timezone.utc)
""" """
if not now: if not now:
now = datetime.now(timezone.utc) now = datetime.now(UTC)
return len(PairLocks.get_pair_locks("*", now, side)) > 0 return len(PairLocks.get_pair_locks("*", now, side)) > 0
@@ -173,7 +173,7 @@ class PairLocks:
defaults to datetime.now(timezone.utc) defaults to datetime.now(timezone.utc)
""" """
if not now: if not now:
now = datetime.now(timezone.utc) now = datetime.now(UTC)
return len(PairLocks.get_pair_locks(pair, now, side)) > 0 or PairLocks.is_global_lock( return len(PairLocks.get_pair_locks(pair, now, side)) > 0 or PairLocks.is_global_lock(
now, side now, side
+12 -13
View File
@@ -6,9 +6,9 @@ import logging
from collections import defaultdict from collections import defaultdict
from collections.abc import Sequence from collections.abc import Sequence
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timezone from datetime import UTC, datetime
from math import isclose from math import isclose
from typing import Any, ClassVar, Optional, cast from typing import Any, ClassVar, Optional, Self, cast
from sqlalchemy import ( from sqlalchemy import (
Enum, Enum,
@@ -25,7 +25,6 @@ from sqlalchemy import (
select, select,
) )
from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates
from typing_extensions import Self
from freqtrade.constants import ( from freqtrade.constants import (
CANCELED_EXCHANGE_STATES, CANCELED_EXCHANGE_STATES,
@@ -121,13 +120,13 @@ class Order(ModelBase):
@property @property
def order_date_utc(self) -> datetime: def order_date_utc(self) -> datetime:
"""Order-date with UTC timezoneinfo""" """Order-date with UTC timezoneinfo"""
return self.order_date.replace(tzinfo=timezone.utc) return self.order_date.replace(tzinfo=UTC)
@property @property
def order_filled_utc(self) -> datetime | None: def order_filled_utc(self) -> datetime | None:
"""last order-date with UTC timezoneinfo""" """last order-date with UTC timezoneinfo"""
return ( return (
self.order_filled_date.replace(tzinfo=timezone.utc) if self.order_filled_date else None self.order_filled_date.replace(tzinfo=UTC) if self.order_filled_date else None
) )
@property @property
@@ -229,7 +228,7 @@ class Order(ModelBase):
self.order_filled_date = dt_from_ts( self.order_filled_date = dt_from_ts(
safe_value_fallback(order, "lastTradeTimestamp", default_value=dt_ts()) safe_value_fallback(order, "lastTradeTimestamp", default_value=dt_ts())
) )
self.order_update_date = datetime.now(timezone.utc) self.order_update_date = datetime.now(UTC)
def to_ccxt_object(self, stopPriceName: str = "stopPrice") -> dict[str, Any]: def to_ccxt_object(self, stopPriceName: str = "stopPrice") -> dict[str, Any]:
order: dict[str, Any] = { order: dict[str, Any] = {
@@ -286,7 +285,7 @@ class Order(ModelBase):
self.order_date.strftime(DATETIME_PRINT_FORMAT) if self.order_date else None self.order_date.strftime(DATETIME_PRINT_FORMAT) if self.order_date else None
), ),
"order_timestamp": ( "order_timestamp": (
int(self.order_date.replace(tzinfo=timezone.utc).timestamp() * 1000) int(self.order_date.replace(tzinfo=UTC).timestamp() * 1000)
if self.order_date if self.order_date
else None else None
), ),
@@ -533,7 +532,7 @@ class LocalTrade:
@property @property
def open_date_utc(self): def open_date_utc(self):
return self.open_date.replace(tzinfo=timezone.utc) return self.open_date.replace(tzinfo=UTC)
@property @property
def stoploss_last_update_utc(self): def stoploss_last_update_utc(self):
@@ -543,7 +542,7 @@ class LocalTrade:
@property @property
def close_date_utc(self): def close_date_utc(self):
return self.close_date.replace(tzinfo=timezone.utc) if self.close_date else None return self.close_date.replace(tzinfo=UTC) if self.close_date else None
@property @property
def entry_side(self) -> str: def entry_side(self) -> str:
@@ -1056,7 +1055,7 @@ class LocalTrade:
return zero return zero
open_date = self.open_date.replace(tzinfo=None) open_date = self.open_date.replace(tzinfo=None)
now = (self.close_date or datetime.now(timezone.utc)).replace(tzinfo=None) now = (self.close_date or datetime.now(UTC)).replace(tzinfo=None)
sec_per_hour = FtPrecise(3600) sec_per_hour = FtPrecise(3600)
total_seconds = FtPrecise((now - open_date).total_seconds()) total_seconds = FtPrecise((now - open_date).total_seconds())
hours = total_seconds / sec_per_hour or zero hours = total_seconds / sec_per_hour or zero
@@ -1572,12 +1571,12 @@ class LocalTrade:
fee_close=data["fee_close"], fee_close=data["fee_close"],
fee_close_cost=data.get("fee_close_cost"), fee_close_cost=data.get("fee_close_cost"),
fee_close_currency=data.get("fee_close_currency"), fee_close_currency=data.get("fee_close_currency"),
open_date=datetime.fromtimestamp(data["open_timestamp"] // 1000, tz=timezone.utc), open_date=datetime.fromtimestamp(data["open_timestamp"] // 1000, tz=UTC),
open_rate=data["open_rate"], open_rate=data["open_rate"],
open_rate_requested=data.get("open_rate_requested", data["open_rate"]), open_rate_requested=data.get("open_rate_requested", data["open_rate"]),
open_trade_value=data.get("open_trade_value"), open_trade_value=data.get("open_trade_value"),
close_date=( close_date=(
datetime.fromtimestamp(data["close_timestamp"] // 1000, tz=timezone.utc) datetime.fromtimestamp(data["close_timestamp"] // 1000, tz=UTC)
if data["close_timestamp"] if data["close_timestamp"]
else None else None
), ),
@@ -1622,7 +1621,7 @@ class LocalTrade:
if order.get("order_date") if order.get("order_date")
else None, else None,
order_filled_date=( order_filled_date=(
datetime.fromtimestamp(order["order_filled_timestamp"] // 1000, tz=timezone.utc) datetime.fromtimestamp(order["order_filled_timestamp"] // 1000, tz=UTC)
if order["order_filled_timestamp"] if order["order_filled_timestamp"]
else None else None
), ),
+2 -2
View File
@@ -1,5 +1,5 @@
import logging import logging
from datetime import datetime, timezone from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
import pandas as pd import pandas as pd
@@ -638,7 +638,7 @@ def load_and_plot_trades(config: Config):
exchange = ExchangeResolver.load_exchange(config) exchange = ExchangeResolver.load_exchange(config)
IStrategy.dp = DataProvider(config, exchange) IStrategy.dp = DataProvider(config, exchange)
strategy.ft_bot_start() strategy.ft_bot_start()
strategy_safe_wrapper(strategy.bot_loop_start)(current_time=datetime.now(timezone.utc)) strategy_safe_wrapper(strategy.bot_loop_start)(current_time=datetime.now(UTC))
plot_elements = init_plotscript(config, list(exchange.markets), strategy.startup_candle_count) plot_elements = init_plotscript(config, list(exchange.markets), strategy.startup_candle_count)
timerange = plot_elements["timerange"] timerange = plot_elements["timerange"]
trades = plot_elements["trades"] trades = plot_elements["trades"]
+3 -3
View File
@@ -3,7 +3,7 @@ Protection manager class
""" """
import logging import logging
from datetime import datetime, timezone from datetime import UTC, datetime
from typing import Any from typing import Any
from freqtrade.constants import Config, LongShort from freqtrade.constants import Config, LongShort
@@ -49,7 +49,7 @@ class ProtectionManager:
def global_stop(self, now: datetime | None = None, side: LongShort = "long") -> PairLock | None: def global_stop(self, now: datetime | None = None, side: LongShort = "long") -> PairLock | None:
if not now: if not now:
now = datetime.now(timezone.utc) now = datetime.now(UTC)
result = None result = None
for protection_handler in self._protection_handlers: for protection_handler in self._protection_handlers:
if protection_handler.has_global_stop: if protection_handler.has_global_stop:
@@ -65,7 +65,7 @@ class ProtectionManager:
self, pair, now: datetime | None = None, side: LongShort = "long" self, pair, now: datetime | None = None, side: LongShort = "long"
) -> PairLock | None: ) -> PairLock | None:
if not now: if not now:
now = datetime.now(timezone.utc) now = datetime.now(UTC)
result = None result = None
for protection_handler in self._protection_handlers: for protection_handler in self._protection_handlers:
if protection_handler.has_local_stop: if protection_handler.has_local_stop:
+2 -2
View File
@@ -1,7 +1,7 @@
import logging import logging
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta, timezone from datetime import UTC, datetime, timedelta
from typing import Any from typing import Any
from freqtrade.constants import Config, LongShort from freqtrade.constants import Config, LongShort
@@ -127,7 +127,7 @@ class IProtection(LoggingMixin, ABC):
max_date: datetime = max([trade.close_date for trade in trades if trade.close_date]) max_date: datetime = max([trade.close_date for trade in trades if trade.close_date])
# coming from Database, tzinfo is not set. # coming from Database, tzinfo is not set.
if max_date.tzinfo is None: if max_date.tzinfo is None:
max_date = max_date.replace(tzinfo=timezone.utc) max_date = max_date.replace(tzinfo=UTC)
if self._unlock_at is not None: if self._unlock_at is not None:
# unlock_at case with fixed hour of the day # unlock_at case with fixed hour of the day