38 lines
1.2 KiB
Python
38 lines
1.2 KiB
Python
from __future__ import annotations
|
|
|
|
import pandas as pd
|
|
|
|
from .constants import TREND_BEAR, TREND_BULL
|
|
|
|
|
|
def backtest_signals(df: pd.DataFrame) -> dict[str, float | int]:
|
|
if len(df) < 4:
|
|
return {"trades": 0, "wins": 0, "losses": 0, "win_rate": 0.0}
|
|
|
|
trend_series = df["trend_state"]
|
|
trend_change = trend_series != trend_series.shift(1)
|
|
signal_idx = df.index[trend_change & trend_series.isin([TREND_BULL, TREND_BEAR])]
|
|
|
|
wins = 0
|
|
losses = 0
|
|
|
|
for idx in signal_idx:
|
|
pos = df.index.get_loc(idx)
|
|
if pos + 1 >= len(df):
|
|
continue
|
|
|
|
entry_close = float(df.iloc[pos]["Close"])
|
|
next_close = float(df.iloc[pos + 1]["Close"])
|
|
signal_trend = df.iloc[pos]["trend_state"]
|
|
|
|
if signal_trend == TREND_BULL:
|
|
wins += int(next_close > entry_close)
|
|
losses += int(next_close <= entry_close)
|
|
elif signal_trend == TREND_BEAR:
|
|
wins += int(next_close < entry_close)
|
|
losses += int(next_close >= entry_close)
|
|
|
|
trades = wins + losses
|
|
win_rate = (wins / trades * 100.0) if trades else 0.0
|
|
return {"trades": trades, "wins": wins, "losses": losses, "win_rate": round(win_rate, 2)}
|