Ichimoku Cloud

Silver-Dad
Posts: 2
Joined: 06 Sep 2022

Ichimoku Cloud

Postby Silver-Dad » 09 Sep 2022

This indicator plots the Ichimoku Kinko Hyo indicator (see https://www.investopedia.com/terms/i/ichimokuchart.asp), including the cloud which is plotted out 25 bars ahead of the current bar. The 5th indicator line "Chikou" is not included (see discussion).

Remember to increase your chart shift (Format Window -> X - Time Scale -> Settings -> Chart Shift:) so you can see the future cloud.

IchimokuCloud.png
(243.55 KiB) Not downloaded yet
screenshot

Discussion:
The cloud and extended Span lines are drawn over the background using the IChartCustomDrawer interface. Occasionally the grid will hide portions of the extended Span A or Span B lines; you can ignore this or fix it by turning off the grid or changing input "LayerToDraw" to "BeforeSeries", which will hide the grid behind the cloud.
The Span A and Span B lines, and the cloud do not include the current bar due the large increase in processor load it would require to keep them updated on a tick-by-tick basis. The Chikou line was not included for the same reason, it could be easily added up to the next-to-last bar, but I don't use it and didn't bother. (Exercise for the reader...)

The code demonstrates how to convert between chart coordinates (Bar Index, Price) and window coordinates (screen X, screen Y) and the use of the IChartCustomDrawer interface to draw clouds and other objects.

Enjoy!
Attachments
IchimokuCloud.pln
(6.74 KiB) Downloaded 105 times

Mir
Posts: 8
Joined: 30 Sep 2021

Re: Ichimoku Cloud

Postby Mir » 22 Oct 2022

Hey Silver

Thanks for sharing your file. I cannot open .pln file. It would be very kind of you if you send it by text formet, so i can rewrite it on Power language editor. Thanks

Mir

Silver-Dad
Posts: 2
Joined: 06 Sep 2022

Re: Ichimoku Cloud

Postby Silver-Dad » 22 Oct 2022

Hi Mir,
Here's the source, "IchimokuCloud.Indicator.CS"
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading;
using PowerLanguage.Function;

namespace PowerLanguage.Indicator
{
[SameAsSymbol(true), UpdateOnEveryTick(true), SkipIdenticalTicks(true)]
public class IchimokuCloud : IndicatorObject, IChartCustomDrawer
{
#region Inputs
[Input]
public uint Tenkan_Period { get; set; }

[Input]
public uint Kijun_Period { get; set; }

[Input]
public Color BearishColor { get; set; }

[Input]
public Color BullishColor { get; set; }

[Input]
public EDrawPhases LayerToDraw { get; set; }
#endregion Inputs

#region Drawing
private readonly IchimokuCloudSet cloudSet = new IchimokuCloudSet();
private enum CalcPhase { NotStarted, Started, AllBarsOnChart, Ending };
private CalcPhase calcPhase;

// The following are for conversion between (absolute bar index, price) and (screen X, screen Y)
// They are set up by "Draw(DrawContext, EDrawPhases)" whenever the full chart is to be drawn.
private uint firstBar, lastBar;
private int firstBarX, lastBarX;
private double topPrice, pricePerPixel, barsPerPixel;
#endregion Drawing

// Normally we would set up the following [Tenken, ...] as VariableSeries<double>'s, but then they couldn't be easily accessed in "Draw(DrawContext, EDrawPhases)".
// So we instead make them List<double>'s which are synchronized to Bars.FullSymbolData and indexed from [0] (oldest bar) to [Bars.FullSymbolData.Current - 1]
// HighSeries "hi" and LowSeries "low" allow us to access the bar highs and lows indexed the same way (see comments at their definitions).
// For Example, if Bars.LastBarOnChart == true, then the following are all equivalent:
// Bars.High[0] ≡ hi[Bars.FullSymbolData.Count - 1] ≡ [in "Draw(...)"] context.Environment.Bars[context.Environment.Bars.Count - 1].High
// This setup requires a little extra work in CalcBar() to keep the Lists synchronized.
private List<double> Tenken = new List<double>(), Kijun = new List<double>(), SpanA = new List<double>(), SpanB = new List<double>();
private HighSeries hi;
private LowSeries low;

// SpanA & SpanB are written in CalcBar() and read in DrawIchimokuCloud(), which run in different threads.
private readonly ReaderWriterLockSlim RWLock = new ReaderWriterLockSlim();

// The standard plots.
private IPlotObject Tenkan_Plot, Kijun_Plot;
private IPlotObject SpanA_Plot, SpanB_Plot;

public IchimokuCloud(object _ctx) : base(_ctx)
{
Tenkan_Period = 9;
Kijun_Period = 26;
BearishColor = Color.FromArgb(80, 0, 0);
BullishColor = Color.FromArgb(0, 48, 0);
LayerToDraw = EDrawPhases.AfterBGFill;
}

protected override void Create()
{
calcPhase = CalcPhase.NotStarted;
ChartCustomDraw.Register(this);
Tenkan_Plot = AddPlot(new PlotAttributes("Tenkan", EPlotShapes.Line, Color.Cyan, Color.Empty, 1, EPlotStyle.Solid, false));
Kijun_Plot = AddPlot(new PlotAttributes("Kijun", EPlotShapes.Line, Color.FromArgb(255, 126, 156), Color.Empty, 1, EPlotStyle.Solid, false));
SpanA_Plot = AddPlot(new PlotAttributes("Span A", EPlotShapes.Line, Color.FromArgb(181, 181, 181), Color.Empty, 1, EPlotStyle.Solid, false));
SpanB_Plot = AddPlot(new PlotAttributes("Span B", EPlotShapes.Line, Color.FromArgb(231, 190, 0), Color.Empty, 1, EPlotStyle.Solid, false));
}

protected override void Destroy()
{
ChartCustomDraw.Unregister(this);
calcPhase = CalcPhase.Ending;
}

protected override void StartCalc()
{
firstBar = lastBar = 0;
firstBarX = lastBarX = 0;
calcPhase = CalcPhase.Started;
Tenken.Clear();
Kijun.Clear();
SpanA.Clear();
SpanB.Clear();
cloudSet.Clear();
cloudSet.BullColor = BullishColor;
cloudSet.BearColor = BearishColor;

hi = new HighSeries(Bars);
low = new LowSeries(Bars);
}

protected override void CalcBar()
{
// Set up Tenken, etc. to be synchronized with Bars.FullSymbolData (See comment above "private List<double> Tenken ...")
int end = Bars.FullSymbolData.Current;
int index = Math.Max(0, end - 1);
bool upToDate = Tenken.Count == end;
if (!upToDate)
{
// Synchronize Tenken, etc. to Bars.FullSymbolData
for (int i = Tenken.Count; i < end; ++i)
{
double x = (Highest(hi, i, (int)Tenkan_Period) + Lowest(low, i, (int)Tenkan_Period)) / 2;
Tenken.Add(x);
double y = (Highest(hi, i, (int)Kijun_Period) + Lowest(low, i, (int)Kijun_Period)) / 2;
Kijun.Add(y);
// Adding elements to a List<> is not thread safe, lock them.
RWLock.EnterWriteLock();
try
{
SpanA.Add((x + y) / 2);
x = (Highest(hi, i, 2 * (int)Kijun_Period) + Lowest(low, i, 2 * (int)Kijun_Period)) / 2;
SpanB.Add(x);
}
finally { RWLock.ExitWriteLock(); }
}
}
else
{
// Update the last element of Tenken, etc.
double x = (Highest(hi, index, (int)Tenkan_Period) + Lowest(low, index, (int)Tenkan_Period)) / 2;
Tenken[index] = x;
double y = (Highest(hi, index, (int)Kijun_Period) + Lowest(low, index, (int)Kijun_Period)) / 2;
Kijun[index] = y;
SpanA[index] = (x + y) / 2;
x = (Highest(hi, index, 2 * (int)Kijun_Period) + Lowest(low, index, 2 * (int)Kijun_Period)) / 2;
SpanB[index] = x;
}

// Once all of the bars are processed, enable drawing the cloud.
if (Bars.LastBarOnChart && calcPhase != CalcPhase.AllBarsOnChart) { calcPhase = CalcPhase.AllBarsOnChart; ChartCustomDraw.ReDraw(); }

// The standard plots. Note that SpanA and SpanB will not plot past the last bar.
Tenkan_Plot.Set(Tenken[index]);
Kijun_Plot.Set(Kijun[index]);
index -= (int)Kijun_Period;
if (index > (int)Kijun_Period)
{
SpanA_Plot.Set(SpanA[index]);
SpanB_Plot.Set(SpanB[index]);
}

cloudSet.SetExtendSpan(SpanA_Plot.Styles[0], SpanB_Plot.Styles[0], SpanA_Plot.Colors[0], SpanB_Plot.Colors[0], SpanA_Plot.Widths[0], SpanB_Plot.Widths[0]);
}

public void Draw(DrawContext context, EDrawPhases phase)
{
// Don't draw until all the bars have been processed through CalcBar()
if ((phase == LayerToDraw) && (calcPhase == CalcPhase.AllBarsOnChart))
{
// This is a check for a valid context. While debugging I've seen Draw called with context.Environment.Bars = null and FullRect.Width = 0;
// That might not really be an issue when not debugging, but I've seen no problems with this included even when debugging, so I'll go with it...
IDrawSymbolBars bars = context.Environment.Bars;
int midX = (int)(context.FullRect.Width + 1) / 2;
if ((bars != null) && (midX > 0))
{
if (context.FullRect == context.DrawRect)
{
// set up the conversion between (absolute bar index, price) and (screen X, screen Y) and draw the cloud.
firstBar = context.Environment.PointX2BarIndex(0);
lastBar = context.Environment.PointX2BarIndex((int)context.FullRect.Width);
firstBarX = context.Environment.BarIndex2PointX(firstBar);
lastBarX = context.Environment.BarIndex2PointX(lastBar);
topPrice = context.Environment.Point2ChartPoint(new Point(midX, 0)).Price;
pricePerPixel = (context.Environment.Point2ChartPoint(new Point(midX, (int)context.FullRect.Height)).Price - topPrice) / Math.Max(context.FullRect.Height - 1, 1);
barsPerPixel = ((double)(lastBar - firstBar)) / Math.Max(lastBarX - firstBarX, 1);

// Draw the Ichimoku Cloud.
DrawIchimokuCloud(context);
}
else
{
// Just updating a portion of the cloud, no need to set up the conversion. Just draw what's needed.
ReDrawIchimokuCloud(context);
}
}
}
}

// The whole chart is being drawn, set up and draw the Ichimoku Cloud.
private void DrawIchimokuCloud(DrawContext context)
{
cloudSet.Clear();
// Note: lastIndex can be up to "Kijun_Period" past the last bar.
int lastIndex = (int)Math.Floor(BarIndex(context.FullRect.Width));
lastIndex = Math.Min(lastIndex, (int)(SpanA.Count + Kijun_Period - 2));

// Create the CloudSet and draw it.
RWLock.EnterReadLock();
try
{
for (int i = (int)firstBar; i <= lastIndex; ++i)
{
int index = i - (int)Kijun_Period;
if (index > Kijun_Period)
cloudSet.Add(ChartBarPixelX((uint)i), ChartPricePixelY(SpanA[index]), ChartPricePixelY(SpanB[index]), i >= SpanA.Count);
}
}
finally { RWLock.ExitReadLock(); }
cloudSet.Finish();
cloudSet.Draw(context);
}

// Partial chart redraw. Touch up the Ichimoku Cloud.
private void ReDrawIchimokuCloud(DrawContext context)
{
// ReDraw a portion of the CloudSet.
double xStart = context.DrawRect.Left - (1.0 / barsPerPixel);
double xEnd = context.DrawRect.Right + (1.0 / barsPerPixel);
cloudSet.Draw(context, xStart, xEnd, context.DrawRect.Top, context.DrawRect.Bottom);
}

// A LineShape is an array of line segments and an associated fill color.
public class LineShape
{
public LineShape() { Color = Color.Transparent; }
public LineShape(Color c) { Color = c; }
public Color Color { get; set; }
public int Count { get { return _points.Count; } }

// Slice = The portion of a cloud between xMin and xMax.
// This version is adequate for IchimokuCloud, but in general we would have to do more work to be sure the
// slice is extended to xMin and yMin even if there are no "knots" at those values of x.
// Here the caller [IchimokuCloudSet.Draw(context, minX, maxX, minY, maxY)] will make sure that xMin and xMax
// extend left and right of the DrawRect, and let GDI clip it to the DrawRect.
public LineShape Slice(double xMin = double.MinValue, double xMax = double.MaxValue)
{
if (xMin <= _xMin && xMax >= _xMax) return this;

LineShape cloud = new LineShape(Color);
for (int i = 0; i < _points.Count; i++)
if (_points.X >= xMin && _points.X <= xMax)
cloud.Add(_points);
return cloud;
}

public LineShape Close()
{
if (_points.Count > 0 && _points[_points.Count - 1] != _points[0])
_points.Add(_points[0]);
return this;
}

public double MinX { get { return _xMin; } }
public double MaxX { get { return _xMax; } }
public double MinY { get { return _yMin; } }
public double MaxY { get { return _yMax; } }
public void Add(float X, float Y) { _points.Add(new PointF(X, Y)); _xMin = Math.Min(_xMin, X); _xMax = Math.Max(_xMax, X); _yMin = Math.Min(_xMin, Y); _yMax = Math.Max(_xMax, Y); }
public void Add(double X, double Y) { _points.Add(new PointF((float)X, (float)Y)); _xMin = Math.Min(_xMin, X); _xMax = Math.Max(_xMax, X); _yMin = Math.Min(_xMin, Y); _yMax = Math.Max(_xMax, Y); }
public void Add(PointF p) { _points.Add(p); _xMin = Math.Min(_xMin, p.X); _xMax = Math.Max(_xMax, p.X); _yMin = Math.Min(_xMin, p.Y); _yMax = Math.Max(_xMax, p.Y); }
public void Add(PointF[] pts) { for (int i = 0; i < pts.Length; i++) Add(pts); }
public void Clear() { _points.Clear(); _xMin = double.MaxValue; _xMax = double.MinValue; _yMin = double.MaxValue; _yMax = double.MinValue; }

public GraphicsPath GraphicsPath { get { GraphicsPath path = new GraphicsPath(); path.AddLines(_points.ToArray()); return path; } }
public void Draw(DrawContext context) { if (Count > 2) { Brush brsh = new SolidBrush(Color); context.graphics.FillPath(brsh, GraphicsPath); } }
public void DrawOutline(DrawContext context, Color color, float width) { if (Count > 1) { context.graphics.DrawPath(new Pen(color, width), GraphicsPath); } }

private readonly List<PointF> _points = new List<PointF>();
private double _xMin = double.MaxValue, _xMax = double.MinValue;
private double _yMin = double.MaxValue, _yMax = double.MinValue;
}

// IchimokuCloudSet is a series of LineShape's which alternate in fill color between BullishColor and BearishColor.
// It contains only the portion of the Ichimoku Cloud needed to draw on the chart, and the data is in screen coordinates.
// It is cleared out and redrawn in "DrawIchimokuCloud" every time the full chart is redrawn, for example when a new bar
// is added or the plot is resized or bar spacing changes, etc...
// The data is held for when only part of the screen needs to be redrawn, for example when the last bar is updated.
// "ReDrawIchimokuCloud(...)" uses this data to redraw a portion of the screen when needed.
public class IchimokuCloudSet
{
public IchimokuCloudSet() { BullColor = Color.FromArgb(0, 48, 0); BearColor = Color.FromArgb(80, 0, 0); }
public enum State { empty, undetermined, bullish, bearish };
public void Clear() { _clouds.Clear(); _tops.Clear(); _bottoms.Clear(); SpanA_Line.Clear(); SpanB_Line.Clear(); _state = State.empty; leftCrossover = NoPoint; rightCrossover = NoPoint; }
public Color BullColor, BearColor;

// These are needed to extend SpanA and SpanB beyond the last bar.
public EPlotStyle SpanA_Plot_Style, SpanB_Plot_Style;
public Color SpanA_Plot_Color, SpanB_Plot_Color;
public int SpanA_Plot_Width, SpanB_Plot_Width;

// Set SpanA_Plot, SpanB_Plot line information so they can be extended.
public void SetExtendSpan(EPlotStyle sA, EPlotStyle sB, Color cA, Color cB, int wA, int wB)
{ SpanA_Plot_Style = sA; SpanB_Plot_Style = sB; SpanA_Plot_Color = cA; SpanB_Plot_Color = cB; SpanA_Plot_Width = wA; SpanB_Plot_Width = wB; }

public void Add(double x, double spanA, double spanB, bool afterLastBar)
{
// Except when starting (State.empty or State.undetermined) State is always bullish or bearish.
// *** NOTE: These are SCREEN coordinates - the Y axis is INVERTED. So spanA > spanB is Bearish!!! (spanA below spanB) *** DoubleLess(spanA, spanB) => bullish DoubleGreater(spanA, spanB) => bearish
switch (_state)
{
case State.empty:
Clear();
_state = PublicFunctions.DoubleGreater(spanA, spanB) ? State.bearish : PublicFunctions.DoubleLess(spanA, spanB) ? State.bullish : State.undetermined;
last_x = x; last_spanA = spanA; last_spanB = spanB;
Add(x, spanA, spanB, afterLastBar);
break;

case State.undetermined:
if ((_state = PublicFunctions.DoubleGreater(spanA, spanB) ? State.bearish : PublicFunctions.DoubleLess(spanA, spanB) ? State.bullish : State.undetermined) == State.undetermined)
leftCrossover = new PointF((float)x, (float)(spanA + spanB) / 2);
else
Add(x, spanA, spanB, afterLastBar);
break;

case State.bullish:
if ((_state = PublicFunctions.DoubleGreater(spanA, spanB) ? State.bearish : State.bullish) == State.bearish)
{
rightCrossover = Cross(last_x, x, last_spanA, spanA, last_spanB, spanB);
CloseCloud(BullColor);
_tops.Add(new PointF((float)x, (float)spanB));
_bottoms.Add(new PointF((float)x, (float)spanA));
}
else
{
_tops.Add(new PointF((float)x, (float)spanA));
_bottoms.Add(new PointF((float)x, (float)spanB));
}
break;

case State.bearish:
if ((_state = PublicFunctions.DoubleLess(spanA, spanB) ? State.bullish : State.bearish) == State.bullish)
{
rightCrossover = Cross(last_x, x, last_spanA, spanA, last_spanB, spanB);
CloseCloud(BearColor);
_tops.Add(new PointF((float)x, (float)spanA));
_bottoms.Add(new PointF((float)x, (float)spanB));
}
else
{
_tops.Add(new PointF((float)x, (float)spanB));
_bottoms.Add(new PointF((float)x, (float)spanA));
}
break;

default:
break;
}

if (afterLastBar)
{
if (SpanA_Line.Count <= 0) SpanA_Line.Add(last_x, last_spanA);
if (SpanB_Line.Count <= 0) SpanB_Line.Add(last_x, last_spanB);
SpanA_Line.Add(x, spanA);
SpanB_Line.Add(x, spanB);
}

last_x = x; last_spanA = spanA; last_spanB = spanB;
}

public void Finish() { CloseCloud(_state == State.bullish ? BullColor : BearColor); }

public void Draw(DrawContext context)
{
foreach (LineShape cloud in _clouds)
cloud.Draw(context);
if (SpanA_Plot_Style != EPlotStyle.Invisible)
SpanA_Line.DrawOutline(context, SpanA_Plot_Color, SpanA_Plot_Width);
if (SpanB_Plot_Style != EPlotStyle.Invisible)
SpanB_Line.DrawOutline(context, SpanB_Plot_Color, SpanB_Plot_Width);
}

public void Draw(DrawContext context, double minX, double maxX, double minY, double maxY)
{
foreach (LineShape cloud in _clouds)
{
if (cloud.MaxX > minX && cloud.MinX < maxX && cloud.MaxY > minY && cloud.MinY < maxY)
cloud.Slice(minX, maxX).Close().Draw(context);
}
if (SpanA_Plot_Style != EPlotStyle.Invisible && SpanA_Line.MaxX > minX && SpanA_Line.MinX < maxX && SpanA_Line.MaxY > minY && SpanA_Line.MinY < maxY)
SpanA_Line.Slice(minX, maxX).DrawOutline(context, SpanA_Plot_Color, SpanA_Plot_Width);
if (SpanB_Plot_Style != EPlotStyle.Invisible && SpanB_Line.MaxX > minX && SpanB_Line.MinX < maxX && SpanB_Line.MaxY > minY && SpanB_Line.MinY < maxY)
SpanB_Line.Slice(minX, maxX).DrawOutline(context, SpanB_Plot_Color, SpanB_Plot_Width);
}

private void CloseCloud(Color color)
{
if (_tops.Count > 0 && _bottoms.Count > 0)
{
LineShape cloud = new LineShape(color);
if (!IsEmpty(leftCrossover)) { cloud.Add(leftCrossover); leftCrossover = NoPoint; }
for (int i = 0; i < _tops.Count; ++i) cloud.Add(_tops);
if (!IsEmpty(rightCrossover)) { cloud.Add(rightCrossover); leftCrossover = rightCrossover; rightCrossover = NoPoint; }
for (int i = _bottoms.Count - 1; i >= 0; --i) cloud.Add(_bottoms);
_clouds.Add(cloud.Close());
}
_tops.Clear();
_bottoms.Clear();
}

private readonly List<LineShape> _clouds = new List<LineShape>();
private LineShape SpanA_Line = new LineShape(), SpanB_Line = new LineShape();
private readonly List<PointF> _tops = new List<PointF>(), _bottoms = new List<PointF>();
private State _state = State.empty;
private PointF leftCrossover = new PointF(float.NaN, float.NaN), rightCrossover = new PointF(float.NaN, float.NaN);
private double last_x, last_spanA, last_spanB;
private static readonly PointF NoPoint = new PointF(float.NaN, float.NaN);
}

private static bool IsEmpty(PointF x) { return float.IsNaN(x.X) || float.IsNaN(x.Y); }

// The intersection PointF of the 2 lines {(x1, F1) → (x2, F2)} and {(x1, S1) → (x2, S2)}
private static PointF Cross(double x1, double x2, double F1, double F2, double S1, double S2)
{
double denom = S1 - S2 + F2 - F1;
double x = -(x2 * (F1 - S1) + x1 * (S2 - F2)) / denom;
double y = (F2 * S1 - F1 * S2) / denom;
return new PointF((float)x, (float)y);
}

// Convert a price to chart screen y value.
private double ChartPricePixelY(double price) { return (price - topPrice) / pricePerPixel; }

// Convert a bar index to chart screen x value.
private double ChartBarPixelX(uint index) { return firstBarX + ((index - firstBar) / barsPerPixel); }

// Convert a chart screen x value to a bar index (non integer - may be rounded to form a true index.)
private double BarIndex(double x) { return firstBar + barsPerPixel * (x - firstBarX); }

// Highest(list, end, length) returns the Maximum of {list[end], list[end-1], ..., list[end - length + 1]}
public double Highest(IList<double> list, int end, int length)
{
double rtn = double.MinValue;
for (int i = 0; i < Math.Min(length, end + 1); ++i)
rtn = Math.Max(rtn, list[end - i]);
return rtn;
}

// Lowest(list, end, length) returns the Minimum of {list[end], list[end-1], ..., list[end - length + 1]}
public double Lowest(IList<double> list, int end, int length)
{
double rtn = double.MaxValue;
for (int i = 0; i < Math.Min(length, end + 1); ++i)
rtn = Math.Min(rtn, list[end - i]);
return rtn;
}


// This is an Interface to access the FullSymbolData Highs of an IInstrument (i.e. "Bars") as a List<double> in forward order,
// e.g. index "0" accesses the oldest High and index "Count - 1" accesses the newest high.
// For example...
// HighSeries High = new HighSeries(Bars);
// . . .
// double accum = 0.0;
// for (int i = 0; i < High.Count; ++i)
// accum += High;
// double AvgHigh = accum / High.Count;
//
// NOTE: When (If) MultiCharts.NET migrates to .NET 4.5+, this should be implemented as an IReadOnlyList<double>,
// which is a much simpler interface that List<T> implements. (All of the NotImplementedException's will go away.)
public class HighSeries : IList<double>
{
public HighSeries(IInstrument t) { this.series = t; }

private IInstrument series;

public int Count { get { return series.FullSymbolData.Count; } }

public bool IsReadOnly { get { return true; } }

public double this[int index]
{
get { return series.FullSymbolData.High[series.CurrentBarAbsolute() - index]; }
set { throw new NotImplementedException(); }
}

public int IndexOf(double item) { throw new NotImplementedException(); }
public void Insert(int index, double item) { throw new NotImplementedException(); }
public void RemoveAt(int index) { throw new NotImplementedException(); }
public void Add(double item) { throw new NotImplementedException(); }
public void Clear() { throw new NotImplementedException(); }
public bool Contains(double item) { throw new NotImplementedException(); }
public void CopyTo(double[] array, int arrayIndex) { throw new NotImplementedException(); }
public bool Remove(double item) { throw new NotImplementedException(); }

public IEnumerator<double> GetEnumerator() { throw new NotImplementedException(); }
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
}

// This is an Interface to access the FullSymbolData Lows of an IInstrument (i.e. "Bars") as a List<double> in forward order.
// See HighSeries comments.
public class LowSeries : IList<double>
{
public LowSeries(IInstrument t) { this.series = t; }

private IInstrument series;

public int Count { get { return series.FullSymbolData.Count; } }

public bool IsReadOnly { get { return true; } }

public double this[int index]
{
get { return series.FullSymbolData.Low[series.CurrentBarAbsolute() - index]; }
set { throw new NotImplementedException(); }
}

public int IndexOf(double item) { throw new NotImplementedException(); }
public void Insert(int index, double item) { throw new NotImplementedException(); }
public void RemoveAt(int index) { throw new NotImplementedException(); }
public void Add(double item) { throw new NotImplementedException(); }
public void Clear() { throw new NotImplementedException(); }
public bool Contains(double item) { throw new NotImplementedException(); }
public void CopyTo(double[] array, int arrayIndex) { throw new NotImplementedException(); }
public bool Remove(double item) { throw new NotImplementedException(); }

public IEnumerator<double> GetEnumerator() { throw new NotImplementedException(); }
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
}


}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------

Good Luck!

Mir
Posts: 8
Joined: 30 Sep 2021

Re: Ichimoku Cloud

Postby Mir » 25 Feb 2023

Thanks a lot. I am not a programmer but i will try.


Return to “User Contributed Studies”