Skip to main content

Elliott Patterns

info

In similar fashion to the XABCD pattern (See XABCD doc page), every Elliott tool such as: impulse / motive / wave, Single / Double / Triple Corrections (ABC/WXYXZ) patterns CAN be represented with a PolyLineAnnotation instance with user defined point counts and labels: ["0", "1", "2", "3", "4", "5"].

Optionally - the 1st point can be left without a label "" or labeled with "0" to keep the wave start unmarked.

For example, an Elliott impulse wave can be drawn as a simple 6-point PolyLineAnnotation📘.

const {
AnnotationHoverModifier,
ECursorStyle,
EVerticalTextPosition,
NumberRange,
NumericAxis,
SciChartSurface
} = SciChart; // or import from "scichart"
const {
EAnnotationVisibilityMode,
EMultiPointLabelAnchorMode,
PolyLineAnnotation,
SciTraderLightTheme
} = SciChartFinancialTools; // if using npm, import from "scichart-financial-tools";

const { wasmContext, sciChartSurface } = await SciChartSurface.create(divElementId, {
theme: new SciTraderLightTheme()
});

sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(0, 70) }));
sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(90, 140) }));

sciChartSurface.annotations.add(
new PolyLineAnnotation({
points: [
{ x: 6, y: 98 },
{ x: 18, y: 118 },
{ x: 28, y: 108 },
{ x: 42, y: 132 },
{ x: 52, y: 114 },
{ x: 64, y: 136 }
],
stroke: "#7C3AED",
strokeThickness: 3,
// fill: "#7C3AED22", // no need for "fill"
isEditable: true,

// Loop over an array of labels and assign each to a point index:
labels: ["0", "1", "2", "3", "4", "5"].map((text, pointIndex) => ({
anchorMode: EMultiPointLabelAnchorMode.Point,
pointIndex,
text: `${text}`,

// all labels not changed in the "formatLabelStyle" will have this "below" style
verticalTextPosition: EVerticalTextPosition.Below,
yOffset: 5,
})),

pointLabelVisibility: EAnnotationVisibilityMode.Always,
gripVisibility: EAnnotationVisibilityMode.Always,

// optional but recommended -> Makes the label positions dynamic based on the slope of the lines between points:
formatLabelStyle: ({ annotation, labelIndex }) => {
const points = annotation.points;

const currentPoint = points[labelIndex];
const previousPoint = points[labelIndex - 1];
const nextPoint = points[labelIndex + 1];

if (previousPoint && nextPoint) {
const previousSlope = (currentPoint.y - previousPoint.y) / (currentPoint.x - previousPoint.x);
const nextSlope = (nextPoint.y - currentPoint.y) / (nextPoint.x - currentPoint.x);
if (previousSlope > nextSlope) {
return {
verticalTextPosition: EVerticalTextPosition.Above,
yOffset: -5,
};
}
} else {
if (labelIndex === 0 && nextPoint.y < currentPoint.y
|| previousPoint.y < currentPoint.y
) {
return {
verticalTextPosition: EVerticalTextPosition.Above,
yOffset: -5,
};
}
}
return {}; // keep using the "Below" style defined in constructor
},
})
);

sciChartSurface.chartModifiers.add(
new AnnotationHoverModifier({ // for better default cursor styles
enableHover: true,
enableCursor: true,
idleCursor: ECursorStyle.Crosshair
})
);

Keep the annotation editable so traders can adjust the vertices after placement.

Other Elliott patterns​

This example shows two more variants:

  • An Elliott Motive Wave with labels: ["", "A", "B", "C", "D", "E"]
  • An Elliott Triple correction with labels: ["(0)", "(W)", "(X)", "(Y)", "(X)", "(Z)"]

The important part is to keep in mind that ANY pattern can be drawn with a PolyLineAnnotation and the labels can be assigned to any point index. The rest is just a styling choice.

