如何正确计算 Fisher 变换指标

Posted

技术标签:

【中文标题】如何正确计算 Fisher 变换指标【英文标题】:How to correctly calculate Fisher Transform indicator 【发布时间】:2019-09-29 09:47:48 【问题描述】:

我正在编写一个小型技术分析库,其中包含 TA-lib 中不可用的项目。我从在 cTrader 找到的示例开始,并将其与 TradingView 版本中的代码进行匹配。

这是来自 TradingView 的 Pine 脚本代码:

len = input(9, minval=1, title="Length")

high_ = highest(hl2, len)
low_ = lowest(hl2, len)

round_(val) => val > .99 ? .999 : val < -.99 ? -.999 : val

value = 0.0
value := round_(.66 * ((hl2 - low_) / max(high_ - low_, .001) - .5) + .67 * nz(value[1]))

fish1 = 0.0
fish1 := .5 * log((1 + value) / max(1 - value, .001)) + .5 * nz(fish1[1])

fish2 = fish1[1]

这是我的尝试来实现该指标:

    public class FisherTransform : IndicatorBase
    
        public int Length = 9;

        public decimal[] Fish  get; set; 
        public decimal[] Trigger  get; set; 

        decimal _maxHigh;
        decimal _minLow;
 
        private decimal _value1;
        private decimal _lastValue1;

        public FisherTransform(IEnumerable<Candle> candles, int length) 
            : base(candles)
        
            Length = length;
            RequiredCount = Length;
            _lastValue1 = 1;
        

        protected override void Initialize()
        
            Fish = new decimal[Series.Length];
            Trigger = new decimal[Series.Length];
        

        public override void Compute(int startIndex = 0, int? endIndex = null)
        
            if (endIndex == null)
                endIndex = Series.Length;

            for (int index = 0; index < endIndex; index++)
            
                if (index == 1)
                
                    Fish[index - 1] = 1;
                
              
                _minLow = Series.Average.Lowest(Length, index);
                _maxHigh = Series.Average.Highest(Length, index);

                _value1 = Maths.Normalize(0.66m * ((Maths.Divide(Series.Average[index] - _minLow, Math.Max(_maxHigh - _minLow, 0.001m)) - 0.5m) + 0.67m * _lastValue1));

                _lastValue1 = _value1;

                Fish[index] = 0.5m * Maths.Log(Maths.Divide(1 + _value1, Math.Max(1 - _value1, .001m))) + 0.5m * Fish[index - 1];
                Trigger[index] = Fish[index - 1];
            
        
    

IndicatorBase class and CandleSeries class

Math Helpers

问题

输出值似乎在预期范围内,但是我的 Fisher 变换交叉与我在 TradingView 的指标版本中看到的匹配。

问题

如何在 C# 中正确实现 Fisher 变换指示器?我希望这与 TradingView 的 Fisher 变换输出相匹配。

我所知道的

我已经对照我个人编写的其他指标和来自 TA-Lib 的指标检查了我的数据,并且这些指标通过了我的单元测试。我还逐个对照 TradingView 数据检查了我的数据,发现我的数据符合预期。所以我不怀疑我的数据是问题所在。

细节

CSV Data - NFLX 5 min agg

下图是上面显示的应用于 TradingView 图表的 Fisher 变换代码。我的目标是尽可能地匹配这个输出。

Fisher 青色 触发器 洋红色

预期输出:

交叉在东部时间 15:30 完成

Fisher 值约为 2.86

大约触发值为 1.79

交叉在东部时间 10:45 完成

Fisher 值约为 -3.67

大约触发值为 -3.10

我的实际输出:

交叉在东部时间 15:30 完成

我的费雪值是 1.64

我的触发值为 1.99

交叉在东部时间 10:45 完成

我的费雪值是 -1.63

我的触发值是-2.00

赏金

为了让您的生活更轻松,我提供了一个小型控制台应用程序 完成通过和失败的单元测试。所有单元测试都是 针对相同的数据集进行。通过的单元测试来自 测试工作 简单移动平均线指标。失败的单位 测试针对有问题的 Fisher 变换 指标。

