Индекс относительной силы в Swift

Я пытаюсь закодировать RSI (для меня это был хороший способ изучить выборку данных API и алгоритмы).

API, из которого я получаю данные, получен из авторитетного обмена, поэтому я знаю, что значения, которые анализирует мой алгоритм, верны, и это хорошее начало.

У меня проблема в том, что результат моих расчетов полностью отличается от того, что я могу прочитать на этом конкретном обмене и который также предоставляет индикатор RSI (я предполагаю, что они анализируют свои собственные данные, поэтому те же данные, что и у меня).

Я использовал точно такой же API для перевода индикатора Ichimoku в код, и на этот раз все правильно! Я считаю, что мои расчеты RSI могут быть неверными, но я проверял и перепроверял много раз.

У меня также есть "буквальная" версия кода, где каждый шаг вычисляется как таблица Excel. Это довольно глупо в коде, но оно проверяет логику вычислений, и результаты такие же, как в следующем коде.

Вот мой код для расчета RSI:

    let period = 14

    // Upward Movements and Downward Movements
    var upwardMovements : [Double] = []
    var downwardMovements : [Double] = []

    for idx in 0..<15 {
        let diff = items[idx + 1].close - items[idx].close
        upwardMovements.append(max(diff, 0))
        downwardMovements.append(max(-diff, 0))
    }

    // Average Upward Movements and Average Downward Movements
    let averageUpwardMovement1 = upwardMovements[0..<period].reduce(0, +) / Double(period)
    let averageDownwardMovement1 = downwardMovements[0..<period].reduce(0, +) / Double(period)

    let averageUpwardMovement2 = (averageUpwardMovement1 * Double(period - 1) + upwardMovements[period]) / Double(period)
    let averageDownwardMovement2 = (averageDownwardMovement1 * Double(period - 1) + downwardMovements[period]) / Double(period)

    // Relative Strength
    let relativeStrength1 = averageUpwardMovement1 / averageDownwardMovement1
    let relativeStrength2 = averageUpwardMovement2 / averageDownwardMovement2

    // Relative Strength Index
    let rSI1 = 100 - (100 / (relativeStrength1 + 1))
    let rSI2 = 100 - (100 / (relativeStrength2 + 1))

    // Relative Strength Index Average
    let relativeStrengthAverage = (rSI1 + rSI2) / 2

    BitcoinRelativeStrengthIndex.bitcoinRSI = relativeStrengthAverage

Чтения в 15:23 сегодня днем ​​дают 73.93 для моего алгоритма и 18.74 на обмен. Поскольку рынки сейчас терпят крах, и у меня есть доступ к различным RSI на разных биржах, все они показывают RSI ниже 20 так что мои расчеты выключены.

Ребята, у вас есть идеи?

0 ответов

Я отвечаю на это 2 года спустя, но, надеюсь, это кому-то поможет.

RSI становится тем точнее, чем больше точек данных вы вводите в него. Для периода RSI по умолчанию, равного 14, у вас должно быть не менее 200 предыдущих точек данных. Чем больше, тем лучше!

Предположим, у вас есть массив цен на закрытые свечи для данного рынка. Следующая функция вернет значения RSI для каждой свечи. Вы всегда должны игнорировать первые точки данных, так как они недостаточно точны или количество свечей не равно 14 (или какому-либо вашему periods номер есть).

func computeRSI(on prices: [Double], periods: Int = 14, minimumPoints: Int = 200) -> [Double] {
    precondition(periods > 1 && minimumPoints > periods && prices.count >= minimumPoints)

    return Array(unsafeUninitializedCapacity: prices.count) { (buffer, count) in
        buffer.initialize(repeating: 50)
        
        var (previousPrice, gain, loss) = (prices[0], 0.0, 0.0)
        for p in stride(from: 1, through: periods, by: 1) {
            let price = prices[p]

            let value = price - previousPrice
            if value > 0 {
                gain += value
            } else {
                loss -= value
            }

            previousPrice = price
        }

        let (numPeriods, numPeriodsMinusOne) = (Double(periods), Double(periods &- 1))
        var avg = (gain: gain / numPeriods, loss: loss /numPeriods)
        buffer[periods] = (avg.loss > .zero) ? 100 - 100 / (1 + avg.gain/avg.loss) : 100

        for p in stride(from: periods &+ 1, to: prices.count, by: 1) {
            let price = prices[p]
            avg.gain *= numPeriodsMinusOne
            avg.loss *= numPeriodsMinusOne

            let value = price - previousPrice
            if value > 0 {
                avg.gain += value
            } else {
                avg.loss -= value
            }

            avg.gain /= numPeriods
            avg.loss /= numPeriods

            if avgLoss > .zero {
                buffer[p] = 100 - 100 / (1 + avg.gain/avg.loss)
            } else {
                buffer[p] = 100
            }
            
            previousPrice = price
        }

        count = prices.count
    }
}

Обратите внимание, что код очень важен, чтобы уменьшить количество операций / циклов и получить максимальную оптимизацию компилятора. Однако, возможно, вы сможете добиться большей производительности, используя платформу Accelerate. Мы также работаем с крайним случаем, когда вы можете получить все прибыли или убытки за определенный период.

Если вы хотите иметь текущий расчет RSI. Просто сохраните последнее значение RSI и выполните уравнение RSI для новой цены.

Другие вопросы по тегам