@tradingaction/series 2.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +5 -0
  3. package/lib/AlternateDataSeries.d.ts +5 -0
  4. package/lib/AlternateDataSeries.js +16 -0
  5. package/lib/AlternateDataSeries.js.map +1 -0
  6. package/lib/AlternatingFillAreaSeries.d.ts +77 -0
  7. package/lib/AlternatingFillAreaSeries.js +69 -0
  8. package/lib/AlternatingFillAreaSeries.js.map +1 -0
  9. package/lib/AreaOnlySeries.d.ts +42 -0
  10. package/lib/AreaOnlySeries.js +53 -0
  11. package/lib/AreaOnlySeries.js.map +1 -0
  12. package/lib/AreaSeries.d.ts +46 -0
  13. package/lib/AreaSeries.js +21 -0
  14. package/lib/AreaSeries.js.map +1 -0
  15. package/lib/BarSeries.d.ts +36 -0
  16. package/lib/BarSeries.js +91 -0
  17. package/lib/BarSeries.js.map +1 -0
  18. package/lib/BollingerSeries.d.ts +33 -0
  19. package/lib/BollingerSeries.js +59 -0
  20. package/lib/BollingerSeries.js.map +1 -0
  21. package/lib/CandlestickSeries.d.ts +65 -0
  22. package/lib/CandlestickSeries.js +115 -0
  23. package/lib/CandlestickSeries.js.map +1 -0
  24. package/lib/ElderRaySeries.d.ts +45 -0
  25. package/lib/ElderRaySeries.js +66 -0
  26. package/lib/ElderRaySeries.js.map +1 -0
  27. package/lib/GroupedBarSeries.d.ts +33 -0
  28. package/lib/GroupedBarSeries.js +22 -0
  29. package/lib/GroupedBarSeries.js.map +1 -0
  30. package/lib/KagiSeries.d.ts +45 -0
  31. package/lib/KagiSeries.js +108 -0
  32. package/lib/KagiSeries.js.map +1 -0
  33. package/lib/LineSeries.d.ts +84 -0
  34. package/lib/LineSeries.js +102 -0
  35. package/lib/LineSeries.js.map +1 -0
  36. package/lib/MACDSeries.d.ts +55 -0
  37. package/lib/MACDSeries.js +62 -0
  38. package/lib/MACDSeries.js.map +1 -0
  39. package/lib/OHLCSeries.d.ts +32 -0
  40. package/lib/OHLCSeries.js +67 -0
  41. package/lib/OHLCSeries.js.map +1 -0
  42. package/lib/OverlayBarSeries.d.ts +35 -0
  43. package/lib/OverlayBarSeries.js +71 -0
  44. package/lib/OverlayBarSeries.js.map +1 -0
  45. package/lib/PointAndFigureSeries.d.ts +33 -0
  46. package/lib/PointAndFigureSeries.js +92 -0
  47. package/lib/PointAndFigureSeries.js.map +1 -0
  48. package/lib/RSISeries.d.ts +68 -0
  49. package/lib/RSISeries.js +82 -0
  50. package/lib/RSISeries.js.map +1 -0
  51. package/lib/RenkoSeries.d.ts +42 -0
  52. package/lib/RenkoSeries.js +65 -0
  53. package/lib/RenkoSeries.js.map +1 -0
  54. package/lib/SARSeries.d.ts +34 -0
  55. package/lib/SARSeries.js +69 -0
  56. package/lib/SARSeries.js.map +1 -0
  57. package/lib/SVGComponent.d.ts +8 -0
  58. package/lib/SVGComponent.js +9 -0
  59. package/lib/SVGComponent.js.map +1 -0
  60. package/lib/ScatterSeries.d.ts +24 -0
  61. package/lib/ScatterSeries.js +60 -0
  62. package/lib/ScatterSeries.js.map +1 -0
  63. package/lib/StackedBarSeries.d.ts +44 -0
  64. package/lib/StackedBarSeries.js +157 -0
  65. package/lib/StackedBarSeries.js.map +1 -0
  66. package/lib/StochasticSeries.d.ts +39 -0
  67. package/lib/StochasticSeries.js +42 -0
  68. package/lib/StochasticSeries.js.map +1 -0
  69. package/lib/StraightLine.d.ts +38 -0
  70. package/lib/StraightLine.js +81 -0
  71. package/lib/StraightLine.js.map +1 -0
  72. package/lib/VolumeProfileSeries.d.ts +45 -0
  73. package/lib/VolumeProfileSeries.js +161 -0
  74. package/lib/VolumeProfileSeries.js.map +1 -0
  75. package/lib/index.d.ts +23 -0
  76. package/lib/index.js +24 -0
  77. package/lib/index.js.map +1 -0
  78. package/lib/markers/CircleMarker.d.ts +25 -0
  79. package/lib/markers/CircleMarker.js +35 -0
  80. package/lib/markers/CircleMarker.js.map +1 -0
  81. package/lib/markers/SquareMarker.d.ts +25 -0
  82. package/lib/markers/SquareMarker.js +37 -0
  83. package/lib/markers/SquareMarker.js.map +1 -0
  84. package/lib/markers/TriangleMarker.d.ts +27 -0
  85. package/lib/markers/TriangleMarker.js +89 -0
  86. package/lib/markers/TriangleMarker.js.map +1 -0
  87. package/lib/markers/index.d.ts +3 -0
  88. package/lib/markers/index.js +4 -0
  89. package/lib/markers/index.js.map +1 -0
  90. package/package.json +52 -0
  91. package/src/AlternateDataSeries.tsx +29 -0
  92. package/src/AlternatingFillAreaSeries.tsx +159 -0
  93. package/src/AreaOnlySeries.tsx +106 -0
  94. package/src/AreaSeries.tsx +95 -0
  95. package/src/BarSeries.tsx +151 -0
  96. package/src/BollingerSeries.tsx +90 -0
  97. package/src/CandlestickSeries.tsx +188 -0
  98. package/src/ElderRaySeries.tsx +99 -0
  99. package/src/GroupedBarSeries.tsx +48 -0
  100. package/src/KagiSeries.tsx +155 -0
  101. package/src/LineSeries.tsx +223 -0
  102. package/src/MACDSeries.tsx +110 -0
  103. package/src/OHLCSeries.tsx +116 -0
  104. package/src/OverlayBarSeries.tsx +115 -0
  105. package/src/PointAndFigureSeries.tsx +140 -0
  106. package/src/RSISeries.tsx +158 -0
  107. package/src/RenkoSeries.tsx +118 -0
  108. package/src/SARSeries.tsx +111 -0
  109. package/src/SVGComponent.tsx +13 -0
  110. package/src/ScatterSeries.tsx +105 -0
  111. package/src/StackedBarSeries.tsx +272 -0
  112. package/src/StochasticSeries.tsx +70 -0
  113. package/src/StraightLine.tsx +166 -0
  114. package/src/VolumeProfileSeries.tsx +247 -0
  115. package/src/index.ts +23 -0
  116. package/src/markers/CircleMarker.tsx +69 -0
  117. package/src/markers/SquareMarker.tsx +71 -0
  118. package/src/markers/TriangleMarker.tsx +131 -0
  119. package/src/markers/index.ts +3 -0
