freqtrade_origin/tests/optimize/__init__.py
2024-11-08 04:37:33 +08:00

85 lines
2.3 KiB
Python

from datetime import timedelta
from typing import NamedTuple
from pandas import DataFrame
from freqtrade.enums import ExitType
from freqtrade.exchange import timeframe_to_minutes
from freqtrade.util.datetime_helpers import dt_utc
tests_start_time = dt_utc(2018, 10, 3)
tests_timeframe = "1h"
class BTrade(NamedTuple):
"""
Minimalistic Trade result used for functional backtesting
"""
exit_reason: ExitType
open_tick: int
close_tick: int
enter_tag: str | None = None
is_short: bool = False
class BTContainer(NamedTuple):
"""
Minimal BacktestContainer defining Backtest inputs and results.
"""
data: list[list[float]]
stop_loss: float
roi: dict[str, float]
trades: list[BTrade]
profit_perc: float
trailing_stop: bool = False
trailing_only_offset_is_reached: bool = False
trailing_stop_positive: float | None = None
trailing_stop_positive_offset: float = 0.0
use_exit_signal: bool = False
use_custom_stoploss: bool = False
custom_entry_price: float | None = None
custom_exit_price: float | None = None
leverage: float = 1.0
timeout: int | None = None
adjust_entry_price: float | None = None
def _get_frame_time_from_offset(offset):
minutes = offset * timeframe_to_minutes(tests_timeframe)
return tests_start_time + timedelta(minutes=minutes)
def _build_backtest_dataframe(data):
columns = [
"date",
"open",
"high",
"low",
"close",
"volume",
"enter_long",
"exit_long",
"enter_short",
"exit_short",
]
if len(data[0]) == 8:
# No short columns
data = [d + [0, 0] for d in data]
columns = columns + ["enter_tag"] if len(data[0]) == 11 else columns
frame = DataFrame.from_records(data, columns=columns)
frame["date"] = frame["date"].apply(_get_frame_time_from_offset)
# Ensure floats are in place
for column in ["open", "high", "low", "close", "volume"]:
frame[column] = frame[column].astype("float64")
# Ensure all candles make kindof sense
assert all(frame["low"] <= frame["close"])
assert all(frame["low"] <= frame["open"])
assert all(frame["high"] >= frame["close"])
assert all(frame["high"] >= frame["open"])
return frame