@oanda/labs-crowd-view-widget 1.0.30 → 1.0.32

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 (50) hide show
  1. package/CHANGELOG.md +260 -0
  2. package/dist/main/CrowdViewWidget/Main.js +1 -0
  3. package/dist/main/CrowdViewWidget/Main.js.map +1 -1
  4. package/dist/main/CrowdViewWidget/components/Chart/Chart.js +68 -2
  5. package/dist/main/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
  6. package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js +7 -3
  7. package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
  8. package/dist/main/CrowdViewWidget/components/Chart/constants.js +4 -1
  9. package/dist/main/CrowdViewWidget/components/Chart/constants.js.map +1 -1
  10. package/dist/main/CrowdViewWidget/components/Chart/getOption.js +44 -12
  11. package/dist/main/CrowdViewWidget/components/Chart/getOption.js.map +1 -1
  12. package/dist/main/CrowdViewWidget/components/Chart/types.js.map +1 -1
  13. package/dist/main/CrowdViewWidget/components/Chart/utils.js +103 -16
  14. package/dist/main/CrowdViewWidget/components/Chart/utils.js.map +1 -1
  15. package/dist/main/CrowdViewWidget/config.js +10 -4
  16. package/dist/main/CrowdViewWidget/config.js.map +1 -1
  17. package/dist/main/CrowdViewWidget/types.js +22 -5
  18. package/dist/main/CrowdViewWidget/types.js.map +1 -1
  19. package/dist/module/CrowdViewWidget/Main.js +1 -0
  20. package/dist/module/CrowdViewWidget/Main.js.map +1 -1
  21. package/dist/module/CrowdViewWidget/components/Chart/Chart.js +70 -4
  22. package/dist/module/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
  23. package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js +7 -3
  24. package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
  25. package/dist/module/CrowdViewWidget/components/Chart/constants.js +3 -0
  26. package/dist/module/CrowdViewWidget/components/Chart/constants.js.map +1 -1
  27. package/dist/module/CrowdViewWidget/components/Chart/getOption.js +46 -14
  28. package/dist/module/CrowdViewWidget/components/Chart/getOption.js.map +1 -1
  29. package/dist/module/CrowdViewWidget/components/Chart/types.js.map +1 -1
  30. package/dist/module/CrowdViewWidget/components/Chart/utils.js +100 -15
  31. package/dist/module/CrowdViewWidget/components/Chart/utils.js.map +1 -1
  32. package/dist/module/CrowdViewWidget/config.js +10 -4
  33. package/dist/module/CrowdViewWidget/config.js.map +1 -1
  34. package/dist/module/CrowdViewWidget/types.js +21 -4
  35. package/dist/module/CrowdViewWidget/types.js.map +1 -1
  36. package/dist/types/CrowdViewWidget/components/Chart/ChartWithData.d.ts +1 -1
  37. package/dist/types/CrowdViewWidget/components/Chart/constants.d.ts +3 -0
  38. package/dist/types/CrowdViewWidget/components/Chart/types.d.ts +11 -1
  39. package/dist/types/CrowdViewWidget/components/Chart/utils.d.ts +26 -1
  40. package/dist/types/CrowdViewWidget/types.d.ts +20 -4
  41. package/package.json +3 -3
  42. package/src/CrowdViewWidget/Main.tsx +5 -1
  43. package/src/CrowdViewWidget/components/Chart/Chart.tsx +99 -2
  44. package/src/CrowdViewWidget/components/Chart/ChartWithData.tsx +7 -3
  45. package/src/CrowdViewWidget/components/Chart/constants.tsx +4 -0
  46. package/src/CrowdViewWidget/components/Chart/getOption.ts +72 -19
  47. package/src/CrowdViewWidget/components/Chart/types.ts +13 -2
  48. package/src/CrowdViewWidget/components/Chart/utils.ts +110 -11
  49. package/src/CrowdViewWidget/config.ts +12 -4
  50. package/src/CrowdViewWidget/types.ts +21 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oanda/labs-crowd-view-widget",
