overtime-live-trading-utils 3.0.2-rc.2 → 3.0.2

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.2-rc.2",
3
+ "version": "3.0.2",
4
4
  "description": "",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -1,5 +1,5 @@
1
+ import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
1
2
  import { DIFF_BETWEEN_BOOKMAKERS_MESSAGE, ZERO_ODDS_MESSAGE } from '../../constants/errors';
2
- import { ODDS_THRESHOLD_ANCHORS } from '../../constants/odds';
3
3
  import { processMarket } from '../../utils/markets';
4
4
  import { mapOpticOddsApiFixtureOdds } from '../../utils/opticOdds';
5
5
  import { LeagueMocks } from '../mock/MockLeagueMap';
@@ -10,14 +10,9 @@ import {
10
10
  MockOnlyMoneylineWithDifferentSportsbook,
11
11
  } from '../mock/MockOpticSoccer';
12
12
  import { mockSoccer } from '../mock/MockSoccerRedis';
13
- import {
14
- getLastPolledDataForBookmakers,
15
- getPlayersMap,
16
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
17
- } from '../utils/helper';
13
+ import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
18
14
 
19
15
  const lastPolledData = getLastPolledDataForBookmakers();
20
- const playersMap = getPlayersMap();
21
16
 
22
17
  describe('Bookmakers', () => {
23
18
  it('Should return zero odds for moneyline when one of the bookmakers has no odds', () => {
@@ -30,11 +25,10 @@ describe('Bookmakers', () => {
30
25
  [],
31
26
  true,
32
27
  undefined,
33
- ODDS_THRESHOLD_ANCHORS,
28
+ MAX_IMPLIED_PERCENTAGE_DIFF,
34
29
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
35
30
  lastPolledData,
36
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
37
- playersMap
31
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
38
32
  );
39
33
 
40
34
  const hasOdds = market.odds.some(
@@ -56,11 +50,10 @@ describe('Bookmakers', () => {
56
50
  [],
57
51
  true,
58
52
  undefined,
59
- ODDS_THRESHOLD_ANCHORS,
53
+ 5,
60
54
  LeagueMocks.leagueInfoOnlyParent,
61
55
  lastPolledData,
62
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
63
- playersMap
56
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
64
57
  );
65
58
 
66
59
  const hasOdds = market.odds.some(
@@ -82,11 +75,10 @@ describe('Bookmakers', () => {
82
75
  [],
83
76
  true,
84
77
  undefined,
85
- ODDS_THRESHOLD_ANCHORS,
78
+ MAX_IMPLIED_PERCENTAGE_DIFF,
86
79
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
87
80
  lastPolledData,
88
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
89
- playersMap
81
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
90
82
  );
91
83
 
92
84
  const hasOdds = market.odds.some(
@@ -108,11 +100,10 @@ describe('Bookmakers', () => {
108
100
  [],
109
101
  true,
110
102
  undefined,
111
- ODDS_THRESHOLD_ANCHORS,
103
+ MAX_IMPLIED_PERCENTAGE_DIFF,
112
104
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
113
105
  lastPolledData,
114
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
115
- playersMap
106
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
116
107
  );
117
108
 
118
109
  expect(market.childMarkets.length).toBe(2);
@@ -128,11 +119,10 @@ describe('Bookmakers', () => {
128
119
  [],
129
120
  true,
130
121
  undefined,
131
- ODDS_THRESHOLD_ANCHORS,
122
+ MAX_IMPLIED_PERCENTAGE_DIFF,
132
123
  LeagueMocks.leaguInfoDifferentPrimaryBookmaker,
133
124
  lastPolledData,
134
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
135
- playersMap
125
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
136
126
  );
137
127
 
138
128
  expect(market.childMarkets.length).toBe(3);
@@ -148,11 +138,10 @@ describe('Bookmakers', () => {
148
138
  [],
149
139
  true,
150
140
  undefined,
151
- ODDS_THRESHOLD_ANCHORS,
141
+ MAX_IMPLIED_PERCENTAGE_DIFF,
152
142
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
153
143
  lastPolledData,
154
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
155
- playersMap
144
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
156
145
  );
157
146
 
158
147
  expect(market.childMarkets.length).toBe(1);
@@ -1,20 +1,13 @@
1
+ import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
1
2
  import { NO_MARKETS_FOR_LEAGUE_ID } from '../../constants/errors';
2
- import { ODDS_THRESHOLD_ANCHORS } from '../../constants/odds';
3
3
  import { processMarket } from '../../utils/markets';
4
4
  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 { 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';
8
+ import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
15
9
 
16
10
  const lastPolledData = getLastPolledDataForBookmakers();
17
- const playersMap = getPlayersMap();
18
11
 
19
12
  describe('Markets', () => {
20
13
  describe('LeagueMap configuration', () => {
@@ -29,11 +22,10 @@ describe('Markets', () => {
29
22
  [],
30
23
  true,
31
24
  undefined,
32
- ODDS_THRESHOLD_ANCHORS,
25
+ MAX_IMPLIED_PERCENTAGE_DIFF,
33
26
  LeagueMocks.leagueInfoOnlyParent,
34
27
  lastPolledData,
35
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
36
- playersMap
28
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
37
29
  );
38
30
 
39
31
  expect(market.childMarkets).toHaveLength(0);
@@ -49,11 +41,10 @@ describe('Markets', () => {
49
41
  [],
50
42
  true,
51
43
  undefined,
52
- ODDS_THRESHOLD_ANCHORS,
44
+ MAX_IMPLIED_PERCENTAGE_DIFF,
53
45
  LeagueMocks.leagueInfoMockDisabledChilds,
54
46
  lastPolledData,
55
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
56
- playersMap
47
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
57
48
  );
58
49
 
59
50
  expect(market.childMarkets).toHaveLength(0);
@@ -69,11 +60,10 @@ describe('Markets', () => {
69
60
  [],
70
61
  true,
71
62
  undefined,
72
- ODDS_THRESHOLD_ANCHORS,
63
+ MAX_IMPLIED_PERCENTAGE_DIFF,
73
64
  LeagueMocks.leagueInfoEnabledSpreadDisabledTotals,
74
65
  lastPolledData,
75
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
76
- playersMap
66
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
77
67
  );
78
68
 
79
69
  const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
@@ -93,11 +83,10 @@ describe('Markets', () => {
93
83
  [],
94
84
  true,
95
85
  undefined,
96
- ODDS_THRESHOLD_ANCHORS,
86
+ MAX_IMPLIED_PERCENTAGE_DIFF,
97
87
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
98
88
  lastPolledData,
99
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
100
- playersMap
89
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
101
90
  );
102
91
 
103
92
  const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
@@ -117,11 +106,10 @@ describe('Markets', () => {
117
106
  [],
118
107
  true,
119
108
  undefined,
120
- ODDS_THRESHOLD_ANCHORS,
109
+ MAX_IMPLIED_PERCENTAGE_DIFF,
121
110
  LeagueMocks.leagueInfoEnabledAll,
122
111
  lastPolledData,
123
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
124
- playersMap
112
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
125
113
  );
126
114
 
127
115
  const containsSpread = market.childMarkets.some((child: any) => child.type === 'spread');
@@ -173,11 +161,10 @@ describe('Markets', () => {
173
161
  [],
174
162
  true,
175
163
  undefined,
176
- ODDS_THRESHOLD_ANCHORS,
164
+ MAX_IMPLIED_PERCENTAGE_DIFF,
177
165
  LeagueMocks.leagueInfoOnlyParentDiffSportId,
178
166
  lastPolledData,
179
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
180
- playersMap
167
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
181
168
  );
182
169
 
183
170
  expect(warnSpy).toHaveBeenCalled();
@@ -186,29 +173,5 @@ describe('Markets', () => {
186
173
  // Restore the original implementation
187
174
  warnSpy.mockRestore();
188
175
  });
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
- ODDS_THRESHOLD_ANCHORS,
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
- });
213
176
  });
214
177
  });
@@ -1,5 +1,5 @@
1
+ import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
1
2
  import { ZERO_ODDS_MESSAGE_SINGLE_BOOKMAKER } from '../../constants/errors';
2
- import { ODDS_THRESHOLD_ANCHORS } from '../../constants/odds';
3
3
  import { processMarket } from '../../utils/markets';
4
4
  import { mapOpticOddsApiFixtureOdds } from '../../utils/opticOdds';
5
5
  import { LeagueMocks } from '../mock/MockLeagueMap';
@@ -10,14 +10,9 @@ import {
10
10
  MockZeroOdds,
11
11
  } from '../mock/MockOpticSoccer';
12
12
  import { mockSoccer } from '../mock/MockSoccerRedis';
13
- import {
14
- getLastPolledDataForBookmakers,
15
- getPlayersMap,
16
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
17
- } from '../utils/helper';
13
+ import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
18
14
 
19
15
  const lastPolledData = getLastPolledDataForBookmakers();
20
- const playersMap = getPlayersMap();
21
16
 
22
17
  describe('Odds', () => {
23
18
  it('Should return odds for moneyline', () => {
@@ -30,11 +25,10 @@ describe('Odds', () => {
30
25
  [],
31
26
  true,
32
27
  undefined,
33
- ODDS_THRESHOLD_ANCHORS,
28
+ MAX_IMPLIED_PERCENTAGE_DIFF,
34
29
  LeagueMocks.leagueInfoOnlyParent,
35
30
  lastPolledData,
36
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
37
- playersMap
31
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
38
32
  );
39
33
 
40
34
  const hasOdds = market.odds.some(
@@ -54,11 +48,10 @@ describe('Odds', () => {
54
48
  [],
55
49
  true,
56
50
  undefined,
57
- ODDS_THRESHOLD_ANCHORS,
51
+ MAX_IMPLIED_PERCENTAGE_DIFF,
58
52
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
59
53
  lastPolledData,
60
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
61
- playersMap
54
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
62
55
  );
63
56
 
64
57
  const hasOdds = market.odds.some(
@@ -80,11 +73,10 @@ describe('Odds', () => {
80
73
  [],
81
74
  true,
82
75
  undefined,
83
- ODDS_THRESHOLD_ANCHORS,
76
+ MAX_IMPLIED_PERCENTAGE_DIFF,
84
77
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
85
78
  lastPolledData,
86
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
87
- playersMap
79
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
88
80
  );
89
81
 
90
82
  const hasChildMarkets = market.childMarkets.length > 0;
@@ -101,11 +93,10 @@ describe('Odds', () => {
101
93
  [],
102
94
  true,
103
95
  undefined,
104
- ODDS_THRESHOLD_ANCHORS,
96
+ MAX_IMPLIED_PERCENTAGE_DIFF,
105
97
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
106
98
  lastPolledData,
107
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
108
- playersMap
99
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
109
100
  );
110
101
 
111
102
  expect(market.childMarkets).toHaveLength(0);
@@ -1,18 +1,13 @@
1
+ import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
1
2
  import { ZERO_ODDS_AFTER_SPREAD_ADJUSTMENT } from '../../constants/errors';
2
- import { ODDS_THRESHOLD_ANCHORS } from '../../constants/odds';
3
3
  import { processMarket } from '../../utils/markets';
4
4
  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 {
9
- getLastPolledDataForBookmakers,
10
- getPlayersMap,
11
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
12
- } from '../utils/helper';
8
+ import { getLastPolledDataForBookmakers, MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST } from '../utils/helper';
13
9
 
14
10
  const lastPolledData = getLastPolledDataForBookmakers();
15
- const playersMap = getPlayersMap();
16
11
 
17
12
  describe('Spread configuration', () => {
18
13
  it('Should return zero odds for quotes that sum up total probability above 1', () => {
@@ -25,11 +20,10 @@ describe('Spread configuration', () => {
25
20
  [],
26
21
  false,
27
22
  undefined,
28
- ODDS_THRESHOLD_ANCHORS,
23
+ MAX_IMPLIED_PERCENTAGE_DIFF,
29
24
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
30
25
  lastPolledData,
31
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
32
- playersMap
26
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
33
27
  );
34
28
 
35
29
  const hasOdds = market.odds.some(
@@ -53,11 +47,10 @@ describe('Spread configuration', () => {
53
47
  [],
54
48
  true,
55
49
  undefined,
56
- ODDS_THRESHOLD_ANCHORS,
50
+ MAX_IMPLIED_PERCENTAGE_DIFF,
57
51
  LeagueMocks.leagueInfoOnlyParent,
58
52
  lastPolledData,
59
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
60
- playersMap
53
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
61
54
  )
62
55
  )
63
56
  );
@@ -71,11 +64,10 @@ describe('Spread configuration', () => {
71
64
  [],
72
65
  true,
73
66
  undefined,
74
- ODDS_THRESHOLD_ANCHORS,
67
+ MAX_IMPLIED_PERCENTAGE_DIFF,
75
68
  LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
76
69
  lastPolledData,
77
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
78
- playersMap
70
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
79
71
  )
80
72
  )
81
73
  );
@@ -109,11 +101,10 @@ describe('Spread configuration', () => {
109
101
  [],
110
102
  true,
111
103
  undefined,
112
- ODDS_THRESHOLD_ANCHORS,
104
+ MAX_IMPLIED_PERCENTAGE_DIFF,
113
105
  LeagueMocks.leagueInfoOnlyParent,
114
106
  lastPolledData,
115
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
116
- playersMap
107
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
117
108
  )
118
109
  )
119
110
  );
@@ -127,11 +118,10 @@ describe('Spread configuration', () => {
127
118
  [],
128
119
  true,
129
120
  undefined,
130
- ODDS_THRESHOLD_ANCHORS,
121
+ MAX_IMPLIED_PERCENTAGE_DIFF,
131
122
  LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
132
123
  lastPolledData,
133
- MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
134
- playersMap
124
+ MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST
135
125
  )
136
126
  )
137
127
  );
@@ -8,12 +8,4 @@ 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
-
19
11
  export const MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST = 30000; // 30 seconds
package/src/types/odds.ts CHANGED
@@ -7,20 +7,22 @@ export type Fixture = {
7
7
  awayTeam: string;
8
8
  };
9
9
 
10
- export type Odds = {
11
- id: string;
12
- sportsBookName: string;
13
- name: string;
14
- price: number;
15
- timestamp: number;
16
- points: number;
17
- isMain: boolean;
18
- isLive: boolean;
19
- marketName: string;
20
- playerId: string;
21
- selection: string;
22
- selectionLine: string;
23
- }[];
10
+ export type Odds = [
11
+ {
12
+ id: string;
13
+ sportsBookName: string;
14
+ name: string;
15
+ price: number;
16
+ timestamp: number;
17
+ points: number;
18
+ isMain: boolean;
19
+ isLive: boolean;
20
+ marketName: string;
21
+ playerId: string;
22
+ selection: string;
23
+ selectionLine: string;
24
+ }
25
+ ];
24
26
 
25
27
  export type OddsObject = {
26
28
  gameId: string;
@@ -76,8 +78,3 @@ export type ScoresObject = {
76
78
  };
77
79
 
78
80
  export type HomeAwayTeams = { homeTeam: string; awayTeam: string };
79
-
80
- export type Anchor = {
81
- our: number;
82
- otherMin: number;
83
- };
@@ -1,3 +1,5 @@
1
+ import * as oddslib from 'oddslib';
2
+ import { MIN_ODDS_FOR_DIFF_CHECKING } from '../constants/common';
1
3
  import {
2
4
  DIFF_BETWEEN_BOOKMAKERS_MESSAGE,
3
5
  NO_MATCHING_BOOKMAKERS_MESSAGE,
@@ -5,7 +7,7 @@ import {
5
7
  ZERO_ODDS_MESSAGE_SINGLE_BOOKMAKER,
6
8
  } from '../constants/errors';
7
9
  import { BookmakersConfig } from '../types/bookmakers';
8
- import { Anchor, OddsWithLeagueInfo } from '../types/odds';
10
+ import { OddsWithLeagueInfo } from '../types/odds';
9
11
  import { LastPolledArray, LeagueConfigInfo } from '../types/sports';
10
12
 
11
13
  export const getBookmakersArray = (
@@ -30,23 +32,12 @@ export const getBookmakersArray = (
30
32
  };
31
33
 
32
34
  export const getBookmakersFromLeagueConfig = (sportId: string | number, leagueInfoArray: LeagueConfigInfo[]) => {
33
- const uniqueBookmakers: string[] = [];
34
-
35
- for (const leagueInfo of leagueInfoArray) {
36
- if (Number(leagueInfo.sportId) === Number(sportId) && leagueInfo.enabled === 'true') {
37
- const primary = leagueInfo.primaryBookmaker?.toLowerCase();
38
- const secondary = leagueInfo.secondaryBookmaker?.toLowerCase();
39
- if (primary) {
40
- uniqueBookmakers.push(primary);
41
- }
42
- if (secondary && secondary !== primary) {
43
- uniqueBookmakers.push(secondary);
44
- }
45
- break;
46
- }
47
- }
35
+ const leagueInfoArrayFiltered: string[] = leagueInfoArray
36
+ .filter((leagueInfo) => Number(leagueInfo.sportId) === Number(sportId) && leagueInfo.enabled === 'true')
37
+ .flatMap((item) => [item.primaryBookmaker?.toLowerCase(), item.secondaryBookmaker?.toLowerCase()])
38
+ .filter((item): item is string => !!item && item.length > 0);
48
39
 
49
- return uniqueBookmakers;
40
+ return [...new Set(leagueInfoArrayFiltered)];
50
41
  };
51
42
 
52
43
  export const getBookmakersForLeague = (
@@ -72,7 +63,8 @@ export const checkOddsFromBookmakers = (
72
63
  oddsMap: Map<string, any>,
73
64
  arrayOfBookmakers: string[],
74
65
  isTwoPositionalSport: boolean,
75
- anchors: Anchor[]
66
+ maxImpliedPercentageDifference: number,
67
+ minOddsForDiffChecking: number
76
68
  ) => {
77
69
  // Main bookmaker odds
78
70
  const firstBookmakerOdds = oddsMap.get(arrayOfBookmakers[0].toLowerCase());
@@ -134,10 +126,46 @@ export const checkOddsFromBookmakers = (
134
126
  const otherAwayOdd = line.awayOdds;
135
127
  const otherDrawOdd = line.drawOdds;
136
128
 
129
+ const homeOddsImplied = oddslib.from('decimal', homeOdd).to('impliedProbability');
130
+
131
+ const awayOddsImplied = oddslib.from('decimal', awayOdd).to('impliedProbability');
132
+
133
+ // Calculate implied odds for the "draw" if it's not a two-positions sport
134
+ const drawOddsImplied = isTwoPositionalSport
135
+ ? 0
136
+ : oddslib.from('decimal', drawOdd).to('impliedProbability');
137
+
138
+ const otherHomeOddImplied = oddslib.from('decimal', otherHomeOdd).to('impliedProbability');
139
+
140
+ const otherAwayOddImplied = oddslib.from('decimal', otherAwayOdd).to('impliedProbability');
141
+
142
+ // Calculate implied odds for the "draw" if it's not a two-positions sport
143
+ const otherDrawOddImplied = isTwoPositionalSport
144
+ ? 0
145
+ : oddslib.from('decimal', otherDrawOdd).to('impliedProbability');
146
+
147
+ // Calculate the percentage difference for implied odds
148
+ const homeOddsDifference = calculateImpliedOddsDifference(homeOddsImplied, otherHomeOddImplied);
149
+
150
+ const awayOddsDifference = calculateImpliedOddsDifference(awayOddsImplied, otherAwayOddImplied);
151
+
152
+ // Check implied odds difference for the "draw" only if it's not a two-positions sport
153
+ const drawOddsDifference = isTwoPositionalSport
154
+ ? 0
155
+ : calculateImpliedOddsDifference(drawOddsImplied, otherDrawOddImplied);
156
+
157
+ // Check if the percentage difference exceeds the threshold
137
158
  if (
138
- shouldBlockOdds(homeOdd, otherHomeOdd, anchors) ||
139
- shouldBlockOdds(awayOdd, otherAwayOdd, anchors) ||
140
- shouldBlockOdds(drawOdd, otherDrawOdd, anchors)
159
+ (homeOddsDifference > maxImpliedPercentageDifference &&
160
+ homeOddsImplied > minOddsForDiffChecking &&
161
+ otherHomeOddImplied > minOddsForDiffChecking) ||
162
+ (awayOddsDifference > maxImpliedPercentageDifference &&
163
+ awayOddsImplied > minOddsForDiffChecking &&
164
+ otherAwayOddImplied > minOddsForDiffChecking) ||
165
+ (!isTwoPositionalSport &&
166
+ drawOddsDifference > maxImpliedPercentageDifference &&
167
+ drawOddsImplied > minOddsForDiffChecking &&
168
+ otherDrawOddImplied > minOddsForDiffChecking)
141
169
  ) {
142
170
  return true;
143
171
  }
@@ -167,7 +195,7 @@ export const checkOddsFromBookmakersForChildMarkets = (
167
195
  oddsProviders: string[],
168
196
  lastPolledData: LastPolledArray,
169
197
  maxAllowedProviderDataStaleDelay: number,
170
- anchors: Anchor[]
198
+ maxImpliedPercentageDifference: number
171
199
  ): OddsWithLeagueInfo => {
172
200
  const formattedOdds = Object.entries(odds as any).reduce((acc: any, [key, value]: [string, any]) => {
173
201
  const [sportsBookName, marketName, points, selection, selectionLine] = key.split('_');
@@ -199,12 +227,21 @@ export const checkOddsFromBookmakersForChildMarkets = (
199
227
  `${secondaryBookmaker}_${marketName.toLowerCase()}_${points}_${selection}_${selectionLine}`
200
228
  ];
201
229
  if (secondaryBookmakerObject) {
202
- if (shouldBlockOdds(value.price, secondaryBookmakerObject.price, anchors)) {
203
- // Block this odd
204
- return acc;
230
+ const primaryOdds = oddslib.from('decimal', value.price).to('impliedProbability');
231
+ const secondaryOdds = oddslib
232
+ .from('decimal', secondaryBookmakerObject.price)
233
+ .to('impliedProbability');
234
+ if (
235
+ primaryOdds >= MIN_ODDS_FOR_DIFF_CHECKING &&
236
+ secondaryOdds >= MIN_ODDS_FOR_DIFF_CHECKING
237
+ ) {
238
+ const homeOddsDifference = calculateImpliedOddsDifference(primaryOdds, secondaryOdds);
239
+ if (Number(homeOddsDifference) <= Number(maxImpliedPercentageDifference)) {
240
+ acc.push(value);
241
+ }
242
+ } else {
243
+ acc.push(value);
205
244
  }
206
-
207
- acc.push(value);
208
245
  }
209
246
  }
210
247
  }
@@ -260,49 +297,3 @@ export const calculateImpliedOddsDifference = (impliedOddsA: number, impliedOdds
260
297
  const percentageDifference = (Math.abs(impliedOddsA - impliedOddsB) / impliedOddsA) * 100;
261
298
  return percentageDifference;
262
299
  };
263
-
264
- const getRequiredOtherOdds = (odds: number, anchors: Anchor[]) => {
265
- // If below the first anchor, extrapolate using first segment
266
- if (odds <= anchors[0].our) {
267
- const a = anchors[0];
268
- const b = anchors[1];
269
- const t = (odds - a.our) / (b.our - a.our);
270
- return a.otherMin + t * (b.otherMin - a.otherMin);
271
- }
272
-
273
- // If above the last anchor, extrapolate using last segment
274
- const last = anchors[anchors.length - 1];
275
- const prev = anchors[anchors.length - 2];
276
- if (odds >= last.our) {
277
- const t = (odds - prev.our) / (last.our - prev.our);
278
- return prev.otherMin + t * (last.otherMin - prev.otherMin);
279
- }
280
-
281
- // Otherwise, find the segment we fall into and interpolate
282
- for (let i = 1; i < anchors.length; i++) {
283
- const a = anchors[i - 1];
284
- const b = anchors[i];
285
-
286
- if (odds <= b.our) {
287
- const t = (odds - a.our) / (b.our - a.our);
288
- return a.otherMin + t * (b.otherMin - a.otherMin);
289
- }
290
- }
291
-
292
- // Fallback (should never hit)
293
- return last.otherMin;
294
- };
295
-
296
- const shouldBlockOdds = (ourOdds: number, otherOdds: number, anchors: Anchor[]) => {
297
- // basic sanity check
298
- if (ourOdds <= 1 || otherOdds <= 1) return true;
299
-
300
- // If we are equal or shorter than the other book,
301
- // we are not at risk.
302
- if (ourOdds <= otherOdds) return false;
303
-
304
- const requiredOther = getRequiredOtherOdds(ourOdds, anchors);
305
-
306
- // Block if the other book is below the required threshold
307
- return otherOdds < requiredOther;
308
- };