@@ -0,0 +1,95 @@
1
+ import { strokeDashTypes } from "@tradingaction/core";
2
+ import { ScaleContinuousNumeric } from "d3-scale";
3
+ import { CurveFactory } from "d3-shape";
4
+ import React, { Component } from "react";
5
+ import { AreaOnlySeries } from "./AreaOnlySeries";
6
+ import { LineSeries } from "./LineSeries";
7
+
8
+ export interface AreaSeriesProps {
9
+ /**
10
+ * The base y value to draw the area to.
11
+ */
12
+ readonly baseAt?:
13
+ | number
14
+ | ((yScale: ScaleContinuousNumeric<number, number>, d: [number, number], moreProps: any) => number);
15
+ readonly canvasClip?: (context: CanvasRenderingContext2D, moreProps: any) => void;
16
+ /**
17
+ * Whether to connect the area between undefined data points.
18
+ */
19
+ readonly connectNulls?: boolean;
20
+ /**
21
+ * Color, gradient, or pattern to use for fill.
22
+ */
23
+ readonly fillStyle?:
24
+ | string
25
+ | ((context: CanvasRenderingContext2D, moreProps: any) => string | CanvasGradient | CanvasPattern);
26
+ /**
27
+ * A factory for a curve generator for the area and line.
28
+ */
29
+ readonly curve?: CurveFactory;
30
+ /**
31
+ * Color, gradient, or pattern to use for the stroke.
32
+ */
33
+ readonly strokeStyle?: string;
34
+ /**
35
+ * Stroke dash.
36
+ */
37
+ readonly strokeDasharray?: strokeDashTypes;
38
+ /**
39
+ * Stroke width.
40
+ */
41
+ readonly strokeWidth?: number;
42
+ /**
43
+ * Selector for data to plot.
44
+ */
45
+ readonly yAccessor: (data: any) => number | undefined;
46
+ }
47
+
48
+ /**
49
+ * `AreaSeries` component is similar to a `LineSeries` but with the area between the line and base filled.
50
+ */
51
+ export class AreaSeries extends Component<AreaSeriesProps> {
52
+ public static defaultProps: Partial<AreaSeriesProps> = {
53
+ fillStyle: "rgba(33, 150, 243, 0.1)",
54
+ strokeStyle: "#2196f3",
55
+ strokeWidth: 3,
56
+ strokeDasharray: "Solid",
57
+ };
58
+
59
+ public render() {
60
+ const {
61
+ baseAt,
62
+ connectNulls,
63
+ strokeStyle,
64
+ strokeWidth,
65
+ strokeDasharray,
66
+ fillStyle,
67
+ curve,
68
+ canvasClip,
69
+ yAccessor,
70
+ } = this.props;
71
+
72
+ return (
73
+ <g>
74
+ <AreaOnlySeries
75
+ connectNulls={connectNulls}
76
+ yAccessor={yAccessor}
77
+ curve={curve}
78
+ base={baseAt}
79
+ fillStyle={fillStyle}
80
+ canvasClip={canvasClip}
81
+ />
82
+ <LineSeries
83
+ connectNulls={connectNulls}
84
+ yAccessor={yAccessor}
85
+ strokeStyle={strokeStyle}
86
+ strokeWidth={strokeWidth}
87
+ strokeDasharray={strokeDasharray}
88
+ curve={curve}
89
+ canvasClip={canvasClip}
90
+ highlightOnHover={false}
91
+ />
92
+ </g>
93
+ );
94
+ }
95
+ }
@@ -0,0 +1,151 @@
1
+ import { functor, head, getAxisCanvas, GenericChartComponent, plotDataLengthBarWidth } from "@tradingaction/core";
2
+ import { group } from "d3-array";
3
+ import { ScaleContinuousNumeric, ScaleTime } from "d3-scale";
4
+ import * as React from "react";
5
+ import { drawOnCanvasHelper, identityStack } from "./StackedBarSeries";
6
+
7
+ interface IBar {
8
+ readonly x: number;
9
+ readonly y: number;
10
+ readonly height: number;
11
+ readonly width: number;
12
+ readonly fillStyle: string;
13
+ }
14
+
15
+ export interface BarSeriesProps {
16
+ readonly baseAt?:
17
+ | number
18
+ | ((
19
+ xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>,
20
+ yScale: ScaleContinuousNumeric<number, number>,
21
+ d: [number, number],
22
+ moreProps: any,
23
+ ) => number);
24
+ readonly clip?: boolean;
25
+ readonly fillStyle?: string | ((data: any) => string);
26
+ readonly strokeStyle?: string;
27
+ readonly swapScales?: boolean;
28
+ readonly width?: number | ((props: { widthRatio: number }, moreProps: any) => number);
29
+ readonly widthRatio?: number;
30
+ readonly yAccessor: (data: any) => number | undefined;
31
+ }
32
+
33
+ /**
34
+ * A `BarSeries` component.
35
+ */
36
+ export class BarSeries extends React.Component<BarSeriesProps> {
37
+ public static defaultProps = {
38
+ baseAt: (
39
+ xScale: ScaleContinuousNumeric<number, number>,
40
+ yScale: ScaleContinuousNumeric<number, number> /* , d*/,
41
+ ) => head(yScale.range()),
42
+ clip: true,
43
+ fillStyle: "rgba(70, 130, 180, 0.5)",
44
+ swapScales: false,
45
+ width: plotDataLengthBarWidth,
46
+ widthRatio: 0.8,
47
+ };
48
+
49
+ public render() {
50
+ const { clip } = this.props;
51
+
52
+ return (
53
+ <GenericChartComponent
54
+ clip={clip}
55
+ canvasToDraw={getAxisCanvas}
56
+ canvasDraw={this.drawOnCanvas}
57
+ drawOn={["pan"]}
58
+ />
59
+ );
60
+ }
61
+
62
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
63
+ if (this.props.swapScales) {
64
+ const { xAccessor } = moreProps;
65
+
66
+ drawOnCanvasHelper(ctx, this.props, moreProps, xAccessor, identityStack);
67
+ } else {
68
+ const bars = this.getBars(moreProps);
69
+
70
+ const { strokeStyle } = this.props;
71
+
72
+ const nest = group(bars, (d: any) => d.fillStyle);
73
+
74
+ nest.forEach((values, key) => {
75
+ if (strokeStyle !== undefined) {
76
+ if (head(values).width > 1) {
77
+ ctx.strokeStyle = strokeStyle;
78
+ }
79
+ }
80
+ ctx.fillStyle = key;
81
+
82
+ values.forEach((d) => {
83
+ if (d.width <= 1) {
84
+ ctx.fillRect(d.x - 0.5, d.y, 1, d.height);
85
+ } else {
86
+ ctx.fillRect(d.x + 0.5, d.y + 0.5, d.width, d.height);
87
+ if (strokeStyle !== undefined) {
88
+ ctx.strokeRect(d.x, d.y, d.width, d.height);
89
+ }
90
+ }
91
+ });
92
+ });
93
+ }
94
+ };
95
+
96
+ private readonly getBars = (moreProps: {
97
+ chartConfig: any;
98
+ xAccessor: (data: any) => number | Date;
99
+ xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
100
+ plotData: any[];
101
+ }) => {
102
+ const { baseAt, fillStyle, width, yAccessor } = this.props;
103
+
104
+ const {
105
+ xScale,
106
+ xAccessor,
107
+ plotData,
108
+ chartConfig: { yScale },
109
+ } = moreProps;
110
+
111
+ const getFill = functor(fillStyle);
112
+ const getBase = functor(baseAt);
113
+ const getWidth = functor(width);
114
+
115
+ const barWidth = getWidth(this.props, {
116
+ xScale,
117
+ xAccessor,
118
+ plotData,
119
+ });
120
+
121
+ const offset = 0.5 * barWidth;
122
+
123
+ return plotData
124
+ .map((d) => {
125
+ const yValue = yAccessor(d);
126
+ if (yValue === undefined) {
127
+ return undefined;
128
+ }
129
+
130
+ const xValue = xAccessor(d);
131
+ const x = xScale(xValue) - offset;
132
+
133
+ let y = yScale(yValue);
134
+
135
+ let h = getBase(xScale, yScale, d) - yScale(yValue);
136
+ if (h < 0) {
137
+ y = y + h;
138
+ h = -h;
139
+ }
140
+
141
+ return {
142
+ x,
143
+ y: Math.round(y),
144
+ height: Math.round(h),
145
+ width: offset * 2,
146
+ fillStyle: getFill(d),
147
+ };
148
+ })
149
+ .filter((d) => d !== undefined) as IBar[];
150
+ };
151
+ }
@@ -0,0 +1,90 @@
1
+ import { ScaleContinuousNumeric } from "d3-scale";
2
+ import * as React from "react";
3
+ import { AreaOnlySeries } from "./AreaOnlySeries";
4
+ import { LineSeries } from "./LineSeries";
5
+
6
+ export interface BollingerSeriesProps {
7
+ readonly areaClassName?: string;
8
+ readonly className?: string;
9
+ readonly fillStyle?: string;
10
+ readonly strokeStyle?: {
11
+ top: string;
12
+ middle: string;
13
+ bottom: string;
14
+ };
15
+ readonly yAccessor?: (data: any) => { bottom: number; middle: number; top: number };
16
+ }
17
+
18
+ export class BollingerSeries extends React.Component<BollingerSeriesProps> {
19
+ public static defaultProps = {
20
+ areaClassName: "react-financial-charts-bollinger-band-series-area",
21
+ fillStyle: "rgba(38, 166, 153, 0.05)",
22
+ strokeStyle: {
23
+ top: "#26a69a",
24
+ middle: "#812828",
25
+ bottom: "#26a69a",
26
+ },
27
+ yAccessor: (data: any) => data.bb,
28
+ };
29
+
30
+ public render() {
31
+ const { className, strokeStyle = BollingerSeries.defaultProps.strokeStyle, fillStyle } = this.props;
32
+
33
+ return (
34
+ <g className={className}>
35
+ <LineSeries yAccessor={this.yAccessorForTop} strokeStyle={strokeStyle.top} />
36
+ <LineSeries yAccessor={this.yAccessorForMiddle} strokeStyle={strokeStyle.middle} />
37
+ <LineSeries yAccessor={this.yAccessorForBottom} strokeStyle={strokeStyle.bottom} />
38
+ <AreaOnlySeries
39
+ yAccessor={this.yAccessorForTop}
40
+ base={this.yAccessorForScaledBottom}
41
+ fillStyle={fillStyle}
42
+ />
43
+ </g>
44
+ );
45
+ }
46
+
47
+ private readonly yAccessorForScaledBottom = (scale: ScaleContinuousNumeric<number, number>, d: any) => {
48
+ const { yAccessor = BollingerSeries.defaultProps.yAccessor } = this.props;
49
+
50
+ const bb = yAccessor(d);
51
+ if (bb === undefined) {
52
+ return undefined;
53
+ }
54
+
55
+ return scale(bb.bottom);
56
+ };
57
+
58
+ private readonly yAccessorForBottom = (d: any) => {
59
+ const { yAccessor = BollingerSeries.defaultProps.yAccessor } = this.props;
60
+
61
+ const bb = yAccessor(d);
62
+ if (bb === undefined) {
63
+ return undefined;
64
+ }
65
+
66
+ return bb.bottom;
67
+ };
68
+
69
+ private readonly yAccessorForMiddle = (d: any) => {
70
+ const { yAccessor = BollingerSeries.defaultProps.yAccessor } = this.props;
71
+
72
+ const bb = yAccessor(d);
73
+ if (bb === undefined) {
74
+ return undefined;
75
+ }
76
+
77
+ return bb.middle;
78
+ };
79
+
80
+ private readonly yAccessorForTop = (d: any) => {
81
+ const { yAccessor = BollingerSeries.defaultProps.yAccessor } = this.props;
82
+
83
+ const bb = yAccessor(d);
84
+ if (bb === undefined) {
85
+ return undefined;
86
+ }
87
+
88
+ return bb.top;
89
+ };
90
+ }
@@ -0,0 +1,188 @@
1
+ import { functor, getAxisCanvas, GenericChartComponent, plotDataLengthBarWidth } from "@tradingaction/core";
2
+ import { group } from "d3-array";
3
+ import { ScaleContinuousNumeric, ScaleTime } from "d3-scale";
4
+ import * as React from "react";
5
+
6
+ export interface ICandle {
7
+ readonly x: number;
8
+ readonly y: number;
9
+ readonly height: number;
10
+ readonly fill: string;
11
+ readonly stroke: string;
12
+ readonly direction: number;
13
+ readonly width: number;
14
+ readonly wick: {
15
+ readonly stroke: string;
16
+ readonly x: number;
17
+ readonly y1: number;
18
+ readonly y2: number;
19
+ readonly y3: number;
20
+ readonly y4: number;
21
+ };
22
+ }
23
+
24
+ export interface CandlestickSeriesProps {
25
+ readonly candleStrokeWidth?: number;
26
+ readonly clip?: boolean;
27
+ readonly fill?: string | ((data: any) => string);
28
+ readonly stroke?: string | ((data: any) => string);
29
+ readonly wickStroke?: string | ((data: any) => string);
30
+ readonly width?: number | ((props: CandlestickSeriesProps, moreProps: any) => number);
31
+ readonly widthRatio?: number;
32
+ readonly yAccessor: (data: any) => { open: number; high: number; low: number; close: number } | undefined;
33
+ readonly onClickWhenHover?: (e: React.MouseEvent, moreProps: any) => void;
34
+ readonly onDoubleClickWhenHover?: (e: React.MouseEvent, moreProps: any) => void;
35
+ readonly onDoubleClick?: (e: React.MouseEvent, moreProps: any) => void;
36
+ readonly onContextMenu?: (e: React.MouseEvent, moreProps: any) => void;
37
+ readonly onClickOutside?: (e: React.MouseEvent, moreProps: any) => void;
38
+ }
39
+
40
+ export class CandlestickSeries extends React.Component<CandlestickSeriesProps> {
41
+ public static defaultProps = {
42
+ candleStrokeWidth: 0.5,
43
+ clip: true,
44
+ fill: (d: any) => (d.close > d.open ? "#26a69a" : "#ef5350"),
45
+ stroke: "none",
46
+ wickStroke: (d: any) => (d.close > d.open ? "#26a69a" : "#ef5350"),
47
+ width: plotDataLengthBarWidth,
48
+ widthRatio: 0.8,
49
+ yAccessor: (d: any) => ({ open: d.open, high: d.high, low: d.low, close: d.close }),
50
+ };
51
+
52
+ public render() {
53
+ const { clip } = this.props;
54
+
55
+ return (
56
+ <GenericChartComponent
57
+ clip={clip}
58
+ canvasDraw={this.drawOnCanvas}
59
+ canvasToDraw={getAxisCanvas}
60
+ drawOn={["pan", "mousemove"]}
61
+ onClickWhenHover={this.props.onClickWhenHover}
62
+ onDoubleClickWhenHover={this.props.onDoubleClickWhenHover}
63
+ onDoubleClick={this.props.onDoubleClick}
64
+ onContextMenu={this.props.onContextMenu}
65
+ onClickOutside={this.props.onClickOutside}
66
+ key={"candle"}
67
+ />
68
+ );
69
+ }
70
+
71
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
72
+ const { candleStrokeWidth = CandlestickSeries.defaultProps.candleStrokeWidth } = this.props;
73
+ const {
74
+ xScale,
75
+ chartConfig: { yScale },
76
+ plotData,
77
+ xAccessor,
78
+ } = moreProps;
79
+
80
+ const candleData = this.getCandleData(xAccessor, xScale, yScale, plotData);
81
+
82
+ const wickNest = group(candleData, (d) => d.wick.stroke);
83
+
84
+ wickNest.forEach((values, key) => {
85
+ ctx.fillStyle = key;
86
+ values.forEach((each) => {
87
+ const d = each.wick;
88
+
89
+ ctx.fillRect(d.x - 0.5, d.y1, 1, d.y2 - d.y1);
90
+ ctx.fillRect(d.x - 0.5, d.y3, 1, d.y4 - d.y3);
91
+ });
92
+ });
93
+
94
+ const candleNest = group(
95
+ candleData,
96
+ (d) => d.stroke,
97
+ // @ts-ignore typings are incorrect for d3-array
98
+ (d) => d.fill,
99
+ );
100
+
101
+ candleNest.forEach((strokeValues, strokeKey) => {
102
+ if (strokeKey !== "none") {
103
+ // @ts-ignore
104
+ ctx.strokeStyle = strokeKey;
105
+ ctx.lineWidth = candleStrokeWidth;
106
+ }
107
+ strokeValues.forEach((values, key) => {
108
+ // @ts-ignore
109
+ ctx.fillStyle = key;
110
+
111
+ // @ts-ignore
112
+ values.forEach((d) => {
113
+ if (d.width <= 1) {
114
+ ctx.fillRect(d.x - 0.5, d.y, 1, d.height);
115
+ } else if (d.height === 0) {
116
+ ctx.fillRect(d.x - 0.5, d.y, d.width, 1);
117
+ } else {
118
+ ctx.fillRect(d.x - 0.5, d.y, d.width, d.height);
119
+ if (strokeKey !== "none") {
120
+ ctx.strokeRect(d.x, d.y, d.width, d.height);
121
+ }
122
+ }
123
+ });
124
+ });
125
+ });
126
+ };
127
+
128
+ private readonly getCandleData = (
129
+ xAccessor: (data: any) => number | Date,
130
+ xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>,
131
+ yScale: ScaleContinuousNumeric<number, number>,
132
+ plotData: any[],
133
+ ) => {
134
+ const { fill: fillProp, stroke: strokeProp, yAccessor, wickStroke: wickStrokeProp } = this.props;
135
+
136
+ const fill = functor(fillProp);
137
+ const stroke = functor(strokeProp);
138
+ const wickStroke = functor(wickStrokeProp);
139
+ const widthFunctor = functor(this.props.width);
140
+ const width = widthFunctor(this.props, {
141
+ xScale,
142
+ xAccessor,
143
+ plotData,
144
+ });
145
+
146
+ const offset = 0.5 * width;
147
+
148
+ return plotData
149
+ .filter((d) => {
150
+ const ohlc = yAccessor(d);
151
+ if (ohlc === undefined) {
152
+ return false;
153
+ }
154
+
155
+ return true;
156
+ })
157
+ .map((d) => {
158
+ const ohlc = yAccessor(d);
159
+ if (ohlc === undefined) {
160
+ return undefined;
161
+ }
162
+
163
+ const xValue = xAccessor(d);
164
+ const x = xScale(xValue);
165
+ const y = Math.round(yScale(Math.max(ohlc.open, ohlc.close)));
166
+ const height = Math.max(1, Math.round(Math.abs(yScale(ohlc.open) - yScale(ohlc.close))));
167
+
168
+ return {
169
+ x: x - offset,
170
+ y,
171
+ wick: {
172
+ stroke: wickStroke(ohlc),
173
+ x,
174
+ y1: Math.round(yScale(ohlc.high)),
175
+ y2: y,
176
+ y3: y + height,
177
+ y4: Math.round(yScale(ohlc.low)),
178
+ },
179
+ height,
180
+ width: offset * 2,
181
+ fill: fill(ohlc),
182
+ stroke: stroke(ohlc),
183
+ direction: ohlc.close - ohlc.open,
184
+ };
185
+ })
186
+ .filter((d) => d !== undefined) as ICandle[];
187
+ };
188
+ }
@@ -0,0 +1,99 @@
1
+ import { strokeDashTypes } from "@tradingaction/core";
2
+ import * as React from "react";
3
+ import { OverlayBarSeries } from "./OverlayBarSeries";
4
+ import { StraightLine } from "./StraightLine";
5
+
6
+ export interface ElderRaySeriesProps {
7
+ readonly fillStyle?: {
8
+ bearPower: string;
9
+ bullPower: string;
10
+ };
11
+ readonly className?: string;
12
+ readonly clip?: boolean;
13
+ readonly stroke?: boolean;
14
+ readonly straightLineStrokeStyle?: string;
15
+ readonly straightLineStrokeDasharray?: strokeDashTypes;
16
+ readonly widthRatio?: number;
17
+ readonly yAccessor: (data: any) => { bearPower: number; bullPower: number };
18
+ }
19
+
20
+ /**
21
+ * This indicator consists of three separate indicators
22
+ * known as "bull power" and "bear power", which are derived from a 13-period
23
+ * exponential moving average (EMA). The three indicator help traders determine
24
+ * the trend direction and isolate spots to enter and exit trades.
25
+ */
26
+ export class ElderRaySeries extends React.Component<ElderRaySeriesProps> {
27
+ public static defaultProps = {
28
+ fillStyle: {
29
+ bearPower: "rgba(239, 83, 80, 0.7)",
30
+ bullPower: "rgba(38, 166, 153, 0.7)",
31
+ },
32
+ className: "react-financial-charts-elderray-series",
33
+ clip: true,
34
+ stroke: true,
35
+ straightLineStrokeStyle: "rgba(0, 0, 0, 0.7)",
36
+ straightLineStrokeDasharray: "Dash",
37
+ widthRatio: 0.8,
38
+ };
39
+
40
+ public render() {
41
+ const { className, clip, stroke, straightLineStrokeStyle, straightLineStrokeDasharray, widthRatio } =
42
+ this.props;
43
+
44
+ return (
45
+ <g className={className}>
46
+ <OverlayBarSeries
47
+ baseAt={this.yAccessorForBarBase}
48
+ stroke={stroke}
49
+ fillStyle={this.fillForEachBar}
50
+ widthRatio={widthRatio}
51
+ clip={clip}
52
+ yAccessor={[
53
+ this.yAccessorBullTop,
54
+ this.yAccessorBearTop,
55
+ this.yAccessorBullBottom,
56
+ this.yAccessorBearBottom,
57
+ ]}
58
+ />
59
+ <StraightLine yValue={0} strokeStyle={straightLineStrokeStyle} lineDash={straightLineStrokeDasharray} />
60
+ </g>
61
+ );
62
+ }
63
+
64
+ private readonly yAccessorBullTop = (d: any) => {
65
+ const { yAccessor } = this.props;
66
+ return yAccessor(d) && (yAccessor(d).bullPower > 0 ? yAccessor(d).bullPower : undefined);
67
+ };
68
+
69
+ private readonly yAccessorBearTop = (d: any) => {
70
+ const { yAccessor } = this.props;
71
+ return yAccessor(d) && (yAccessor(d).bearPower > 0 ? yAccessor(d).bearPower : undefined);
72
+ };
73
+
74
+ private readonly yAccessorBullBottom = (d: any) => {
75
+ const { yAccessor } = this.props;
76
+ return yAccessor(d) && (yAccessor(d).bullPower < 0 ? 0 : undefined);
77
+ };
78
+
79
+ private readonly yAccessorBearBottom = (d: any) => {
80
+ const { yAccessor } = this.props;
81
+ return (
82
+ yAccessor(d) &&
83
+ (yAccessor(d).bullPower < 0 || yAccessor(d).bullPower * yAccessor(d).bearPower < 0 // bullPower is +ve and bearPower is -ve
84
+ ? Math.min(0, yAccessor(d).bullPower)
85
+ : undefined)
86
+ );
87
+ };
88
+
89
+ private readonly yAccessorForBarBase = (_: any, yScale: any, d: any) => {
90
+ const { yAccessor } = this.props;
91
+ const y = yAccessor(d) && Math.min(yAccessor(d).bearPower, 0);
92
+ return yScale(y);
93
+ };
94
+
95
+ private readonly fillForEachBar = (_: any, yAccessorNumber: number) => {
96
+ const { fillStyle } = this.props;
97
+ return yAccessorNumber % 2 === 0 ? fillStyle!.bullPower : fillStyle!.bearPower;
98
+ };
99
+ }
@@ -0,0 +1,48 @@
1
+ import { getAxisCanvas, GenericChartComponent } from "@tradingaction/core";
2
+ import { ScaleContinuousNumeric, ScaleTime } from "d3-scale";
3
+ import * as React from "react";
4
+ import { drawOnCanvasHelper, identityStack, StackedBarSeries } from "./StackedBarSeries";
5
+
6
+ export interface GroupedBarSeriesProps {
7
+ readonly baseAt:
8
+ | number
9
+ | ((
10
+ xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>,
11
+ yScale: ScaleContinuousNumeric<number, number>,
12
+ datum: any,
13
+ ) => number);
14
+ readonly direction: "up" | "down";
15
+ readonly fillStyle?: string | ((data: any) => string);
16
+ readonly spaceBetweenBar?: number;
17
+ readonly stroke: boolean;
18
+ readonly widthRatio?: number;
19
+ readonly yAccessor: ((data: any) => number | undefined) | ((d: any) => number)[];
20
+ }
21
+
22
+ export class GroupedBarSeries extends React.Component<GroupedBarSeriesProps> {
23
+ public static defaultProps = {
24
+ ...StackedBarSeries.defaultProps,
25
+ spaceBetweenBar: 5,
26
+ widthRatio: 0.8,
27
+ };
28
+
29
+ public render() {
30
+ return <GenericChartComponent canvasDraw={this.drawOnCanvas} canvasToDraw={getAxisCanvas} drawOn={["pan"]} />;
31
+ }
32
+
33
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
34
+ const { xAccessor } = moreProps;
35
+
36
+ drawOnCanvasHelper(ctx, this.props, moreProps, xAccessor, identityStack, this.postProcessor);
37
+ };
38
+
39
+ private readonly postProcessor = (array: any[]) => {
40
+ return array.map((each) => {
41
+ return {
42
+ ...each,
43
+ x: each.x + each.offset - each.groupOffset,
44
+ width: each.groupWidth,
45
+ };
46
+ });
47
+ };
48
+ }