3
- "version": "1.0.30",
3
+ "version": "1.0.32",
4
4
  "description": "Labs Crowd View Widget",
5
5
  "main": "dist/main/index.js",
6
6
  "module": "dist/module/index.js",
@@ -12,7 +12,7 @@
12
12
  "author": "OANDA",
13
13
  "license": "UNLICENSED",
14
14
  "dependencies": {
15
- "@oanda/labs-widget-common": "^1.0.212",
15
+ "@oanda/labs-widget-common": "^1.0.214",
16
16
  "@oanda/mono-i18n": "10.0.1",
17
17
  "graphql": "16.8.1"
18
18
  },
@@ -20,5 +20,5 @@
20
20
  "@graphql-codegen/cli": "5.0.0",
21
21
  "@graphql-codegen/client-preset": "4.1.0"
22
22
  },
23
- "gitHead": "53a43d8d60d462d74949c32e30a75b09e86f659d"
23
+ "gitHead": "a23750aa48956806673092c040ba5df282b4de0d"
24
24
  }
@@ -83,7 +83,11 @@ const Main = ({ division }: MainProps) => {
83
83
  </div>
84
84
  </div>
85
85
 
86
- <ChartWithData bookType={bookType} instrument={instrument.id} />
86
+ <ChartWithData
87
+ bookType={bookType}
88
+ granularity={granularity.id}
89
+ instrument={instrument.id}
90
+ />
87
91
 
88
92
  <Legend
89
93
  longValues={[0.15, 0.25, 0.4, 0.55]}
@@ -10,15 +10,17 @@ import {
10
10
  DataZoomInsideComponent,
11
11
  GraphicComponent,
12
12
  GridSimpleComponent,
13
+ MarkPointComponent,
13
14
  TooltipComponent,
14
15
  } from 'echarts/components';
15
16
  import * as echarts from 'echarts/core';
16
17
  import { CanvasRenderer } from 'echarts/renderers';
17
18
  import React, { useEffect, useRef } from 'react';
18
19
 
19
- import { CHART_HEIGHT } from './constants';
20
+ import { CHART_HEIGHT, MAX_LABELS_COUNT } from './constants';
20
21
  import { getDesktopOption, getOption } from './getOption';
21
22
  import type { ChartProps } from './types';
23
+ import { getLabelData, isDifferenceGreaterThanTwoWeeks } from './utils';
22
24
 
23
25
  echarts.use([
24
26
  GridSimpleComponent,
@@ -29,6 +31,7 @@ echarts.use([
29
31
  CustomChart,
30
32
  TooltipComponent,
31
33
  CandlestickChart,
34
+ MarkPointComponent,
32
35
  ]);
33
36
 
34
37
  echarts.registerTheme('dark_theme', getChartTheme(Theme.Dark));
@@ -43,8 +46,101 @@ const Chart = ({ data }: ChartProps) => {
43
46
  const echartInstance = echartRef.current.getEchartsInstance();
44
47
 
45
48
  echartInstance.setOption(getDesktopOption({ isDark }));
49
+
50
+ echartInstance.off('datazoom');
51
+ echartInstance.on('datazoom', () => {
52
+ const {
53
+ dataZoom,
54
+ // @ts-ignore
55
+ title: { text },
56
+ } = echartInstance.getOption();
57
+
58
+ const { start, end } = (
59
+ dataZoom as { start: number; end: number }[]
60
+ )[0];
61
+ const prevInterval = Number((text as string).split(',')[0]);
62
+ const prevIsGreaterThanTwoWeeks = Boolean(
63
+ Number((text as string).split(',')[1])
64
+ );
65
+
66
+ const visibleItemsCount = Math.round(
67
+ (data.xAxisData.length * (end - start)) / 100
68
+ );
69
+
70
+ const interval =
71
+ visibleItemsCount > MAX_LABELS_COUNT
72
+ ? Math.floor(visibleItemsCount / MAX_LABELS_COUNT)
73
+ : 0;
74
+
75
+ if (interval !== prevInterval) {
76
+ echartInstance.setOption({
77
+ xAxis: {
78
+ axisLabel: {
79
+ interval,
80
+ },
81
+ },
82
+ });
83
+ }
84
+
85
+ const visibleXAxisData = data.xAxisData.slice(
86
+ (data.xAxisData.length * start) / 100,
87
+ (data.xAxisData.length * end) / 100
88
+ );
89
+
90
+ const isGreaterThanTwoWeeks = isDifferenceGreaterThanTwoWeeks(
91
+ visibleXAxisData[0],
92
+ visibleXAxisData[visibleXAxisData.length - 1]
93
+ );
94
+
95
+ if (isGreaterThanTwoWeeks !== prevIsGreaterThanTwoWeeks) {
96
+ const labelsData = getLabelData({
97
+ xAxisData: data.xAxisData,
98
+ isGreaterThanTwoWeeks,
99
+ });
100
+
101
+ echartInstance.setOption({
102
+ series: [
103
+ {
104
+ id: 'candlestick',
105
+ markPoint: {
106
+ data: labelsData,
107
+ },
108
+ },
109
+ ],
110
+ });
111
+
112
+ echartInstance.setOption({
113
+ xAxis: {
114
+ axisLabel: {
115
+ formatter: (value: string) => {
116
+ const date = new Date(value);
117
+ return isGreaterThanTwoWeeks
118
+ ? `${date.toLocaleTimeString(undefined, {
119
+ hour: '2-digit',
120
+ minute: '2-digit',
121
+ })}`
122
+ : `${date.toLocaleDateString(undefined, {
123
+ day: 'numeric',
124
+ })}`;
125
+ },
126
+ },
127
+ },
128
+ });
129
+ }
130
+
131
+ if (
132
+ interval !== prevInterval ||
133
+ isGreaterThanTwoWeeks !== prevIsGreaterThanTwoWeeks
134
+ ) {
135
+ echartInstance.setOption({
136
+ title: {
137
+ text: `${interval},${isGreaterThanTwoWeeks ? 1 : 0}`,
138
+ },
139
+ });
140
+ }
141
+ });
46
142
  }
47
- }, [echartRef, isDark]);
143
+ }, [echartRef, isDark, data]);
48
144
 
