overtime-live-trading-utils 3.0.0-rc.3 → 3.0.2-rc.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overtime-live-trading-utils",
3
- "version": "3.0.0-rc.3",
3
+ "version": "3.0.2-rc.0",
4
4
  "description": "",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -14,7 +14,7 @@
14
14
  "dependencies": {
15
15
  "@types/node": "^20.8.10",
16
16
  "oddslib": "^2.1.1",
17
- "overtime-utils": "^0.1.44",
17
+ "overtime-utils": "^0.1.50",
18
18
  "react": "^17.0.1"
19
19
  },
20
20
  "devDependencies": {
@@ -1,7 +1,7 @@
1
1
  export const ZERO = 0;
2
2
  export const DRAW = 'Draw';
3
3
  export const MONEYLINE_TYPE_ID = 0;
4
- export const MIN_ODDS_FOR_DIFF_CHECKING = 0.2;
4
+ export const MIN_ODDS_FOR_DIFF_CHECKING = 0.1;
5
5
  export const MAX_IMPLIED_PERCENTAGE_DIFF = 20; // 20%
6
6
  export const TAG_CHILD_SPREAD = 10001;
7
7
  export const TAG_CHILD_TOTALS = 10002;
@@ -10,9 +10,14 @@ import {
10
10
  MockOnlyMoneylineWithDifferentSportsbook,
11
11
  } from '../mock/MockOpticSoccer';
12
12
  import { mockSoccer } from '../mock/MockSoccerRedis';
13
- import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
13
+ import {
14
+ getLastPolledDataForBookmakers,
15
+ getPlayersMap,
16
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
17
+ } from '../utils/helper';
14
18
 
15
19
  const lastPolledData = getLastPolledDataForBookmakers();
20
+ const playersMap = getPlayersMap();
16
21
 
17
22
  describe('Bookmakers', () => {
18
23
  it('Should return zero odds for moneyline when one of the bookmakers has no odds', () => {
@@ -28,7 +33,8 @@ describe('Bookmakers', () => {
28
33
  MAX_IMPLIED_PERCENTAGE_DIFF,
29
34
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
30
35
  lastPolledData,
31
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
36
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
37
+ playersMap
32
38
  );
33
39
 
34
40
  const hasOdds = market.odds.some(
@@ -53,7 +59,8 @@ describe('Bookmakers', () => {
53
59
  5,
54
60
  LeagueMocks.leagueInfoOnlyParent,
55
61
  lastPolledData,
56
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
62
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
63
+ playersMap
57
64
  );
58
65
 
59
66
  const hasOdds = market.odds.some(
@@ -78,7 +85,8 @@ describe('Bookmakers', () => {
78
85
  MAX_IMPLIED_PERCENTAGE_DIFF,
79
86
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
80
87
  lastPolledData,
81
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
88
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
89
+ playersMap
82
90
  );
83
91
 
84
92
  const hasOdds = market.odds.some(
@@ -103,7 +111,8 @@ describe('Bookmakers', () => {
103
111
  MAX_IMPLIED_PERCENTAGE_DIFF,
104
112
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
105
113
  lastPolledData,
106
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
114
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
115
+ playersMap
107
116
  );
108
117
 
109
118
  expect(market.childMarkets.length).toBe(2);
@@ -122,7 +131,8 @@ describe('Bookmakers', () => {
122
131
  MAX_IMPLIED_PERCENTAGE_DIFF,
123
132
  LeagueMocks.leaguInfoDifferentPrimaryBookmaker,
124
133
  lastPolledData,
125
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
134
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
135
+ playersMap
126
136
  );
127
137
 
128
138
  expect(market.childMarkets.length).toBe(3);
@@ -141,7 +151,8 @@ describe('Bookmakers', () => {
141
151
  MAX_IMPLIED_PERCENTAGE_DIFF,
142
152
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
143
153
  lastPolledData,
144
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
154
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
155
+ playersMap
145
156
  );
146
157
 
147
158
  expect(market.childMarkets.length).toBe(1);
@@ -5,9 +5,16 @@ import { mapOpticOddsApiFixtureOdds } from '../../utils/opticOdds';
5
5
  import { LeagueMocks } from '../mock/MockLeagueMap';
6
6
  import { MockOnlyMoneyline, MockOpticSoccer } from '../mock/MockOpticSoccer';
7
7
  import { mockSoccer } from '../mock/MockSoccerRedis';
8
- import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
8
+ import { MockNbaData } from '../mock/OpticOddsMock/MockNBA';
9
+ import { MockRedisNba } from '../mock/OpticOddsMock/MockRedisNba';
10
+ import {
11
+ getLastPolledDataForBookmakers,
12
+ getPlayersMap,
13
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
14
+ } from '../utils/helper';
9
15
 
10
16
  const lastPolledData = getLastPolledDataForBookmakers();
17
+ const playersMap = getPlayersMap();
11
18
 
12
19
  describe('Markets', () => {
13
20
  describe('LeagueMap configuration', () => {
@@ -25,7 +32,8 @@ describe('Markets', () => {
25
32
  MAX_IMPLIED_PERCENTAGE_DIFF,
26
33
  LeagueMocks.leagueInfoOnlyParent,
27
34
  lastPolledData,
28
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
35
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
36
+ playersMap
29
37
  );
30
38
 
31
39
  expect(market.childMarkets).toHaveLength(0);
@@ -44,7 +52,8 @@ describe('Markets', () => {
44
52
  MAX_IMPLIED_PERCENTAGE_DIFF,
45
53
  LeagueMocks.leagueInfoMockDisabledChilds,
46
54
  lastPolledData,
47
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
55
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
56
+ playersMap
48
57
  );
49
58
 
50
59
  expect(market.childMarkets).toHaveLength(0);
@@ -63,7 +72,8 @@ describe('Markets', () => {
63
72
  MAX_IMPLIED_PERCENTAGE_DIFF,
64
73
  LeagueMocks.leagueInfoEnabledSpreadDisabledTotals,
65
74
  lastPolledData,
66
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
75
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
76
+ playersMap
67
77
  );
68
78
 
69
79
  const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
@@ -86,7 +96,8 @@ describe('Markets', () => {
86
96
  MAX_IMPLIED_PERCENTAGE_DIFF,
87
97
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
88
98
  lastPolledData,
89
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
99
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
100
+ playersMap
90
101
  );
91
102
 
92
103
  const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
@@ -109,7 +120,8 @@ describe('Markets', () => {
109
120
  MAX_IMPLIED_PERCENTAGE_DIFF,
110
121
  LeagueMocks.leagueInfoEnabledAll,
111
122
  lastPolledData,
112
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
123
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
124
+ playersMap
113
125
  );
114
126
 
115
127
  const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
@@ -164,7 +176,8 @@ describe('Markets', () => {
164
176
  MAX_IMPLIED_PERCENTAGE_DIFF,
165
177
  LeagueMocks.leagueInfoOnlyParentDiffSportId,
166
178
  lastPolledData,
167
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
179
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
180
+ playersMap
168
181
  );
169
182
 
170
183
  expect(warnSpy).toHaveBeenCalled();
@@ -173,5 +186,29 @@ describe('Markets', () => {
173
186
  // Restore the original implementation
174
187
  warnSpy.mockRestore();
175
188
  });
189
+
190
+ it('Should return child markets with player props', () => {
191
+ const freshMockSoccer = JSON.parse(JSON.stringify(MockRedisNba));
192
+ const freshMockOpticSoccer = JSON.parse(JSON.stringify(MockNbaData));
193
+ const market = processMarket(
194
+ freshMockSoccer,
195
+ mapOpticOddsApiFixtureOdds([freshMockOpticSoccer])[0],
196
+ ['bovada', 'draftkings'], // this will be ignored as primaryBookmaker is defined in LeagueMap
197
+ [],
198
+ true,
199
+ undefined,
200
+ MAX_IMPLIED_PERCENTAGE_DIFF,
201
+ LeagueMocks.PlayerAssist, // league map with player props configured
202
+ lastPolledData,
203
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
204
+ playersMap
205
+ );
206
+
207
+ market.childMarkets.forEach((child: any) => {
208
+ expect(child.playerProps).toBeDefined();
209
+ expect(child.playerProps.playerId).toBeDefined();
210
+ expect(child.playerProps.playerName).toBeDefined();
211
+ });
212
+ });
176
213
  });
177
214
  });
@@ -10,9 +10,14 @@ import {
10
10
  MockZeroOdds,
11
11
  } from '../mock/MockOpticSoccer';
12
12
  import { mockSoccer } from '../mock/MockSoccerRedis';
13
- import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
13
+ import {
14
+ getLastPolledDataForBookmakers,
15
+ getPlayersMap,
16
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
17
+ } from '../utils/helper';
14
18
 
15
19
  const lastPolledData = getLastPolledDataForBookmakers();
20
+ const playersMap = getPlayersMap();
16
21
 
17
22
  describe('Odds', () => {
18
23
  it('Should return odds for moneyline', () => {
@@ -28,7 +33,8 @@ describe('Odds', () => {
28
33
  MAX_IMPLIED_PERCENTAGE_DIFF,
29
34
  LeagueMocks.leagueInfoOnlyParent,
30
35
  lastPolledData,
31
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
36
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
37
+ playersMap
32
38
  );
33
39
 
34
40
  const hasOdds = market.odds.some(
@@ -51,7 +57,8 @@ describe('Odds', () => {
51
57
  MAX_IMPLIED_PERCENTAGE_DIFF,
52
58
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
53
59
  lastPolledData,
54
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
60
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
61
+ playersMap
55
62
  );
56
63
 
57
64
  const hasOdds = market.odds.some(
@@ -76,7 +83,8 @@ describe('Odds', () => {
76
83
  MAX_IMPLIED_PERCENTAGE_DIFF,
77
84
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
78
85
  lastPolledData,
79
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
86
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
87
+ playersMap
80
88
  );
81
89
 
82
90
  const hasChildMarkets = market.childMarkets.length > 0;
@@ -96,7 +104,8 @@ describe('Odds', () => {
96
104
  MAX_IMPLIED_PERCENTAGE_DIFF,
97
105
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
98
106
  lastPolledData,
99
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
107
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
108
+ playersMap
100
109
  );
101
110
 
102
111
  expect(market.childMarkets).toHaveLength(0);
@@ -5,9 +5,14 @@ import { mapOpticOddsApiFixtureOdds } from '../../utils/opticOdds';
5
5
  import { LeagueMocks } from '../mock/MockLeagueMap';
6
6
  import { MockAfterSpreadZeroOdds1, MockOnlyMoneylineFavorite, MockOpticSoccer } from '../mock/MockOpticSoccer';
7
7
  import { mockSoccer } from '../mock/MockSoccerRedis';
8
- import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
8
+ import {
9
+ getLastPolledDataForBookmakers,
10
+ getPlayersMap,
11
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
12
+ } from '../utils/helper';
9
13
 
10
14
  const lastPolledData = getLastPolledDataForBookmakers();
15
+ const playersMap = getPlayersMap();
11
16
 
12
17
  describe('Spread configuration', () => {
13
18
  it('Should return zero odds for quotes that sum up total probability above 1', () => {
@@ -23,7 +28,8 @@ describe('Spread configuration', () => {
23
28
  MAX_IMPLIED_PERCENTAGE_DIFF,
24
29
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
25
30
  lastPolledData,
26
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
31
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
32
+ playersMap
27
33
  );
28
34
 
29
35
  const hasOdds = market.odds.some(
@@ -50,7 +56,8 @@ describe('Spread configuration', () => {
50
56
  MAX_IMPLIED_PERCENTAGE_DIFF,
51
57
  LeagueMocks.leagueInfoOnlyParent,
52
58
  lastPolledData,
53
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
59
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
60
+ playersMap
54
61
  )
55
62
  )
56
63
  );
@@ -67,7 +74,8 @@ describe('Spread configuration', () => {
67
74
  MAX_IMPLIED_PERCENTAGE_DIFF,
68
75
  LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
69
76
  lastPolledData,
70
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
77
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
78
+ playersMap
71
79
  )
72
80
  )
73
81
  );
@@ -104,7 +112,8 @@ describe('Spread configuration', () => {
104
112
  MAX_IMPLIED_PERCENTAGE_DIFF,
105
113
  LeagueMocks.leagueInfoOnlyParent,
106
114
  lastPolledData,
107
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
115
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
116
+ playersMap
108
117
  )
109
118
  )
110
119
  );
@@ -121,7 +130,8 @@ describe('Spread configuration', () => {
121
130
  MAX_IMPLIED_PERCENTAGE_DIFF,
122
131
  LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
123
132
  lastPolledData,
124
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
133
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
134
+ playersMap
125
135
  )
126
136
  )
127
137
  );
@@ -8,4 +8,12 @@ export const getLastPolledDataForBookmakers = () => {
8
8
  return lastPolledData;
9
9
  };
10
10
 
11
+ export const getPlayersMap = () => {
12
+ const playersMap: Map<string, number> = new Map<string, number>();
13
+ playersMap.set('0C07D14CC5DC', 13234);
14
+ playersMap.set('AD91EA260284', 56789);
15
+ playersMap.set('674851E026BC', 98765);
16
+ return playersMap;
17
+ };
18
+
11
19
  export const MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST = 30000; // 30 seconds
@@ -30,7 +30,8 @@ export const processMarket = (
30
30
  maxPercentageDiffBetwenOdds: number,
31
31
  leagueMap: any,
32
32
  lastPolledData: LastPolledArray,
33
- maxAllowedProviderDataStaleDelay: number
33
+ maxAllowedProviderDataStaleDelay: number,
34
+ playersMap: Map<string, number>
34
35
  ) => {
35
36
  const sportSpreadData = spreadData.filter((data: any) => data.sportId === String(market.leagueId));
36
37
  const leagueInfo = getLeagueInfo(market.leagueId, leagueMap);
@@ -89,7 +90,8 @@ export const processMarket = (
89
90
  leagueMap,
90
91
  lastPolledData,
91
92
  maxAllowedProviderDataStaleDelay,
92
- maxPercentageDiffBetwenOdds
93
+ maxPercentageDiffBetwenOdds,
94
+ playersMap
93
95
  );
94
96
 
95
97
  const packedChildMarkets = childMarkets.map((childMarket: any) => {
package/src/utils/odds.ts CHANGED
@@ -141,9 +141,6 @@ export const getParentOdds = (
141
141
  0 // typeId for moneyline
142
142
  );
143
143
 
144
- console.log('defaultProviders', liveOddsProviders);
145
- console.log('bookmakers for moneyline', bookmakers);
146
-
147
144
  const isValidLastPolled = isLastPolledForBookmakersValid(
148
145
  lastPolledData,
149
146
  maxAllowedProviderDataStaleDelay,
@@ -217,7 +214,8 @@ export const createChildMarkets: (
217
214
  leagueMap: any,
218
215
  lastPolledData: LastPolledArray,
219
216
  maxAllowedProviderDataStaleDelay: number,
220
- maxImpliedPercentageDifference: number
217
+ maxImpliedPercentageDifference: number,
218
+ playersMap: Map<string, number>
221
219
  ) => ChildMarket[] = (
222
220
  apiResponseWithOdds,
223
221
  spreadDataForSport,
@@ -227,7 +225,8 @@ export const createChildMarkets: (
227
225
  leagueMap,
228
226
  lastPolledData,
229
227
  maxAllowedProviderDataStaleDelay,
230
- maxImpliedPercentageDifference
228
+ maxImpliedPercentageDifference,
229
+ playersMap
231
230
  ) => {
232
231
  const [spreadOdds, totalOdds, moneylineOdds, correctScoreOdds, doubleChanceOdds, ggOdds, childMarkets]: any[] = [
233
232
  [],
@@ -245,7 +244,7 @@ export const createChildMarkets: (
245
244
  };
246
245
 
247
246
  if (leagueInfo.length > 0) {
248
- const allChildOdds = filterOddsByMarketNameBookmaker(apiResponseWithOdds.odds, leagueInfo);
247
+ const allChildOdds = filterOdds(apiResponseWithOdds.odds, leagueInfo, playersMap);
249
248
  const checkedChildOdds = checkOddsFromBookmakersForChildMarkets(
250
249
  allChildOdds,
251
250
  leagueInfo,
@@ -272,7 +271,7 @@ export const createChildMarkets: (
272
271
 
273
272
  const homeAwayFormattedOdds = [
274
273
  ...groupAndFormatSpreadOdds(spreadOdds, commonData),
275
- ...groupAndFormatTotalOdds(totalOdds, commonData),
274
+ ...groupAndFormatTotalOdds(totalOdds, commonData), // playerProps are handled inside this function
276
275
  ...groupAndFormatMoneylineOdds(moneylineOdds, commonData),
277
276
  ...groupAndFormatGGOdds(ggOdds),
278
277
  ...groupAndFormatDoubleChanceOdds(doubleChanceOdds, commonData),
@@ -287,12 +286,20 @@ export const createChildMarkets: (
287
286
  );
288
287
 
289
288
  homeAwayOddsWithSpreadAdjusted.forEach((data) => {
289
+ let playerProps = undefined;
290
+ if (data.playerProps) {
291
+ playerProps = {
292
+ playerId: playersMap.get(data.playerProps.playerId.toString()), // convert from opticOdds playerId to our internal playerId
293
+ playerName: data.playerProps.playerName,
294
+ };
295
+ }
290
296
  const childMarket = {
291
297
  leagueId: Number(data.sportId),
292
298
  typeId: Number(data.typeId),
293
299
  type: MarketTypeMap[data.typeId as MarketType]?.key || '',
294
300
  line: Number(data.line || 0),
295
301
  odds: data.odds,
302
+ playerProps,
296
303
  };
297
304
  const leagueInfoByTypeId = leagueInfo.find((league) => Number(league.typeId) === Number(data.typeId));
298
305
  const minOdds = leagueInfoByTypeId?.minOdds; // minimum odds configured for child market (e.g. 0.95 implied probability)
@@ -346,7 +353,7 @@ export const createChildMarkets: (
346
353
  * @param {string} oddsProvider - The main odds provider to filter by.
347
354
  * @returns {Array} The filtered odds array.
348
355
  */
349
- export const filterOddsByMarketNameBookmaker = (oddsArray: Odds, leagueInfos: LeagueConfigInfo[]): any => {
356
+ export const filterOdds = (oddsArray: Odds, leagueInfos: LeagueConfigInfo[], playersMap: Map<string, number>): any => {
350
357
  const allChildMarketsTypes = leagueInfos
351
358
  .filter(
352
359
  (leagueInfo) =>
@@ -356,7 +363,10 @@ export const filterOddsByMarketNameBookmaker = (oddsArray: Odds, leagueInfos: Le
356
363
  .map((leagueInfo) => leagueInfo.marketName.toLowerCase());
357
364
  return oddsArray.reduce((acc: any, odd: any) => {
358
365
  if (allChildMarketsTypes.includes(odd.marketName.toLowerCase())) {
359
- const { points, marketName, selection, selectionLine, sportsBookName } = odd;
366
+ const { points, marketName, selection, selectionLine, sportsBookName, playerId } = odd;
367
+ if (playerId && !playersMap.has(playerId)) {
368
+ return acc;
369
+ }
360
370
  const key = `${sportsBookName.toLowerCase()}_${marketName.toLowerCase()}_${points}_${selection}_${selectionLine}`;
361
371
  acc[key] = {
362
372
  ...odd,
@@ -443,6 +453,13 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
443
453
  acc[key].typeId = odd.typeId;
444
454
  acc[key].type = odd.type;
445
455
  acc[key].sportId = odd.sportId;
456
+
457
+ if (odd.playerId) {
458
+ acc[key].playerProps = {
459
+ playerId: odd.playerId, // Player ID from OpticOdds, this will be converted to our internal playerId later
460
+ playerName: odd.selection,
461
+ };
462
+ }
446
463
  }
447
464
 
448
465
  return acc;
@@ -450,8 +467,8 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
450
467
 
451
468
  // Format the grouped odds into the desired output
452
469
  const formattedOdds = Object.entries(groupedOdds as any).reduce((acc: any, [key, value]) => {
453
- const [_marketName, selection, selectionLine] = key.split('_');
454
- const line = parseFloat(selectionLine);
470
+ const [_marketName, selection, points] = key.split('_');
471
+ const line = parseFloat(points);
455
472
 
456
473
  // if we have away team in total odds we know the market is team total and we need to increase typeId by one.
457
474
  // if this is false typeId is already mapped correctly
@@ -463,6 +480,7 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
463
480
  typeId: !isAwayTeam ? (value as any).typeId : Number((value as any).typeId) + 1,
464
481
  sportId: (value as any).sportId,
465
482
  type: (value as any).type,
483
+ playerProps: (value as any).playerProps,
466
484
  });
467
485
  }
468
486
  return acc;