// Backtest: returns @ w → cumret, vol, MaxDD, Sharpe.
(function () {

  // Förbereder returns som en Float64Array per rad (snabbare lookups)
  Kv.prepareReturns = function (returnsRaw) {
    const T = returnsRaw.length;
    const N = returnsRaw[0].length;
    const arr = new Array(T);
    for (let t = 0; t < T; t++) {
      const row = new Float64Array(N);
      const src = returnsRaw[t];
      for (let i = 0; i < N; i++) row[i] = src[i];
      arr[t] = row;
    }
    return { arr, T, N };
  };

  // Beräknar daglig pnl, kumulativ avkastning och statistik.
  // costs: valfri array (årlig avgift per instrument, fraktion) som
  // dras av som en konstant daglig kostnad = Σ w_i · cost_i / 252.
  Kv.backtest = function (w, returnsPrep, costs) {
    const { arr, T, N } = returnsPrep;
    let dailyFee = 0;
    if (costs) {
      for (let i = 0; i < N; i++) dailyFee += w[i] * (costs[i] || 0);
      dailyFee /= 252;
    }
    const pnl = new Float64Array(T);
    for (let t = 0; t < T; t++) {
      const row = arr[t];
      let s = 0;
      for (let i = 0; i < N; i++) s += row[i] * w[i];
      pnl[t] = s - dailyFee;
    }

    const cum = new Float64Array(T);
    cum[0] = 1 + pnl[0];
    for (let t = 1; t < T; t++) cum[t] = cum[t - 1] * (1 + pnl[t]);

    let meanD = 0;
    for (let t = 0; t < T; t++) meanD += pnl[t];
    meanD /= T;
    let varD = 0;
    for (let t = 0; t < T; t++) { const d = pnl[t] - meanD; varD += d * d; }
    varD /= T;

    const annRet = Math.pow(cum[T - 1], 252 / T) - 1;
    const annVol = Math.sqrt(varD * 252);
    const sharpe = annVol > 1e-9 ? (annRet - 0.03) / annVol : 0;

    // Max drawdown
    let peak = cum[0], maxDD = 0;
    for (let t = 0; t < T; t++) {
      if (cum[t] > peak) peak = cum[t];
      const dd = cum[t] / peak - 1;
      if (dd < maxDD) maxDD = dd;
    }

    return { pnl, cum, annRet, annVol, sharpe, maxDD };
  };
})();
