@oanda/labs-crowd-view-widget 1.0.51 → 1.0.52

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 (88) hide show
  1. package/CHANGELOG.md +212 -0
  2. package/dist/main/CrowdViewWidget/components/Chart/Chart.js +60 -21
  3. package/dist/main/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
  4. package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js +3 -3
  5. package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
  6. package/dist/main/CrowdViewWidget/components/Chart/chartOptions.js +208 -42
  7. package/dist/main/CrowdViewWidget/components/Chart/chartOptions.js.map +1 -1
  8. package/dist/main/CrowdViewWidget/components/Chart/types.js.map +1 -1
  9. package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js +25 -6
  10. package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
  11. package/dist/main/CrowdViewWidget/components/Chart/utils/chartUtils.js +12 -10
  12. package/dist/main/CrowdViewWidget/components/Chart/utils/chartUtils.js.map +1 -1
  13. package/dist/main/CrowdViewWidget/components/Chart/utils/getChartStyles.js +27 -0
  14. package/dist/main/CrowdViewWidget/components/Chart/utils/getChartStyles.js.map +1 -0
  15. package/dist/main/CrowdViewWidget/components/Chart/utils/getGridLines.js +123 -0
  16. package/dist/main/CrowdViewWidget/components/Chart/utils/getGridLines.js.map +1 -0
  17. package/dist/main/CrowdViewWidget/components/Chart/utils/index.js +22 -0
  18. package/dist/main/CrowdViewWidget/components/Chart/utils/index.js.map +1 -1
  19. package/dist/main/CrowdViewWidget/components/Chart/utils/processSentiments.js +28 -0
  20. package/dist/main/CrowdViewWidget/components/Chart/utils/processSentiments.js.map +1 -0
  21. package/dist/main/CrowdViewWidget/components/Legend/Legend.js +1 -1
  22. package/dist/main/CrowdViewWidget/components/Legend/Legend.js.map +1 -1
  23. package/dist/main/CrowdViewWidget/constants.js +13 -3
  24. package/dist/main/CrowdViewWidget/constants.js.map +1 -1
  25. package/dist/main/gql/getSentiments.js +11 -0
  26. package/dist/main/gql/getSentiments.js.map +1 -0
  27. package/dist/main/gql/types/gql.js +2 -1
  28. package/dist/main/gql/types/gql.js.map +1 -1
  29. package/dist/main/gql/types/graphql.js +162 -1
  30. package/dist/main/gql/types/graphql.js.map +1 -1
  31. package/dist/module/CrowdViewWidget/components/Chart/Chart.js +63 -24
  32. package/dist/module/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
  33. package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js +3 -3
  34. package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
  35. package/dist/module/CrowdViewWidget/components/Chart/chartOptions.js +208 -43
  36. package/dist/module/CrowdViewWidget/components/Chart/chartOptions.js.map +1 -1
  37. package/dist/module/CrowdViewWidget/components/Chart/types.js.map +1 -1
  38. package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js +26 -7
  39. package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
  40. package/dist/module/CrowdViewWidget/components/Chart/utils/chartUtils.js +12 -10
  41. package/dist/module/CrowdViewWidget/components/Chart/utils/chartUtils.js.map +1 -1
  42. package/dist/module/CrowdViewWidget/components/Chart/utils/getChartStyles.js +20 -0
  43. package/dist/module/CrowdViewWidget/components/Chart/utils/getChartStyles.js.map +1 -0
  44. package/dist/module/CrowdViewWidget/components/Chart/utils/getGridLines.js +116 -0
  45. package/dist/module/CrowdViewWidget/components/Chart/utils/getGridLines.js.map +1 -0
  46. package/dist/module/CrowdViewWidget/components/Chart/utils/index.js +2 -0
  47. package/dist/module/CrowdViewWidget/components/Chart/utils/index.js.map +1 -1
  48. package/dist/module/CrowdViewWidget/components/Chart/utils/processSentiments.js +21 -0
  49. package/dist/module/CrowdViewWidget/components/Chart/utils/processSentiments.js.map +1 -0
  50. package/dist/module/CrowdViewWidget/components/Legend/Legend.js +1 -1
  51. package/dist/module/CrowdViewWidget/components/Legend/Legend.js.map +1 -1
  52. package/dist/module/CrowdViewWidget/constants.js +12 -2
  53. package/dist/module/CrowdViewWidget/constants.js.map +1 -1
  54. package/dist/module/gql/getSentiments.js +6 -0
  55. package/dist/module/gql/getSentiments.js.map +1 -0
  56. package/dist/module/gql/types/gql.js +2 -1
  57. package/dist/module/gql/types/gql.js.map +1 -1
  58. package/dist/module/gql/types/graphql.js +161 -0
  59. package/dist/module/gql/types/graphql.js.map +1 -1
  60. package/dist/types/CrowdViewWidget/components/Chart/types.d.ts +43 -0
  61. package/dist/types/CrowdViewWidget/components/Chart/utils/chartUtils.d.ts +2 -2
  62. package/dist/types/CrowdViewWidget/components/Chart/utils/getChartStyles.d.ts +10 -0
  63. package/dist/types/CrowdViewWidget/components/Chart/utils/getGridLines.d.ts +97 -0
  64. package/dist/types/CrowdViewWidget/components/Chart/utils/index.d.ts +2 -0
  65. package/dist/types/CrowdViewWidget/components/Chart/utils/processSentiments.d.ts +3 -0
  66. package/dist/types/CrowdViewWidget/constants.d.ts +11 -1
  67. package/dist/types/gql/getSentiments.d.ts +2 -0
  68. package/dist/types/gql/types/gql.d.ts +9 -0
  69. package/dist/types/gql/types/graphql.d.ts +36 -0
  70. package/package.json +3 -3
  71. package/src/CrowdViewWidget/components/Chart/Chart.tsx +86 -34
  72. package/src/CrowdViewWidget/components/Chart/ChartWithData.tsx +3 -3
  73. package/src/CrowdViewWidget/components/Chart/chartOptions.ts +242 -72
  74. package/src/CrowdViewWidget/components/Chart/types.ts +55 -0
  75. package/src/CrowdViewWidget/components/Chart/useCrowdViewData.ts +35 -3
  76. package/src/CrowdViewWidget/components/Chart/utils/chartUtils.ts +33 -14
  77. package/src/CrowdViewWidget/components/Chart/utils/getChartStyles.ts +42 -0
  78. package/src/CrowdViewWidget/components/Chart/utils/getGridLines.ts +148 -0
  79. package/src/CrowdViewWidget/components/Chart/utils/index.ts +2 -0
  80. package/src/CrowdViewWidget/components/Chart/utils/processSentiments.ts +42 -0
  81. package/src/CrowdViewWidget/components/Legend/Legend.tsx +1 -1
  82. package/src/CrowdViewWidget/constants.ts +17 -1
  83. package/src/gql/getSentiments.ts +25 -0
  84. package/src/gql/types/gql.ts +8 -0
  85. package/src/gql/types/graphql.ts +161 -0
  86. package/test/components/Chart/utils/chartUtils.test.ts +76 -2
  87. package/test/components/Chart/utils/getChartStyles.test.ts +64 -0
  88. package/test/components/Chart/utils/processSentiments.test.ts +130 -0
