// 计算移动平均线MA的函数，接收收盘价格数组和计算所需的天数作为参数
export function calculateMA (closingPrices, dayCount) {
  // 检查数据点的数量是否足够计算移动平均线
  if (closingPrices.length < dayCount) {
    return null // 数据不足，返回null
  }

  let result = []
  // 从第dayCount个数据点开始计算（因为前dayCount-1个数据点不足以计算一个完整的移动平均线）
  for (let i = 0; i <= closingPrices.length - dayCount; i++) {
    let sum = 0
    // 计算当前窗口内所有价格的总和
    for (let j = 0; j < dayCount; j++) {
      sum += closingPrices[i + j]
    }
    // 计算并添加移动平均线值到结果数组
    result.push(sum / dayCount)
  }
  result = result.map(item => parseFloat(item.toFixed(2)))
  return result // 返回计算出的移动平均线值数组
}

// 计算标准差的函数
export function calculateStdDeviation (prices) {
  if (prices.length === 0) {
    throw new Error("价格数组不能为空")
  }
  // 计算平均值
  const mean = prices.reduce((sum, price) => sum + price, 0) / prices.length

  // 计算每个价格与平均值的差的平方和
  const varianceSum = prices.reduce((sum, price) => sum + Math.pow(price - mean, 2), 0)

  // 计算方差（样本方差使用N-1作为分母）
  const variance = varianceSum / (prices.length - 1)

  // 计算标准差（方差的平方根）,取两位小数
  const stDeviation = parseFloat(Math.sqrt(variance).toFixed(2))

  return stDeviation
}


export function calculateEMA (prices, period) {
  let ema = []
  let multiplier = 2 / (period + 1)
  let previousEMA = prices.reduce((sum, price) => sum + price, 0) / period // 初始EMA为前period天的收盘价平均值

  ema.push(previousEMA) // 添加第一个EMA值

  for (let i = period; i < prices.length; i++) {
    let currentEMA = (prices[i] - previousEMA) * multiplier + previousEMA
    ema.push(currentEMA)
    previousEMA = currentEMA
  }

  // 我们只关心最后一个EMA值（即最新周期的EMA），但这里返回整个EMA数组以便调试
  return ema
}


// 计算DIF的函数，但dif数组长度将受限于价格数组和EMA计算所需的最小长度
export function calculateDIF (prices, shortPeriod, longPeriod) {
  // 确保价格数组足够长以计算所需的EMA
  if (prices.length < longPeriod + 1) {
    return [] // 或抛出错误
  }

  // 计算整个价格数组的EMA，但通常只关注最近的EMA值
  let shortEMA = calculateEMA(prices, shortPeriod)
  let longEMA = calculateEMA(prices, longPeriod)

  // DIF数组，从两个EMA数组都有值的起始位置开始计算
  let dif = []
  let startIndex = Math.max(shortEMA.length - 1, longEMA.length - 1) - (longPeriod - 1) // 找到两个EMA都能计算的起始索引（可能需要根据实际情况调整）
  // 注意：这里的startIndex计算可能需要根据实际需求进行调整，因为它依赖于EMA数组的实际可用长度和所需的计算周期。
  // 下面的循环确保了只有当两个EMA数组在相同索引处都有值时，才计算DIF。
  for (let i = startIndex; i < Math.min(shortEMA.length, longEMA.length); i++) {
    dif.push(shortEMA[i] - longEMA[i])
  }

  // 如果需要，可以在dif数组前面填充null或0，以使其长度与prices相同（但这在金融分析上可能没有意义）
  // while (dif.length < prices.length) {
  //   dif.unshift(null); // 或0，或其他适当的填充值
  // }

  return dif // 返回DIF数组，其长度可能小于prices数组
}
// 计算DEA的函数
export function calculateDEA (dif, deaPeriod) {
  // DEA就是DIF的EMA，所以直接使用calculateEMA函数计算DIF数组的EMA
  return calculateEMA(dif, deaPeriod)
}

// MACD指标的计算函数
export function calculateMACD (
  prices,
  shortPeriod = 12,
  longPeriod = 26,
  deaPeriod = 9
) {
  function calculateEMA (prices, period) {
    let ema = []
    let multiplier = 2 / (period + 1)
    let sum = 0
    for (let i = 0; i < period; i++) {
      sum += prices[i]
    }
    let previousEMA = sum / period
    ema.push(previousEMA)
    for (let i = period; i < prices.length; i++) {
      let currentEMA = (prices[i] - previousEMA) * multiplier + previousEMA
      ema.push(currentEMA)
      previousEMA = currentEMA
    }
    return ema
  }

  let shortEMA = calculateEMA(prices, shortPeriod)
  let longEMA = calculateEMA(prices, longPeriod)
  let dif = []
  for (let i = 0; i < Math.min(shortEMA.length, longEMA.length); i++) {
    dif.push(shortEMA[i] - longEMA[i])
  }
  let dea = calculateEMA(dif, deaPeriod)
  let macd = []
  for (let i = 0; i < Math.min(dif.length, dea.length); i++) {
    macd.push((dif[i] - dea[i]) * 2)
  }
  // 将dif, dea, macd中的值保留两位小数     
  dif = dif.map((item) => parseFloat(item.toFixed(2)))
  dea = dea.map((item) => parseFloat(item.toFixed(2)))
  macd = macd.map((item) => parseFloat(item.toFixed(2)))
  return {
    dif,
    dea,
    macd
  }
}




