Built-in graphic shapes
An indicator can place ready-made shapes on the chart without drawing them itself: horizontal levels, trend lines,
rectangles, horizontal lines that last until the first touch, and text labels. For anything else, draw in OnRender
(see the drawing article).
Horizontal levels
A LineSeries is a horizontal line at a fixed value, added to the LineSeries collection of the indicator; the user sees it in the settings like a data series. The oscillator below lives in its own panel and has two levels, 30 and 70, like the RSI:
using System.Windows.Media;
using ATAS.Indicators;
using OFT.Rendering.Settings;
namespace ATAS.Docs.Samples.ChartIndicators;
public class HorizontalLevelsIndicator : Indicator
{
public HorizontalLevelsIndicator()
{
Panel = IndicatorDataProvider.NewPanel;
LineSeries.Add(new LineSeries("Down")
{
Color = Colors.Orange,
LineDashStyle = LineDashStyle.Dash,
Value = 30,
Width = 1
});
LineSeries.Add(new LineSeries("Up")
{
Color = Colors.Orange,
LineDashStyle = LineDashStyle.Dash,
Value = 70,
Width = 1
});
}
protected override void OnCalculate(int bar, decimal value)
{
// Position of the close price inside the bar range, in percent (0..100)
var candle = GetCandle(bar);
var range = candle.High - candle.Low;
this[bar] = range == 0 ? 50 : (candle.Close - candle.Low) * 100 / range;
}
}
The color of a LineSeries is a System.Windows.Media.Color, like the colors of the indicator settings. The shapes
below use the System.Drawing types (Pen, Brush, Color); to convert a color from one type to the other, use the
Convert() extension method of the ATAS.Indicators namespace.
Trend lines
Create a TrendLine with the first bar and price, the second bar and price and the pen, and add it to the TrendLines collection. The IsRay flag turns the line into a ray.
public TrendLine(int firstBar, decimal firstPrice, int secondBar, decimal secondPrice, Pen pen)
Rectangles
Create a DrawingRectangle with the two corners (bar and price), the
pen of the border and the brush of the fill, and add it to the
Rectangles collection. The second constructor also takes the pen
of the middle horizontal line, drawn when MidLineEnabled is set.
public DrawingRectangle(int firstBar, decimal firstPrice, int secondBar, decimal secondPrice, Pen outlinePen, Brush fillBrush)
public DrawingRectangle(int firstBar, decimal firstPrice, int secondBar, decimal secondPrice, Pen outlinePen, Brush fillBrush, Pen midPen)
Horizontal lines until the first touch
A LineTillTouch starts at a bar and a price and is prolonged until the price touches it. Pass it to AddHorizontalLineTillTouch rather than adding it to the HorizontalLinesTillTouch collection directly: a direct change of the collection works, but makes the indicator rescan all the lines to find the ones that are not touched yet.
public LineTillTouch(int bar, decimal price, Pen pen) // until the first touch
public LineTillTouch(int bar, decimal price, Pen pen, int fixedBarsCount) // a fixed length, completed at once, no touch tracking
Text labels
AddText places a text label at a bar and a price and returns the
DrawingText object, whose parameters can be changed later. Adding a text
with an existing tag replaces the previous label.
AddText(string tag, string text, bool isAbovePrice, int bar, decimal price,
int yOffset, int xOffset, Color textColor, Color outlineColor, Color fillColor,
float fontSize, DrawingText.TextAlign align, bool autoSize = false)
AddText(string tag, string text, bool isAbovePrice, int bar, decimal price,
Color textColor, Color outlineColor, Color fillColor,
float fontSize, DrawingText.TextAlign align, bool autoSize = false)
AddText(string tag, string text, bool isAbovePrice, int bar, decimal price,
Color textColor, Color fillColor, float fontSize, DrawingText.TextAlign align,
bool autoSize = false)
| Parameter | Meaning |
|---|---|
tag |
A unique identifier of the label |
text |
The displayed text |
isAbovePrice |
Whether the text is placed above the price or below it |
bar, price |
The position |
yOffset, xOffset |
Offsets in pixels |
textColor, outlineColor, fillColor |
The text, the frame and the background colors (System.Drawing.Color) |
fontSize |
The font size |
align |
Left, right or center |
autoSize |
Scale the text with the chart |
Recalculation
When the indicator is recalculated (for example, after RecalculateValues()), it clears the trend lines, the
rectangles, the lines until the first touch and the text labels. Add these objects in OnCalculate, so that they are
created again during the recalculation. The horizontal levels of the LineSeries collection are not cleared.
The indicator below adds a trend line, a rectangle, a line until the first touch and a text label every 50 bars:
using System.Drawing;
using ATAS.Indicators;
using ATAS.Indicators.Drawing;
namespace ATAS.Docs.Samples.ChartIndicators;
public class ShapesEveryFiftyBarsIndicator : Indicator
{
private readonly Pen _linePen = new(Color.DodgerBlue, 2);
private readonly Pen _levelPen = new(Color.Orange, 1);
private readonly Brush _fillBrush = new SolidBrush(Color.FromArgb(60, Color.Green));
private int _lastProcessedBar = -1;
public ShapesEveryFiftyBarsIndicator() : base(true)
{
DenyToChangePanel = true;
DataSeries[0].IsHidden = true;
}
protected override void OnCalculate(int bar, decimal value)
{
if (bar == 0)
_lastProcessedBar = -1;
// OnCalculate is called repeatedly for the last bar, so add the shapes once, for a closed bar
var closedBar = bar - 1;
if (closedBar < 10 || closedBar % 50 != 0 || closedBar == _lastProcessedBar)
return;
_lastProcessedBar = closedBar;
var candle = GetCandle(closedBar);
var prevCandle = GetCandle(closedBar - 10);
// A trend line between the closes of two bars
TrendLines.Add(new TrendLine(closedBar - 10, prevCandle.Close, closedBar, candle.Close, _linePen));
// A rectangle around the range of the bar
Rectangles.Add(new DrawingRectangle(closedBar - 2, candle.High, closedBar + 2, candle.Low, _linePen, _fillBrush));
// A horizontal line from the high of the bar until the price touches it
AddHorizontalLineTillTouch(new LineTillTouch(closedBar, candle.High, _levelPen));
// A text label above the high of the bar
AddText($"label{closedBar}", "High", true, closedBar, candle.High, Color.White, Color.Black, Color.DimGray, 10, DrawingText.TextAlign.Center);
}
}