"""EXIT-14 — protezione GIVEBACK dal picco (trailing sul PROFITTO, non sul prezzo).

Idea: una fade puo' correre a favore quasi fino al TP (alla media) e poi
ritracciare prima di toccarlo, restituendo gran parte del guadagno gia' maturato.
Questa policy traccia l'high-water-mark (hwm) del PROFITTO non realizzato sul
CLOSE; quando il profitto corrente scende sotto (1-g)*hwm_profit -- cioe' si e'
restituita una frazione g del picco -- e il picco era gia' "significativo"
(hwm_profit > soglia * dist(entry, tp0)), esce al close del bar (after_bar).
Il TP fisso tp0 e lo SL fisso sl0 RESTANO invariati e prioritari intrabar.

Razionale: protegge il profitto maturato senza toccare i livelli; non e' un
ladder (ieri scartato perche' al TP/media il movimento e' esaurito) ma un
trailing sul drawdown del trade quando ha gia' fatto buona parte del lavoro.

ANTI-LOOK-AHEAD:
  - levels(j) NON e' toccato (TP/SL fissi): nessun dato futuro.
  - after_bar(j) decide sul CLOSE del bar j (eseguibile al poll). Aggiorna l'hwm
    con il profitto a close[j] e poi confronta: tutto con dati <= j. Il bar j e'
    lecito in after_bar per contratto. L'hwm e' un cliquet (non scende mai).

GRID: g in {0.4, 0.6} x arm_frac in {0.3, 0.5} della distanza al TP (4 celle).
  - g = frazione del picco di profitto restituita che fa scattare l'uscita.
  - arm_frac = il giveback e' armato solo quando hwm_profit ha superato
    arm_frac * dist(entry, tp0): finche' il trade non ha "fatto strada"
    (frazione del cammino verso la media) non interviene -> non taglia i trade
    che partono storti, solo quelli che hanno gia' guadagnato e poi mollano.
"""
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from exit_lab import ExitPolicy, evaluate  # noqa: E402


class Giveback(ExitPolicy):
    name = "giveback"

    def __init__(self, ctx, i, d, entry, tp0, sl0, mb, **params):
        super().__init__(ctx, i, d, entry, tp0, sl0, mb, **params)
        self.g = float(params.get("g", 0.4))
        self.arm_frac = float(params.get("arm_frac", 0.3))
        self.close = ctx["close"]
        # distanza (in prezzo, sempre positiva) dall'entrata al TP iniziale
        self.dist_tp = abs(self.tp0 - entry) if self.tp0 is not None else 0.0
        self.arm_level = self.arm_frac * self.dist_tp
        self.hwm_profit = 0.0          # high-water-mark del profitto a favore (cliquet)

    def after_bar(self, j: int) -> bool:
        if self.dist_tp <= 0.0:
            return False
        # profitto NON realizzato a favore, valutato sul close del bar j (lecito qui)
        profit = (self.close[j] - self.entry) * self.d
        if profit > self.hwm_profit:
            self.hwm_profit = profit   # aggiorna il picco (non scende mai)
        # arma solo se il picco ha superato la soglia (trade gia' "in cammino")
        if self.hwm_profit < self.arm_level:
            return False
        # esci se il profitto corrente ha restituito >= g del picco
        if profit < (1.0 - self.g) * self.hwm_profit:
            return True
        return False


GRID = [
    {"g": 0.4, "arm_frac": 0.3},
    {"g": 0.4, "arm_frac": 0.5},
    {"g": 0.6, "arm_frac": 0.3},
    {"g": 0.6, "arm_frac": 0.5},
]


if __name__ == "__main__":
    evaluate(Giveback, GRID)
