@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
@@ -42,6 +42,7 @@ export enum AssetClassName {
42
42
  EquityShares = 'EQUITY_SHARES',
43
43
  Etfs = 'ETFS',
44
44
  Indices = 'INDICES',
45
+ Metals = 'METALS',
45
46
  Rates = 'RATES',
46
47
  }
47
48
 
@@ -211,6 +212,15 @@ export enum OrderBookDataSource {
211
212
  Ty3 = 'TY3',
212
213
  }
213
214
 
215
+ export type OrderPositionBooksData = {
216
+ __typename?: 'OrderPositionBooksData';
217
+ books?: Maybe<Array<OrderPositionData>>;
218
+ bucketWidth: Scalars['Float']['output'];
219
+ displayPrecision: Scalars['Int']['output'];
220
+ sentimentThresholdMax: Scalars['Float']['output'];
221
+ sentimentThresholdMin: Scalars['Float']['output'];
222
+ };
223
+
214
224
  export type OrderPositionBucket = {
215
225
  __typename?: 'OrderPositionBucket';
216
226
  longCountPercent?: Maybe<Scalars['Float']['output']>;
@@ -242,12 +252,13 @@ export type Query = {
242
252
  mapInstrumentNames?: Maybe<Array<Maybe<Instrument>>>;
243
253
  marginRates?: Maybe<Array<MarginRate>>;
244
254
  orderPositionBook: Array<Maybe<OrderPositionData>>;
245
- orderPositionBooks: Array<Maybe<OrderPositionData>>;
255
+ orderPositionBooks: OrderPositionBooksData;
246
256
  priceCandles: CandlesData;
247
257
  resolveInstrumentsByDivision?: Maybe<Array<Instrument>>;
248
258
  resolveInstrumentsWithFilters?: Maybe<InstrumentTableResult>;
249
259
  sentiment?: Maybe<Array<SentimentInstrument>>;
250
260
  sentimentList?: Maybe<Array<SentimentInstrument>>;
261
+ sentiments: SentimentData;
251
262
  topicalInstruments?: Maybe<Array<TopicalInstrument>>;
252
263
  topicalInstrumentsCharts?: Maybe<Array<TopicalInstrumentChart>>;
253
264
  topicalInstrumentsTotalCount: Scalars['Int']['output'];
@@ -301,6 +312,8 @@ export type QueryOrderPositionBookArgs = {
301
312
 
302
313
  export type QueryOrderPositionBooksArgs = {
303
314
  bookType: BookType;
315
+ bucketMargin?: Scalars['Int']['input'];
316
+ bucketMultiplier?: Scalars['Int']['input'];
304
317
  granularity: Granularity;
305
318
  instrument: Scalars['String']['input'];
306
319
  maxBookPrice?: InputMaybe<Scalars['Float']['input']>;
@@ -342,6 +355,12 @@ export type QuerySentimentListArgs = {
342
355
  sort?: InputMaybe<Sort>;
343
356
  };
344
357
 
358
+ export type QuerySentimentsArgs = {
359
+ granularity: Granularity;
360
+ instrument: Scalars['String']['input'];
361
+ timeSpan: TimeSpan;
362
+ };
363
+
345
364
  export type QueryTopicalInstrumentsArgs = {
346
365
  assetClass?: InputMaybe<AssetClassName>;
347
366
  count?: InputMaybe<Scalars['Int']['input']>;
@@ -395,6 +414,11 @@ export type Sentiment = {
395
414
  shortPercent: Scalars['Float']['output'];
396
415
  };
397
416
 
417
+ export type SentimentData = {
418
+ __typename?: 'SentimentData';
419
+ sentiments: Array<Maybe<SentimentWithTime>>;
420
+ };
421
+
398
422
  export type SentimentInstrument = {
399
423
  __typename?: 'SentimentInstrument';
400
424
  displayName: Scalars['String']['output'];
@@ -403,6 +427,12 @@ export type SentimentInstrument = {
403
427
  updatedAt: Scalars['String']['output'];
404
428
  };
405
429
 
430
+ export type SentimentWithTime = {
431
+ __typename?: 'SentimentWithTime';
432
+ sentiment: Sentiment;
433
+ time: Scalars['String']['output'];
434
+ };
435
+
406
436
  export enum Sort {
407
437
  Bearish = 'BEARISH',
408
438
  Bullish = 'BULLISH',
@@ -532,21 +562,28 @@ export type GetOrderPositionBooksQueryVariables = Exact<{
532
562
  granularity: Granularity;
533
563
  maxBookPrice?: InputMaybe<Scalars['Float']['input']>;
534
564
  minBookPrice?: InputMaybe<Scalars['Float']['input']>;
565
+ bucketMultiplier: Scalars['Int']['input'];
566
+ bucketMargin: Scalars['Int']['input'];
535
567
  }>;
536
568
 
537
569
  export type GetOrderPositionBooksQuery = {
538
570
  __typename?: 'Query';
539
- orderPositionBooks: Array<{
540
- __typename?: 'OrderPositionData';
571
+ orderPositionBooks: {
572
+ __typename?: 'OrderPositionBooksData';
541
573
  bucketWidth: number;
542
- price?: number | null;
543
- time: string;
544
- buckets: Array<{
545
- __typename?: 'OrderPositionBucket';
546
- price: number;
547
- sentiment?: number | null;
548
- } | null>;
549
- } | null>;
574
+ sentimentThresholdMax: number;
575
+ sentimentThresholdMin: number;
576
+ books?: Array<{
577
+ __typename?: 'OrderPositionData';
578
+ time: string;
579
+ price?: number | null;
580
+ buckets: Array<{
581
+ __typename?: 'OrderPositionBucket';
582
+ price: number;
583
+ sentiment?: number | null;
584
+ } | null>;
585
+ }> | null;
586
+ };
550
587
  };
551
588
 
552
589
  export type GetPriceCandlesQueryVariables = Exact<{
@@ -561,6 +598,7 @@ export type GetPriceCandlesQuery = {
561
598
  __typename?: 'Query';
562
599
  priceCandles: {
563
600
  __typename?: 'CandlesData';
601
+ pipsLocation: number;
564
602
  candle: Array<{
565
603
  __typename?: 'Candle';
566
604
  point: string;
@@ -572,6 +610,28 @@ export type GetPriceCandlesQuery = {
572
610
  };
573
611
  };
574
612
 
613
+ export type GetSentimentsQueryVariables = Exact<{
614
+ instrument: Scalars['String']['input'];
615
+ granularity: Granularity;
616
+ timeSpan: TimeSpan;
617
+ }>;
618
+
619
+ export type GetSentimentsQuery = {
620
+ __typename?: 'Query';
621
+ sentiments: {
622
+ __typename?: 'SentimentData';
623
+ sentiments: Array<{
624
+ __typename?: 'SentimentWithTime';
625
+ time: string;
626
+ sentiment: {
627
+ __typename?: 'Sentiment';
628
+ longPercent: number;
629
+ shortPercent: number;
630
+ };
631
+ } | null>;
632
+ };
633
+ };
634
+
575
635
  export const GetOrderPositionBooksDocument = {
576
636
  kind: 'Document',
577
637
  definitions: [
@@ -652,6 +712,28 @@ export const GetOrderPositionBooksDocument = {
652
712
  },
653
713
  type: { kind: 'NamedType', name: { kind: 'Name', value: 'Float' } },
654
714
  },
715
+ {
716
+ kind: 'VariableDefinition',
717
+ variable: {
718
+ kind: 'Variable',
719
+ name: { kind: 'Name', value: 'bucketMultiplier' },
720
+ },
721
+ type: {
722
+ kind: 'NonNullType',
723
+ type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } },
724
+ },
725
+ },
726
+ {
727
+ kind: 'VariableDefinition',
728
+ variable: {
729
+ kind: 'Variable',
730
+ name: { kind: 'Name', value: 'bucketMargin' },
731
+ },
732
+ type: {
733
+ kind: 'NonNullType',
734
+ type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } },
735
+ },
736
+ },
655
737
  ],
656
738
  selectionSet: {
657
739
  kind: 'SelectionSet',
@@ -708,27 +790,63 @@ export const GetOrderPositionBooksDocument = {
708
790
  name: { kind: 'Name', value: 'minBookPrice' },
709
791
  },
710
792
  },
793
+ {
794
+ kind: 'Argument',
795
+ name: { kind: 'Name', value: 'bucketMultiplier' },
796
+ value: {
797
+ kind: 'Variable',
798
+ name: { kind: 'Name', value: 'bucketMultiplier' },
799
+ },
800
+ },
801
+ {
802
+ kind: 'Argument',
803
+ name: { kind: 'Name', value: 'bucketMargin' },
804
+ value: {
805
+ kind: 'Variable',
806
+ name: { kind: 'Name', value: 'bucketMargin' },
807
+ },
808
+ },
711
809
  ],
712
810
  selectionSet: {
713
811
  kind: 'SelectionSet',
714
812
  selections: [
715
- { kind: 'Field', name: { kind: 'Name', value: 'bucketWidth' } },
716
- { kind: 'Field', name: { kind: 'Name', value: 'price' } },
717
- { kind: 'Field', name: { kind: 'Name', value: 'time' } },
718
813
  {
719
814
  kind: 'Field',
720
- name: { kind: 'Name', value: 'buckets' },
815
+ name: { kind: 'Name', value: 'books' },
721
816
  selectionSet: {
722
817
  kind: 'SelectionSet',
723
818
  selections: [
819
+ { kind: 'Field', name: { kind: 'Name', value: 'time' } },
724
820
  { kind: 'Field', name: { kind: 'Name', value: 'price' } },
725
821
  {
726
822
  kind: 'Field',
727
- name: { kind: 'Name', value: 'sentiment' },
823
+ name: { kind: 'Name', value: 'buckets' },
824
+ selectionSet: {
825
+ kind: 'SelectionSet',
826
+ selections: [
827
+ {
828
+ kind: 'Field',
829
+ name: { kind: 'Name', value: 'price' },
830
+ },
831
+ {
832
+ kind: 'Field',
833
+ name: { kind: 'Name', value: 'sentiment' },
834
+ },
835
+ ],
836
+ },
728
837
  },
729
838
  ],
730
839
  },
731
840
  },
841
+ { kind: 'Field', name: { kind: 'Name', value: 'bucketWidth' } },
842
+ {
843
+ kind: 'Field',
844
+ name: { kind: 'Name', value: 'sentimentThresholdMax' },
845
+ },
846
+ {
847
+ kind: 'Field',
848
+ name: { kind: 'Name', value: 'sentimentThresholdMin' },
849
+ },
732
850
  ],
733
851
  },
734
852
  },
@@ -884,6 +1002,10 @@ export const GetPriceCandlesDocument = {
884
1002
  ],
885
1003
  },
886
1004
  },
1005
+ {
1006
+ kind: 'Field',
1007
+ name: { kind: 'Name', value: 'pipsLocation' },
1008
+ },
887
1009
  ],
888
1010
  },
