@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.
- package/CHANGELOG.md +212 -0
- package/dist/main/CrowdViewWidget/components/Chart/Chart.js +60 -21
- package/dist/main/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js +3 -3
- package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions.js +208 -42
- package/dist/main/CrowdViewWidget/components/Chart/chartOptions.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/types.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js +25 -6
- package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/utils/chartUtils.js +12 -10
- package/dist/main/CrowdViewWidget/components/Chart/utils/chartUtils.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/utils/getChartStyles.js +27 -0
- package/dist/main/CrowdViewWidget/components/Chart/utils/getChartStyles.js.map +1 -0
- package/dist/main/CrowdViewWidget/components/Chart/utils/getGridLines.js +123 -0
- package/dist/main/CrowdViewWidget/components/Chart/utils/getGridLines.js.map +1 -0
- package/dist/main/CrowdViewWidget/components/Chart/utils/index.js +22 -0
- package/dist/main/CrowdViewWidget/components/Chart/utils/index.js.map +1 -1
- package/dist/main/CrowdViewWidget/components/Chart/utils/processSentiments.js +28 -0
- package/dist/main/CrowdViewWidget/components/Chart/utils/processSentiments.js.map +1 -0
- package/dist/main/CrowdViewWidget/components/Legend/Legend.js +1 -1
- package/dist/main/CrowdViewWidget/components/Legend/Legend.js.map +1 -1
- package/dist/main/CrowdViewWidget/constants.js +13 -3
- package/dist/main/CrowdViewWidget/constants.js.map +1 -1
- package/dist/main/gql/getSentiments.js +11 -0
- package/dist/main/gql/getSentiments.js.map +1 -0
- package/dist/main/gql/types/gql.js +2 -1
- package/dist/main/gql/types/gql.js.map +1 -1
- package/dist/main/gql/types/graphql.js +162 -1
- package/dist/main/gql/types/graphql.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/Chart.js +63 -24
- package/dist/module/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js +3 -3
- package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions.js +208 -43
- package/dist/module/CrowdViewWidget/components/Chart/chartOptions.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/types.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js +26 -7
- package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/utils/chartUtils.js +12 -10
- package/dist/module/CrowdViewWidget/components/Chart/utils/chartUtils.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/utils/getChartStyles.js +20 -0
- package/dist/module/CrowdViewWidget/components/Chart/utils/getChartStyles.js.map +1 -0
- package/dist/module/CrowdViewWidget/components/Chart/utils/getGridLines.js +116 -0
- package/dist/module/CrowdViewWidget/components/Chart/utils/getGridLines.js.map +1 -0
- package/dist/module/CrowdViewWidget/components/Chart/utils/index.js +2 -0
- package/dist/module/CrowdViewWidget/components/Chart/utils/index.js.map +1 -1
- package/dist/module/CrowdViewWidget/components/Chart/utils/processSentiments.js +21 -0
- package/dist/module/CrowdViewWidget/components/Chart/utils/processSentiments.js.map +1 -0
- package/dist/module/CrowdViewWidget/components/Legend/Legend.js +1 -1
- package/dist/module/CrowdViewWidget/components/Legend/Legend.js.map +1 -1
- package/dist/module/CrowdViewWidget/constants.js +12 -2
- package/dist/module/CrowdViewWidget/constants.js.map +1 -1
- package/dist/module/gql/getSentiments.js +6 -0
- package/dist/module/gql/getSentiments.js.map +1 -0
- package/dist/module/gql/types/gql.js +2 -1
- package/dist/module/gql/types/gql.js.map +1 -1
- package/dist/module/gql/types/graphql.js +161 -0
- package/dist/module/gql/types/graphql.js.map +1 -1
- package/dist/types/CrowdViewWidget/components/Chart/types.d.ts +43 -0
- package/dist/types/CrowdViewWidget/components/Chart/utils/chartUtils.d.ts +2 -2
- package/dist/types/CrowdViewWidget/components/Chart/utils/getChartStyles.d.ts +10 -0
- package/dist/types/CrowdViewWidget/components/Chart/utils/getGridLines.d.ts +97 -0
- package/dist/types/CrowdViewWidget/components/Chart/utils/index.d.ts +2 -0
- package/dist/types/CrowdViewWidget/components/Chart/utils/processSentiments.d.ts +3 -0
- package/dist/types/CrowdViewWidget/constants.d.ts +11 -1
- package/dist/types/gql/getSentiments.d.ts +2 -0
- package/dist/types/gql/types/gql.d.ts +9 -0
- package/dist/types/gql/types/graphql.d.ts +36 -0
- package/package.json +3 -3
- package/src/CrowdViewWidget/components/Chart/Chart.tsx +86 -34
- package/src/CrowdViewWidget/components/Chart/ChartWithData.tsx +3 -3
- package/src/CrowdViewWidget/components/Chart/chartOptions.ts +242 -72
- package/src/CrowdViewWidget/components/Chart/types.ts +55 -0
- package/src/CrowdViewWidget/components/Chart/useCrowdViewData.ts +35 -3
- package/src/CrowdViewWidget/components/Chart/utils/chartUtils.ts +33 -14
- package/src/CrowdViewWidget/components/Chart/utils/getChartStyles.ts +42 -0
- package/src/CrowdViewWidget/components/Chart/utils/getGridLines.ts +148 -0
- package/src/CrowdViewWidget/components/Chart/utils/index.ts +2 -0
- package/src/CrowdViewWidget/components/Chart/utils/processSentiments.ts +42 -0
- package/src/CrowdViewWidget/components/Legend/Legend.tsx +1 -1
- package/src/CrowdViewWidget/constants.ts +17 -1
- package/src/gql/getSentiments.ts +25 -0
- package/src/gql/types/gql.ts +8 -0
- package/src/gql/types/graphql.ts +161 -0
- package/test/components/Chart/utils/chartUtils.test.ts +76 -2
- package/test/components/Chart/utils/getChartStyles.test.ts +64 -0
- 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
|
|
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.
|
|
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:
|
|
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
|
-
|
|
120
|
-
|
|
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
|
|
132
|
-
const
|
|
133
|
-
|
|
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
|
-
|
|
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 };
|
package/src/gql/types/gql.ts
CHANGED
|
@@ -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] ?? {};
|