А вот еще код Ишимоку из не менее извесного софта:
Click to reveal..

using System;
using System.Collections.Generic;
using System.ComponentModel;
using OEC.UI;
using OEC.Chart;
using OEC.Chart.Indicators;
using OEC.Chart.Details;
using OEC.Chart.BaseSeries;
using OEC.Chart.Custom.Import;
using System.Runtime.InteropServices;
using System.Drawing.Drawing2D;
using System.Drawing;

namespace OEC.Chart.Custom.Sandbox
{

enum IchimokuSeries { TenkanSen = 0, KijunSen = 1, SenkouSpanA = 2, SenkouSpanB = 3, ChinkouSpan = 4 }

[TimeSeries("Ichimoku Kinko Hyo", "Ichimoku", "Samples", AreaScale.Any, SourceScale = AreaScale.Price)]
public sealed class IchimokuKinkoHyoIndicator : OEC.Chart.Custom.CustomIndicator
{
HighestLowest highest_1 = new HighestLowest(HighestLowest.CompareMode.Highest);
HighestLowest lowest_1 = new HighestLowest(HighestLowest.CompareMode.Lowest);
HighestLowest highest_2 = new HighestLowest(HighestLowest.CompareMode.Highest);
HighestLowest lowest_2 = new HighestLowest(HighestLowest.CompareMode.Lowest);
HighestLowest highest_3 = new HighestLowest(HighestLowest.CompareMode.Highest);
HighestLowest lowest_3 = new HighestLowest(HighestLowest.CompareMode.Lowest);

protected override void Initialize()
{
base.Initialize();
UpdateOffset();
}

void UpdateOffset()
{
SubSeries[(int)IchimokuSeries.SenkouSpanA].Offset = SecondPeriod;
SubSeries[(int)IchimokuSeries.SenkouSpanB].Offset = SecondPeriod;
SubSeries[(int)IchimokuSeries.ChinkouSpan].Offset = -SecondPeriod;
OnChanged(DataChangedMode.Insert);
}

public override void Recalculate(RecalculateArg arg)
{
if (arg.End < SecondPeriod)
return;

highest_1.Start(0, FirstPeriod);
lowest_1.Start(0, FirstPeriod);
highest_2.Start(0, SecondPeriod);
lowest_2.Start(0, SecondPeriod);
highest_3.Start(0, ThirdPeriod);
lowest_3.Start(0, ThirdPeriod);

for (int i = 0; i < arg.End; ++i)
{
double high = arg.High[i, 0];
double low = arg.Low[i, 0];
double close = arg.Input[i, 0];

highest_1.Add(i, high);
highest_2.Add(i, high);
highest_3.Add(i, high);
lowest_1.Add(i, low);
lowest_2.Add(i, low);
lowest_3.Add(i, low);

double TenkanSen = (lowest_1.Result + highest_1.Result) / 2;
double KijunSen = (lowest_2.Result + highest_2.Result) / 2;
double SenkouSpanA = (TenkanSen + KijunSen) / 2;
double SenkouSpanB = (lowest_3.Result + highest_3.Result) / 2;
double ChinkouSpan = close;

if (i >= FirstPeriod)
arg.RArray[i, (int)IchimokuSeries.TenkanSen] = TenkanSen;

if (i >= SecondPeriod)
arg.RArray[i, (int)IchimokuSeries.KijunSen] = KijunSen;

if (i >= ThirdPeriod)
{
arg.RArray[i, (int)IchimokuSeries.SenkouSpanA] = SenkouSpanA;
arg.RArray[i, (int)IchimokuSeries.SenkouSpanB] = SenkouSpanB;
}

if (i >= SecondPeriod)
arg.RArray[i, (int)IchimokuSeries.ChinkouSpan] = ChinkouSpan;
}
}

[Browsable(true), Description("First Period, Tenkan-sen"), DisplayName("First, Tenkan-sen"), Category("Periods"), XmlSerializable]
public int FirstPeriod
{
get
{
return _FirstPeriod;
}
set
{
if (_FirstPeriod != value && value > 0)
{
_FirstPeriod = value;
OnChanged(DataChangedMode.Insert);
}
}
}
int _FirstPeriod = 9;

[Browsable(true), Description("Second Period, Kijun-sen"), DisplayName("Second, Kijun-sen"), Category("Periods"), XmlSerializable]
public int SecondPeriod
{
get
{
return _SecondPeriod;
}
set
{
if (_SecondPeriod != value && value > 0)
{
_SecondPeriod = value;
UpdateOffset();
}
}
}
int _SecondPeriod = 26;

[Browsable(true), Description("Third Period, Senkou Span B"), DisplayName("Third, Senkou Span B"), Category("Periods"), XmlSerializable]
public int ThirdPeriod
{
get
{
return _ThirdPeriod;
}
set
{
if (_ThirdPeriod != value && value > 0)
{
_ThirdPeriod = value;
OnChanged(DataChangedMode.Insert);
}
}
}
int _ThirdPeriod = 52;

protected override DataSeries[] DefaultSubseries
{
get
{
CustomDrawDataSeries a = new CustomDrawDataSeries(this, "Senkou Span A", new ChartStyle(SeriesChartType.Area, System.Drawing.Color.SandyBrown, 1, DashStyle.Dash));
CustomDrawDataSeries b = new CustomDrawDataSeries(this, "Senkou Span B", new ChartStyle(SeriesChartType.Area, System.Drawing.Color.Thistle, 1, DashStyle.Dash));
a.opposite = b;
b.opposite = a;
return new DataSeries[]{
new DataSeries(this, "Tenkan sen", new ChartStyle(SeriesChartType.Line,System.Drawing.Color.Red,1,DashStyle.Solid)),
new DataSeries(this, "Kijun sen", new ChartStyle(SeriesChartType.Line,System.Drawing.Color.Blue,1,DashStyle.Solid)),
a,
b,
new DataSeries(this, "Chinkou Span", new ChartStyle(SeriesChartType.Line,System.Drawing.Color.Lime,1,DashStyle.Solid))
};
}
}
}

class CustomDrawDataSeries : DataSeries
{
public CustomDrawDataSeries opposite;
public CustomDrawDataSeries(TimeSeriesBase TimeSeries, string Name, ChartStyle Style)
: base(TimeSeries, Name, Style)
{

}

public override void Draw(Graphics g, int fromIndex, int toIndex)
{
if (Style.ChartType == SeriesChartType.Area)
DrawCustomLines(g, fromIndex, toIndex, 0);
else
base.Draw(g, fromIndex, toIndex);
}

protected void DrawCustomLines(Graphics g, int fromIndex, int toIndex, int i_subseries)
{
PointF[] pnts = GetPoints(fromIndex, toIndex, i_subseries);
PointF[] pnts_o = opposite.GetPoints(fromIndex, toIndex, i_subseries);
if (pnts.Length > 1)
{
int len = pnts.Length - 1;
for (int i = 0; i < len; ++i)
{
g.DrawLine(CurrentPen, pnts[i].X, pnts[i].Y, pnts[i + 1].X, pnts[i + 1].Y);
if (pnts[i + 1].Y < pnts_o[i + 1].Y)
g.DrawLine(CurrentPen, pnts[i + 1].X, pnts[i + 1].Y, pnts_o[i + 1].X, pnts_o[i + 1].Y);
if (i == 0 && pnts[i].Y < pnts_o[i].Y)
g.DrawLine(CurrentPen, pnts[i].X, pnts[i].Y, pnts_o[i].X, pnts_o[i].Y);
}
}
}
}
}