overtime-live-trading-utils 3.0.2-rc.0 → 3.0.2-rc.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.0",
3
+ "version": "3.0.2-rc.2",
4
4
  "description": "",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -0,0 +1,19 @@
1
+ // For each ourOdds, this is the minimum otherOdds we require to NOT block
2
+ // USED FOR TESTS ONLY, real anchors are passed from risk repo
3
+ export const ODDS_THRESHOLD_ANCHORS = [
4
+ { our: 1.05, otherMin: 1.03 },
5
+ { our: 1.1, otherMin: 1.06 },
6
+ { our: 1.2, otherMin: 1.15 },
7
+ { our: 1.3, otherMin: 1.25 },
8
+ { our: 1.4, otherMin: 1.33 },
9
+ { our: 1.5, otherMin: 1.4 },
10
+
11
+ { our: 2.0, otherMin: 1.85 },
12
+ { our: 2.5, otherMin: 2.25 },
13
+ { our: 3.0, otherMin: 2.5 },
14
+ { our: 4.0, otherMin: 3.5 },
15
+
16
+ { our: 8.0, otherMin: 6.5 },
17
+ { our: 10.0, otherMin: 8.0 },
18
+ { our: 100.0, otherMin: 70.0 },
19
+ ];
@@ -1,5 +1,5 @@
1
- import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
2
1
  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';
