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

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 (153) hide show
  1. package/CHANGELOG.md +428 -0
  2. package/dist/main/CrowdViewWidget/Main.js +1 -5
  3. package/dist/main/CrowdViewWidget/Main.js.map +1 -1
  4. package/dist/main/CrowdViewWidget/components/Chart/Chart.js +73 -24
  5. package/dist/main/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
  6. package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js +18 -9
  7. package/dist/main/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
  8. package/dist/main/CrowdViewWidget/components/Chart/chartOptions.js +265 -59
  9. package/dist/main/CrowdViewWidget/components/Chart/chartOptions.js.map +1 -1
  10. package/dist/main/CrowdViewWidget/components/Chart/types.js.map +1 -1
  11. package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js +68 -26
  12. package/dist/main/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
  13. package/dist/main/CrowdViewWidget/components/Chart/utils/chartUtils.js +20 -19
  14. package/dist/main/CrowdViewWidget/components/Chart/utils/chartUtils.js.map +1 -1
  15. package/dist/main/CrowdViewWidget/components/Chart/utils/getChartStyles.js +27 -0
  16. package/dist/main/CrowdViewWidget/components/Chart/utils/getChartStyles.js.map +1 -0
  17. package/dist/main/CrowdViewWidget/components/Chart/utils/getGridLines.js +123 -0
  18. package/dist/main/CrowdViewWidget/components/Chart/utils/getGridLines.js.map +1 -0
  19. package/dist/main/CrowdViewWidget/components/Chart/utils/index.js +15 -26
  20. package/dist/main/CrowdViewWidget/components/Chart/utils/index.js.map +1 -1
  21. package/dist/main/CrowdViewWidget/components/Chart/utils/processOrderPositionBooks.js +54 -12
  22. package/dist/main/CrowdViewWidget/components/Chart/utils/processOrderPositionBooks.js.map +1 -1
  23. package/dist/main/CrowdViewWidget/components/Chart/utils/processPriceCandles.js +49 -27
  24. package/dist/main/CrowdViewWidget/components/Chart/utils/processPriceCandles.js.map +1 -1
  25. package/dist/main/CrowdViewWidget/components/Chart/utils/processSentiments.js +43 -0
  26. package/dist/main/CrowdViewWidget/components/Chart/utils/processSentiments.js.map +1 -0
  27. package/dist/main/CrowdViewWidget/components/Chart/utils/validateData.js +8 -2
  28. package/dist/main/CrowdViewWidget/components/Chart/utils/validateData.js.map +1 -1
  29. package/dist/main/CrowdViewWidget/components/Legend/Legend.js +3 -4
  30. package/dist/main/CrowdViewWidget/components/Legend/Legend.js.map +1 -1
  31. package/dist/main/CrowdViewWidget/components/Legend/LegendBar.js +2 -2
  32. package/dist/main/CrowdViewWidget/components/Legend/LegendBar.js.map +1 -1
  33. package/dist/main/CrowdViewWidget/constants.js +14 -8
  34. package/dist/main/CrowdViewWidget/constants.js.map +1 -1
  35. package/dist/main/gql/getOrderPositionBooks.js +1 -1
  36. package/dist/main/gql/getOrderPositionBooks.js.map +1 -1
  37. package/dist/main/gql/getPriceCandles.js +1 -1
  38. package/dist/main/gql/getPriceCandles.js.map +1 -1
  39. package/dist/main/gql/getSentiments.js +11 -0
  40. package/dist/main/gql/getSentiments.js.map +1 -0
  41. package/dist/main/gql/types/gql.js +3 -2
  42. package/dist/main/gql/types/gql.js.map +1 -1
  43. package/dist/main/gql/types/graphql.js +273 -19
  44. package/dist/main/gql/types/graphql.js.map +1 -1
  45. package/dist/module/CrowdViewWidget/Main.js +2 -6
  46. package/dist/module/CrowdViewWidget/Main.js.map +1 -1
  47. package/dist/module/CrowdViewWidget/components/Chart/Chart.js +76 -27
  48. package/dist/module/CrowdViewWidget/components/Chart/Chart.js.map +1 -1
  49. package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js +18 -9
  50. package/dist/module/CrowdViewWidget/components/Chart/ChartWithData.js.map +1 -1
  51. package/dist/module/CrowdViewWidget/components/Chart/chartOptions.js +265 -60
  52. package/dist/module/CrowdViewWidget/components/Chart/chartOptions.js.map +1 -1
  53. package/dist/module/CrowdViewWidget/components/Chart/types.js.map +1 -1
  54. package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js +69 -27
  55. package/dist/module/CrowdViewWidget/components/Chart/useCrowdViewData.js.map +1 -1
  56. package/dist/module/CrowdViewWidget/components/Chart/utils/chartUtils.js +21 -20
  57. package/dist/module/CrowdViewWidget/components/Chart/utils/chartUtils.js.map +1 -1
  58. package/dist/module/CrowdViewWidget/components/Chart/utils/getChartStyles.js +20 -0
  59. package/dist/module/CrowdViewWidget/components/Chart/utils/getChartStyles.js.map +1 -0
  60. package/dist/module/CrowdViewWidget/components/Chart/utils/getGridLines.js +116 -0
  61. package/dist/module/CrowdViewWidget/components/Chart/utils/getGridLines.js.map +1 -0
  62. package/dist/module/CrowdViewWidget/components/Chart/utils/index.js +2 -3
  63. package/dist/module/CrowdViewWidget/components/Chart/utils/index.js.map +1 -1
  64. package/dist/module/CrowdViewWidget/components/Chart/utils/processOrderPositionBooks.js +54 -12
  65. package/dist/module/CrowdViewWidget/components/Chart/utils/processOrderPositionBooks.js.map +1 -1
  66. package/dist/module/CrowdViewWidget/components/Chart/utils/processPriceCandles.js +49 -27
  67. package/dist/module/CrowdViewWidget/components/Chart/utils/processPriceCandles.js.map +1 -1
  68. package/dist/module/CrowdViewWidget/components/Chart/utils/processSentiments.js +36 -0
  69. package/dist/module/CrowdViewWidget/components/Chart/utils/processSentiments.js.map +1 -0
  70. package/dist/module/CrowdViewWidget/components/Chart/utils/validateData.js +8 -2
  71. package/dist/module/CrowdViewWidget/components/Chart/utils/validateData.js.map +1 -1
  72. package/dist/module/CrowdViewWidget/components/Legend/Legend.js +3 -4
  73. package/dist/module/CrowdViewWidget/components/Legend/Legend.js.map +1 -1
  74. package/dist/module/CrowdViewWidget/components/Legend/LegendBar.js +2 -2
  75. package/dist/module/CrowdViewWidget/components/Legend/LegendBar.js.map +1 -1
  76. package/dist/module/CrowdViewWidget/constants.js +13 -7
  77. package/dist/module/CrowdViewWidget/constants.js.map +1 -1
  78. package/dist/module/gql/getOrderPositionBooks.js +1 -1
  79. package/dist/module/gql/getOrderPositionBooks.js.map +1 -1
  80. package/dist/module/gql/getPriceCandles.js +1 -1
  81. package/dist/module/gql/getPriceCandles.js.map +1 -1
  82. package/dist/module/gql/getSentiments.js +6 -0
  83. package/dist/module/gql/getSentiments.js.map +1 -0
  84. package/dist/module/gql/types/gql.js +3 -2
  85. package/dist/module/gql/types/gql.js.map +1 -1
  86. package/dist/module/gql/types/graphql.js +272 -18
  87. package/dist/module/gql/types/graphql.js.map +1 -1
  88. package/dist/types/CrowdViewWidget/components/Chart/Chart.d.ts +1 -1
  89. package/dist/types/CrowdViewWidget/components/Chart/types.d.ts +69 -9
  90. package/dist/types/CrowdViewWidget/components/Chart/utils/chartUtils.d.ts +5 -6
  91. package/dist/types/CrowdViewWidget/components/Chart/utils/getChartStyles.d.ts +10 -0
  92. package/dist/types/CrowdViewWidget/components/Chart/utils/getGridLines.d.ts +97 -0
  93. package/dist/types/CrowdViewWidget/components/Chart/utils/index.d.ts +2 -3
  94. package/dist/types/CrowdViewWidget/components/Chart/utils/processOrderPositionBooks.d.ts +10 -7
  95. package/dist/types/CrowdViewWidget/components/Chart/utils/processPriceCandles.d.ts +6 -21
  96. package/dist/types/CrowdViewWidget/components/Chart/utils/processSentiments.d.ts +6 -0
  97. package/dist/types/CrowdViewWidget/components/Chart/utils/validateData.d.ts +1 -1
  98. package/dist/types/CrowdViewWidget/components/Legend/Legend.d.ts +2 -2
  99. package/dist/types/CrowdViewWidget/components/Legend/LegendBar.d.ts +1 -1
  100. package/dist/types/CrowdViewWidget/constants.d.ts +12 -6
  101. package/dist/types/gql/getSentiments.d.ts +2 -0
  102. package/dist/types/gql/types/gql.d.ts +15 -4
  103. package/dist/types/gql/types/graphql.d.ts +66 -11
  104. package/package.json +3 -3
  105. package/src/CrowdViewWidget/Main.tsx +2 -4
  106. package/src/CrowdViewWidget/components/Chart/Chart.tsx +99 -38
  107. package/src/CrowdViewWidget/components/Chart/ChartWithData.tsx +24 -7
  108. package/src/CrowdViewWidget/components/Chart/chartOptions.ts +305 -87
  109. package/src/CrowdViewWidget/components/Chart/types.ts +82 -16
  110. package/src/CrowdViewWidget/components/Chart/useCrowdViewData.ts +105 -56
  111. package/src/CrowdViewWidget/components/Chart/utils/chartUtils.ts +65 -34
  112. package/src/CrowdViewWidget/components/Chart/utils/getChartStyles.ts +42 -0
  113. package/src/CrowdViewWidget/components/Chart/utils/getGridLines.ts +148 -0
  114. package/src/CrowdViewWidget/components/Chart/utils/index.ts +2 -3
  115. package/src/CrowdViewWidget/components/Chart/utils/processOrderPositionBooks.ts +84 -22
  116. package/src/CrowdViewWidget/components/Chart/utils/processPriceCandles.ts +52 -38
  117. package/src/CrowdViewWidget/components/Chart/utils/processSentiments.ts +55 -0
  118. package/src/CrowdViewWidget/components/Chart/utils/validateData.ts +10 -2
  119. package/src/CrowdViewWidget/components/Legend/Legend.tsx +5 -6
  120. package/src/CrowdViewWidget/components/Legend/LegendBar.tsx +3 -3
  121. package/src/CrowdViewWidget/constants.ts +18 -7
  122. package/src/gql/getOrderPositionBooks.ts +13 -5
  123. package/src/gql/getPriceCandles.ts +1 -0
  124. package/src/gql/getSentiments.ts +25 -0
  125. package/src/gql/types/gql.ts +14 -6
  126. package/src/gql/types/graphql.ts +259 -16
  127. package/test/components/Chart/utils/chartUtils.test.ts +105 -13
  128. package/test/components/Chart/utils/getChartStyles.test.ts +64 -0
  129. package/test/components/Chart/utils/processSentiments.test.ts +238 -0
  130. package/test/utils/processOrderPositionBooks.test.ts +201 -84
  131. package/test/utils/processPriceCandles.test.ts +93 -67
  132. package/test/utils/validateData.test.ts +136 -38
  133. package/dist/main/CrowdViewWidget/components/Chart/utils/aggregateBuckets.js +0 -37
  134. package/dist/main/CrowdViewWidget/components/Chart/utils/aggregateBuckets.js.map +0 -1
  135. package/dist/main/CrowdViewWidget/components/Chart/utils/getTargetBucketWidth.js +0 -14
  136. package/dist/main/CrowdViewWidget/components/Chart/utils/getTargetBucketWidth.js.map +0 -1
  137. package/dist/main/CrowdViewWidget/components/Chart/utils/processBuckets.js +0 -29
  138. package/dist/main/CrowdViewWidget/components/Chart/utils/processBuckets.js.map +0 -1
  139. package/dist/module/CrowdViewWidget/components/Chart/utils/aggregateBuckets.js +0 -29
  140. package/dist/module/CrowdViewWidget/components/Chart/utils/aggregateBuckets.js.map +0 -1
  141. package/dist/module/CrowdViewWidget/components/Chart/utils/getTargetBucketWidth.js +0 -7
  142. package/dist/module/CrowdViewWidget/components/Chart/utils/getTargetBucketWidth.js.map +0 -1
  143. package/dist/module/CrowdViewWidget/components/Chart/utils/processBuckets.js +0 -22
  144. package/dist/module/CrowdViewWidget/components/Chart/utils/processBuckets.js.map +0 -1
  145. package/dist/types/CrowdViewWidget/components/Chart/utils/aggregateBuckets.d.ts +0 -2
  146. package/dist/types/CrowdViewWidget/components/Chart/utils/getTargetBucketWidth.d.ts +0 -3
  147. package/dist/types/CrowdViewWidget/components/Chart/utils/processBuckets.d.ts +0 -3
  148. package/src/CrowdViewWidget/components/Chart/utils/aggregateBuckets.ts +0 -44
  149. package/src/CrowdViewWidget/components/Chart/utils/getTargetBucketWidth.ts +0 -13
  150. package/src/CrowdViewWidget/components/Chart/utils/processBuckets.ts +0 -43
  151. package/test/utils/aggregateBuckets.test.ts +0 -82
  152. package/test/utils/getTargetBucketWidth.test.ts +0 -37
  153. package/test/utils/processBuckets.test.ts +0 -153