@@ -3,11 +3,14 @@ import { useMemo } from 'react';
3
3
 
4
4
  import { getOrderPositionBooks } from '../../../gql/getOrderPositionBooks';
5
5
  import { getPriceCandles } from '../../../gql/getPriceCandles';
6
+ import { getSentiments } from '../../../gql/getSentiments';
6
7
  import type {
7
8
  GetOrderPositionBooksQuery,
8
9
  GetOrderPositionBooksQueryVariables,
9
10
  GetPriceCandlesQuery,
10
11
  GetPriceCandlesQueryVariables,
12
+ GetSentimentsQuery,
13
+ GetSentimentsQueryVariables,
11
14
  } from '../../../gql/types/graphql';
12
15
  import { BookType, DataSource, Division } from '../../../gql/types/graphql';
13
16
  import { BUCKET_CONFIG, INSTRUMENTS_CONFIG } from '../../constants';
@@ -18,6 +21,7 @@ import {
18
21
  processBuckets,
19
22
  processOrderPositionBooks,
20
23
  processPriceCandles,
24
+ processSentiments,
21
25
  validateData,
22
26
  } from './utils';
23
27
 
@@ -92,7 +96,23 @@ export const useCrowdViewData = ({
92
96
  }
93
97
  );
94
98
 
95
- const loading = priceCandlesLoading || orderPositionLoading;
99
+ const {
100
+ loading: sentimentsLoading,
101
+ data: sentimentsData,
102
+ error: sentimentsError,
103
+ } = useQuery<GetSentimentsQuery, GetSentimentsQueryVariables>(getSentiments, {
104
+ variables: {
105
+ instrument: INSTRUMENTS_CONFIG[instrument].v20name,
106
+ granularity,
107
+ timeSpan: getTimeSpanForGranularity(granularity),
108
+ },
109
+ fetchPolicy: 'no-cache',
110
+ skip: priceCandlesLoading || !!priceCandlesError,
111
+ });
112
+
113
+ const loading =
114
+ priceCandlesLoading || orderPositionLoading || sentimentsLoading;
115
+ const xAxisData = candles.map((candle) => candle?.point || '');
96
116
 