889
1011
  },
@@ -895,3 +1017,124 @@ export const GetPriceCandlesDocument = {
895
1017
  GetPriceCandlesQuery,
896
1018
  GetPriceCandlesQueryVariables
897
1019
  >;
1020
+ export const GetSentimentsDocument = {
1021
+ kind: 'Document',
1022
+ definitions: [
1023
+ {
1024
+ kind: 'OperationDefinition',
1025
+ operation: 'query',
1026
+ name: { kind: 'Name', value: 'GetSentiments' },
1027
+ variableDefinitions: [
1028
+ {
1029
+ kind: 'VariableDefinition',
1030
+ variable: {
1031
+ kind: 'Variable',
1032
+ name: { kind: 'Name', value: 'instrument' },
1033
+ },
1034
+ type: {
1035
+ kind: 'NonNullType',
1036
+ type: {
1037
+ kind: 'NamedType',
1038
+ name: { kind: 'Name', value: 'String' },
1039
+ },
1040
+ },
1041
+ },
1042
+ {
1043
+ kind: 'VariableDefinition',
1044
+ variable: {
1045
+ kind: 'Variable',
1046
+ name: { kind: 'Name', value: 'granularity' },
1047
+ },
1048
+ type: {
1049
+ kind: 'NonNullType',
1050
+ type: {
1051
+ kind: 'NamedType',
1052
+ name: { kind: 'Name', value: 'Granularity' },
1053
+ },
1054
+ },
1055
+ },
1056
+ {
1057
+ kind: 'VariableDefinition',
1058
+ variable: {
1059
+ kind: 'Variable',
1060
+ name: { kind: 'Name', value: 'timeSpan' },
1061
+ },
1062
+ type: {
1063
+ kind: 'NonNullType',
1064
+ type: {
1065
+ kind: 'NamedType',
1066
+ name: { kind: 'Name', value: 'TimeSpan' },
1067
+ },
1068
+ },
1069
+ },
1070
+ ],
1071
+ selectionSet: {
1072
+ kind: 'SelectionSet',
1073
+ selections: [
1074
+ {
1075
+ kind: 'Field',
1076
+ name: { kind: 'Name', value: 'sentiments' },
1077
+ arguments: [
1078
+ {
1079
+ kind: 'Argument',
1080
+ name: { kind: 'Name', value: 'instrument' },
1081
+ value: {
1082
+ kind: 'Variable',
1083
+ name: { kind: 'Name', value: 'instrument' },
1084
+ },
1085
+ },
1086
+ {
1087
+ kind: 'Argument',
1088
+ name: { kind: 'Name', value: 'granularity' },
1089
+ value: {
1090
+ kind: 'Variable',
1091
+ name: { kind: 'Name', value: 'granularity' },
1092
+ },
1093
+ },
1094
+ {
1095
+ kind: 'Argument',
1096
+ name: { kind: 'Name', value: 'timeSpan' },
1097
+ value: {
1098
+ kind: 'Variable',
1099
+ name: { kind: 'Name', value: 'timeSpan' },
1100
+ },
1101
+ },
1102
+ ],
1103
+ selectionSet: {
1104
+ kind: 'SelectionSet',
1105
+ selections: [
1106
+ {
1107
+ kind: 'Field',
1108
+ name: { kind: 'Name', value: 'sentiments' },
1109
+ selectionSet: {
1110
+ kind: 'SelectionSet',
1111
+ selections: [
1112
+ {
1113
+ kind: 'Field',
1114
+ name: { kind: 'Name', value: 'sentiment' },
1115
+ selectionSet: {
1116
+ kind: 'SelectionSet',
1117
+ selections: [
1118
+ {
1119
+ kind: 'Field',
1120
+ name: { kind: 'Name', value: 'longPercent' },
1121
+ },
1122
+ {
1123
+ kind: 'Field',
1124
+ name: { kind: 'Name', value: 'shortPercent' },
1125
+ },
1126
+ ],
1127
+ },
1128
+ },
1129
+ { kind: 'Field', name: { kind: 'Name', value: 'time' } },
1130
+ ],
1131
+ },
1132
+ },
1133
+ ],
1134
+ },
1135
+ },
1136
+ ],
1137
+ },
1138
+ },
1139
+ ],
1140
+ } as unknown as DocumentNode<GetSentimentsQuery, GetSentimentsQueryVariables>;
@@ -1,3 +1,4 @@
1
+ import type { TooltipParam } from '../../../../src/CrowdViewWidget/components/Chart/types';
1
2
  import {
2
3
  formatXAxisLabel,
3
4
  getLabelData,
@@ -6,16 +7,18 @@ import {
6
7
  getTooltipFormatter,
7
8
  isDifferenceGreaterThanTwoWeeks,
8
9
  } from '../../../../src/CrowdViewWidget/components/Chart/utils/chartUtils';
9
- import {
10
- BOOKS_THRESHOLDS,
11
- COLOR_MAP,
12
- } from '../../../../src/CrowdViewWidget/constants';
10
+ import { COLOR_MAP } from '../../../../src/CrowdViewWidget/constants';
13
11
  import {
14
12
  BookType,
15
13
  Granularity,
16
14
  TimeSpan,
17
15
  } from '../../../../src/gql/types/graphql';
18
16
 
17
+ const TEST_THRESHOLDS = {
18
+ MIN: 0.15,
19
+ MAX: 0.55,
20
+ } as const;
21
+
19
22
  describe('chartUtils', () => {
20
23
  describe('getTimeSpanForGranularity', () => {
21
24
  it('maps granularity to expected TimeSpan', () => {
@@ -49,7 +52,12 @@ describe('chartUtils', () => {
49
52
 
50
53
  describe('getRectColor', () => {
51
54
  it('uses long color scale for positive sentiment in light mode', () => {
52
- const color = getRectColor(BOOKS_THRESHOLDS.MAX, false);
55
+ const color = getRectColor(
56
+ TEST_THRESHOLDS.MAX,
57
+ false,
58
+ TEST_THRESHOLDS.MIN,
59
+ TEST_THRESHOLDS.MAX
60
+ );
53
61
  expect(typeof color).toBe('string');
54
62
  // At max threshold, should be at or near target color
55
63
  expect(color.toLowerCase()).toContain(
@@ -58,7 +66,12 @@ describe('chartUtils', () => {
58
66
  });
59
67
 
60
68
  it('uses short color scale for negative sentiment in light mode', () => {
61
- const color = getRectColor(-BOOKS_THRESHOLDS.MAX, false);
69
+ const color = getRectColor(
70
+ -TEST_THRESHOLDS.MAX,
71
+ false,
72
+ TEST_THRESHOLDS.MIN,
73
+ TEST_THRESHOLDS.MAX
74
+ );
62
75
  expect(typeof color).toBe('string');
63
76
  expect(color.toLowerCase()).toContain(
64
77
  COLOR_MAP.light.short[1].slice(1).toLowerCase().substring(0, 3)
@@ -66,7 +79,12 @@ describe('chartUtils', () => {
66
79
  });
67
80
 
68
81
  it('uses long color scale for positive sentiment in dark mode', () => {
69
- const color = getRectColor(BOOKS_THRESHOLDS.MAX, true);
82
+ const color = getRectColor(
83
+ TEST_THRESHOLDS.MAX,
84
+ true,
85
+ TEST_THRESHOLDS.MIN,
86
+ TEST_THRESHOLDS.MAX
87
+ );
70
88
  expect(typeof color).toBe('string');
71
89
  // At max threshold, should be at or near target color
72
90
  expect(color.toLowerCase()).toContain(
@@ -75,7 +93,12 @@ describe('chartUtils', () => {
75
93
  });
76
94
 
77
95
  it('uses short color scale for negative sentiment in dark mode', () => {
78
- const color = getRectColor(-BOOKS_THRESHOLDS.MAX, true);
96
+ const color = getRectColor(
97
+ -TEST_THRESHOLDS.MAX,
98
+ true,
99
+ TEST_THRESHOLDS.MIN,
100
+ TEST_THRESHOLDS.MAX
101
+ );
79
102
  expect(typeof color).toBe('string');
80
103
  expect(color.toLowerCase()).toContain(
81
104
  COLOR_MAP.dark.short[1].slice(1).toLowerCase().substring(0, 3)
@@ -110,7 +133,7 @@ describe('chartUtils', () => {
110
133
 
111
134
  it('emits label when day changes for < two weeks case', () => {
112
135
  const labels = getLabelData({
113
- xAxisData: dates,
136
+ dates,
114
137
  isGreaterThanTwoWeeks: true,
115
138
  });
116
139
  // First change happens between 1st and 2nd
@@ -125,7 +148,7 @@ describe('chartUtils', () => {
125
148
  '2025-02-15T00:00:00Z',
126
149
  ];
127
150
  const labels = getLabelData({
128
- xAxisData: monthSpanDates,
151
+ dates: monthSpanDates,
129
152
  isGreaterThanTwoWeeks: false,
130
153
  });
131
154
  expect(labels.length).toBe(1);
@@ -137,12 +160,16 @@ describe('chartUtils', () => {
137
160
  const labelCallback = (k: string) => k;
138
161
 
139
162
  it('renders candle and book details when available', () => {
140
- const params = [
163
+ const params: TooltipParam[] = [
141
164
  {
165
+ seriesId: 'candlestick' as const,
142
166
  axisValue: '2025-03-15T10:30:00Z',
143
167
  value: [0, 1.11111, 1.22222, 1.00001, 1.33333],
144
168
  },
145
- { value: ['2025-03-15T10:30:00Z', 1.33333, 0] },
169
+ {
170
+ seriesId: 'heatmap' as const,
171
+ value: ['2025-03-15T10:30:00Z', 1.33333, 0],
172
+ },
146
173
  ];
147
174
 
148
175
  const buckets = [
@@ -157,10 +184,10 @@ describe('chartUtils', () => {
157
184
  buckets,
158
185
  bucketWidth: 0.0005,
159
186
  selectedPrice: 1.3306,
160
- precision: 5,
161
187
  bookType: BookType.Order,
162
188
  labelCallback,
163
189
  });
190
+ expect(html).toBeDefined();
164
191
  expect(html).toContain('candle');
165
192
  expect(html).toContain('open_price');
166
193
  expect(html).toContain('close_price');
@@ -171,5 +198,70 @@ describe('chartUtils', () => {
171
198
  // Selected price 1.3306 falls into second bucket 1.3305 - 1.3310 which has negative sentiment
172
199
  expect(html).toContain('sell_overbalance');
173
200
  });
201
+
202
+ it('renders sentiment details when available', () => {
203
+ const params: TooltipParam[] = [
204
+ {
205
+ seriesId: 'candlestick' as const,
206
+ axisValue: '2025-03-15T10:30:00Z',
207
+ value: [0, 1.11111, 1.22222, 1.00001, 1.33333],
208
+ },
209
+ {
210
+ seriesId: 'sentiment' as const,
211
+ value: ['2025-03-15T10:30:00Z', 30.5, 69.5],
212
+ },
213
+ ];
214
+
215
+ const buckets: never[] = [];
216
+
217
+ const html = getTooltipFormatter({
218
+ params,
219
+ buckets,
220
+ bucketWidth: 0.0005,
221
+ selectedPrice: 1.3306,
222
+ bookType: BookType.Order,
223
+ labelCallback,
224
+ });
225
+ expect(html).toBeDefined();
226
+ expect(html).toContain('candle');
227
+ expect(html).toContain('sentiment');
228
+ expect(html).toContain('long');
229
+ expect(html).toContain('short');
230
+ expect(html).toContain('30.50');
231
+ expect(html).toContain('69.50');
232
+ });
233
+
234
+ it('returns undefined when no candlestick param is provided', () => {
235
+ const params: TooltipParam[] = [
236
+ {
237
+ seriesId: 'heatmap' as const,
238
+ value: ['2025-03-15T10:30:00Z', 1.33333, 0],
239
+ },
240
+ ];
241
+
242
+ const buckets: never[] = [];
243
+
244
+ const html = getTooltipFormatter({
245
+ params,
246
+ buckets,
247
+ bucketWidth: 0.0005,
248
+ selectedPrice: 1.3306,
249
+ bookType: BookType.Order,
250
+ labelCallback,
251
+ });
252
+ expect(html).toBeUndefined();
253
+ });
254
+
255
+ it('returns undefined when params is empty', () => {
256
+ const html = getTooltipFormatter({
257
+ params: [],
258
+ buckets: [],
259
+ bucketWidth: 0.0005,
260
+ selectedPrice: 1.3306,
261
+ bookType: BookType.Order,
262
+ labelCallback,
263
+ });
264
+ expect(html).toBeUndefined();
265
+ });
174
266
  });
175
267
  });
@@ -0,0 +1,64 @@
1
+ import { colorPalette } from '@oanda/labs-widget-common';
2
+
3
+ import { getChartStyles } from '../../../../src/CrowdViewWidget/components/Chart/utils/getChartStyles';
4
+
5
+ describe('getChartStyles', () => {
6
+ it('returns correct styles for dark mode', () => {
7
+ const styles = getChartStyles(true);
8
+
9
+ expect(styles.sentimentLongColor).toBe(colorPalette.darkBlue90);
10
+ expect(styles.sentimentShortColor).toBe(colorPalette.darkYellow90);
11
+ expect(styles.candleLongColor).toBe(colorPalette.bottleGreenDark);
12
+ expect(styles.candleShortColor).toBe(colorPalette.orange);
13
+ expect(styles.sentimentAreaOpacity).toBe(0.5);
14
+ expect(styles.tooltipLinesColor).toBe(colorPalette.orange);
15
+ expect(styles.sentimentLabelColor).toBe(colorPalette.white);
16
+ });
17
+
18
+ it('returns correct styles for light mode', () => {
19
+ const styles = getChartStyles(false);
20
+
21
+ expect(styles.sentimentLongColor).toBe(colorPalette.lightBlue90);
22
+ expect(styles.sentimentShortColor).toBe(colorPalette.lightYellow90);
23
+ expect(styles.candleLongColor).toBe(colorPalette.bottleGreenLight);
24
+ expect(styles.candleShortColor).toBe(colorPalette.raspberryLight);
25
+ expect(styles.sentimentAreaOpacity).toBe(0.2);
26
+ expect(styles.tooltipLinesColor).toBe(colorPalette.bottleGreenLight);
27
+ expect(styles.sentimentLabelColor).toBe(colorPalette.black);
28
+ });
29
+
30
+ it('returns all required style properties', () => {
31
+ const darkStyles = getChartStyles(true);
32
+ const lightStyles = getChartStyles(false);
33
+
34
+ const requiredProperties = [
35
+ 'sentimentLongColor',
36
+ 'sentimentShortColor',
37
+ 'candleLongColor',
38
+ 'candleShortColor',
39
+ 'sentimentAreaOpacity',
40
+ 'tooltipLinesColor',
41
+ 'sentimentLabelColor',
42
+ ];
43
+
44
+ requiredProperties.forEach((prop) => {
45
+ expect(darkStyles).toHaveProperty(prop);
46
+ expect(lightStyles).toHaveProperty(prop);
47
+ expect(typeof darkStyles[prop as keyof typeof darkStyles]).not.toBe(
48
+ 'undefined'
49
+ );
50
+ expect(typeof lightStyles[prop as keyof typeof lightStyles]).not.toBe(
51
+ 'undefined'
52
+ );
53
+ });
54
+ });
55
+
56
+ it('returns different opacity values for dark and light modes', () => {
57
+ const darkStyles = getChartStyles(true);
58
+ const lightStyles = getChartStyles(false);
59
+
60
+ expect(darkStyles.sentimentAreaOpacity).toBeGreaterThan(
61
+ lightStyles.sentimentAreaOpacity
62
+ );
63
+ });
64
+ });