sciChartSurface.annotations.add(
new PolyLineAnnotation({
points: [
{ x: 6, y: 148 },
{ x: 18, y: 178 },
{ x: 28, y: 164 },
{ x: 42, y: 192 },
{ x: 52, y: 159 },
{ x: 64, y: 196 }
],
stroke: "#38F",
strokeThickness: 2,
fill: "#38F2",
isEditable: true,

// Loop over an array of labels and assign each to a point index:
labels: ["", "A", "B", "C", "D", "E"].map((text, pointIndex) => ({
anchorMode: EMultiPointLabelAnchorMode.Point,
pointIndex,
text: `${text}`,

// cheap trick to alternate label positions above and below points:
verticalTextPosition: pointIndex % 2 === 0 ? EVerticalTextPosition.Below : EVerticalTextPosition.Above,
// for a smarter solution, see the "formatLabelStyle" callback from the first annotation example on this page
})),
}),
new PolyLineAnnotation({
points: [
{ x: 6, y: 108 },
{ x: 18, y: 128 },
{ x: 28, y: 118 },
{ x: 42, y: 142 },
{ x: 52, y: 109 },
{ x: 64, y: 146 }
],
stroke: "#F83",
strokeThickness: 2,
// fill: "#F832",
isEditable: true,

// Loop over an array of labels and assign each to a point index:
labels: ["(0)", "(W)", "(X)", "(Y)", "(X)", "(Z)"].map((text, pointIndex) => ({
anchorMode: EMultiPointLabelAnchorMode.Point,
pointIndex,
text: `${text}`,

// cheap trick to alternate label positions above and below points:
verticalTextPosition: pointIndex % 2 === 0 ? EVerticalTextPosition.Below : EVerticalTextPosition.Above,
// for a smarter solution, see the "formatLabelStyle" callback from the first annotation example on this page
})),
})
);

Side-by-Side Elliott Layout​

This variant keeps the same PolyLineAnnotation recipe but shows two labeled wave structures on the same chart. It is a nice way to compare an impulse wave with a correction wave while keeping the label placement readable.

const {
AnnotationHoverModifier,
ECursorStyle,
EHorizontalAnchorPoint,
EVerticalAnchorPoint,
EVerticalTextPosition,
NativeTextAnnotation,
NumberRange,
NumericAxis,
SciChartSurface
} = SciChart; // or import from "scichart"
const {
EAnnotationVisibilityMode,
EMultiPointLabelAnchorMode,
PolyLineAnnotation,
SciTraderLightTheme
} = SciChartFinancialTools; // if using npm, import from "scichart-financial-tools";

const { wasmContext, sciChartSurface } = await SciChartSurface.create(divElementId, {
theme: new SciTraderLightTheme()
});

sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(0, 70) }));
sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(92, 220) }));

const buildWave = (points, stroke, fill, labels) =>
new PolyLineAnnotation({
points,
stroke,
strokeThickness: 2.5,
fill,
isEditable: true,
gripVisibility: EAnnotationVisibilityMode.Always,
pointLabelVisibility: EAnnotationVisibilityMode.Always,
labels: labels.map((text, pointIndex) => ({
anchorMode: EMultiPointLabelAnchorMode.Point,
pointIndex,
text,
verticalTextPosition: pointIndex % 2 === 0 ? EVerticalTextPosition.Below : EVerticalTextPosition.Above,
yOffset: pointIndex % 2 === 0 ? 5 : -5
}))
});

sciChartSurface.annotations.add(
new NativeTextAnnotation({
x1: 5,
y1: 214,
text: "The same PolyLineAnnotation class can show an impulse wave and a correction wave side by side.",
horizontalAnchorPoint: EHorizontalAnchorPoint.Left,
verticalAnchorPoint: EVerticalAnchorPoint.Top,
fontSize: 13,
textColor: "#111827"
}),
buildWave(
[
{ x: 6, y: 138 },
{ x: 16, y: 164 },
{ x: 28, y: 152 },
{ x: 40, y: 182 },
{ x: 50, y: 162 },
{ x: 62, y: 196 }
],
"#7C3AED",
"#7C3AED22",
["0", "1", "2", "3", "4", "5"]
),
buildWave(
[
{ x: 8, y: 100 },
{ x: 18, y: 122 },
{ x: 30, y: 112 },
{ x: 42, y: 136 },
{ x: 54, y: 118 },
{ x: 64, y: 146 }
],
"#F97316",
"#F9731620",
["A", "B", "C", "D", "E", "F"]
)
);

sciChartSurface.chartModifiers.add(
new AnnotationHoverModifier({ // not needed, but makes the annotation Grips hover/drag Cursor style match actions
enableHover: true,
enableCursor: true,
idleCursor: ECursorStyle.Crosshair
})
);

See Also​