计算阿隆指标系列

Calculating Aroon Indicator Series

我正在尝试构建一个 class 来创建 Aroon 系列。但似乎我不太了解这些步骤。我不确定我必须使用 period 参数的目的。

这是我的第一次尝试:

/// <summary>
/// Aroon
/// </summary>
public class Aroon : IndicatorCalculatorBase
{
    public override List<Ohlc> OhlcList { get; set; }
    public int Period { get; set; }

    public Aroon(int period) 
    {
        this.Period = period;
    }

    /// <summary>
    /// Aroon up: {((number of periods) - (number of periods since highest high)) / (number of periods)} x 100
    /// Aroon down: {((number of periods) - (number of periods since lowest low)) / (number of periods)} x 100
    /// </summary>
    /// <see cref="http://www.investopedia.com/ask/answers/112814/what-aroon-indicator-formula-and-how-indicator-calculated.asp"/>
    /// <returns></returns>
    public override IIndicatorSerie Calculate()
    {
        AroonSerie aroonSerie = new AroonSerie();

        int indexToProcess = 0;

        while (indexToProcess < this.OhlcList.Count)
        {
            List<Ohlc> tempOhlc = this.OhlcList.Skip(indexToProcess).Take(Period).ToList();
            indexToProcess += tempOhlc.Count;

            for (int i = 0; i < tempOhlc.Count; i++)
            {   
                int highestHighIndex = 0, lowestLowIndex = 0;
                double highestHigh = tempOhlc.Min(x => x.High), lowestLow = tempOhlc.Max(x => x.Low);
                for (int j = 0; j < i; j++)
                {
                    if (tempOhlc[j].High > highestHigh)
                    {
                        highestHighIndex = j;
                        highestHigh = tempOhlc[j].High;
                    }

                    if (tempOhlc[j].Low < lowestLow)
                    {
                        lowestLowIndex = j;
                        lowestLow = tempOhlc[j].Low;
                    }
                }

                int up = ((this.Period - (i - highestHighIndex)) / this.Period) * 100;
                aroonSerie.Up.Add(up);

                int down = ((this.Period - (i - lowestLowIndex)) / this.Period) * 100;
                aroonSerie.Down.Add(down);
            }
        }

        return aroonSerie;
   }
}

之前有没有人试过这样做?

这是我使用的 csv 文件:

https://drive.google.com/file/d/0Bwv_-8Q17wGaRDVCa2FhMWlyRUk/view

但是Aroon up和down的结果集与R的TTR包中的aroon函数的结果不匹配

table <- read.csv("table.csv", header = TRUE, sep = ",")
trend <- aroon(table[,c("High", "Low")], n=5)
View(trend)

R结果截图:

提前致谢,

只需从您的代码中添加方法 HighestBarNum 和 LowestBarnum 的实现

 public class Aroon 
{  
    public bool AroonDown
    {
        get;
        set;
    }
    public double Period
    {
        get;
        set;
    }
    public Aroon()
    {
    }
    public IList<double> Execute(IList<double> src)
    {
        if (!this.AroonDown)
        {
            return this.ExecuteUp(src);
        }
        return this.ExecuteDown(src);
    }
    public IList<double> ExecuteDown(IList<double> src)
    {
        double[] period = new double[src.Count];
        for (int i = 1; i < src.Count; i++)
        {
            double num = LowestBarNum(src, i, Period);
            period[i] = 100 * (Period - num) / Period;
        }
        return period;
    }
    public IList<double> ExecuteUp(IList<double> src)
    {
        double[] period = new double[src.Count];
        for (int i = 1; i < src.Count; i++)
        {
            double num = HighestBarNum(src, i, Period);
            period[i] = 100 * ((Period - num) / Period;
        }
        return period;
    }}

@anilca, 为了全面披露,我学到了很多东西来回答你的问题(我对 Finetec 一无所知......)。谢谢!这是一次有趣的经历!

你的实现有几个问题:

  1. 在语句中:

i - highestHighIndex

i - lowestLowIndex

变量"i"小于或等于highestHighIndex、lowestLowIndex 所以声明:

this.Period - (i - highestHighIndex)

this.Period - (i - lowestLowIndex)

会 returns 错误的值(大多数时候...)

