import numpy as np def barrier_labels(high, low, close, atr, sl_mult, tp_mult, horizon, spread): """Faithful port of CExpertSignalAIBase::TripleBarrierLabel. Arrays are CHRONOLOGICAL (index 0 = oldest). Stop is tested before target on each side, so a bar spanning both barriers scores as the loss. Returns 0=Buy 1=Sell 2=Neutral, plus a timed-out mask (neither side resolved at all).""" n = len(close) lab = np.full(n, 2, dtype=np.int8) timed = np.zeros(n, dtype=bool) valid = np.zeros(n, dtype=bool) for j in range(n): a = atr[j] if not np.isfinite(a) or a <= 0: continue last = min(j + horizon, n - 1) if last <= j: continue e = close[j]; risk = sl_mult*a; rew = tp_mult*a lTp = e + spread + rew; lSl = e + spread - risk sTp = e - rew - spread; sSl = e + risk - spread lW=lL=sW=sL=False hs = high[j+1:last+1]; ls = low[j+1:last+1] for k in range(len(hs)): hi=hs[k]; lo=ls[k] if not (lW or lL): if lo <= lSl: lL=True elif hi >= lTp: lW=True if not (sW or sL): if hi >= sSl: sL=True elif lo <= sTp: sW=True if (lW or lL) and (sW or sL): break valid[j]=True if lW and not sW: lab[j]=0 elif sW and not lW: lab[j]=1 else: lab[j]=2 timed[j] = not (lW or lL or sW or sL) return lab, timed, valid