// ----------------------------计算KDJ指标的函数----------------------------
// 数据整理
export function changeShape (res) {
  // 获取对象的键（这里我们知道键是 'date', 'low', 'high', 'close'，但为了通用性，我们还是获取所有键）
  const keys = Object.keys(res)

  // 初始化一个空数组来存储结果
  let result = []

  // 假设所有对象的属性（date, low, high, close）都有相同的索引范围
  // 这里我们取第一个对象的键集合来确定索引范围（假设它们都有0和1这两个键）
  const indexRange = Object.keys(res.date) // 或者使用任何其他对象的键集合，因为它们应该有相同的索引

  // 遍历索引范围
  for (let index of indexRange) {
    // 将索引转换为数字类型，以便进行数学运算（虽然在这个例子中它们已经是数字字符串）
    const numIndex = parseInt(index, 10)

    // 收集对应索引的值到一个子数组中
    const row = [
      res.date[numIndex],
      res.low[numIndex],
      res.high[numIndex],
      res.close[numIndex]
    ]

    // 将子数组添加到结果数组中
    result.push(row)
  }
  return result
}
// 计算函数
export function calculateKDJ (prices) {

  prices = changeShape(prices)
  let lows = []
  let highs = []
  let closes = []
  // 提取最低价、最高价、收盘价数组
  prices.forEach((price) => {
    lows.push(price[1])
    highs.push(price[2])
    closes.push(price[3])
  })
  let kValues = []
  let dValues = []
  let jValues = []
  let period = 9 // 默认的计算周期，可以根据实际情况调整
  for (let i = 0; i < closes.length; i++) {
    if (i < period - 1) {
      kValues.push(10)
      dValues.push(10)
      jValues.push(10)
      continue
    }
    // 计算RSV值（未成熟随机值）
    let lowPeriod = Math.min(...lows.slice(i - period + 1, i + 1))
    let highPeriod = Math.max(...highs.slice(i - period + 1, i + 1))
    let rsv = ((closes[i] - lowPeriod) / (highPeriod - lowPeriod)) * 100
    if (i === period - 1) {
      kValues.push(rsv)
      dValues.push(rsv)
    } else {
      // 计算K值，一般采用加权移动平均的方式，这里简化为前一日K值的2/3加上今日RSV的1/3
      let k = (2 / 3) * kValues[i - 1] + (1 / 3) * rsv
      kValues.push(k)
      // 计算D值，一般是前一日D值的2/3加上今日K值的1/3
      let d = (2 / 3) * dValues[i - 1] + (1 / 3) * k
      dValues.push(d)
    }
    // 计算J值，一般公式为3*K - 2*D
    let j = 3 * kValues[i] - 2 * dValues[i]
    jValues.push(j)
  }
  kValues = kValues.map(item => parseFloat(item.toFixed(2)))
  dValues = dValues.map(item => parseFloat(item.toFixed(2)))
  jValues = jValues.map(item => parseFloat(item.toFixed(2)))
  return {
    kValues,
    dValues,
    jValues
  }
}
// -------------------------------------------------------------------

// ----------------------------计算RSI指标的函数----------------------------
// RSI 的时间跨度推荐 6、12、24 三个值，6 日近似一周的时间周期，12 日可以看作半个月的时间跨度，而 24 日约为一个月的时间跨度。
// 短期 RSI 对于价格的变化情况反应比较灵敏，RSI 的值波动较大;长期 RSI 值反应相对迟钝，其波动相对较小。
export function calculateRSI (closePrices, period = 6) {
  let gains = []
  let losses = []
  let rsi = []

  for (let i = 0; i < closePrices.length; i++) {
    if (i === 0) {
      gains.push(0)
      losses.push(0)
    } else {
      let diff = closePrices[i] - closePrices[i - 1]
      if (diff > 0) {
        gains.push(diff)
        losses.push(0)
      } else {
        gains.push(0)
        losses.push(Math.abs(diff))
      }
    }

    if (i >= period - 1) {
      let sumGain = 0
      let sumLoss = 0
      for (let j = i - (period - 1); j <= i; j++) {
        sumGain += gains[j]
        sumLoss += losses[j]
      }

      let avgGain = sumGain / period
      let avgLoss = sumLoss / period
      let rs = avgGain / avgLoss
      rsi.push(100 - (100 / (1 + rs)))
    }
  }
  rsi = rsi.map(item => parseFloat(item.toFixed(2)))
  return rsi
}

// ----------------------------计算VOL指标的函数----------------------------

export function calculateVOL (close, high, low) {
  let arr = []
  let volvalues = Object.values(close)
  let highvalues = Object.values(high)
  let lowvalues = Object.values(low)
  
  for (let i = 0; i < volvalues.length; i++) {
    let change = (highvalues[i] + lowvalues[i]) / 2
    arr.push({
      value: volvalues[i],
      itemStyle: {
        color: volvalues[i] >= change ? '#FF0000' : '#00FF00'  // 根据值的正负设置颜色
      }
    })
  }

  return arr
}




