斯威夫特的相对强弱指数

时间:2018-02-05 14:27:59

标签: swift algorithm finance technical-indicator

我正在尝试编写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

今天下午3:23的读数为我的算法提供了73.93,在交换时提供了18.74。由于市场正在崩溃,我可以在不同的交易所访问不同的RSI,它们都显示低于20的RSI,因此我的计算结束了。

你们有什么想法吗?

1 个答案:

答案 0 :(得分:0)

两年后我会回答,但希望它能对某人有所帮助。

您输入的数据点越多,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方程即可。