Загрузка данных


from pathlib import Path
import re

path = Path("/content/AIQuant/aiquant/models/ensemble_pipeline.py")
text = path.read_text()

start = text.index("def _evaluate_threshold(")

# Ищем конец функции — следующую строку, начинающуюся не пробелом
m = re.search(r"\n(?=[^\s#].*)", text[start + 1:])
if not m:
    raise RuntimeError("Не удалось определить конец функции")

end = start + 1 + m.start()

new_func = '''def _evaluate_threshold(lt, st, idx):
    """Evaluate thresholds only on the supplied validation/test indices."""
    if idx is None or len(idx) == 0:
        return None

    idx = np.asarray(idx)
    scores = ens_score[idx]
    prices = c[idx]

    sig = np.zeros(len(idx), dtype=np.int8)
    sig[scores > lt] = 1
    sig[scores < -st] = -1

    changes = np.where(np.diff(sig, prepend=0) != 0)[0]

    if len(changes) < 20:
        return None

    equity = np.full(len(idx), INITIAL_CAPITAL, dtype=np.float64)

    position = 0
    entry_price = 0.0
    capital = INITIAL_CAPITAL
    trade_pnls = []

    for i in range(len(idx)):
        price = prices[i]
        new_position = int(sig[i])

        if new_position != position:
            if position != 0:
                pnl = position * (price - entry_price) / entry_price
                pnl -= FEE
                capital *= (1.0 + pnl)
                trade_pnls.append(pnl)

            if new_position != 0:
                capital *= (1.0 - FEE)
                entry_price = price

            position = new_position

        equity[i] = capital

    if position != 0:
        pnl = position * (prices[-1] - entry_price) / entry_price
        pnl -= FEE
        capital *= (1.0 + pnl)
        equity[-1] = capital

    total_return = capital / INITIAL_CAPITAL - 1.0

    returns = np.diff(equity) / np.maximum(equity[:-1], 1e-12)

    if len(returns) > 1 and np.std(returns) > 0:
        sharpe = np.mean(returns) / np.std(returns) * np.sqrt(1440 * 365)
    else:
        sharpe = 0.0

    running_max = np.maximum.accumulate(equity)
    drawdown = equity / np.maximum(running_max, 1e-12) - 1.0
    max_dd = float(np.min(drawdown))

    n_trades = len(trade_pnls)

    if n_trades > 0:
        wins = [x for x in trade_pnls if x > 0]
        losses = [x for x in trade_pnls if x < 0]

        win_rate = len(wins) / n_trades

        gross_profit = sum(wins)
        gross_loss = abs(sum(losses))

        profit_factor = (
            gross_profit / gross_loss
            if gross_loss > 0
            else np.inf
        )
    else:
        win_rate = 0.0
        profit_factor = 0.0

    n_days = max(len(idx) / 1440.0, 1.0)

    annual_return = (1.0 + total_return) ** (365.0 / n_days) - 1.0

    calmar = (
        annual_return / abs(max_dd)
        if max_dd < 0
        else 0.0
    )

    return {
        "return": total_return,
        "sharpe": sharpe,
        "calmar": calmar,
        "max_dd": max_dd,
        "profit_factor": profit_factor,
        "win_rate": win_rate,
        "n_trades": n_trades,
        "long_thresh": lt,
        "short_thresh": st,
    }
'''

text = text[:start] + new_func + text[end:]

path.write_text(text)

print("✅ _evaluate_threshold заменена")