@@ -3,21 +3,23 @@ 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';
14
17
  import type { UseCrowdViewDataProps, UseCrowdViewDataReturn } from './types';
15
18
  import {
16
- getTargetBucketWidth,
17
19
  getTimeSpanForGranularity,
18
- processBuckets,
19
20
  processOrderPositionBooks,
20
21
  processPriceCandles,
22
+ processSentiments,
21
23
  validateData,
22
24
  } from './utils';
23
25
 
@@ -31,6 +33,8 @@ export const useCrowdViewData = ({
31
33
  division === Division.Ogm || division === Division.Oj
32
34
  ? DataSource.Mt5
33
35
  : DataSource.V20;
36
+
37
+ // Get price candles data
34
38
  const {
35
39
  loading: priceCandlesLoading,
36
40
  data: priceCandlesData,
@@ -52,26 +56,19 @@ export const useCrowdViewData = ({
52
56
  }
53
57
  );
54
58
 
55
- const priceCandlesProcessed = useMemo(
56
- () => processPriceCandles(priceCandlesData),
57
- [priceCandlesData]
58
- );
59
-
60
- const { minPrice, maxPrice, hasValidCandles, candleMap, candles } =
61
- priceCandlesProcessed;
62
-
63
- const targetBucketWidth = getTargetBucketWidth(granularity, instrument);
64
-
65
- const maxBookPrice = useMemo(
66
- () => maxPrice + targetBucketWidth * BUCKET_CONFIG.PRICE_PADDING_MULTIPLIER,
67
- [maxPrice, targetBucketWidth]
68
- );
69
-
70
- const minBookPrice = useMemo(
71
- () => minPrice - targetBucketWidth * BUCKET_CONFIG.PRICE_PADDING_MULTIPLIER,
72
- [minPrice, targetBucketWidth]
73
- );
74
-
59
+ const {
60
+ minPrice,
61
+ maxPrice,
62
+ hasValidCandles,
63
+ dates,
64
+ candlesOpen,
65
+ candlesClose,
66
+ candlesLow,
67
+ candlesHigh,
68
+ pipsLocation,
69
+ } = useMemo(() => processPriceCandles(priceCandlesData), [priceCandlesData]);
70
+
71
+ // Get order position books data
75
72
  const {
76
73
  loading: orderPositionLoading,
77
74
  data: orderPositionData,
@@ -84,26 +81,53 @@ export const useCrowdViewData = ({
84
81
  bookType: bookType || BookType.Order,
85
82
  timeSpan: getTimeSpanForGranularity(granularity),
86
83
  granularity,
87
- maxBookPrice,
88
- minBookPrice,
84
+ maxBookPrice: maxPrice,
85
+ minBookPrice: minPrice,
86
+ bucketMultiplier: 3,
87
+ bucketMargin: BUCKET_CONFIG.PRICE_MARGIN_MULTIPLIER,
89
88
  },
90
89
  fetchPolicy: 'no-cache',
91
90
  skip: priceCandlesLoading || !!priceCandlesError,
92
91
  }
93
92
  );
94
93
 
95
- const loading = priceCandlesLoading || orderPositionLoading;
96
-
97
- const orderPositionBooks = useMemo(
98
- () => processOrderPositionBooks(orderPositionData, candleMap),
99
- [orderPositionData, candleMap]
94
+ const {
95
+ bookPrices,
96
+ bookIndexes,
97
+ buckets,
98
+ bucketWidth,
99
+ sentimentThresholdMin,
100
+ sentimentThresholdMax,
101
+ hasValidBooks,
102
+ } = useMemo(
103
+ () => processOrderPositionBooks(orderPositionData, dates),
104
+ [orderPositionData, dates]
100
105
  );
101
106
 
102
- const buckets = useMemo(
103
- () => processBuckets(orderPositionData, targetBucketWidth),
104
- [orderPositionData, targetBucketWidth]
107
+ // Get sentiments data
108
+ const {
109
+ loading: sentimentsLoading,
110
+ data: sentimentsData,
111
+ error: sentimentsError,
112
+ } = useQuery<GetSentimentsQuery, GetSentimentsQueryVariables>(getSentiments, {
113
+ variables: {
114
+ instrument: INSTRUMENTS_CONFIG[instrument].v20name,
115
+ granularity,
116
+ timeSpan: getTimeSpanForGranularity(granularity),
117
+ },
118
+ fetchPolicy: 'no-cache',
119
+ skip: priceCandlesLoading || !!priceCandlesError,
120
+ });
121
+
122
+ const { sentimentLongs, sentimentShorts, hasValidSentiments } = useMemo(
123
+ () => processSentiments(sentimentsData, dates),
124
+ [sentimentsData, dates]
105
125
  );
106
126
 
127
+ // Gather all results
128
+ const loading =
129
+ priceCandlesLoading || orderPositionLoading || sentimentsLoading;
130
+
107
131
  const error = useMemo((): Error | null => {
108
132
  if (priceCandlesError) {
109
133
  return new Error(`Price candles error: ${priceCandlesError.message}`);
@@ -111,57 +135,82 @@ export const useCrowdViewData = ({
111
135
  if (orderPositionError) {
112
136
  return new Error(`Order position error: ${orderPositionError.message}`);
113
137
  }
138
+ if (sentimentsError) {
139
+ return new Error(`Sentiments error: ${sentimentsError.message}`);
140
+ }
114
141
  if (loading) {
115
142
  return null;
116
143
  }
117
- return validateData(priceCandlesData, orderPositionData, hasValidCandles);
144
+ return validateData(
145
+ priceCandlesData,
146
+ orderPositionData,
147
+ hasValidCandles,
148
+ hasValidBooks,
149
+ hasValidSentiments
150
+ );
118
151
  }, [
119
152
  priceCandlesError,
120
153
  orderPositionError,
154
+ sentimentsError,
121
155
  loading,
122
156
  priceCandlesData,
123
157
  orderPositionData,
124
158
  hasValidCandles,
159
+ hasValidBooks,
160
+ hasValidSentiments,
125
161
  ]);
126
162
 
127
163
  const data = useMemo(() => {
128
- if (!priceCandlesData || !orderPositionData || error) {
164
+ if (!priceCandlesData || !orderPositionData || !sentimentsData || error) {
129
165
  return null;
130
166
  }
131
167
 
132
- const xAxisData = candles.map((candle) => candle?.point || '');
133
- const candlesSeriesData: [number, number, number, number][] = candles.map(
134
- (candle) => [
135
- candle?.open || 0,
136
- candle?.close || 0,
137
- candle?.low || 0,
138
- candle?.high || 0,
139
- ]
140
- );
141
-
142
168
  return {
143
- buckets,
144
- xAxisData,
145
- candlesSeriesData,
146
- orderPositionBooks,
147
- bucketWidth: targetBucketWidth,
148
- precision: INSTRUMENTS_CONFIG[instrument].precision,
149
- bookType,
169
+ mainData: {
170
+ dates,
171
+ candlesOpen,
172
+ candlesClose,
173
+ candlesLow,
174
+ candlesHigh,
175
+ bookPrices,
176
+ bookIndexes,
177
+ sentimentShorts,
178
+ sentimentLongs,
179
+ },
180
+ additionalData: {
181
+ bucketWidth,
182
+ buckets,
183
+ displayPrecision: pipsLocation,
184
+ bookType,
185
+ sentimentThresholdMin,
186
+ sentimentThresholdMax,
187
+ },
150
188
  };
151
189
  }, [
152
190
  priceCandlesData,
153
191
  orderPositionData,
192
+ sentimentsData,
154
193
  error,
155
- candles,
194
+ dates,
195
+ candlesOpen,
196
+ candlesClose,
197
+ candlesLow,
198
+ candlesHigh,
199
+ bookPrices,
200
+ bookIndexes,
201
+ sentimentShorts,
202
+ sentimentLongs,
203
+ bucketWidth,
156
204
  buckets,
157
- orderPositionBooks,
158
- targetBucketWidth,
159
- instrument,
205
+ pipsLocation,
160
206
  bookType,
207
+ sentimentThresholdMin,
208
+ sentimentThresholdMax,
161
209
  ]);
162
210
 
163
211
  return {
164
- data,
212
+ mainData: data?.mainData,
213
+ additionalData: data?.additionalData,
165
214
  loading,
166
215
  error: !!error,
167
216
  };
@@ -1,19 +1,14 @@
1
1
  import chroma from 'chroma-js';
2
2
 
3
3
  import { BookType, Granularity, TimeSpan } from '../../../../gql/types/graphql';
4
- import {
5
- BOOKS_THRESHOLDS,
6
- CHART_CONFIG,
7
- COLOR_MAP,
8
- TIME_THRESHOLDS,
9
- } from '../../../constants';
10
- import type { Bucket, GetLabelsDataProps } from '../types';
4
+ import { CHART_CONFIG, COLOR_MAP, TIME_THRESHOLDS } from '../../../constants';
5
+ import type { Bucket, GetLabelsDataProps, TooltipParam } from '../types';
11
6
 
12
7
  export const getLabelData = ({
13
- xAxisData,
8
+ dates,
14
9
  isGreaterThanTwoWeeks,
15
10
  }: GetLabelsDataProps) =>
16
- xAxisData
11
+ dates
17
12
  .filter((record, index, arr) => {
18
13
  if (index === 0) {
19
14
  return false;
@@ -32,7 +27,7 @@ export const getLabelData = ({
32
27
  day: isGreaterThanTwoWeeks ? 'numeric' : undefined,
33
28
  }),
34
29
  xAxis: item,
35
- y: CHART_CONFIG.HEIGHT - 22,
30
+ y: CHART_CONFIG.MAIN_HEIGHT + CHART_CONFIG.X_LABEL_SIZE - 22,
36
31
  silent: true,
37
32
  emphasis: {
38
33
  disabled: true,
@@ -74,29 +69,41 @@ export const getTimeSpanForGranularity = (
74
69
  const getGradientColor = (
75
70
  value: number,
76
71
  startColor: string,
77
- targetColor: string
72
+ targetColor: string,
73
+ minThreshold: number,
74
+ maxThreshold: number
78
75
  ): string => {
79
- const startThreshold = BOOKS_THRESHOLDS.MIN;
80
- const endThreshold = BOOKS_THRESHOLDS.MAX;
81
-
82
76
  const colorScale = chroma
83
77
  .scale([startColor, targetColor])
84
- .domain([startThreshold, endThreshold])
78
+ .domain([minThreshold, maxThreshold])
85
79
  .mode('rgb');
86
80
 
87
81
  return colorScale(value).hex();
88
82
  };
89
83
 
90
- export const getRectColor = (sentiment: number, isDark: boolean) => {
84
+ export const getRectColor = (
85
+ sentiment: number,
86
+ isDark: boolean,
87
+ minThreshold: number,
88
+ maxThreshold: number
89
+ ) => {
91
90
  const colorPalette = isDark ? COLOR_MAP.dark : COLOR_MAP.light;
92
91
 
93
92
  return sentiment < 0
94
93
  ? getGradientColor(
95
94
  sentiment * -1,
96
95
  colorPalette.short[0],
97
- colorPalette.short[1]
96
+ colorPalette.short[1],
97
+ minThreshold,
98
+ maxThreshold
98
99
  )
99
- : getGradientColor(sentiment, colorPalette.long[0], colorPalette.long[1]);
100
+ : getGradientColor(
101
+ sentiment,
102
+ colorPalette.long[0],
103
+ colorPalette.long[1],
104
+ minThreshold,
105
+ maxThreshold
106
+ );
100
107
  };
101
108
 
102
109
  export const getTooltipFormatter = ({
@@ -104,33 +111,44 @@ export const getTooltipFormatter = ({
104
111
  buckets,
105
112
  bucketWidth,
106
113
  selectedPrice,
107
- precision,
108
114
  bookType,
109
115
  labelCallback,
110
116
  }: {
111
- params: unknown;
117
+ params: TooltipParam[];
112
118
  buckets: Bucket[][];
113
119
  bucketWidth: number;
114
120
  selectedPrice: number;
115
- precision: number;
116
121
  bookType: BookType;
117
122
  labelCallback: (key: string) => string;
118
123
  }) => {
119
- const arr = params as unknown as Array<Record<string, unknown>>;
120
- if (!arr || !Array.isArray(arr) || arr.length === 0) {
124
+ const bucketDisplayPrecision =
125
+ bucketWidth.toString().split('.')[1]?.length || 0;
126
+
127
+ if (!params || !Array.isArray(params) || params.length === 0) {
128
+ return undefined;
129
+ }
130
+ const candleParam = params.find(
131
+ (series): series is Extract<TooltipParam, { seriesId: 'candlestick' }> =>
132
+ series.seriesId === 'candlestick'
133
+ );
134
+ const booksParam = params.find(
135
+ (series): series is Extract<TooltipParam, { seriesId: 'heatmap' }> =>
136
+ series.seriesId === 'heatmap'
137
+ );
138
+ const sentimentParam = params.find(
139
+ (series): series is Extract<TooltipParam, { seriesId: 'sentiment' }> =>
140
+ series.seriesId === 'sentiment'
141
+ );
142
+
143
+ if (!candleParam) {
121
144
  return undefined;
122
145
  }
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
146
  const time = new Date(candleParam.axisValue as string);
129
147
 
130
148
  const candleData = candleParam.value;
131
- const booksData = booksParam?.value ?? [];
132
- const bucketsIndex = booksData[2];
133
- const selectedBuckets = buckets[bucketsIndex];
149
+ const bucketsIndex = booksParam?.value[2];
150
+ const selectedBuckets =
151
+ bucketsIndex !== undefined ? buckets[bucketsIndex] : undefined;
134
152
 
135
153
  const matchedBucket = selectedBuckets?.find(
136
154
  ({ price }) => selectedPrice >= price && selectedPrice < price + bucketWidth
@@ -142,6 +160,9 @@ export const getTooltipFormatter = ({
142
160
  return undefined;
143
161
  }
144
162
 
163
+ const showSentiment =
164
+ !!sentimentParam?.value[1] && !!sentimentParam?.value[2];
165
+
145
166
  return `<p>${time.toLocaleString(undefined, {
146
167
  hour: '2-digit',
147
168
  minute: '2-digit',
@@ -163,7 +184,11 @@ ${
163
184
  ${
164
185
  matchedBucket
165
186
  ? `<br /><p><b>${labelCallback(bookType === BookType.Order ? 'orders' : 'positions')}:</b></p>
166
- <p>${labelCallback('price_range')}: ${matchedBucket.price.toFixed(precision - 1)} - ${Number(matchedBucket.price + bucketWidth).toFixed(precision - 1)} </p>
187
+ <p>${labelCallback('price_range')}: ${matchedBucket.price.toFixed(
188
+ bucketDisplayPrecision
189
+ )} - ${Number(matchedBucket.price + bucketWidth).toFixed(
190
+ bucketDisplayPrecision
191
+ )} </p>
167
192
  <p>${
168
193
  matchedBucket.sentiment < 0
169
194
  ? labelCallback(
@@ -176,9 +201,15 @@ ${
176
201
  ? 'buy_overbalance'
177
202
  : 'long_overbalance'
178
203
  )
179
- }: ${Math.abs(matchedBucket.sentiment)}% </p>`
204
+ }: ${Math.abs(Number(matchedBucket.sentiment.toFixed(bucketDisplayPrecision)))}% </p>`
180
205
  : ''
181
- }`;
206
+ }${
207
+ showSentiment && sentimentParam
208
+ ? `<br /><p><b>${labelCallback('sentiment')}:</b></p>
209
+ <p>${labelCallback('long')}: ${sentimentParam.value[2].toFixed(2)}% </p>
210
+ <p>${labelCallback('short')}: ${sentimentParam.value[1].toFixed(2)}% </p>`
211
+ : ''
212
+ }`;
182
213
  };
183
214
 
184
215
  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,6 @@
1
- export * from './aggregateBuckets';
2
1
  export * from './chartUtils';
3
- export * from './getTargetBucketWidth';
4
- export * from './processBuckets';
2
+ export * from './getChartStyles';
5
3
  export * from './processOrderPositionBooks';
6
4
  export * from './processPriceCandles';
5
+ export * from './processSentiments';
7
6
  export * from './validateData';