49
145
  return (
50
146
  <BaseChart
@@ -52,6 +148,7 @@ const Chart = ({ data }: ChartProps) => {
52
148
  chartHeight={CHART_HEIGHT}
53
149
  echarts={echarts}
54
150
  isDark={isDark}
151
+ lazyUpdate={true}
55
152
  option={getOption(data)}
56
153
  />
57
154
  );
@@ -18,7 +18,11 @@ import { Chart } from './Chart';
18
18
  import type { ChartWithDataProps } from './types';
19
19
  import { transformDataForChart } from './utils';
20
20
 
21
- const ChartWithData = ({ instrument, bookType }: ChartWithDataProps) => {
21
+ const ChartWithData = ({
22
+ instrument,
23
+ bookType,
24
+ granularity,
25
+ }: ChartWithDataProps) => {
22
26
  const { size } = useLayoutProvider();
23
27
  const isDesktop = size === Size.DESKTOP;
24
28
 
@@ -38,8 +42,8 @@ const ChartWithData = ({ instrument, bookType }: ChartWithDataProps) => {
38
42
 
39
43
  const transformedData = useMemo(() => {
40
44
  if (!data) return undefined;
41
- return transformDataForChart(data);
42
- }, [data]);
45
+ return transformDataForChart({ data, granularity });
46
+ }, [data, granularity]);
43
47
 
44
48
  return (
45
49
  <>
@@ -2,3 +2,7 @@ export const X_LABEL_SIZE = 40;
2
2
  export const Y_LABEL_SIZE_DESKTOP = 60;
3
3
  export const CHART_WIDTH = 9999;
4
4
  export const CHART_HEIGHT = 425;
5
+
6
+ export const INITIAL_START_ZOOM = 80;
7
+ export const INITIAL_END_ZOOM = 100;
8
+ export const MAX_LABELS_COUNT = 14;
@@ -8,11 +8,18 @@ import * as echarts from 'echarts/core';
8
8
  import {
9
9
  CHART_HEIGHT,
10
10
  CHART_WIDTH,
11
+ INITIAL_END_ZOOM,
12
+ INITIAL_START_ZOOM,
13
+ MAX_LABELS_COUNT,
11
14
  X_LABEL_SIZE,
12
15
  Y_LABEL_SIZE_DESKTOP,
13
16
  } from './constants';
14
17
  import type { GetOptionType, GetResponsiveOptionsProps } from './types';
15
- import { getRectColor } from './utils';
18
+ import {
19
+ getLabelData,
20
+ getRectColor,
21
+ isDifferenceGreaterThanTwoWeeks,
22
+ } from './utils';
16
23
 
17
24
  export const getDesktopOption = ({ isDark }: GetResponsiveOptionsProps) => {
18
25
  const desktopGridLines = getGridLines({
@@ -60,31 +67,66 @@ export const getDesktopOption = ({ isDark }: GetResponsiveOptionsProps) => {
60
67
  };
61
68
  };
62
69
 
70
+ // @ts-ignore
63
71
  export const getOption: GetOptionType = ({
64
72
  xAxisData,
65
73
  ordersPositionsChartData,
66
74
  ordersPositionsBucketWidth,
67
75
  candlesSeriesData,
68
76
  }) => {
77
+ const visibleXAxisData = xAxisData.slice(
78
+ (xAxisData.length * INITIAL_START_ZOOM) / 100,
79
+ (xAxisData.length * INITIAL_END_ZOOM) / 100
80
+ );
81
+
82
+ const isGreaterThanTwoWeeks = isDifferenceGreaterThanTwoWeeks(
83
+ visibleXAxisData[0],
84
+ visibleXAxisData[visibleXAxisData.length - 1]
85
+ );
86
+ const labelsData = getLabelData({
87
+ xAxisData,
88
+ isGreaterThanTwoWeeks,
89
+ });
90
+
91
+ const visibleItemsCount = Math.round(
92
+ (xAxisData.length * (INITIAL_END_ZOOM - INITIAL_START_ZOOM)) / 100
93
+ );
94
+
95
+ const initialInterval =
96
+ visibleItemsCount > MAX_LABELS_COUNT
97
+ ? Math.floor(visibleItemsCount / MAX_LABELS_COUNT)
98
+ : 0;
99
+
69
100
  return {
101
+ title: {
102
+ show: false,
103
+ text: `${initialInterval},${isGreaterThanTwoWeeks}`,
104
+ },
70
105
  animation: false,
71
106
  dataZoom: [
72
107
  {
73
108
  type: 'inside',
74
109
  xAxisIndex: 0,
75
- start: 80,
76
- end: 100,
77
- },
78
- {
79
- type: 'inside',
80
- yAxisIndex: 0,
81
- startValue: 1.5,
82
- endValue: 1.7,
110
+ start: INITIAL_START_ZOOM,
111
+ end: INITIAL_END_ZOOM,
83
112
  },
84
113
  ],
85
114
  tooltip: {
86
115
  trigger: 'axis',
87
- formatter: '{c}',
116
+ formatter: (val) => {
117
+ // @ts-ignore
118
+ const timestamp = val[0].axisValue as string;
119
+
120
+ return `${new Date(timestamp).toLocaleTimeString(undefined, {
121
+ hour: '2-digit',
122
+ minute: '2-digit',
123
+ })}
124
+ ${new Date(timestamp).toLocaleDateString(undefined, {
125
+ day: 'numeric',
126
+ month: 'short',
127
+ })}
128
+ `;
129
+ },
88
130
  },
89
131
  xAxis: {
90
132
  type: 'category',
@@ -95,16 +137,24 @@ export const getOption: GetOptionType = ({
95
137
  axisLabel: {
96
138
  padding: [8, 16, 8, 16],
97
139
  margin: 0,
98
- formatter: (value) =>
99
- `${new Date(value).toLocaleTimeString(undefined, {
100
- hour: '2-digit',
101
- minute: '2-digit',
102
- })}`,
140
+ interval: initialInterval,
141
+ formatter: (value) => {
142
+ const date = new Date(value);
143
+ return isGreaterThanTwoWeeks
144
+ ? `${date.toLocaleTimeString(undefined, {
145
+ hour: '2-digit',
146
+ minute: '2-digit',
147
+ })}`
148
+ : `${date.toLocaleDateString(undefined, {
149
+ day: 'numeric',
150
+ })}`;
151
+ },
103
152
  },
104
153
  },
105
154
  yAxis: {
106
155
  type: 'value',
107
156
  position: 'right',
157
+ scale: true,
108
158
  axisLine: { show: false },
109
159
  axisTick: { show: false },
110
160
  axisLabel: {
@@ -115,36 +165,39 @@ export const getOption: GetOptionType = ({
115
165
  series: [
116
166
  {
117
167
  type: 'candlestick',
168
+ id: 'candlestick',
118
169
  data: candlesSeriesData,
119
170
  itemStyle: {
120
171
  color: colorPalette.raspberryLight,
121
172
  color0: colorPalette.bottleGreenLight,
122
173
  },
174
+ markPoint: {
175
+ symbol: 'circle',
176
+ symbolSize: 0,
177
+ data: labelsData,
178
+ },
123
179
  },
124
180
  {
125
181
  type: 'custom',
126
182
  name: 'heatmap',
183
+ id: 'heatmap',
127
184
  silent: true,
128
185
  renderItem: (params, api) => {
129
186
  const { coordSys } = params;
130
-
131
187
  const xVal = api.value(0);
132
188
  const yVal = api.value(1);
133
189
  const sentiment = api.value(2) as number;
134
190
  const start = api.coord([xVal, yVal]);
135
-
136
191
  const [rectWidth, rectHeight] = api.size!([
137
192
  0,
138
193
  ordersPositionsBucketWidth,
139
194
  ]) as number[];
140
-
141
195
  const boundaries = coordSys as unknown as {
142
196
  x: number;
143
197
  y: number;
144
198
  width: number;
145
199
  height: number;
146
200
  };
147
-
148
201
  const shape = echarts.graphic.clipRectByRect(
149
202
  {
150
203
  x: start[0] - rectWidth / 2,
@@ -2,6 +2,7 @@ import type { GetOrderPositionBooksQuery } from '@oanda/labs-order-book-widget/s
2
2
  import type { EChartsOption } from 'echarts';
3
3
 
4
4
  import type { BookType } from '../../../gql/types/graphql';
5
+ import type { GranularityId } from '../../types';
5
6
 
6
7
  interface ChartOptionsProps {
7
8
  xAxisData: string[];
@@ -18,7 +19,6 @@ interface ChartOptionsProps {
18
19
  }
19
20
 
20
21
  export type GetOptionType = (props: ChartOptionsProps) => EChartsOption;
21
-
22
22
  export interface GetResponsiveOptionsProps {
23
23
  isDark: boolean;
24
24
  }
@@ -30,8 +30,19 @@ export interface ChartProps {
30
30
  export interface ChartWithDataProps {
31
31
  bookType: BookType;
32
32
  instrument: string;
33
+ granularity: GranularityId;
34
+ }
35
+
36
+ interface TransformDataForChartTypeProps {
37
+ data: GetOrderPositionBooksQuery;
38
+ granularity: GranularityId;
33
39
  }
34
40
 
35
41
  export type TransformDataForChartType = (
36
- props: GetOrderPositionBooksQuery
42
+ props: TransformDataForChartTypeProps
37
43
  ) => ChartOptionsProps;
44
+
45
+ export interface GetLabelsDataProps {
46
+ xAxisData: string[];
47
+ isGreaterThanTwoWeeks: boolean;
48
+ }
@@ -1,7 +1,9 @@
1
1
  import type { GetOrderPositionBooksQuery } from '../../../gql/types/graphql';
2
2
  import { colorMap } from '../../config';
3
+ import { TimeSpanId } from '../../types';
4
+ import { CHART_HEIGHT } from './constants';
3
5
  import { getPriceCandlesMock } from './getPriceCandlesMock';
4
- import type { TransformDataForChartType } from './types';
6
+ import type { GetLabelsDataProps, TransformDataForChartType } from './types';
5
7
 
6
8
  export const getRectColor = (sentiment: number) => {
7
9
  const colors = sentiment < 0 ? colorMap.short : colorMap.long;
@@ -26,14 +28,55 @@ export const getRectColor = (sentiment: number) => {
26
28
  return 'transparent';
27
29
  };
28
30
 
31
+ export enum GranularityId {
32
+ MINUTE_5 = 'MINUTE_5',
33
+ MINUTE_15 = 'MINUTE_15',
34
+ MINUTE_30 = 'MINUTE_30',
35
+ HOUR_1 = 'HOUR_1',
36
+ HOUR_4 = 'HOUR_4',
37
+ DAY_1 = 'DAY_1',
38
+ }
39
+
40
+ const timeSpansInMilliseconds: Record<TimeSpanId, number> = {
41
+ [TimeSpanId.HOUR_1]: 60 * 60 * 1000,
42
+ [TimeSpanId.HOUR_12]: 12 * 60 * 60 * 1000,
43
+ [TimeSpanId.DAY_1]: 24 * 60 * 60 * 1000,
44
+ [TimeSpanId.DAY_2]: 2 * 24 * 60 * 60 * 1000,
45
+ [TimeSpanId.WEEK_1]: 7 * 24 * 60 * 60 * 1000,
46
+ [TimeSpanId.WEEK_2]: 14 * 24 * 60 * 60 * 1000,
47
+ [TimeSpanId.WEEK_3]: 21 * 24 * 60 * 60 * 1000,
48
+ [TimeSpanId.MONTH_1]: 30 * 24 * 60 * 60 * 1000, // Approximation
49
+ [TimeSpanId.MONTH_3]: 3 * 30 * 24 * 60 * 60 * 1000, // Approximation
50
+ [TimeSpanId.MONTH_6]: 6 * 30 * 24 * 60 * 60 * 1000, // Approximation
51
+ [TimeSpanId.YEAR_1]: 365 * 24 * 60 * 60 * 1000, // Approximation
52
+ [TimeSpanId.YEAR_5]: 5 * 365 * 24 * 60 * 60 * 1000, // Approximation
53
+ };
54
+
55
+ const granularityInMilliseconds: Record<GranularityId, number> = {
56
+ [GranularityId.MINUTE_5]: 5 * 60 * 1000,
57
+ [GranularityId.MINUTE_15]: 15 * 60 * 1000,
58
+ [GranularityId.MINUTE_30]: 30 * 60 * 1000,
59
+ [GranularityId.HOUR_1]: 60 * 60 * 1000,
60
+ [GranularityId.HOUR_4]: 4 * 60 * 60 * 1000,
61
+ [GranularityId.DAY_1]: 24 * 60 * 60 * 1000,
62
+ };
63
+
64
+ const temporaryGranularityTimeSpanMap: Record<GranularityId, TimeSpanId> = {
65
+ [GranularityId.MINUTE_5]: TimeSpanId.DAY_2,
66
+ [GranularityId.MINUTE_15]: TimeSpanId.WEEK_1,
67
+ [GranularityId.MINUTE_30]: TimeSpanId.WEEK_2,
68
+ [GranularityId.HOUR_1]: TimeSpanId.MONTH_1,
69
+ [GranularityId.HOUR_4]: TimeSpanId.MONTH_3,
70
+ [GranularityId.DAY_1]: TimeSpanId.MONTH_6,
71
+ };
72
+
29
73
  const mockOrderPositionDataForHistoricalData = (
30
- data: GetOrderPositionBooksQuery
74
+ data: GetOrderPositionBooksQuery,
75
+ granularityId: GranularityId
31
76
  ) => {
32
- const oneMinuteInMilliseconds = 60000;
33
- const granularity = oneMinuteInMilliseconds * 5; // 5min
34
- const timeSpan = oneMinuteInMilliseconds * 60 * 24; // 24h
35
- // const timeSpan = oneMinuteInMilliseconds * 60 * 6 // 6h
36
- // const timeSpan = oneMinuteInMilliseconds * 15 //15min
77
+ const granularity = granularityInMilliseconds[granularityId];
78
+ const timeSpan =
79
+ timeSpansInMilliseconds[temporaryGranularityTimeSpanMap[granularityId]];
37
80
 
38
81
  const currentTime = data.orderPositionBooks[0]!.time;
39
82
 
@@ -50,13 +93,68 @@ const mockOrderPositionDataForHistoricalData = (
50
93
  buckets: data.orderPositionBooks[0]!.buckets,
51
94
  bucketWidth: data.orderPositionBooks[0]!.bucketWidth,
52
95
  };
53
- });
96
+ })
97
+ .reverse();
54
98
 
55
99
  return orderPositionDataForHistorical;
56
100
  };
57
101
 
58
- export const transformDataForChart: TransformDataForChartType = (data) => {
59
- const mockedData = mockOrderPositionDataForHistoricalData(data);
102
+ export const getLabelData = ({
103
+ xAxisData,
104
+ isGreaterThanTwoWeeks,
105
+ }: GetLabelsDataProps) =>
106
+ xAxisData
107
+ .filter((record, index, arr) => {
108
+ if (index === 0) {
109
+ return false;
110
+ }
111
+ const previousTimestamp = arr[index - 1];
112
+ const currentDate = new Date(record);
113
+ const previousDate = new Date(previousTimestamp);
114
+
115
+ return isGreaterThanTwoWeeks
116
+ ? currentDate.getDate() !== previousDate.getDate()
117
+ : currentDate.getMonth() !== previousDate.getMonth();
118
+ })
119
+ .map((item) => ({
120
+ name: new Date(item).toLocaleDateString(undefined, {
121
+ month: 'short',
122
+ day: isGreaterThanTwoWeeks ? 'numeric' : undefined,
123
+ }),
124
+ xAxis: item,
125
+ y: CHART_HEIGHT - 22,
126
+ silent: true,
127
+ emphasis: {
128
+ disabled: true,
129
+ },
130
+ label: {
131
+ fontFamily: 'Sofia W03',
132
+ fontSize: 10,
133
+ position: 'bottom',
134
+ align: 'center',
135
+ formatter: '{b}',
136
+ },
137
+ }));
138
+
139
+ export const isDifferenceGreaterThanTwoWeeks = (
140
+ startDate: string,
141
+ endDate: string
142
+ ) => {
143
+ const date1 = new Date(startDate);
144
+ const date2 = new Date(endDate);
145
+
146
+ const TWO_WEEKS_IN_MS = 14 * 24 * 60 * 60 * 1000;
147
+
148
+ const differenceInMs = Math.abs(date2.getTime() - date1.getTime());
149
+
150
+ return differenceInMs < TWO_WEEKS_IN_MS;
151
+ };
152
+
153
+ export const transformDataForChart: TransformDataForChartType = ({
154
+ data,
155
+ granularity,
156
+ }) => {
157
+ const mockedData = mockOrderPositionDataForHistoricalData(data, granularity);
60
158
 
61
159
  const xAxisData = mockedData.map(({ time }) => time);
62
160
  const ordersPositionsChartData = mockedData
@@ -70,7 +168,7 @@ export const transformDataForChart: TransformDataForChartType = (data) => {
70
168
  )
71
169
  .filter((item) => Math.abs(item[2]) > 0.15);
72
170
 
73
- const mockedCandles = getPriceCandlesMock(ordersPositionsChartData.length);
171
+ const mockedCandles = getPriceCandlesMock(xAxisData.length);
74
172
 
75
173
  const candlesSeriesData: [number, number, number, number][] =
76
174
  mockedCandles.map(({ close, open, low, high }) => [
@@ -85,5 +183,6 @@ export const transformDataForChart: TransformDataForChartType = (data) => {
85
183
  ordersPositionsChartData,
86
184
  ordersPositionsBucketWidth: mockedData[0]!.bucketWidth,
87
185
  candlesSeriesData,
186
+ granularity,
88
187
  };
89
188
  };
@@ -105,19 +105,27 @@ const instrumentPrecisionConfig: Record<InstrumentId, number> = {
105
105
 
106
106
  const granularitySelectConfig = [
107
107
  {
108
- id: GranularityId.M5,
108
+ id: GranularityId.MINUTE_5,
109
109
  label: '5_minutes',
110
110
  },
111
111
  {
112
- id: GranularityId.M15,
112
+ id: GranularityId.MINUTE_15,
113
113
  label: '15_minutes',
114
114
  },
115
115
  {
116
- id: GranularityId.H1,
116
+ id: GranularityId.MINUTE_30,
117
+ label: '30_minutes',
118
+ },
119
+ {
120
+ id: GranularityId.HOUR_1,
117
121
  label: '1_hour',
118
122
  },
119
123
  {
120
- id: GranularityId.D1,
124
+ id: GranularityId.HOUR_4,
125
+ label: '4_hours',
126
+ },
127
+ {
128
+ id: GranularityId.DAY_1,
121
129
  label: '1_day',
122
130
  },
123
131
  ];
@@ -29,10 +29,27 @@ export enum InstrumentId {
29
29
  }
30
30
 
31
31
  export enum GranularityId {
32
- M5 = '5M',
33
- M15 = '15M',
34
- H1 = '1H',
35
- D1 = '1D',
32
+ MINUTE_5 = 'MINUTE_5',
33
+ MINUTE_15 = 'MINUTE_15',
34
+ MINUTE_30 = 'MINUTE_30',
35
+ HOUR_1 = 'HOUR_1',
36
+ HOUR_4 = 'HOUR_4',
37
+ DAY_1 = 'DAY_1',
38
+ }
39
+
40
+ export enum TimeSpanId {
41
+ HOUR_1 = 'HOUR_1',
42
+ HOUR_12 = 'HOUR_12',
43
+ DAY_1 = 'DAY_1',
44
+ DAY_2 = 'DAY_2',
45
+ WEEK_1 = 'WEEK_1',
46
+ WEEK_2 = 'WEEK_2',
47
+ WEEK_3 = 'WEEK_3',
48
+ MONTH_1 = 'MONTH_1',
49
+ MONTH_3 = 'MONTH_3',
50
+ MONTH_6 = 'MONTH_6',
51
+ YEAR_1 = 'YEAR_1',
52
+ YEAR_5 = 'YEAR_5',
36
53
  }
37
54
 
38
55
  export interface OrdersPositionsData {