@@ -30,7 +30,7 @@ describe('Bookmakers', () => {
30
30
  [],
31
31
  true,
32
32
  undefined,
33
- MAX_IMPLIED_PERCENTAGE_DIFF,
33
+ ODDS_THRESHOLD_ANCHORS,
34
34
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
35
35
  lastPolledData,
36
36
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -56,7 +56,7 @@ describe('Bookmakers', () => {
56
56
  [],
57
57
  true,
58
58
  undefined,
59
- 5,
59
+ ODDS_THRESHOLD_ANCHORS,
60
60
  LeagueMocks.leagueInfoOnlyParent,
61
61
  lastPolledData,
62
62
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -82,7 +82,7 @@ describe('Bookmakers', () => {
82
82
  [],
83
83
  true,
84
84
  undefined,
85
- MAX_IMPLIED_PERCENTAGE_DIFF,
85
+ ODDS_THRESHOLD_ANCHORS,
86
86
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
87
87
  lastPolledData,
88
88
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -108,7 +108,7 @@ describe('Bookmakers', () => {
108
108
  [],
109
109
  true,
110
110
  undefined,
111
- MAX_IMPLIED_PERCENTAGE_DIFF,
111
+ ODDS_THRESHOLD_ANCHORS,
112
112
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
113
113
  lastPolledData,
114
114
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -128,7 +128,7 @@ describe('Bookmakers', () => {
128
128
  [],
129
129
  true,
130
130
  undefined,
131
- MAX_IMPLIED_PERCENTAGE_DIFF,
131
+ ODDS_THRESHOLD_ANCHORS,
132
132
  LeagueMocks.leaguInfoDifferentPrimaryBookmaker,
133
133
  lastPolledData,
134
134
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -148,7 +148,7 @@ describe('Bookmakers', () => {
148
148
  [],
149
149
  true,
150
150
  undefined,
151
- MAX_IMPLIED_PERCENTAGE_DIFF,
151
+ ODDS_THRESHOLD_ANCHORS,
152
152
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
153
153
  lastPolledData,
154
154
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -1,5 +1,5 @@
1
- import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
2
1
  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';
@@ -29,7 +29,7 @@ describe('Markets', () => {
29
29
  [],
30
30
  true,
31
31
  undefined,
32
- MAX_IMPLIED_PERCENTAGE_DIFF,
32
+ ODDS_THRESHOLD_ANCHORS,
33
33
  LeagueMocks.leagueInfoOnlyParent,
34
34
  lastPolledData,
35
35
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -49,7 +49,7 @@ describe('Markets', () => {
49
49
  [],
50
50
  true,
51
51
  undefined,
52
- MAX_IMPLIED_PERCENTAGE_DIFF,
52
+ ODDS_THRESHOLD_ANCHORS,
53
53
  LeagueMocks.leagueInfoMockDisabledChilds,
54
54
  lastPolledData,
55
55
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -69,7 +69,7 @@ describe('Markets', () => {
69
69
  [],
70
70
  true,
71
71
  undefined,
72
- MAX_IMPLIED_PERCENTAGE_DIFF,
72
+ ODDS_THRESHOLD_ANCHORS,
73
73
  LeagueMocks.leagueInfoEnabledSpreadDisabledTotals,
74
74
  lastPolledData,
75
75
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -93,7 +93,7 @@ describe('Markets', () => {
93
93
  [],
94
94
  true,
95
95
  undefined,
96
- MAX_IMPLIED_PERCENTAGE_DIFF,
96
+ ODDS_THRESHOLD_ANCHORS,
97
97
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
98
98
  lastPolledData,
99
99
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -117,7 +117,7 @@ describe('Markets', () => {
117
117
  [],
118
118
  true,
119
119
  undefined,
120
- MAX_IMPLIED_PERCENTAGE_DIFF,
120
+ ODDS_THRESHOLD_ANCHORS,
121
121
  LeagueMocks.leagueInfoEnabledAll,
122
122
  lastPolledData,
123
123
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -173,7 +173,7 @@ describe('Markets', () => {
173
173
  [],
174
174
  true,
175
175
  undefined,
176
- MAX_IMPLIED_PERCENTAGE_DIFF,
176
+ ODDS_THRESHOLD_ANCHORS,
177
177
  LeagueMocks.leagueInfoOnlyParentDiffSportId,
178
178
  lastPolledData,
179
179
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -197,7 +197,7 @@ describe('Markets', () => {
197
197
  [],
198
198
  true,
199
199
  undefined,
200
- MAX_IMPLIED_PERCENTAGE_DIFF,
200
+ ODDS_THRESHOLD_ANCHORS,
201
201
  LeagueMocks.PlayerAssist, // league map with player props configured
202
202
  lastPolledData,
203
203
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -1,5 +1,5 @@
1
- import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
2
1
  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';
@@ -30,7 +30,7 @@ describe('Odds', () => {
30
30
  [],
31
31
  true,
32
32
  undefined,
33
- MAX_IMPLIED_PERCENTAGE_DIFF,
33
+ ODDS_THRESHOLD_ANCHORS,
34
34
  LeagueMocks.leagueInfoOnlyParent,
35
35
  lastPolledData,
36
36
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -54,7 +54,7 @@ describe('Odds', () => {
54
54
  [],
55
55
  true,
56
56
  undefined,
57
- MAX_IMPLIED_PERCENTAGE_DIFF,
57
+ ODDS_THRESHOLD_ANCHORS,
58
58
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
59
59
  lastPolledData,
60
60
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -80,7 +80,7 @@ describe('Odds', () => {
80
80
  [],
81
81
  true,
82
82
  undefined,
83
- MAX_IMPLIED_PERCENTAGE_DIFF,
83
+ ODDS_THRESHOLD_ANCHORS,
84
84
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
85
85
  lastPolledData,
86
86
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -101,7 +101,7 @@ describe('Odds', () => {
101
101
  [],
102
102
  true,
103
103
  undefined,
104
- MAX_IMPLIED_PERCENTAGE_DIFF,
104
+ ODDS_THRESHOLD_ANCHORS,
105
105
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
106
106
  lastPolledData,
107
107
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -1,5 +1,5 @@
1
- import { MAX_IMPLIED_PERCENTAGE_DIFF } from '../../constants/common';
2
1
  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';
@@ -25,7 +25,7 @@ describe('Spread configuration', () => {
25
25
  [],
26
26
  false,
27
27
  undefined,
28
- MAX_IMPLIED_PERCENTAGE_DIFF,
28
+ ODDS_THRESHOLD_ANCHORS,
29
29
  LeagueMocks.leagueInfoEnabledSpeadAndTotals,
30
30
  lastPolledData,
31
31
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -53,7 +53,7 @@ describe('Spread configuration', () => {
53
53
  [],
54
54
  true,
55
55
  undefined,
56
- MAX_IMPLIED_PERCENTAGE_DIFF,
56
+ ODDS_THRESHOLD_ANCHORS,
57
57
  LeagueMocks.leagueInfoOnlyParent,
58
58
  lastPolledData,
59
59
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -71,7 +71,7 @@ describe('Spread configuration', () => {
71
71
  [],
72
72
  true,
73
73
  undefined,
74
- MAX_IMPLIED_PERCENTAGE_DIFF,
74
+ ODDS_THRESHOLD_ANCHORS,
75
75
  LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
76
76
  lastPolledData,
77
77
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -109,7 +109,7 @@ describe('Spread configuration', () => {
109
109
  [],
110
110
  true,
111
111
  undefined,
112
- MAX_IMPLIED_PERCENTAGE_DIFF,
112
+ ODDS_THRESHOLD_ANCHORS,
113
113
  LeagueMocks.leagueInfoOnlyParent,
114
114
  lastPolledData,
115
115
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
@@ -127,7 +127,7 @@ describe('Spread configuration', () => {
127
127
  [],
128
128
  true,
129
129
  undefined,
130
- MAX_IMPLIED_PERCENTAGE_DIFF,
130
+ ODDS_THRESHOLD_ANCHORS,
131
131
  LeagueMocks.leagueInfoOnlyParentWithSpreadAdded,
132
132
  lastPolledData,
133
133
  MAX_ALLOWED_PROVIDER_DATA_STALE_DELAY_TEST,
package/src/types/odds.ts CHANGED
@@ -7,22 +7,20 @@ export type Fixture = {
7
7
  awayTeam: string;
8
8
  };
9
9
 
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
- ];
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
+ }[];
26
24
 
27
25
  export type OddsObject = {
28
26
  gameId: string;
@@ -78,3 +76,8 @@ export type ScoresObject = {
78
76
  };
79
77
 
80
78
  export type HomeAwayTeams = { homeTeam: string; awayTeam: string };
79
+
80
+ export type Anchor = {
81
+ our: number;
82
+ otherMin: number;
83
+ };
@@ -1,5 +1,3 @@
1
- import * as oddslib from 'oddslib';
2
- import { MIN_ODDS_FOR_DIFF_CHECKING } from '../constants/common';
3
1
  import {
4
2
  DIFF_BETWEEN_BOOKMAKERS_MESSAGE,
5
3
  NO_MATCHING_BOOKMAKERS_MESSAGE,
@@ -7,7 +5,7 @@ import {
7
5
  ZERO_ODDS_MESSAGE_SINGLE_BOOKMAKER,
8
6
  } from '../constants/errors';
9
7
  import { BookmakersConfig } from '../types/bookmakers';
10
- import { OddsWithLeagueInfo } from '../types/odds';
8
+ import { Anchor, OddsWithLeagueInfo } from '../types/odds';
11
9
  import { LastPolledArray, LeagueConfigInfo } from '../types/sports';
12
10
 
13
11
  export const getBookmakersArray = (
@@ -74,8 +72,7 @@ export const checkOddsFromBookmakers = (
74
72
  oddsMap: Map<string, any>,
75
73
  arrayOfBookmakers: string[],
76
74
  isTwoPositionalSport: boolean,
77
- maxImpliedPercentageDifference: number,
78
- minOddsForDiffChecking: number
75
+ anchors: Anchor[]
79
76
  ) => {
80
77
  // Main bookmaker odds
81
78
  const firstBookmakerOdds = oddsMap.get(arrayOfBookmakers[0].toLowerCase());
@@ -137,46 +134,10 @@ export const checkOddsFromBookmakers = (
137
134
  const otherAwayOdd = line.awayOdds;
138
135
  const otherDrawOdd = line.drawOdds;
139
136
 
140
- const homeOddsImplied = oddslib.from('decimal', homeOdd).to('impliedProbability');
141
-
142
- const awayOddsImplied = oddslib.from('decimal', awayOdd).to('impliedProbability');
143
-
144
- // Calculate implied odds for the "draw" if it's not a two-positions sport
145
- const drawOddsImplied = isTwoPositionalSport
146
- ? 0
147
- : oddslib.from('decimal', drawOdd).to('impliedProbability');
148
-
149
- const otherHomeOddImplied = oddslib.from('decimal', otherHomeOdd).to('impliedProbability');
150
-
151
- const otherAwayOddImplied = oddslib.from('decimal', otherAwayOdd).to('impliedProbability');
152
-
153
- // Calculate implied odds for the "draw" if it's not a two-positions sport
154
- const otherDrawOddImplied = isTwoPositionalSport
155
- ? 0
156
- : oddslib.from('decimal', otherDrawOdd).to('impliedProbability');
157
-
158
- // Calculate the percentage difference for implied odds
159
- const homeOddsDifference = calculateImpliedOddsDifference(homeOddsImplied, otherHomeOddImplied);
160
-
161
- const awayOddsDifference = calculateImpliedOddsDifference(awayOddsImplied, otherAwayOddImplied);
162
-
163
- // Check implied odds difference for the "draw" only if it's not a two-positions sport
164
- const drawOddsDifference = isTwoPositionalSport
165
- ? 0
166
- : calculateImpliedOddsDifference(drawOddsImplied, otherDrawOddImplied);
167
-
168
- // Check if the percentage difference exceeds the threshold
169
137
  if (
170
- (homeOddsDifference > maxImpliedPercentageDifference &&
171
- homeOddsImplied > minOddsForDiffChecking &&
172
- otherHomeOddImplied > minOddsForDiffChecking) ||
173
- (awayOddsDifference > maxImpliedPercentageDifference &&
174
- awayOddsImplied > minOddsForDiffChecking &&
175
- otherAwayOddImplied > minOddsForDiffChecking) ||
176
- (!isTwoPositionalSport &&
177
- drawOddsDifference > maxImpliedPercentageDifference &&
178
- drawOddsImplied > minOddsForDiffChecking &&
179
- otherDrawOddImplied > minOddsForDiffChecking)
138
+ shouldBlockOdds(homeOdd, otherHomeOdd, anchors) ||
139
+ shouldBlockOdds(awayOdd, otherAwayOdd, anchors) ||
140
+ shouldBlockOdds(drawOdd, otherDrawOdd, anchors)
180
141
  ) {
181
142
  return true;
182
143
  }
@@ -206,7 +167,7 @@ export const checkOddsFromBookmakersForChildMarkets = (
206
167
  oddsProviders: string[],
207
168
  lastPolledData: LastPolledArray,
208
169
  maxAllowedProviderDataStaleDelay: number,
209
- maxImpliedPercentageDifference: number
170
+ anchors: Anchor[]
210
171
  ): OddsWithLeagueInfo => {
211
172
  const formattedOdds = Object.entries(odds as any).reduce((acc: any, [key, value]: [string, any]) => {
212
173
  const [sportsBookName, marketName, points, selection, selectionLine] = key.split('_');
@@ -238,21 +199,12 @@ export const checkOddsFromBookmakersForChildMarkets = (
238
199
  `${secondaryBookmaker}_${marketName.toLowerCase()}_${points}_${selection}_${selectionLine}`
239
200
  ];
240
201
  if (secondaryBookmakerObject) {
241
- const primaryOdds = oddslib.from('decimal', value.price).to('impliedProbability');
242
- const secondaryOdds = oddslib
243
- .from('decimal', secondaryBookmakerObject.price)
244
- .to('impliedProbability');
245
- if (
246
- primaryOdds >= MIN_ODDS_FOR_DIFF_CHECKING &&
247
- secondaryOdds >= MIN_ODDS_FOR_DIFF_CHECKING
248
- ) {
249
- const homeOddsDifference = calculateImpliedOddsDifference(primaryOdds, secondaryOdds);
250
- if (Number(homeOddsDifference) <= Number(maxImpliedPercentageDifference)) {
251
- acc.push(value);
252
- }
253
- } else {
254
- acc.push(value);
202
+ if (shouldBlockOdds(value.price, secondaryBookmakerObject.price, anchors)) {
203
+ // Block this odd
204
+ return acc;
255
205
  }
206
+
207
+ acc.push(value);
256
208
  }
257
209
  }
258
210
  }
@@ -308,3 +260,49 @@ export const calculateImpliedOddsDifference = (impliedOddsA: number, impliedOdds
308
260
  const percentageDifference = (Math.abs(impliedOddsA - impliedOddsB) / impliedOddsA) * 100;
309
261
  return percentageDifference;
310
262
  };
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
+ };
@@ -1,6 +1,6 @@
1
1
  import * as oddslib from 'oddslib';
2
2
  import { ZERO_ODDS_AFTER_SPREAD_ADJUSTMENT } from '../constants/errors';
3
- import { OddsObject } from '../types/odds';
3
+ import { Anchor, OddsObject } from '../types/odds';
4
4
  import { LastPolledArray } from '../types/sports';
5
5
  import { createChildMarkets, getParentOdds } from './odds';
6
6
  import { getLeagueInfo } from './sports';
@@ -16,8 +16,10 @@ import { adjustAddedSpread } from './spread';
16
16
  * @param {Array} spreadData - Spread data for odds.
17
17
  * @param {Boolean} isDrawAvailable - Is it two or three-positional sport
18
18
  * @param {Number} defaultSpreadForLiveMarkets - Default spread for live markets
19
- * @param {Number} maxPercentageDiffBetwenOdds - Maximum allowed percentage difference between same position odds from different providers
20
- * @param {Boolean} isTestnet - Flag showing should we process for testnet or mainnet
19
+ * @param {Object} leagueMap - League map for additional league information
20
+ * @param {LastPolledArray} lastPolledData - Array containing last polled timestamps for bookmakers
21
+ * @param {Number} maxAllowedProviderDataStaleDelay - Maximum allowed delay for provider data to be considered fresh
22
+ * @param {Map<string, number>} playersMap - Map of player OO IDs to our internal player ID
21
23
  * @returns {Promise<Object|null>} A promise that resolves to the processed event object or null if the event is invalid or mapping fails.
22
24
  */
23
25
  export const processMarket = (
@@ -27,7 +29,7 @@ export const processMarket = (
27
29
  spreadData: any,
28
30
  isDrawAvailable: any,
29
31
  defaultSpreadForLiveMarkets: any,
30
- maxPercentageDiffBetwenOdds: number,
32
+ anchors: Anchor[],
31
33
  leagueMap: any,
32
34
  lastPolledData: LastPolledArray,
33
35
  maxAllowedProviderDataStaleDelay: number,
@@ -43,7 +45,7 @@ export const processMarket = (
43
45
  apiResponseWithOdds,
44
46
  market.leagueId,
45
47
  defaultSpreadForLiveMarkets,
46
- maxPercentageDiffBetwenOdds,
48
+ anchors,
47
49
  leagueInfo,
48
50
  lastPolledData,
49
51
  maxAllowedProviderDataStaleDelay
@@ -90,7 +92,7 @@ export const processMarket = (
90
92
  leagueMap,
91
93
  lastPolledData,
92
94
  maxAllowedProviderDataStaleDelay,
93
- maxPercentageDiffBetwenOdds,
95
+ anchors,
94
96
  playersMap
95
97
  );
96
98
 
package/src/utils/odds.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as oddslib from 'oddslib';
2
2
  import { MarketType, MarketTypeMap } from 'overtime-utils';
3
- import { DRAW, MIN_ODDS_FOR_DIFF_CHECKING, MONEYLINE_TYPE_ID, ZERO } from '../constants/common';
3
+ import { DRAW, MONEYLINE_TYPE_ID, ZERO } from '../constants/common';
4
4
  import { LAST_POLLED_TOO_OLD, NO_MARKETS_FOR_LEAGUE_ID } from '../constants/errors';
5
5
  import { MoneylineTypes } from '../enums/sports';
6
- import { HomeAwayTeams, Odds, OddsObject } from '../types/odds';
6
+ import { Anchor, HomeAwayTeams, Odds, OddsObject } from '../types/odds';
7
7
  import { ChildMarket, LastPolledArray, LeagueConfigInfo } from '../types/sports';
8
8
  import {
9
9
  checkOddsFromBookmakers,
@@ -128,7 +128,7 @@ export const getParentOdds = (
128
128
  oddsApiObject: OddsObject,
129
129
  sportId: string,
130
130
  defaultSpreadForLiveMarkets: number,
131
- maxPercentageDiffBetwenOdds: number,
131
+ anchors: Anchor[],
132
132
  leagueInfo: LeagueConfigInfo[],
133
133
  lastPolledData: LastPolledArray,
134
134
  maxAllowedProviderDataStaleDelay: number
@@ -164,13 +164,7 @@ export const getParentOdds = (
164
164
  );
165
165
 
166
166
  // CHECKING AND COMPARING ODDS FOR THE GIVEN BOOKMAKERS
167
- const oddsObject = checkOddsFromBookmakers(
168
- moneylineOddsMap,
169
- bookmakers,
170
- isTwoPositionalSport,
171
- maxPercentageDiffBetwenOdds,
172
- MIN_ODDS_FOR_DIFF_CHECKING
173
- );
167
+ const oddsObject = checkOddsFromBookmakers(moneylineOddsMap, bookmakers, isTwoPositionalSport, anchors);
174
168
 
175
169
  if (oddsObject.errorMessage) {
176
170
  return {
@@ -214,7 +208,7 @@ export const createChildMarkets: (
214
208
  leagueMap: any,
215
209
  lastPolledData: LastPolledArray,
216
210
  maxAllowedProviderDataStaleDelay: number,
217
- maxImpliedPercentageDifference: number,
211
+ anchors: Anchor[],
218
212
  playersMap: Map<string, number>
219
213
  ) => ChildMarket[] = (
220
214
  apiResponseWithOdds,
@@ -225,7 +219,7 @@ export const createChildMarkets: (
225
219
  leagueMap,
226
220
  lastPolledData,
227
221
  maxAllowedProviderDataStaleDelay,
228
- maxImpliedPercentageDifference,
222
+ anchors,
229
223
  playersMap
230
224
  ) => {
231
225
  const [spreadOdds, totalOdds, moneylineOdds, correctScoreOdds, doubleChanceOdds, ggOdds, childMarkets]: any[] = [
@@ -251,7 +245,7 @@ export const createChildMarkets: (
251
245
  liveOddsProviders,
252
246
  lastPolledData,
253
247
  maxAllowedProviderDataStaleDelay,
254
- maxImpliedPercentageDifference
248
+ anchors
255
249
  );
256
250
  checkedChildOdds.forEach((odd) => {
257
251
  if (odd.type === 'Total') {
@@ -286,21 +280,29 @@ export const createChildMarkets: (
286
280
  );
287
281
 
288
282
  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
- }
296
- const childMarket = {
283
+ let childMarket = {
297
284
  leagueId: Number(data.sportId),
298
285
  typeId: Number(data.typeId),
299
286
  type: MarketTypeMap[data.typeId as MarketType]?.key || '',
300
287
  line: Number(data.line || 0),
301
288
  odds: data.odds,
302
- playerProps,
289
+ playerProps: {
290
+ playerId: 0,
291
+ playerName: '',
292
+ },
293
+ isPlayerPropsMarket: false,
303
294
  };
295
+ if (data.playerProps) {
296
+ childMarket = {
297
+ ...childMarket,
298
+ playerProps: {
299
+ playerId: playersMap.get(data.playerProps.playerId.toString()) || 0, // convert from opticOdds playerId to our internal playerId
300
+ playerName: data.playerProps.playerName,
301
+ },
302
+ isPlayerPropsMarket: true,
303
+ };
304
+ }
305
+
304
306
  const leagueInfoByTypeId = leagueInfo.find((league) => Number(league.typeId) === Number(data.typeId));
305
307
  const minOdds = leagueInfoByTypeId?.minOdds; // minimum odds configured for child market (e.g. 0.95 implied probability)
306
308
  const maxOdds = leagueInfoByTypeId?.maxOdds; // maximum odds configured for child market (e.g. 0.05 implied probability)