  1. Aroon up和down都是百分比,所以"int"是错误的数据结构

  2. 因为所有变量在:

(this.Period - (i - highestHighIndex)) / this.Period)

((this.Period - (i - lowestLowIndex)) / this.Period)

是整数,您不会收到正确的值。

  1. 还有一件事,你 excel 中的数字是从最新到最旧排序的。(它影响 R 包)

我已经根据你的代码(和你的数据顺序...)实现了算法

public class Aroon : IndicatorCalculatorBase
{

    public override List<OhlcSample> OhlcList { get; set; }
    private readonly int _period;

    public int Period
    {
        get { return _period; }
    }

    public Aroon(int period)
    {
        _period = period;
    }

    public override IIndicatorSerie Calculate()
    {
        var aroonSerie = new AroonSerie();
        for (var i = _period; i < OhlcList.Count; i++)
        {

            var aroonUp = CalculateAroonUp(i);
            var aroonDown = CalculateAroonDown(i);

            aroonSerie.Down.Add(aroonDown);
            aroonSerie.Up.Add(aroonUp);
        }

        return aroonSerie;
    }

    private double CalculateAroonUp(int i)
    {
        var maxIndex = FindMax(i - _period, i);

        var up = CalcAroon(i - maxIndex);

        return up;
    }

    private double CalculateAroonDown(int i)
    {
        var minIndex = FindMin(i - _period, i);

        var down = CalcAroon(i - minIndex);

        return down;
    }

    private double CalcAroon(int numOfDays)
    {
        var result = ((_period - numOfDays)) * ((double)100 / _period);
        return result;
    }

    private int FindMin(int startIndex, int endIndex)
    {
        var min = double.MaxValue;
        var index = startIndex;
        for (var i = startIndex; i <= endIndex; i++)
        {
            if (min < OhlcList[i].Low)
                continue;

            min = OhlcList[i].Low;
            index = i;
        }
        return index;
    }

    private int FindMax(int startIndex, int endIndex)
    {
        var max = double.MinValue;
        var index = startIndex;
        for (var i = startIndex; i <= endIndex; i++)
        {
            if (max > OhlcList[i].High)
                continue;

            max = OhlcList[i].High;
            index = i;
        }
        return index;
    }
}

public abstract class IndicatorCalculatorBase
{
    public abstract List<OhlcSample> OhlcList { get; set; }

    public abstract IIndicatorSerie Calculate();
}

public interface IIndicatorSerie
{
    List<double> Up { get; }
    List<double> Down { get; }
}

internal class AroonSerie : IIndicatorSerie
{
    public List<double> Up { get; private set; }
    public List<double> Down { get; private set; }

    public AroonSerie()
    {
        Up = new List<double>();
        Down = new List<double>();
    }


}

public class OhlcSample
{

    public double High { get; private set; }
    public double Low { get; private set; }

    public OhlcSample(double high, double low)
    {
        High = high;
        Low = low;
    }

}

使用此测试方法进行调试:

    private Aroon _target;

    [TestInitialize]
    public void TestInit()
    {
        _target=new Aroon(5)
        {
            OhlcList = new List<OhlcSample>
            {
                new OhlcSample(166.90, 163.65),
                new OhlcSample(165.00, 163.12),
                new OhlcSample(165.91, 163.21),
                new OhlcSample(167.29, 165.11),
                new OhlcSample(169.99, 166.84),
                new OhlcSample(170.92, 167.90),
                new OhlcSample(168.47, 165.90),
                new OhlcSample(167.75, 165.75),
                new OhlcSample(166.14, 161.89),
                new OhlcSample(164.77, 161.44),
                new OhlcSample(163.19, 161.49),
                new OhlcSample(162.50, 160.95),
                new OhlcSample(163.25, 158.84),
                new OhlcSample(159.20, 157.00),
                new OhlcSample(159.33, 156.14),
                new OhlcSample(160.00, 157.00),
                new OhlcSample(159.35, 158.07),
                new OhlcSample(160.70, 158.55),
                new OhlcSample(160.90, 157.66),
                new OhlcSample(164.38, 158.45),
                new OhlcSample(167.75, 165.70),
                new OhlcSample(168.93, 165.60),
                new OhlcSample(165.73, 164.00),
                new OhlcSample(167.00, 164.66),
                new OhlcSample(169.35, 165.01),
                new OhlcSample(168.12, 164.65),
                new OhlcSample(168.89, 165.79),
                new OhlcSample(168.65, 165.57),
                new OhlcSample(170.85, 166.00),
                new OhlcSample(171.61, 169.10)
            }
        };
    }


    [TestMethod]
    public void JustToHelpYou()
    {
        var result = _target.Calculate();

        var expectedUp = new List<double>()
        {
            100,80,60,40,20,0,0,0, 0,0,40,20,0,100,100,100,100,80, 60,100,80,60,40,100,100
        };

        var expectedDown = new List<double>
        {
            20,0,0,100,100,80,100,100,100,100,80,60,40,20,0,0,40,20,0,0,40,20,0,40,20
        };

        Assert.IsTrue( result.Up.SequenceEqual(expectedUp));
        Assert.IsTrue( result.Down.SequenceEqual(expectedDown));

    }
