overtime-live-trading-utils 2.0.16 → 2.0.18

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": "2.0.16",
3
+ "version": "2.0.18",
4
4
  "description": "",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -15,7 +15,7 @@
15
15
  "@types/node": "^20.8.10",
16
16
  "bytes32": "^0.0.3",
17
17
  "oddslib": "^2.1.1",
18
- "overtime-utils": "^0.0.44",
18
+ "overtime-utils": "^0.0.47",
19
19
  "react": "^17.0.1"
20
20
  },
21
21
  "devDependencies": {
@@ -306,6 +306,7 @@ export const LeagueIdMapOpticOdds: Record<number, string> = {
306
306
  20147: 'CONCACAF - Champions Cup',
307
307
  20148: 'UEFA - Nations League Women',
308
308
  20149: 'Canada - Premier League',
309
+ 20150: 'Norway - Eliteserien',
309
310
  20200: 'Eurocup',
310
311
  20201: 'Spain - Liga ACB',
311
312
  20202: 'Italy - Lega Basket Serie A',
@@ -30,6 +30,26 @@ const totalMock: LeagueConfigInfo = {
30
30
  minOdds: 0.75,
31
31
  };
32
32
 
33
+ const doubleChanceMock: LeagueConfigInfo = {
34
+ sportId: 9806,
35
+ enabled: 'true',
36
+ marketName: 'Double Chance',
37
+ typeId: 10003,
38
+ type: 'Double Chance',
39
+ maxOdds: 0.01,
40
+ minOdds: 0.99,
41
+ };
42
+
43
+ const correctScoreMock: LeagueConfigInfo = {
44
+ sportId: 9806,
45
+ enabled: 'true',
46
+ marketName: 'Correct Score',
47
+ typeId: 10100,
48
+ type: 'Correct Score',
49
+ maxOdds: 0.25,
50
+ minOdds: 0.75,
51
+ };
52
+
33
53
  const childMoneylineMock: LeagueConfigInfo = {
34
54
  sportId: 9806,
35
55
  enabled: 'true',
@@ -54,6 +74,8 @@ const leagueInfoMockDisabledChilds: LeagueConfigInfo[] = [
54
74
  baseLeagueInfo,
55
75
  { ...spreadMock, enabled: 'false' },
56
76
  { ...totalMock, enabled: 'false' },
77
+ { ...doubleChanceMock, enabled: 'false' },
78
+ { ...correctScoreMock, enabled: 'false' },
57
79
  ];
58
80
 
59
81
  const leagueInfoEnabledSpreadDisabledTotals: LeagueConfigInfo[] = [
@@ -62,8 +84,23 @@ const leagueInfoEnabledSpreadDisabledTotals: LeagueConfigInfo[] = [
62
84
  { ...totalMock, enabled: 'false' },
63
85
  ];
64
86
 
87
+ const leagueInfoDisabledCorrectScoreAndDoubleChance: LeagueConfigInfo[] = [
88
+ baseLeagueInfo,
89
+ spreadMock,
90
+ totalMock,
91
+ { ...doubleChanceMock, enabled: 'false' },
92
+ { ...correctScoreMock, enabled: 'false' },
93
+ ];
94
+
65
95
  const leagueInfoEnabledSpeadAndTotals: LeagueConfigInfo[] = [baseLeagueInfo, spreadMock, totalMock];
66
- const leagueInfoEnabledAll: LeagueConfigInfo[] = [baseLeagueInfo, spreadMock, totalMock, childMoneylineMock];
96
+ const leagueInfoEnabledAll: LeagueConfigInfo[] = [
97
+ baseLeagueInfo,
98
+ spreadMock,
99
+ totalMock,
100
+ childMoneylineMock,
101
+ doubleChanceMock,
102
+ correctScoreMock,
103
+ ];
67
104
 
68
105
  // Grouped Exports
69
106
  export const LeagueMocks = {
@@ -74,4 +111,5 @@ export const LeagueMocks = {
74
111
  leagueInfoEnabledSpreadDisabledTotals,
75
112
  leagueInfoEnabledSpeadAndTotals,
76
113
  leagueInfoEnabledAll,
114
+ leagueInfoDisabledCorrectScoreAndDoubleChance,
77
115
  };
@@ -101,10 +101,14 @@ describe('Markets', () => {
101
101
  const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
102
102
  const containsTotal = market.childMarkets.some((child: any) => child.type === 'total');
103
103
  const containsChildMoneyline = market.childMarkets.some((child: any) => child.type === 'moneyline');
104
+ const containsChildCorrectScore = market.childMarkets.some((child: any) => child.type === 'correct score');
105
+ const containsChildDoubleChance = market.childMarkets.some((child: any) => child.type === 'double chance');
104
106
 
105
107
  expect(containsSpread).toBe(true);
106
108
  expect(containsTotal).toBe(true);
107
109
  expect(containsChildMoneyline).toBe(true);
110
+ expect(containsChildCorrectScore).toBe(true);
111
+ expect(containsChildDoubleChance).toBe(true);
108
112
  });
109
113
 
110
114
  it('Should return warning message that there are is no configuration available in league map csv', () => {
@@ -14,14 +14,16 @@ describe('Sports', () => {
14
14
  });
15
15
 
16
16
  it('Should return all enabled bet types for league', () => {
17
- const betTypes = getBetTypesForLeague(9806, LeagueMocks.leagueInfoEnabledSpeadAndTotals);
17
+ const betTypes = getBetTypesForLeague(9806, LeagueMocks.leagueInfoEnabledAll);
18
18
 
19
19
  expect(betTypes).toContain('Moneyline');
20
20
  expect(betTypes).toContain('Goal Spread');
21
21
  expect(betTypes).toContain('Total Goals');
22
+ expect(betTypes).toContain('Double Chance');
23
+ expect(betTypes).toContain('Correct Score');
22
24
  });
23
25
 
24
- it('Should return all enabled bet types for league, and not contain disabled ones', () => {
26
+ it('Should return all enabled bet types for league, and not contain disabled ones (Totals)', () => {
25
27
  const betTypes = getBetTypesForLeague(9806, LeagueMocks.leagueInfoEnabledSpreadDisabledTotals);
26
28
 
27
29
  expect(betTypes).toContain('Moneyline');
@@ -29,6 +31,15 @@ describe('Sports', () => {
29
31
  expect(betTypes).not.toContain('Total Goals');
30
32
  });
31
33
 
34
+ it('Should return all enabled bet types for league, and not contain disabled ones (Double Chance and Correct Score)', () => {
35
+ const betTypes = getBetTypesForLeague(9806, LeagueMocks.leagueInfoDisabledCorrectScoreAndDoubleChance);
36
+
37
+ expect(betTypes).toContain('Moneyline');
38
+ expect(betTypes).toContain('Goal Spread');
39
+ expect(betTypes).not.toContain('Double Chance');
40
+ expect(betTypes).not.toContain('Correct Score');
41
+ });
42
+
32
43
  it('Should return all enabled spread bet types for league', () => {
33
44
  const betTypes = getLeagueSpreadTypes(9806, LeagueMocks.leagueInfoEnabledSpeadAndTotals);
34
45
 
package/src/utils/odds.ts CHANGED
@@ -191,12 +191,20 @@ export const createChildMarkets: (
191
191
  defaultSpreadForLiveMarkets,
192
192
  leagueMap
193
193
  ) => {
194
- const [spreadOdds, totalOdds, moneylineOdds, childMarkets]: any[] = [[], [], [], []];
194
+ const [spreadOdds, totalOdds, moneylineOdds, correctScoreOdds, doubleChanceOdds, childMarkets]: any[] = [
195
+ [],
196
+ [],
197
+ [],
198
+ [],
199
+ [],
200
+ [],
201
+ ];
195
202
  const leagueInfo = getLeagueInfo(leagueId, leagueMap);
196
203
  const commonData = {
197
204
  homeTeam: apiResponseWithOdds.homeTeam,
198
205
  awayTeam: apiResponseWithOdds.awayTeam,
199
206
  };
207
+
200
208
  if (leagueInfo.length > 0) {
201
209
  // TODO ADD ODDS COMPARISON BETWEEN BOOKMAKERS
202
210
  const allChildOdds = filterOddsByMarketNameBookmaker(
@@ -212,22 +220,28 @@ export const createChildMarkets: (
212
220
  if (Math.abs(Number(odd.points) % 1) === 0.5) spreadOdds.push(odd);
213
221
  } else if (odd.type === 'Moneyline') {
214
222
  moneylineOdds.push(odd);
223
+ } else if (odd.type === 'Correct Score') {
224
+ correctScoreOdds.push(odd);
225
+ } else if (odd.type === 'Double Chance') {
226
+ doubleChanceOdds.push(odd);
215
227
  }
216
228
  });
217
229
 
218
- const formattedOdds = [
230
+ const homeAwayFormattedOdds = [
219
231
  ...groupAndFormatSpreadOdds(spreadOdds, commonData),
220
232
  ...groupAndFormatTotalOdds(totalOdds, commonData),
221
233
  ...groupAndFormatMoneylineOdds(moneylineOdds, commonData),
234
+ ...groupAndFormatDoubleChanceOdds(doubleChanceOdds, commonData),
222
235
  ];
236
+ const otherFormattedOdds = [...groupAndFormatCorrectScoreOdds(correctScoreOdds, commonData)];
223
237
 
224
- const oddsWithSpreadAdjusted = adjustSpreadOnChildOdds(
225
- formattedOdds,
238
+ const homeAwayOddsWithSpreadAdjusted = adjustSpreadOnChildOdds(
239
+ homeAwayFormattedOdds,
226
240
  spreadDataForSport,
227
241
  defaultSpreadForLiveMarkets
228
242
  );
229
243
 
230
- oddsWithSpreadAdjusted.forEach((data) => {
244
+ homeAwayOddsWithSpreadAdjusted.forEach((data) => {
231
245
  const childMarket = {
232
246
  leagueId: Number(data.sportId),
233
247
  typeId: Number(data.typeId),
@@ -251,9 +265,29 @@ export const createChildMarkets: (
251
265
  childMarkets.push(childMarket);
252
266
  }
253
267
  });
268
+
269
+ otherFormattedOdds.forEach((data) => {
270
+ const leagueInfoByTypeId = leagueInfo.find((league) => Number(league.typeId) === Number(data.typeId));
271
+ const minOdds = leagueInfoByTypeId?.minOdds;
272
+ const maxOdds = leagueInfoByTypeId?.maxOdds;
273
+
274
+ const childMarket = {
275
+ leagueId: Number(data.sportId),
276
+ typeId: Number(data.typeId),
277
+ type: data.type.toLowerCase(),
278
+ line: Number(data.line || 0),
279
+ odds: data.odds.map((odd: any) => {
280
+ const impliedOdds = convertOddsToImpl(odd) || ZERO;
281
+ return !minOdds || !maxOdds || impliedOdds >= minOdds || impliedOdds <= maxOdds ? 0 : impliedOdds;
282
+ }),
283
+ positionNames: data.positionNames,
284
+ };
285
+ childMarkets.push(childMarket);
286
+ });
254
287
  } else {
255
288
  console.warn(`No child markets for leagueID: ${Number(leagueId)}`);
256
289
  }
290
+
257
291
  return childMarkets;
258
292
  };
259
293
 
@@ -395,11 +429,11 @@ export const groupAndFormatTotalOdds = (oddsArray: any[], commonData: HomeAwayTe
395
429
  };
396
430
 
397
431
  /**
398
- * Groups spread odds by their lines and formats the result.
432
+ * Groups moneyline odds by their lines and formats the result.
399
433
  *
400
434
  * @param {Array} oddsArray - The input array of odds objects.
401
435
  * @param {Object} commonData - The common data object containing homeTeam information.
402
- * @returns {Array} The grouped and formatted spread odds.
436
+ * @returns {Array} The grouped and formatted moneyline odds.
403
437
  */
404
438
  export const groupAndFormatMoneylineOdds = (oddsArray: any[], commonData: HomeAwayTeams) => {
405
439
  // Group odds by their selection points and selection
@@ -439,6 +473,118 @@ export const groupAndFormatMoneylineOdds = (oddsArray: any[], commonData: HomeAw
439
473
  return formattedOdds;
440
474
  };
441
475
 
476
+ /**
477
+ * Groups correct score odds by their lines and formats the result.
478
+ *
479
+ * @param {Array} oddsArray - The input array of odds objects.
480
+ * @param {Object} commonData - The common data object containing homeTeam and awayTeam information.
481
+ * @returns {Array} The grouped and formatted correct score odds.
482
+ */
483
+ export const groupAndFormatCorrectScoreOdds = (oddsArray: any[], commonData: HomeAwayTeams): any[] => {
484
+ const homeTeamKey = commonData.homeTeam.toLowerCase().replace(/\s+/g, '_');
485
+ const awayTeamKey = commonData.awayTeam.toLowerCase().replace(/\s+/g, '_');
486
+
487
+ const oddsMap = {
488
+ draw_0_0: 0,
489
+ draw_1_1: 0,
490
+ draw_2_2: 0,
491
+ draw_3_3: 0,
492
+ draw_4_4: 0,
493
+ [`${homeTeamKey}_1_0`]: 0,
494
+ [`${homeTeamKey}_2_0`]: 0,
495
+ [`${homeTeamKey}_2_1`]: 0,
496
+ [`${homeTeamKey}_3_0`]: 0,
497
+ [`${homeTeamKey}_3_1`]: 0,
498
+ [`${homeTeamKey}_3_2`]: 0,
499
+ [`${homeTeamKey}_4_0`]: 0,
500
+ [`${homeTeamKey}_4_1`]: 0,
501
+ [`${homeTeamKey}_4_2`]: 0,
502
+ [`${homeTeamKey}_4_3`]: 0,
503
+ [`${awayTeamKey}_1_0`]: 0,
504
+ [`${awayTeamKey}_2_0`]: 0,
505
+ [`${awayTeamKey}_2_1`]: 0,
506
+ [`${awayTeamKey}_3_0`]: 0,
507
+ [`${awayTeamKey}_3_1`]: 0,
508
+ [`${awayTeamKey}_3_2`]: 0,
509
+ [`${awayTeamKey}_4_0`]: 0,
510
+ [`${awayTeamKey}_4_1`]: 0,
511
+ [`${awayTeamKey}_4_2`]: 0,
512
+ [`${awayTeamKey}_4_3`]: 0,
513
+ other: 0,
514
+ };
515
+
516
+ // Populate the oddsMap with the odds from the provided array
517
+ oddsArray.forEach((odd) => {
518
+ const normalizedSelection = `${odd.selection.toLowerCase().replace(/\s+/g, '_')}_${odd.selectionLine.replace(
519
+ ':',
520
+ '_'
521
+ )}`;
522
+ if (oddsMap.hasOwnProperty(normalizedSelection)) {
523
+ oddsMap[normalizedSelection] = odd.price;
524
+ }
525
+ });
526
+
527
+ const allOddsAreZero = Object.values(oddsMap).every((odd) => odd === ZERO);
528
+
529
+ if (allOddsAreZero) {
530
+ return [];
531
+ }
532
+
533
+ const positionNames = Object.keys(oddsMap);
534
+
535
+ // Create the market object
536
+ const marketObject = {
537
+ homeTeam: commonData.homeTeam,
538
+ awayTeam: commonData.awayTeam,
539
+ line: 0,
540
+ positionNames: positionNames,
541
+ odds: Object.values(oddsMap),
542
+ type: 'Correct Score',
543
+ typeId: 10100,
544
+ };
545
+ return [marketObject];
546
+ };
547
+
548
+ /**
549
+ * Groups double chance odds by their lines and formats the result.
550
+ *
551
+ * @param {Array} oddsArray - The input array of odds objects.
552
+ * @param {Object} commonData - The common data object containing homeTeam and awayTeam information.
553
+ * @returns {Array} The grouped and formatted correct score odds.
554
+ */
555
+ export const groupAndFormatDoubleChanceOdds = (oddsArray: any[], commonData: HomeAwayTeams) => {
556
+ let probability1X = 0;
557
+ let probability12 = 0;
558
+ let probabilityX2 = 0;
559
+
560
+ oddsArray.forEach((odd) => {
561
+ if (odd.selection.includes(commonData.homeTeam)) {
562
+ if (odd.selection.includes(commonData.awayTeam)) {
563
+ probability12 = odd.price;
564
+ } else {
565
+ probability1X = odd.price;
566
+ }
567
+ } else if (odd.selection.includes(commonData.awayTeam)) {
568
+ probabilityX2 = odd.price;
569
+ }
570
+ });
571
+
572
+ if ([probability1X, probability12, probabilityX2].every((odd) => odd === ZERO)) {
573
+ return [];
574
+ }
575
+ // Create the market object
576
+ const marketObject = {
577
+ homeTeam: commonData.homeTeam,
578
+ awayTeam: commonData.awayTeam,
579
+ line: 0,
580
+ odds: [probability1X, probability12, probabilityX2],
581
+ type: 'Double Chance',
582
+ typeId: 10003,
583
+ };
584
+ return [marketObject];
585
+ };
586
+
587
+ // used for home/away markets
442
588
  export const adjustSpreadOnChildOdds = (
443
589
  iterableGroupedOdds: any[],
444
590
  spreadDataForSport: any,