Project Files(5/14 更新)

帮助我通过 FisherTransform 测试,我将奖励奖金。

如果您需要任何其他资源或信息,请发表评论。

我会考虑的替代答案

在 C# 中提交您自己的工作 FisherTransform

解释为什么我的 FisherTransform 实际上按预期工作

【问题讨论】:

那么我们如何测试我们是否正确?我们如何知道它是否符合您的规范? 如果它与 TradingView 的输出相匹配,我们就是黄金。 @TheGeneral 我认为您需要更多地考虑这一点,TradingViews 的实现有可能是不正确的,而且我们没有可匹配的测试数据,只有一个答案并且您测试它失败了告诉我们这是行不通的。我的意思是这可能会永远持续下去 我同意@TheGeneral,我不止一次发现TradingView formulas did not make sense。他们的商业模式主要依赖于用户提供的、可能未经证实的公式。 为了比较,请随意检查我的开源 .NET 库中Ehlers Fisher Transform 的实现。我在 GitHub 存储库中包含手动计算以进行比较。 【参考方案1】:

代码有两个错误。

1) 额外的括号错误。正确的行是:

_value1 = Maths.Normalize(0.66m * (Maths.Divide(Series.Average[index] - _minLow, Math.Max(_maxHigh - _minLow, 0.001m)) - 0.5m) + 0.67m * _lastValue1);

2) 最小值和最大值函数必须是:

public static decimal Highest(this decimal[] series, int length, int index)

    var maxVal = series[index]; // <----- HERE WAS AN ERROR!

    var lookback = Math.Max(index - length, 0);

    for (int i = index; i-- > lookback;)
        maxVal = Math.Max(series[i], maxVal);

    return maxVal;


public static decimal Lowest(this decimal[] series, int length, int index)

    var minVal = series[index]; // <----- HERE WAS AN ERROR!

    var lookback = Math.Max(index - length, 0);

    for (int i = index; i-- > lookback;)
    
        //if (series[i] != 0) // <----- HERE WAS AN ERROR!
            minVal = Math.Min(series[i], minVal);
    

    return minVal;

3) 混淆测试参数。请重新检查您的单元测试值。更新测试后仍未修复。例如,第一个FisherTransforms_ValuesAreReasonablyClose_First() 具有混合值

var fish = result.Fish.Last(); //is equal to -3.1113144510775780365063063706
var trig = result.Trigger.Last(); //is equal to -3.6057793808025449204415435710

// TradingView Values for NFLX 5m chart at 10:45 ET
var fisherValue = -3.67m;
var triggerValue = -3.10m;

【讨论】:

我很快就会在这里试一试。单元测试值源自 OP 图像中圈出的 TradingView 指标。 FisherTransform 信号是基于交叉创建的。我的目标是让这些交叉点与我在 TradingView 上看到的相当接近,这应该是可能的,因为我们使用与 TradingView 相同的计算。 我不相信测试,因为在一行中有 Fish 和 Trigger 之间的比较。在另一个地方,鱼和扳机显然是在错误的地方。 我明白了。在那种情况下,我一定犯了一个错误。我将检查我的代码并重新上传项目。谢谢。 int startIndex 必须为 1,而不是 0。 Lowest() 和 Highest() 函数必须由 value[index] 正确初始化(不是 0 或 9999)。也许还有别的东西,但我坚持测试。 Unittests 中的另一个错误(我没有测试过)是时区。 CSV 有 +5 时区(我想是你的)。但是 unittest 代码提到了本地时区(new DateTime(2019, 05, 10, 10, 45, 00))。我的时区不是你的。

以上是关于如何正确计算 Fisher 变换指标的主要内容,如果未能解决你的问题,请参考以下文章

检测计算机是不是可以正确支持 3D 变换

如何计算 COLLADA 文件的父子联合变换?

fisher线性判别函数啥时候学

如何计算项目的难度与区分度

关系Fisher内核实现

R中,数据标准化方法