I'm trying to build a class to create Aroon series. But it seems I don't understand the steps well. I'm not sure about for what purpose I have to use the period parameter.
Here is my first attempt:
/// <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;
}
}
Is there anyone else tried to do that before?
Here is the csv file I use:
https://drive.google.com/file/d/0Bwv_-8Q17wGaRDVCa2FhMWlyRUk/view
But the result sets for Aroon up and down don't match with the results of aroon function in TTR package for R.
table <- read.csv("table.csv", header = TRUE, sep = ",")
trend <- aroon(table[,c("High", "Low")], n=5)
View(trend)
Screenshot of R result:
Thanks in advance,
@anilca, for full Disclosure, I learned alot of things to answer your question(i knew nothing in the Finetec...). Thank you! it was an interesting experience!
There are several problems in your implementation:
i - highestHighIndex
and
i - lowestLowIndex
the variable "i" is less or equal to highestHighIndex, lowestLowIndex so statements:
this.Period - (i - highestHighIndex)
and
this.Period - (i - lowestLowIndex)
will returns the wrong values (most of the time...)
Aroon up and down both of them are percentage, therefore "int" is a wrong data structure.
Because all variables in:
(this.Period - (i - highestHighIndex)) / this.Period)
and
((this.Period - (i - lowestLowIndex)) / this.Period)
are integers you won't recieve the right value.
I've implemented the algorithm based on your code(and your data order...)
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;
}
}
Use this test method for debugging:
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));
}