97
117
  const orderPositionBooks = useMemo(
98
118
  () => processOrderPositionBooks(orderPositionData, candleMap),
@@ -104,6 +124,11 @@ export const useCrowdViewData = ({
104
124
  [orderPositionData, targetBucketWidth]
105
125
  );
106
126
 
127
+ const sentiments = useMemo(
128
+ () => processSentiments(sentimentsData, xAxisData),
129
+ [sentimentsData, xAxisData]
130
+ );
131
+
107
132
  const error = useMemo((): Error | null => {
108
133
  if (priceCandlesError) {
109
134
  return new Error(`Price candles error: ${priceCandlesError.message}`);
@@ -111,6 +136,9 @@ export const useCrowdViewData = ({
111
136
  if (orderPositionError) {
112
137
  return new Error(`Order position error: ${orderPositionError.message}`);
113
138
  }
139
+ if (sentimentsError) {
140
+ return new Error(`Sentiments error: ${sentimentsError.message}`);
141
+ }
114
142
  if (loading) {
115
143
  return null;
116
144
  }
@@ -118,6 +146,7 @@ export const useCrowdViewData = ({
118
146
  }, [
119
147
  priceCandlesError,
120
148
  orderPositionError,
149
+ sentimentsError,
121
150
  loading,
122
151
  priceCandlesData,
123
152
  orderPositionData,
@@ -125,11 +154,10 @@ export const useCrowdViewData = ({
125
154
  ]);
126
155
 
127
156
  const data = useMemo(() => {
128
- if (!priceCandlesData || !orderPositionData || error) {
157
+ if (!priceCandlesData || !orderPositionData || !sentimentsData || error) {
129
158
  return null;
130
159
  }
131
160
 
132
- const xAxisData = candles.map((candle) => candle?.point || '');
133
161
  const candlesSeriesData: [number, number, number, number][] = candles.map(
134
162
  (candle) => [
135
163
  candle?.open || 0,
@@ -147,17 +175,21 @@ export const useCrowdViewData = ({
147
175
  bucketWidth: targetBucketWidth,
148
176
  precision: INSTRUMENTS_CONFIG[instrument].precision,
149
177
  bookType,
178
+ sentiments,
150
179
  };
151
180
  }, [
152
181
  priceCandlesData,
153
182
  orderPositionData,
183
+ sentimentsData,
154
184
  error,
155
185
  candles,
156
186
  buckets,
187
+ xAxisData,
157
188
  orderPositionBooks,
158
189
  targetBucketWidth,
159
190
  instrument,
160
191
  bookType,
192
+ sentiments,
161
193
  ]);
162
194
 
163
195
  return {
@@ -7,7 +7,7 @@ import {
7
7
  COLOR_MAP,
8
8
  TIME_THRESHOLDS,
9
9
  } from '../../../constants';
10
- import type { Bucket, GetLabelsDataProps } from '../types';
10
+ import type { Bucket, GetLabelsDataProps, TooltipParam } from '../types';
11
11
 
12
12
  export const getLabelData = ({
13
13
  xAxisData,
@@ -32,7 +32,7 @@ export const getLabelData = ({
32
32
  day: isGreaterThanTwoWeeks ? 'numeric' : undefined,
33
33
  }),
34
34
  xAxis: item,
35
- y: CHART_CONFIG.HEIGHT - 22,
35
+ y: CHART_CONFIG.MAIN_HEIGHT + CHART_CONFIG.X_LABEL_SIZE - 22,
36
36
  silent: true,
37
37
  emphasis: {
38
38
  disabled: true,
@@ -108,7 +108,7 @@ export const getTooltipFormatter = ({
108
108
  bookType,
109
109
  labelCallback,
110
110
  }: {
111
- params: unknown;
111
+ params: TooltipParam[];
112
112
  buckets: Bucket[][];
113
113
  bucketWidth: number;
114
114
  selectedPrice: number;
@@ -116,21 +116,31 @@ export const getTooltipFormatter = ({
116
116
  bookType: BookType;
117
117
  labelCallback: (key: string) => string;
118
118
  }) => {
119
- const arr = params as unknown as Array<Record<string, unknown>>;
120
- if (!arr || !Array.isArray(arr) || arr.length === 0) {
119
+ if (!params || !Array.isArray(params) || params.length === 0) {
120
+ return undefined;
121
+ }
122
+ const candleParam = params.find(
123
+ (series): series is Extract<TooltipParam, { seriesId: 'candlestick' }> =>
124
+ series.seriesId === 'candlestick'
125
+ );
126
+ const booksParam = params.find(
127
+ (series): series is Extract<TooltipParam, { seriesId: 'heatmap' }> =>
128
+ series.seriesId === 'heatmap'
129
+ );
130
+ const sentimentParam = params.find(
131
+ (series): series is Extract<TooltipParam, { seriesId: 'sentiment' }> =>
132
+ series.seriesId === 'sentiment'
133
+ );
134
+
135
+ if (!candleParam) {
121
136
  return undefined;
122
137
  }
123
- const candleParam = arr[0] as {
124
- axisValue: string;
125
- value: [number, number, number, number, number];
126
- };
127
- const booksParam = arr[1] as { value: [string, number, number] };
128
138
  const time = new Date(candleParam.axisValue as string);
129
139
 
130
140
  const candleData = candleParam.value;
131
- const booksData = booksParam?.value ?? [];
132
- const bucketsIndex = booksData[2];
133
- const selectedBuckets = buckets[bucketsIndex];
141
+ const bucketsIndex = booksParam?.value[2];
142
+ const selectedBuckets =
143
+ bucketsIndex !== undefined ? buckets[bucketsIndex] : undefined;
134
144
 
135
145
  const matchedBucket = selectedBuckets?.find(
136
146
  ({ price }) => selectedPrice >= price && selectedPrice < price + bucketWidth
@@ -142,6 +152,9 @@ export const getTooltipFormatter = ({
142
152
  return undefined;
143
153
  }
144
154
 
155
+ const showSentiment =
156
+ !!sentimentParam?.value[1] && !!sentimentParam?.value[2];
157
+
145
158
  return `<p>${time.toLocaleString(undefined, {
146
159
  hour: '2-digit',
147
160
  minute: '2-digit',
@@ -178,7 +191,13 @@ ${
178
191
  )
179
192
  }: ${Math.abs(matchedBucket.sentiment)}% </p>`
180
193
  : ''
181
- }`;
194
+ }${
195
+ showSentiment && sentimentParam
196
+ ? `<br /><p><b>${labelCallback('sentiment')}:</b></p>
197
+ <p>${labelCallback('long')}: ${sentimentParam.value[2].toFixed(2)}% </p>
198
+ <p>${labelCallback('short')}: ${sentimentParam.value[1].toFixed(2)}% </p>`
199
+ : ''
200
+ }`;
182
201
  };
183
202
 
184
203
  export const formatXAxisLabel = (
@@ -0,0 +1,42 @@
1
+ import { colorPalette } from '@oanda/labs-widget-common';
2
+
3
+ export interface ChartStyles {
4
+ sentimentLongColor: string;
5
+ sentimentShortColor: string;
6
+ candleLongColor: string;
7
+ candleShortColor: string;
8
+ sentimentAreaOpacity: number;
9
+ tooltipLinesColor: string;
10
+ sentimentLabelColor: string;
11
+ }
12
+
13
+ export const getChartStyles = (isDark: boolean): ChartStyles => {
14
+ const sentimentLongColor = isDark
15
+ ? colorPalette.darkBlue90
16
+ : colorPalette.lightBlue90;
17
+ const sentimentShortColor = isDark
18
+ ? colorPalette.darkYellow90
19
+ : colorPalette.lightYellow90;
20
+
21
+ const candleLongColor = isDark
22
+ ? colorPalette.bottleGreenDark
23
+ : colorPalette.bottleGreenLight;
24
+ const candleShortColor = isDark
25
+ ? colorPalette.orange
26
+ : colorPalette.raspberryLight;
27
+ const sentimentAreaOpacity = isDark ? 0.5 : 0.2;
28
+ const tooltipLinesColor = isDark
29
+ ? colorPalette.orange
30
+ : colorPalette.bottleGreenLight;
31
+ const sentimentLabelColor = isDark ? colorPalette.white : colorPalette.black;
32
+
33
+ return {
34
+ sentimentLongColor,
35
+ sentimentShortColor,
36
+ candleLongColor,
37
+ candleShortColor,
38
+ sentimentAreaOpacity,
39
+ tooltipLinesColor,
40
+ sentimentLabelColor,
41
+ };
42
+ };
@@ -0,0 +1,148 @@
1
+ import { getLineCommons } from '@oanda/labs-widget-common';
2
+
3
+ import { CHART_CONFIG } from '../../../constants';
4
+
5
+ export const getGridLines = ({
6
+ isDark,
7
+ isDesktop,
8
+ }: {
9
+ isDark: boolean;
10
+ isDesktop: boolean;
11
+ }) => {
12
+ const {
13
+ WIDTH,
14
+ MAIN_HEIGHT,
15
+ MARGIN_BETWEEN,
16
+ SENTIMENT_HEIGHT,
17
+ X_LABEL_SIZE,
18
+ Y_LABEL_SIZE_DESKTOP,
19
+ Y_LABEL_SIZE_MOBILE,
20
+ } = CHART_CONFIG;
21
+ return [
22
+ // Main Top
23
+ {
24
+ ...getLineCommons(isDark),
25
+ top: -2,
26
+ shape: {
27
+ x1: 0,
28
+ y1: 0,
29
+ x2: WIDTH,
30
+ y2: 0,
31
+ },
32
+ },
33
+ // Main Right
34
+ {
35
+ ...getLineCommons(isDark),
36
+ right: -2,
37
+ shape: {
38
+ x1: 0,
39
+ y1: 0,
40
+ x2: 0,
41
+ y2: MAIN_HEIGHT + X_LABEL_SIZE + 2,
42
+ },
43
+ },
44
+ // Main Bottom
45
+ {
46
+ ...getLineCommons(isDark),
47
+ top: MAIN_HEIGHT - 2,
48
+ shape: {
49
+ x1: 0,
50
+ y1: 0,
51
+ x2: WIDTH,
52
+ y2: 0,
53
+ },
54
+ },
55
+ // Main Left
56
+ {
57
+ ...getLineCommons(isDark),
58
+ left: -2,
59
+ shape: {
60
+ x1: 0,
61
+ y1: 0,
62
+ x2: 0,
63
+ y2: MAIN_HEIGHT + X_LABEL_SIZE + 2,
64
+ },
65
+ },
66
+ // Main Y Label
67
+ {
68
+ ...getLineCommons(isDark),
69
+ right: (isDesktop ? Y_LABEL_SIZE_DESKTOP : Y_LABEL_SIZE_MOBILE) - 2,
70
+ top: -2,
71
+ shape: {
72
+ x1: 0,
73
+ y1: 0,
74
+ x2: 0,
75
+ y2: MAIN_HEIGHT,
76
+ },
77
+ },
78
+ // Main X Label
79
+ {
80
+ ...getLineCommons(isDark),
81
+ top: MAIN_HEIGHT + X_LABEL_SIZE,
82
+ shape: {
83
+ x1: 0,
84
+ y1: 0,
85
+ x2: WIDTH,
86
+ y2: 0,
87
+ },
88
+ },
89
+ // Sentiment Top
90
+ {
91
+ ...getLineCommons(isDark),
92
+ top: MAIN_HEIGHT + X_LABEL_SIZE + MARGIN_BETWEEN - 2,
93
+ shape: {
94
+ x1: 0,
95
+ y1: 0,
96
+ x2: WIDTH,
97
+ y2: 0,
98
+ },
99
+ },
100
+ // Sentiment Right
101
+ {
102
+ ...getLineCommons(isDark),
103
+ top: MAIN_HEIGHT + X_LABEL_SIZE + MARGIN_BETWEEN - 2,
104
+ right: -2,
105
+ shape: {
106
+ x1: 0,
107
+ y1: 0,
108
+ x2: 0,
109
+ y2: SENTIMENT_HEIGHT,
110
+ },
111
+ },
112
+ // Sentiment Bottom
113
+ {
114
+ ...getLineCommons(isDark),
115
+ top: MAIN_HEIGHT + X_LABEL_SIZE + MARGIN_BETWEEN + SENTIMENT_HEIGHT - 3,
116
+ shape: {
117
+ x1: 0,
118
+ y1: 0,
119
+ x2: WIDTH,
120
+ y2: 0,
121
+ },
122
+ },
123
+ // Sentiment Left
124
+ {
125
+ ...getLineCommons(isDark),
126
+ top: MAIN_HEIGHT + X_LABEL_SIZE + MARGIN_BETWEEN - 2,
127
+ left: -2,
128
+ shape: {
129
+ x1: 0,
130
+ y1: 0,
131
+ x2: 0,
132
+ y2: SENTIMENT_HEIGHT,
133
+ },
134
+ },
135
+ // Sentiment Y Label
136
+ {
137
+ ...getLineCommons(isDark),
138
+ right: (isDesktop ? Y_LABEL_SIZE_DESKTOP : Y_LABEL_SIZE_MOBILE) - 3,
139
+ top: MAIN_HEIGHT + X_LABEL_SIZE + MARGIN_BETWEEN - 2,
140
+ shape: {
141
+ x1: 0,
142
+ y1: 0,
143
+ x2: 0,
144
+ y2: SENTIMENT_HEIGHT,
145
+ },
146
+ },
147
+ ];
148
+ };
@@ -1,7 +1,9 @@
1
1
  export * from './aggregateBuckets';
2
2
  export * from './chartUtils';
3
+ export * from './getChartStyles';
3
4
  export * from './getTargetBucketWidth';
4
5
  export * from './processBuckets';
5
6
  export * from './processOrderPositionBooks';
6
7
  export * from './processPriceCandles';
8
+ export * from './processSentiments';
7
9
  export * from './validateData';
@@ -0,0 +1,42 @@
1
+ import type { GetSentimentsQuery } from '../../../../gql/types/graphql';
2
+ import type { ProcessedSentiment } from '../types';
3
+
4
+ export const processSentiments = (
5
+ sentimentsData: GetSentimentsQuery | undefined,
6
+ xAxisData: string[]
7
+ ): ProcessedSentiment[] => {
8
+ if (!sentimentsData?.sentiments?.sentiments?.length) {
9
+ return [];
10
+ }
11
+
12
+ const sentimentMap = new Map(
13
+ sentimentsData.sentiments.sentiments
14
+ .filter(
15
+ (item): item is NonNullable<typeof item> =>
16
+ item?.time != null &&
17
+ item.sentiment?.shortPercent != null &&
18
+ item.sentiment?.longPercent != null
19
+ )
20
+ .map((item) => [
21
+ item.time,
22
+ {
23
+ shortPercent: item.sentiment.shortPercent,
24
+ longPercent: item.sentiment.longPercent,
25
+ },
26
+ ])
27
+ );
28
+
29
+ return xAxisData
30
+ .map((time) => {
31
+ const sentiment = sentimentMap.get(time);
32
+ if (!sentiment) {
33
+ return undefined;
34
+ }
35
+ return [
36
+ time,
37
+ sentiment.shortPercent,
38
+ sentiment.longPercent,
39
+ ] as ProcessedSentiment;
40
+ })
41
+ .filter((item): item is ProcessedSentiment => item !== undefined);
42
+ };
@@ -21,7 +21,7 @@ export const Legend = ({
21
21
  const { lang } = useLocale();
22
22
 
23
23
  return (
24
- <div className="lw-mx-auto lw-flex lw-w-full lw-flex-col lw-items-center lw-space-y-4 lw-pb-6 lw-pt-0 sm:lw-max-w-md lg:lw-max-w-xl">
24
+ <div className="lw-mx-auto lw-mt-4 lw-flex lw-w-full lw-flex-col lw-items-center lw-space-y-4 lw-pb-6 lw-pt-0 sm:lw-max-w-md lg:lw-max-w-xl">
25
25
  <LegendBar
26
26
  isDark={isDark}
27
27
  label={lang(bookType === BookType.Order ? 'buy' : 'long')}
@@ -17,7 +17,9 @@ export const TIME_THRESHOLDS = {
17
17
  } as const;
18
18
 
19
19
  export const CHART_CONFIG = {
20
- HEIGHT: 425,
20
+ MAIN_HEIGHT: 400,
21
+ MARGIN_BETWEEN: 50,
22
+ SENTIMENT_HEIGHT: 120,
21
23
  WIDTH: 9999,
22
24
  X_LABEL_SIZE: 40,
23
25
  Y_LABEL_SIZE_DESKTOP: 60,
@@ -25,8 +27,22 @@ export const CHART_CONFIG = {
25
27
  INITIAL_START_ZOOM: 80,
26
28
  INITIAL_END_ZOOM: 100,
27
29
  X_AXIS_DATE_PADDING: ' ',
30
+ SENTIMENT_MIN: 0,
31
+ SENTIMENT_MAX: 100,
32
+ SENTIMENT_INTERVAL: 25,
33
+ SENTIMENT_TEXT_OFFSET: 16,
28
34
  } as const;
29
35
 
36
+ export const CHART_CONFIG_CALCULATED = {
37
+ FULL_HEIGHT:
38
+ CHART_CONFIG.MAIN_HEIGHT +
39
+ CHART_CONFIG.MARGIN_BETWEEN +
40
+ CHART_CONFIG.SENTIMENT_HEIGHT +
41
+ CHART_CONFIG.X_LABEL_SIZE,
42
+ SENTIMENT_TEXT_POSITION:
43
+ CHART_CONFIG.SENTIMENT_HEIGHT + CHART_CONFIG.SENTIMENT_TEXT_OFFSET,
44
+ };
45
+
30
46
  export const COLOR_MAP = {
31
47
  dark: {
32
48
  long: [colorPalette.darkBlue10, colorPalette.darkBlue90],
@@ -0,0 +1,25 @@
1
+ import { gql } from '@apollo/client';
2
+
3
+ const getSentiments = gql`
4
+ query GetSentiments(
5
+ $instrument: String!
6
+ $granularity: Granularity!
7
+ $timeSpan: TimeSpan!
8
+ ) {
9
+ sentiments(
10
+ instrument: $instrument
11
+ granularity: $granularity
12
+ timeSpan: $timeSpan
13
+ ) {
14
+ sentiments {
15
+ sentiment {
16
+ longPercent
17
+ shortPercent
18
+ }
19
+ time
20
+ }
21
+ }
22
+ }
23
+ `;
24
+
25
+ export { getSentiments };
@@ -17,6 +17,8 @@ const documents = {
17
17
  types.GetOrderPositionBooksDocument,
18
18
  '\n query GetPriceCandles(\n $dataSource: DataSource!\n $division: Division!\n $instrument: String!\n $granularity: Granularity!\n $timeSpan: TimeSpan!\n ) {\n priceCandles(\n dataSource: $dataSource\n division: $division\n instrument: $instrument\n granularity: $granularity\n timeSpan: $timeSpan\n ) {\n candle {\n point\n high\n low\n open\n close\n }\n }\n }\n':
19
19
  types.GetPriceCandlesDocument,
20
+ '\n query GetSentiments(\n $instrument: String!\n $granularity: Granularity!\n $timeSpan: TimeSpan!\n ) {\n sentiments(\n instrument: $instrument\n granularity: $granularity\n timeSpan: $timeSpan\n ) {\n sentiments {\n sentiment {\n longPercent\n shortPercent\n }\n time\n }\n }\n }\n':
21
+ types.GetSentimentsDocument,
20
22
  };
21
23
 
22
24
  /**
@@ -45,6 +47,12 @@ export function graphql(
45
47
  export function graphql(
46
48
  source: '\n query GetPriceCandles(\n $dataSource: DataSource!\n $division: Division!\n $instrument: String!\n $granularity: Granularity!\n $timeSpan: TimeSpan!\n ) {\n priceCandles(\n dataSource: $dataSource\n division: $division\n instrument: $instrument\n granularity: $granularity\n timeSpan: $timeSpan\n ) {\n candle {\n point\n high\n low\n open\n close\n }\n }\n }\n'
47
49
  ): (typeof documents)['\n query GetPriceCandles(\n $dataSource: DataSource!\n $division: Division!\n $instrument: String!\n $granularity: Granularity!\n $timeSpan: TimeSpan!\n ) {\n priceCandles(\n dataSource: $dataSource\n division: $division\n instrument: $instrument\n granularity: $granularity\n timeSpan: $timeSpan\n ) {\n candle {\n point\n high\n low\n open\n close\n }\n }\n }\n'];
50
+ /**
51
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
52
+ */
53
+ export function graphql(
54
+ source: '\n query GetSentiments(\n $instrument: String!\n $granularity: Granularity!\n $timeSpan: TimeSpan!\n ) {\n sentiments(\n instrument: $instrument\n granularity: $granularity\n timeSpan: $timeSpan\n ) {\n sentiments {\n sentiment {\n longPercent\n shortPercent\n }\n time\n }\n }\n }\n'
55
+ ): (typeof documents)['\n query GetSentiments(\n $instrument: String!\n $granularity: Granularity!\n $timeSpan: TimeSpan!\n ) {\n sentiments(\n instrument: $instrument\n granularity: $granularity\n timeSpan: $timeSpan\n ) {\n sentiments {\n sentiment {\n longPercent\n shortPercent\n }\n time\n }\n }\n }\n'];
48
56
 
49
57
  export function graphql(source: string) {
50
58
  return (documents as any)[source] ?? {};