overtime-live-trading-utils 0.2.10 → 0.3.1
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/index.ts +0 -1
- package/main.js +1 -1
- package/package.json +1 -1
- package/src/constants/common.ts +1 -1
- package/src/constants/sports.ts +31 -231
- package/src/enums/sports.ts +4 -0
- package/src/types/sports.ts +17 -0
- package/src/utils/markets.ts +6 -149
- package/src/utils/odds.ts +180 -166
- package/src/utils/sports.ts +34 -34
- package/src/enums/statuses.ts +0 -21
package/src/enums/sports.ts
CHANGED
|
@@ -16,6 +16,7 @@ export enum Sport {
|
|
|
16
16
|
GOLF = 'Golf',
|
|
17
17
|
TABLE_TENNIS = 'TableTennis',
|
|
18
18
|
POLITICS = 'Politics',
|
|
19
|
+
FUTURES = 'Futures',
|
|
19
20
|
EMPTY = '',
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -128,6 +129,9 @@ export enum League {
|
|
|
128
129
|
ENGLAND_LEGAUE_1 = 20126,
|
|
129
130
|
URUGUAY_PRIMERA_DIVISION = 20127,
|
|
130
131
|
EUROCUP = 20200,
|
|
132
|
+
NFL_FUTURES = 30002,
|
|
133
|
+
NBA_FUTURES = 30004,
|
|
134
|
+
EPL_FUTURES = 30011,
|
|
131
135
|
GOLF_H2H = 100021,
|
|
132
136
|
GOLF_WINNER = 100121,
|
|
133
137
|
TENNIS_GRAND_SLAM_LIVE_MAPPING_V2_1 = 15312,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type LeagueInfo = {
|
|
2
|
+
sportId: number;
|
|
3
|
+
typeId: number;
|
|
4
|
+
marketName: string;
|
|
5
|
+
type: string;
|
|
6
|
+
enabled: string;
|
|
7
|
+
minOdds: number;
|
|
8
|
+
maxOdds: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type ChildMarket = {
|
|
12
|
+
leagueId: number;
|
|
13
|
+
typeId: number;
|
|
14
|
+
type: string;
|
|
15
|
+
line: number;
|
|
16
|
+
odds: Array<number>;
|
|
17
|
+
};
|
package/src/utils/markets.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import * as oddslib from 'oddslib';
|
|
2
|
-
import {
|
|
3
|
-
import { filterOddsByMarketNameBookmaker, formatSpreadOdds, getParentOdds, processTotalOdds } from './odds';
|
|
4
|
-
import { getLeagueSpreadType, getLeagueTotalType } from './sports';
|
|
2
|
+
import { createChildMarkets, getParentOdds } from './odds';
|
|
5
3
|
/**
|
|
6
4
|
* Processes a single sports event. This function maps event data to a specific format,
|
|
7
5
|
* filters invalid events, and optionally fetches player properties if the sport supports it.
|
|
@@ -25,7 +23,7 @@ export const processMarket = (
|
|
|
25
23
|
isDrawAvailable,
|
|
26
24
|
defaultSpreadForLiveMarkets,
|
|
27
25
|
maxPercentageDiffBetwenOdds,
|
|
28
|
-
|
|
26
|
+
leagueMap
|
|
29
27
|
) => {
|
|
30
28
|
const sportSpreadData = spreadData.filter((data) => data.sportId === String(market.leagueId));
|
|
31
29
|
|
|
@@ -62,13 +60,13 @@ export const processMarket = (
|
|
|
62
60
|
});
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
const childMarkets =
|
|
66
|
-
market.leagueId,
|
|
67
|
-
sportSpreadData,
|
|
63
|
+
const childMarkets = createChildMarkets(
|
|
68
64
|
apiResponseWithOdds,
|
|
65
|
+
sportSpreadData,
|
|
66
|
+
market.leagueId,
|
|
69
67
|
liveOddsProviders,
|
|
70
68
|
defaultSpreadForLiveMarkets,
|
|
71
|
-
|
|
69
|
+
leagueMap
|
|
72
70
|
);
|
|
73
71
|
|
|
74
72
|
const packedChildMarkets = childMarkets.map((childMarket: any) => {
|
|
@@ -96,144 +94,3 @@ export const processMarket = (
|
|
|
96
94
|
|
|
97
95
|
return market;
|
|
98
96
|
};
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Retrieves the child markets for the given event.
|
|
102
|
-
*
|
|
103
|
-
* @param {Object} market - The market object from the API
|
|
104
|
-
* @param {Array} spreadDataForSport - Spread data for sport.
|
|
105
|
-
* @param {Object} apiResponseWithOdds - API response from the provider
|
|
106
|
-
* @param {Number} defaultSpreadForLiveMarkets - Default spread for live markets
|
|
107
|
-
* @param {Boolean} isTestnet - Flag showing should we process for testnet or mainnet
|
|
108
|
-
* @returns {Array} The child markets for the event.
|
|
109
|
-
*/
|
|
110
|
-
const getChildMarkets = (
|
|
111
|
-
leagueId,
|
|
112
|
-
spreadDataForSport,
|
|
113
|
-
apiResponseWithOdds,
|
|
114
|
-
liveOddsProviders,
|
|
115
|
-
defaultSpreadForLiveMarkets,
|
|
116
|
-
isTestnet
|
|
117
|
-
) => {
|
|
118
|
-
let childMarkets = [];
|
|
119
|
-
|
|
120
|
-
// Create Spread Child Markets
|
|
121
|
-
childMarkets = childMarkets.concat(
|
|
122
|
-
createSpreadChildMarkets(
|
|
123
|
-
apiResponseWithOdds,
|
|
124
|
-
leagueId,
|
|
125
|
-
spreadDataForSport,
|
|
126
|
-
liveOddsProviders,
|
|
127
|
-
defaultSpreadForLiveMarkets,
|
|
128
|
-
isTestnet
|
|
129
|
-
)
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
// Create Total Child Markets
|
|
133
|
-
childMarkets = childMarkets.concat(
|
|
134
|
-
createTotalChildMarkets(
|
|
135
|
-
apiResponseWithOdds,
|
|
136
|
-
leagueId,
|
|
137
|
-
spreadDataForSport,
|
|
138
|
-
liveOddsProviders,
|
|
139
|
-
defaultSpreadForLiveMarkets,
|
|
140
|
-
isTestnet
|
|
141
|
-
)
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
return childMarkets;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Creates spread child markets based on the given parameters.
|
|
149
|
-
*
|
|
150
|
-
* @param {Object} market - The market object from the API
|
|
151
|
-
* @param {Array} spreadDataForSport - Spread data for sport.
|
|
152
|
-
* @param {Object} apiResponseWithOdds - API response from the provider
|
|
153
|
-
* @param {Array} liveOddsProviders - Odds providers for live odds
|
|
154
|
-
* @param {Number} defaultSpreadForLiveMarkets - Default spread for live markets
|
|
155
|
-
* @param {Boolean} isTestnet - Flag showing should we process for testnet or mainnet
|
|
156
|
-
* @returns {Array} The spread child markets.
|
|
157
|
-
*/
|
|
158
|
-
export const createSpreadChildMarkets = (
|
|
159
|
-
apiResponseWithOdds,
|
|
160
|
-
leagueId,
|
|
161
|
-
spreadDataForSport,
|
|
162
|
-
liveOddsProviders,
|
|
163
|
-
defaultSpreadForLiveMarkets,
|
|
164
|
-
isTestnet
|
|
165
|
-
) => {
|
|
166
|
-
const childMarkets = [] as any;
|
|
167
|
-
const spreadType = getLeagueSpreadType(leagueId, isTestnet);
|
|
168
|
-
const commonData = {
|
|
169
|
-
homeTeam: apiResponseWithOdds.home_team,
|
|
170
|
-
awayTeam: apiResponseWithOdds.away_team,
|
|
171
|
-
};
|
|
172
|
-
if (spreadType) {
|
|
173
|
-
// TODO ADD ODDS COMPARISON BETWEEN BOOKMAKERS
|
|
174
|
-
const allSpreadOdds = filterOddsByMarketNameBookmaker(
|
|
175
|
-
apiResponseWithOdds.odds,
|
|
176
|
-
spreadType,
|
|
177
|
-
liveOddsProviders[0]
|
|
178
|
-
);
|
|
179
|
-
|
|
180
|
-
if (allSpreadOdds.length > 0) {
|
|
181
|
-
const formattedSpreadOdds = formatSpreadOdds(
|
|
182
|
-
allSpreadOdds,
|
|
183
|
-
commonData,
|
|
184
|
-
leagueId,
|
|
185
|
-
spreadDataForSport,
|
|
186
|
-
TAG_CHILD_SPREAD,
|
|
187
|
-
defaultSpreadForLiveMarkets
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
childMarkets.push(...formattedSpreadOdds);
|
|
191
|
-
}
|
|
192
|
-
} else {
|
|
193
|
-
console.warn(`Spread type for sport ID ${leagueId} not found.`);
|
|
194
|
-
}
|
|
195
|
-
return childMarkets;
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Creates total child markets based on the given parameters.
|
|
200
|
-
*
|
|
201
|
-
* @param {Object} market - The market object from the API
|
|
202
|
-
* @param {Array} spreadDataForSport - Spread data for sport.
|
|
203
|
-
* @param {Object} apiResponseWithOdds - API response from the provider
|
|
204
|
-
* @param {Array} liveOddsProviders - Odds providers for live odds
|
|
205
|
-
* @param {Number} defaultSpreadForLiveMarkets - Default spread for live markets
|
|
206
|
-
* @param {Boolean} isTestnet - Flag showing should we process for testnet or mainnet
|
|
207
|
-
* @returns {Array} The total child markets.
|
|
208
|
-
*/
|
|
209
|
-
export const createTotalChildMarkets = (
|
|
210
|
-
apiResponseWithOdds,
|
|
211
|
-
leagueId,
|
|
212
|
-
spreadDataForSport,
|
|
213
|
-
liveOddsProviders,
|
|
214
|
-
defaultSpreadForLiveMarkets,
|
|
215
|
-
isTestnet
|
|
216
|
-
) => {
|
|
217
|
-
const childMarkets = [] as any;
|
|
218
|
-
const totalType = getLeagueTotalType(leagueId, isTestnet);
|
|
219
|
-
|
|
220
|
-
if (totalType) {
|
|
221
|
-
// TODO ADD ODDS COMPARISON BETWEEN BOOKMAKERS
|
|
222
|
-
const totalOdds = filterOddsByMarketNameBookmaker(apiResponseWithOdds.odds, totalType, liveOddsProviders[0]);
|
|
223
|
-
|
|
224
|
-
if (totalOdds.length > 0) {
|
|
225
|
-
childMarkets.push(
|
|
226
|
-
...processTotalOdds(
|
|
227
|
-
totalOdds,
|
|
228
|
-
leagueId,
|
|
229
|
-
spreadDataForSport,
|
|
230
|
-
TAG_CHILD_TOTALS,
|
|
231
|
-
defaultSpreadForLiveMarkets
|
|
232
|
-
)
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
} else {
|
|
236
|
-
console.warn(`Configuration (totals) for sport ID ${leagueId} not found.`);
|
|
237
|
-
}
|
|
238
|
-
return childMarkets;
|
|
239
|
-
};
|
package/src/utils/odds.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as oddslib from 'oddslib';
|
|
2
|
-
import { DRAW,
|
|
3
|
-
import { statusCodes } from '../enums/statuses';
|
|
2
|
+
import { DRAW, MIN_ODDS_FOR_DIFF_CHECKING, MONEYLINE_TYPE_ID, ZERO } from '../constants/common';
|
|
4
3
|
import { checkOddsFromBookmakers } from './bookmakers';
|
|
5
4
|
import { adjustSpreadOnOdds, getSpreadData } from './spread';
|
|
6
5
|
import { MoneylineTypes } from '../enums/sports';
|
|
6
|
+
import { ChildMarket, LeagueInfo } from '../types/sports';
|
|
7
|
+
import { getLeagueInfo } from './sports';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Converts a given odds value from one format to another.
|
|
@@ -152,7 +153,7 @@ export const getParentOdds = (
|
|
|
152
153
|
: [oddsObject.homeOdds, oddsObject.awayOdds, oddsObject.drawOdds];
|
|
153
154
|
|
|
154
155
|
let parentOdds = primaryBookmakerOdds.map((odd) => convertOddsToImpl(odd));
|
|
155
|
-
const spreadData = getSpreadData(sportSpreadData, sportId,
|
|
156
|
+
const spreadData = getSpreadData(sportSpreadData, sportId, MONEYLINE_TYPE_ID, defaultSpreadForLiveMarkets);
|
|
156
157
|
|
|
157
158
|
if (spreadData !== null) {
|
|
158
159
|
parentOdds = adjustSpreadOnOdds(parentOdds, spreadData.minSpread, spreadData.targetSpread);
|
|
@@ -163,102 +164,123 @@ export const getParentOdds = (
|
|
|
163
164
|
return { odds: parentOdds };
|
|
164
165
|
};
|
|
165
166
|
|
|
166
|
-
// TODO: Expand this method to support multiple marketNames
|
|
167
167
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* @param {Array} oddsArray - The array of odds objects.
|
|
171
|
-
* @param {string} marketName - The market name to filter by.
|
|
172
|
-
* @param {string} oddsProvider - The main odds provider to filter by.
|
|
173
|
-
* @returns {Array} The filtered odds array.
|
|
174
|
-
*/
|
|
175
|
-
export const filterOddsByMarketNameBookmaker = (oddsArray, marketName, oddsProvider) => {
|
|
176
|
-
return oddsArray.filter(
|
|
177
|
-
(odd) =>
|
|
178
|
-
odd.market_name.toLowerCase() === marketName.toLowerCase() &&
|
|
179
|
-
odd.sports_book_name.toLowerCase() == oddsProvider.toLowerCase()
|
|
180
|
-
);
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
// TODO: Unify the same code from formatSpreadOdds method and from processTotalOdds method
|
|
184
|
-
/**
|
|
185
|
-
* Formats the spread odds and creates market objects.
|
|
168
|
+
* Creates child markets based on the given parameters.
|
|
186
169
|
*
|
|
187
|
-
* @param {
|
|
188
|
-
* @param {
|
|
189
|
-
* @param {Object}
|
|
190
|
-
* @param {Array}
|
|
191
|
-
* @param {Number}
|
|
192
|
-
* @param {
|
|
193
|
-
* @returns {Array} The
|
|
170
|
+
* @param {Object} leagueId - leagueId AKA sportId
|
|
171
|
+
* @param {Array} spreadDataForSport - Spread data for sport.
|
|
172
|
+
* @param {Object} apiResponseWithOdds - API response from the provider
|
|
173
|
+
* @param {Array} liveOddsProviders - Odds providers for live odds
|
|
174
|
+
* @param {Number} defaultSpreadForLiveMarkets - Default spread for live markets
|
|
175
|
+
* @param {Boolean} leagueMap - League Map info
|
|
176
|
+
* @returns {Array} The child markets.
|
|
194
177
|
*/
|
|
195
|
-
export const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
leagueId,
|
|
178
|
+
export const createChildMarkets: (
|
|
179
|
+
apiResponseWithOdds: any,
|
|
180
|
+
spreadDataForSport: any,
|
|
181
|
+
leagueId: number,
|
|
182
|
+
liveOddsProviders: any,
|
|
183
|
+
defaultSpreadForLiveMarkets: any,
|
|
184
|
+
leagueMap: any
|
|
185
|
+
) => ChildMarket[] = (
|
|
186
|
+
apiResponseWithOdds,
|
|
199
187
|
spreadDataForSport,
|
|
200
|
-
|
|
201
|
-
|
|
188
|
+
leagueId,
|
|
189
|
+
liveOddsProviders,
|
|
190
|
+
defaultSpreadForLiveMarkets,
|
|
191
|
+
leagueMap
|
|
202
192
|
) => {
|
|
203
|
-
const childMarkets = []
|
|
204
|
-
const
|
|
205
|
-
const
|
|
193
|
+
const [spreadOdds, totalOdds, childMarkets]: any[] = [[], [], []];
|
|
194
|
+
const leagueInfo = getLeagueInfo(leagueId, leagueMap);
|
|
195
|
+
const commonData = {
|
|
196
|
+
homeTeam: apiResponseWithOdds.home_team,
|
|
197
|
+
awayTeam: apiResponseWithOdds.away_team,
|
|
198
|
+
};
|
|
199
|
+
if (leagueInfo.length > 0) {
|
|
200
|
+
// TODO ADD ODDS COMPARISON BETWEEN BOOKMAKERS
|
|
201
|
+
const allChildOdds = filterOddsByMarketNameBookmaker(
|
|
202
|
+
apiResponseWithOdds.odds,
|
|
203
|
+
leagueInfo,
|
|
204
|
+
liveOddsProviders[0]
|
|
205
|
+
);
|
|
206
206
|
|
|
207
|
-
|
|
208
|
-
let homeTeamOdds = convertOddsToImpl(odds[0]) || ZERO;
|
|
209
|
-
let awayTeamOdds = convertOddsToImpl(odds[1]) || ZERO;
|
|
210
|
-
let isZeroOddsChild = homeTeamOdds === ZERO || awayTeamOdds === ZERO;
|
|
207
|
+
const allValidOdds = allChildOdds.filter((odd) => odd && Math.abs(odd.selection_points % 1) === 0.5) as any;
|
|
211
208
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
spreadData.minSpread,
|
|
218
|
-
spreadData.targetSpread
|
|
219
|
-
);
|
|
220
|
-
if (adjustedOdds.some((prob) => prob === ZERO)) {
|
|
221
|
-
isZeroOddsChild = true;
|
|
222
|
-
} else {
|
|
223
|
-
[homeTeamOdds, awayTeamOdds] = adjustedOdds;
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
let adjustedOdds = adjustSpreadOnOdds([homeTeamOdds, awayTeamOdds], defaultSpreadForLiveMarkets, 0);
|
|
227
|
-
if (adjustedOdds.some((prob) => prob === ZERO)) {
|
|
228
|
-
isZeroOddsChild = true;
|
|
229
|
-
} else {
|
|
230
|
-
[homeTeamOdds, awayTeamOdds] = adjustedOdds;
|
|
231
|
-
}
|
|
209
|
+
allValidOdds.forEach((odd) => {
|
|
210
|
+
if (odd.type === 'Total') {
|
|
211
|
+
totalOdds.push(odd);
|
|
212
|
+
} else if (odd.type === 'Spread') {
|
|
213
|
+
spreadOdds.push(odd);
|
|
232
214
|
}
|
|
233
|
-
}
|
|
215
|
+
});
|
|
234
216
|
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
217
|
+
const formattedOdds = [
|
|
218
|
+
...groupAndFormatSpreadOdds(spreadOdds, commonData),
|
|
219
|
+
...groupAndFormatTotalOdds(totalOdds, commonData),
|
|
220
|
+
];
|
|
221
|
+
|
|
222
|
+
const oddsWithSpreadAdjusted = adjustSpreadOnChildOdds(
|
|
223
|
+
formattedOdds,
|
|
224
|
+
spreadDataForSport,
|
|
225
|
+
defaultSpreadForLiveMarkets
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
oddsWithSpreadAdjusted.forEach((data) => {
|
|
229
|
+
const childMarket = {
|
|
230
|
+
leagueId: Number(data.sportId),
|
|
231
|
+
typeId: Number(data.typeId),
|
|
232
|
+
type: data.type.toLowerCase(),
|
|
233
|
+
line: Number(data.line),
|
|
234
|
+
odds: data.odds,
|
|
235
|
+
};
|
|
236
|
+
const leagueInfoByTypeId = leagueInfo.find((league) => Number(league.typeId) === Number(data.typeId));
|
|
237
|
+
const minOdds = leagueInfoByTypeId?.minOdds;
|
|
238
|
+
const maxOdds = leagueInfoByTypeId?.maxOdds;
|
|
239
|
+
if (
|
|
240
|
+
!(
|
|
241
|
+
minOdds &&
|
|
242
|
+
maxOdds &&
|
|
243
|
+
(data.odds[0] >= minOdds ||
|
|
244
|
+
data.odds[0] <= maxOdds ||
|
|
245
|
+
data.odds[1] >= minOdds ||
|
|
246
|
+
data.odds[1] <= maxOdds)
|
|
247
|
+
)
|
|
248
|
+
) {
|
|
249
|
+
childMarkets.push(childMarket);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
} else {
|
|
253
|
+
console.warn(`No child markets for leagueID: ${Number(leagueId)}`);
|
|
254
|
+
}
|
|
259
255
|
return childMarkets;
|
|
260
256
|
};
|
|
261
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Filters the odds array to find entries matching the specified market name.
|
|
260
|
+
*
|
|
261
|
+
* @param {Array} oddsArray - The array of odds objects.
|
|
262
|
+
* @param {string} leagueInfos - The market names to filter by.
|
|
263
|
+
* @param {string} oddsProvider - The main odds provider to filter by.
|
|
264
|
+
* @returns {Array} The filtered odds array.
|
|
265
|
+
*/
|
|
266
|
+
export const filterOddsByMarketNameBookmaker = (oddsArray, leagueInfos: LeagueInfo[], oddsProvider) => {
|
|
267
|
+
const allChildMarketsTypes = leagueInfos
|
|
268
|
+
.filter((leagueInfo) => leagueInfo.marketName.toLowerCase() !== MoneylineTypes.MONEYLINE.toLowerCase())
|
|
269
|
+
.map((leagueInfo) => leagueInfo.marketName.toLowerCase());
|
|
270
|
+
return oddsArray
|
|
271
|
+
.filter(
|
|
272
|
+
(odd) =>
|
|
273
|
+
allChildMarketsTypes.includes(odd.market_name.toLowerCase()) &&
|
|
274
|
+
odd.sports_book_name.toLowerCase() == oddsProvider.toLowerCase()
|
|
275
|
+
)
|
|
276
|
+
.map((odd) => {
|
|
277
|
+
return {
|
|
278
|
+
...odd,
|
|
279
|
+
...leagueInfos.find((leagueInfo) => leagueInfo.marketName === odd.market_name), // using .find() for team totals means that we will always assign 10017 as typeID at this point
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
|
|
262
284
|
/**
|
|
263
285
|
* Groups spread odds by their lines and formats the result.
|
|
264
286
|
*
|
|
@@ -269,13 +291,13 @@ export const formatSpreadOdds = (
|
|
|
269
291
|
export const groupAndFormatSpreadOdds = (oddsArray, commonData) => {
|
|
270
292
|
// Group odds by their selection points and selection
|
|
271
293
|
const groupedOdds = oddsArray.reduce((acc: any, odd: any) => {
|
|
272
|
-
const { selection_points, price, selection } = odd;
|
|
294
|
+
const { selection_points, price, selection, typeId, sportId, type } = odd;
|
|
273
295
|
const isHomeTeam = selection === commonData.homeTeam;
|
|
274
296
|
|
|
275
297
|
const key = isHomeTeam ? selection_points : -selection_points;
|
|
276
298
|
|
|
277
299
|
if (!acc[key]) {
|
|
278
|
-
acc[key] = { home: null, away: null };
|
|
300
|
+
acc[key] = { home: null, away: null, typeId: null, sportId: null };
|
|
279
301
|
}
|
|
280
302
|
|
|
281
303
|
if (isHomeTeam) {
|
|
@@ -284,6 +306,10 @@ export const groupAndFormatSpreadOdds = (oddsArray, commonData) => {
|
|
|
284
306
|
acc[key].away = price;
|
|
285
307
|
}
|
|
286
308
|
|
|
309
|
+
acc[key].typeId = typeId;
|
|
310
|
+
acc[key].type = type;
|
|
311
|
+
acc[key].sportId = sportId;
|
|
312
|
+
|
|
287
313
|
return acc;
|
|
288
314
|
}, {}) as any;
|
|
289
315
|
// Format the grouped odds into the desired output
|
|
@@ -293,6 +319,9 @@ export const groupAndFormatSpreadOdds = (oddsArray, commonData) => {
|
|
|
293
319
|
acc.push({
|
|
294
320
|
line: line as any,
|
|
295
321
|
odds: [(value as any).home, (value as any).away],
|
|
322
|
+
typeId: value.typeId,
|
|
323
|
+
sportId: value.sportId,
|
|
324
|
+
type: value.type,
|
|
296
325
|
});
|
|
297
326
|
}
|
|
298
327
|
return acc;
|
|
@@ -301,89 +330,15 @@ export const groupAndFormatSpreadOdds = (oddsArray, commonData) => {
|
|
|
301
330
|
return formattedOdds;
|
|
302
331
|
};
|
|
303
332
|
|
|
304
|
-
/**
|
|
305
|
-
* Processes total odds to create market objects.
|
|
306
|
-
*
|
|
307
|
-
* @param {Array} totalOdds - The total odds array.
|
|
308
|
-
* @param {Object} commonData - The common data object.
|
|
309
|
-
* @param {Object} market - The sport ID from the API.
|
|
310
|
-
* @param {Array} spreadDataForSport - Spread data for the sport.
|
|
311
|
-
* @param {Number} typeId - typeID
|
|
312
|
-
* @param {Number} defaultSpreadForLiveMarkets - Default spread for live markets,
|
|
313
|
-
* @returns {Array} The processed total odds market objects.
|
|
314
|
-
*/
|
|
315
|
-
export const processTotalOdds = (totalOdds, leagueId, spreadDataForSport, typeId, defaultSpreadForLiveMarkets) => {
|
|
316
|
-
const childMarkets = [] as any;
|
|
317
|
-
const validTotalOdds = totalOdds.filter((odd) => odd && Math.abs(odd.selection_points % 1) === 0.5);
|
|
318
|
-
const groupedOdds = groupOddsBySelectionAndPoints(validTotalOdds);
|
|
319
|
-
const iterableGroupedOdds = Object.entries(groupedOdds) as any;
|
|
320
|
-
|
|
321
|
-
iterableGroupedOdds.forEach(([key, { over, under }]) => {
|
|
322
|
-
const [_, selection_points] = key.split('_');
|
|
323
|
-
|
|
324
|
-
let overOdds = convertOddsToImpl(over) || ZERO;
|
|
325
|
-
let underOdds = convertOddsToImpl(under) || ZERO;
|
|
326
|
-
let isZeroOddsChild = overOdds === ZERO || underOdds === ZERO;
|
|
327
|
-
|
|
328
|
-
if (!isZeroOddsChild) {
|
|
329
|
-
const spreadData = getSpreadData(spreadDataForSport, leagueId, typeId, defaultSpreadForLiveMarkets);
|
|
330
|
-
if (spreadData !== null) {
|
|
331
|
-
let adjustedOdds = adjustSpreadOnOdds(
|
|
332
|
-
[overOdds, underOdds],
|
|
333
|
-
spreadData.minSpread,
|
|
334
|
-
spreadData.targetSpread
|
|
335
|
-
);
|
|
336
|
-
if (adjustedOdds.some((prob) => prob === ZERO)) {
|
|
337
|
-
isZeroOddsChild = true;
|
|
338
|
-
} else {
|
|
339
|
-
[overOdds, underOdds] = adjustedOdds;
|
|
340
|
-
}
|
|
341
|
-
} else {
|
|
342
|
-
// Use min spread by sport if available, otherwise use default min spread
|
|
343
|
-
let adjustedOdds = adjustSpreadOnOdds([overOdds, underOdds], defaultSpreadForLiveMarkets, 0);
|
|
344
|
-
if (adjustedOdds.some((prob) => prob === ZERO)) {
|
|
345
|
-
isZeroOddsChild = true;
|
|
346
|
-
} else {
|
|
347
|
-
[overOdds, underOdds] = adjustedOdds;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const minOdds = process.env.MIN_ODDS_FOR_CHILD_MARKETS_FOR_LIVE;
|
|
353
|
-
const maxOdds = process.env.MAX_ODDS_FOR_CHILD_MARKETS_FOR_LIVE;
|
|
354
|
-
|
|
355
|
-
const childMarket = {
|
|
356
|
-
leagueId,
|
|
357
|
-
typeId: typeId,
|
|
358
|
-
type: 'total',
|
|
359
|
-
results: [],
|
|
360
|
-
status: isZeroOddsChild ? statusCodes.PAUSED : statusCodes.OPEN,
|
|
361
|
-
line: parseFloat(selection_points),
|
|
362
|
-
odds: [overOdds, underOdds],
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
if (
|
|
366
|
-
!(
|
|
367
|
-
minOdds &&
|
|
368
|
-
maxOdds &&
|
|
369
|
-
(overOdds >= minOdds || overOdds <= maxOdds || underOdds >= minOdds || underOdds <= maxOdds)
|
|
370
|
-
)
|
|
371
|
-
) {
|
|
372
|
-
childMarkets.push(childMarket);
|
|
373
|
-
}
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
return childMarkets;
|
|
377
|
-
};
|
|
378
|
-
|
|
379
333
|
/**
|
|
380
334
|
* Groups odds by selection and points over/under.
|
|
381
335
|
*
|
|
382
336
|
* @param {Array} oddsArray - The array of odds objects.
|
|
383
337
|
* @returns {Object} The grouped odds.
|
|
384
338
|
*/
|
|
385
|
-
export const
|
|
386
|
-
|
|
339
|
+
export const groupAndFormatTotalOdds = (oddsArray, commonData) => {
|
|
340
|
+
// Group odds by their selection points and selection
|
|
341
|
+
const groupedOdds = oddsArray.reduce((acc, odd) => {
|
|
387
342
|
if (odd) {
|
|
388
343
|
const key = `${odd.selection}_${odd.selection_points}`;
|
|
389
344
|
if (!acc[key]) {
|
|
@@ -394,8 +349,67 @@ export const groupOddsBySelectionAndPoints = (oddsArray) => {
|
|
|
394
349
|
} else if (odd.selection_line === 'under') {
|
|
395
350
|
acc[key].under = odd.price;
|
|
396
351
|
}
|
|
352
|
+
|
|
353
|
+
acc[key].typeId = odd.typeId;
|
|
354
|
+
acc[key].type = odd.type;
|
|
355
|
+
acc[key].sportId = odd.sportId;
|
|
397
356
|
}
|
|
398
357
|
|
|
399
358
|
return acc;
|
|
400
359
|
}, {});
|
|
360
|
+
|
|
361
|
+
// Format the grouped odds into the desired output
|
|
362
|
+
const formattedOdds = (Object.entries(groupedOdds as any) as any).reduce((acc, [key, value]) => {
|
|
363
|
+
const [selection, selectionLine] = key.split('_');
|
|
364
|
+
const line = parseFloat(selectionLine);
|
|
365
|
+
|
|
366
|
+
// if we have away team in total odds we know the market is team total and we need to increase typeId by one.
|
|
367
|
+
// if this is false typeId is already mapped correctly
|
|
368
|
+
const isAwayTeam = selection === commonData.awayTeam;
|
|
369
|
+
if ((value as any).over !== null && (value as any).under !== null) {
|
|
370
|
+
acc.push({
|
|
371
|
+
line: line as any,
|
|
372
|
+
odds: [(value as any).over, (value as any).under],
|
|
373
|
+
typeId: !isAwayTeam ? value.typeId : Number(value.typeId) + 1,
|
|
374
|
+
sportId: value.sportId,
|
|
375
|
+
type: value.type,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
return acc;
|
|
379
|
+
}, []);
|
|
380
|
+
|
|
381
|
+
return formattedOdds;
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
export const adjustSpreadOnChildOdds = (iterableGroupedOdds, spreadDataForSport, defaultSpreadForLiveMarkets) => {
|
|
385
|
+
const result: any[] = [];
|
|
386
|
+
iterableGroupedOdds.forEach((data) => {
|
|
387
|
+
let homeTeamOdds = convertOddsToImpl(data.odds[0]) || ZERO;
|
|
388
|
+
let awayTeamOdds = convertOddsToImpl(data.odds[1]) || ZERO;
|
|
389
|
+
let isZeroOddsChild = homeTeamOdds === ZERO || awayTeamOdds === ZERO;
|
|
390
|
+
if (!isZeroOddsChild) {
|
|
391
|
+
const spreadData = getSpreadData(
|
|
392
|
+
spreadDataForSport,
|
|
393
|
+
data.sportId,
|
|
394
|
+
data.typeId,
|
|
395
|
+
defaultSpreadForLiveMarkets
|
|
396
|
+
);
|
|
397
|
+
let adjustedOdds;
|
|
398
|
+
if (spreadData !== null) {
|
|
399
|
+
adjustedOdds = adjustSpreadOnOdds(
|
|
400
|
+
[homeTeamOdds, awayTeamOdds],
|
|
401
|
+
spreadData.minSpread,
|
|
402
|
+
spreadData.targetSpread
|
|
403
|
+
);
|
|
404
|
+
} else {
|
|
405
|
+
adjustedOdds = adjustSpreadOnOdds([homeTeamOdds, awayTeamOdds], defaultSpreadForLiveMarkets, 0);
|
|
406
|
+
}
|
|
407
|
+
[homeTeamOdds, awayTeamOdds] = adjustedOdds;
|
|
408
|
+
result.push({
|
|
409
|
+
...data,
|
|
410
|
+
odds: adjustedOdds,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
return result;
|
|
401
415
|
};
|