class AroonData
{
    public double AroonUp;

    public double AroonDown;
}

计算Class:

class AroonCalculationData
{
    public double PeriodHigh;

    public double PeriodLow;

    public double SetAroonUp(List<MarketData> period, double lastHigh)
    {

        /*reverse the set so we can look at it from the current tick
        on back, and ticksSinceHigh will set correctly*/
        period.Reverse();

        int ticksSinceHigh = 0;
        double high = 0.0;//Set 0 so anything will be higher

        for (int i = 0; i < period.Count; i++)
        {
            if (period[i].high > high)
            {
                high = period[i].high;
                ticksSinceHigh = i;
            }
        }

        /*This bit if for if the high just ticked out
        of List<MarketData>.
        Including the current tick (i = 0), List<MarketData> period
        only looks back (period - 1) days. 
        This Checks to see if the last high is still in the set. if it's 
        not, and is still the high for the period, then ticksSinceHigh
        is set to (period)*/
        PeriodHigh = high;
        if (PeriodHigh < lastHigh)
        {
            ticksSinceHigh = period.Count;
        }

        /*Aroon-Up Formula*/
        return (double)(period.Count - ticksSinceHigh ) / (double)period.Count * 100.0;
    }

    //ASIDE FROM LOOKING FOR LOWS INSTEAD OF HIGHS, SAME AS AROON-UP
    public double SetAroonDown(List<MarketData> period, double lastLow)
    {

        period.Reverse();

        int daysSinceLow = 0;
        double low = double.MaxValue;//Set max so anything will be lower

        for (int i = 0; i < period.Count; i++)
        {
            if (period[i].low < low)
            {
                low = period[i].low;
                daysSinceLow = i;
            }
        }

        PeriodLow = low;
        if (PeriodLow > lastLow)
        {
            daysSinceLow = period.Count;
        }

        return (double)(period.Count - daysSinceLow) / (double)period.Count * 100.0;
    }
}

调用代码:

public AroonData[] Aroon(List<MarketData> marketData, int period)
{
    AroonCalculationData[] calculationData = new AroonCalculationData[marketData.Count]
    AroonData[] aroon= new AroonData[marketData.Count]

    for (int i = period; i < marketData.Count; i++)
    {
        /*GetRange(i - period + 1, period) add 1 so that the current tick is 
        included in look back.
        For example, if (period = 10) the first loop (i = 10) then (i - 
        period + 1) = 1 the set will be marketData 1 - 10.*/

        /*calculationData[i - 1].PeriodHigh and calculationData[i - 1].PeriodLow
        are for looking back at the last tick's look back period high and 
        low*/

        data[i].AroonUp = calculationData[i].SetAroonUp(marketData.GetRange(i - period + 1, period), calculationData[i - 1].PeriodHigh);
        data[i].AroonDown = calculationData[i].SetAroonDown(marketData.GetRange(i - period + 1, period), calculationData[i - 1].PeriodLow);
    }
}

旁注: 我遇到的一个问题是将我的数据与 TD Ameritrades Aroon 进行比较,直到我发现它们的周期实际上是周期 1,所以如果您要与 TD 进行比较,请记住这一点。