Codex commited on
Commit
af8ceca
·
1 Parent(s): bf291c4

Expand home run odds book coverage

Browse files
src/commands.js CHANGED
@@ -508,11 +508,7 @@ export const commands = [
508
  .setName('book')
509
  .setDescription('Optionally limit the result to one book. Defaults to all books including Circa.')
510
  .setRequired(false)
511
- .addChoices(
512
- { name: 'Circa', value: 'Circa' },
513
- { name: 'BetMGM', value: 'BetMGM' },
514
- { name: 'Caesars', value: 'Caesars' }
515
- )
516
  ),
517
  new SlashCommandBuilder()
518
  .setName('hitodds')
 
508
  .setName('book')
509
  .setDescription('Optionally limit the result to one book. Defaults to all books including Circa.')
510
  .setRequired(false)
511
+ .addChoices(...SPORTSBOOK_BOOK_CHOICES)
 
 
 
 
512
  ),
513
  new SlashCommandBuilder()
514
  .setName('hitodds')
src/embeds.js CHANGED
@@ -312,7 +312,7 @@ export function buildCommandsEmbed() {
312
  { name: '/scanrun', value: 'Run the market scanner manually. Admin only.' },
313
  { name: '/scanreport', value: 'Post the morning scan reports immediately. Admin only.' },
314
  { name: 'Sharp Market Commands', value: '`/edgeboard`, `/playeredge`, `/marketedge`, `/widthboard`, `/consensusvs`, `/steam`, `/sharpboard`, `/bookscoreboard`, `/markethealth` cover sportsbook comparisons. `/dfsedgeboard`, `/dfsplayeredge`, `/dfsmarketedge`, `/dfswidthboard`, `/dfsconsensusvs` and `/exchangeedgeboard`, `/exchangeplayeredge`, `/exchangemarketedge`, `/exchangewidthboard`, `/exchangeconsensusvs` mirror those views for DFS and exchange lanes.' },
315
- { name: '/hrodds', value: 'Show live Home Run odds for one player across Caesars, BetMGM, and Circa, or filter to one book.' },
316
  { name: 'Other Odds Commands', value: '`/hitodds`, `/tbodds`, `/rbiodds`, `/runodds`, `/sbodds`, `/kodds` stay sportsbook-only. `/dfsodds` and `/exchangeodds` show direct prices inside the DFS or exchange lane.' },
317
  { name: '/circatest', value: 'Run a Circa OCR diagnostic preview. Admin only.' },
318
  { name: 'Circa Market Commands', value: '`/circamarket`, `/circahr`, `/circahits`, `/circatb`, `/circarbis`, `/circaruns`, `/circasb`, `/circahrri`, `/circak` post the latest parsed Circa markets in the channel where you run them.' },
 
312
  { name: '/scanrun', value: 'Run the market scanner manually. Admin only.' },
313
  { name: '/scanreport', value: 'Post the morning scan reports immediately. Admin only.' },
314
  { name: 'Sharp Market Commands', value: '`/edgeboard`, `/playeredge`, `/marketedge`, `/widthboard`, `/consensusvs`, `/steam`, `/sharpboard`, `/bookscoreboard`, `/markethealth` cover sportsbook comparisons. `/dfsedgeboard`, `/dfsplayeredge`, `/dfsmarketedge`, `/dfswidthboard`, `/dfsconsensusvs` and `/exchangeedgeboard`, `/exchangeplayeredge`, `/exchangemarketedge`, `/exchangewidthboard`, `/exchangeconsensusvs` mirror those views for DFS and exchange lanes.' },
315
+ { name: '/hrodds', value: 'Show live Home Run odds for one player across the supported sportsbook books, including Circa, FanDuel, DraftKings, Caesars, Fanatics, Bally Bet, Hard Rock Bet, and BetMGM when available.' },
316
  { name: 'Other Odds Commands', value: '`/hitodds`, `/tbodds`, `/rbiodds`, `/runodds`, `/sbodds`, `/kodds` stay sportsbook-only. `/dfsodds` and `/exchangeodds` show direct prices inside the DFS or exchange lane.' },
317
  { name: '/circatest', value: 'Run a Circa OCR diagnostic preview. Admin only.' },
318
  { name: 'Circa Market Commands', value: '`/circamarket`, `/circahr`, `/circahits`, `/circatb`, `/circarbis`, `/circaruns`, `/circasb`, `/circahrri`, `/circak` post the latest parsed Circa markets in the channel where you run them.' },
src/market-scanner.js CHANGED
@@ -3424,7 +3424,7 @@ const DIRECT_ODDS_MARKET_CONFIG = {
3424
  circaMarketType: 'home_runs',
3425
  preferredSide: 'yes',
3426
  preferredLine: 0.5,
3427
- allowedBooks: ['Caesars', 'BetMGM', 'Circa'],
3428
  },
3429
  batter_hits: {
3430
  marketLabel: 'Hits',
 
3424
  circaMarketType: 'home_runs',
3425
  preferredSide: 'yes',
3426
  preferredLine: 0.5,
3427
+ allowedBooks: ['Circa', 'FanDuel', 'DraftKings', 'BetMGM', 'Caesars', 'Fanatics', 'Bally Bet', 'Hard Rock Bet'],
3428
  },
3429
  batter_hits: {
3430
  marketLabel: 'Hits',
test/market-scanner.test.js CHANGED
@@ -1345,6 +1345,95 @@ test('dfs player odds lookup stays inside the dfs lane', async () => {
1345
  }
1346
  });
1347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1348
  test('direct player odds lookups reuse cached Odds API entries within the ttl window', async () => {
1349
  const scanner = new MarketScanner({
1350
  client: {},
 
1345
  }
1346
  });
1347
 
1348
+ test('home run odds lookup accepts expanded sportsbook books', async () => {
1349
+ const scanner = new MarketScanner({
1350
+ client: {},
1351
+ store: {
1352
+ getLatestCircaSnapshot: async () => null,
1353
+ },
1354
+ embeds: {},
1355
+ config: {
1356
+ enabled: true,
1357
+ oddsWorkflowEnabled: true,
1358
+ circaWorkflowEnabled: false,
1359
+ oddsApiBaseUrl: 'https://api.the-odds-api.com/v4',
1360
+ oddsApiSportKey: 'baseball_mlb',
1361
+ oddsApiKey: 'test-key',
1362
+ oddsApiRegions: 'us,us2',
1363
+ oddsApiBookmakers: ['fanduel', 'hardrockbet'],
1364
+ oddsApiMarkets: ['batter_home_runs'],
1365
+ scanHttpTimeoutMs: 15000,
1366
+ },
1367
+ });
1368
+
1369
+ const originalFetch = global.fetch;
1370
+ global.fetch = async (input) => {
1371
+ const asString = String(input);
1372
+
1373
+ if (asString.includes('/events?')) {
1374
+ return {
1375
+ ok: true,
1376
+ status: 200,
1377
+ headers: new Headers(),
1378
+ json: async () => [{ id: 'event-1', away_team: 'Dodgers', home_team: 'Cubs' }],
1379
+ };
1380
+ }
1381
+
1382
+ if (asString.includes('/events/event-1/odds')) {
1383
+ return {
1384
+ ok: true,
1385
+ status: 200,
1386
+ headers: new Headers(),
1387
+ json: async () => ({
1388
+ id: 'event-1',
1389
+ away_team: 'Dodgers',
1390
+ home_team: 'Cubs',
1391
+ bookmakers: [
1392
+ {
1393
+ key: 'fanduel',
1394
+ title: 'FanDuel',
1395
+ markets: [
1396
+ {
1397
+ key: 'batter_home_runs',
1398
+ outcomes: [
1399
+ { name: 'Yes', description: 'Shohei Ohtani', price: 350 },
1400
+ ],
1401
+ },
1402
+ ],
1403
+ },
1404
+ {
1405
+ key: 'hardrockbet',
1406
+ title: 'Hard Rock Bet',
1407
+ markets: [
1408
+ {
1409
+ key: 'batter_home_runs',
1410
+ outcomes: [
1411
+ { name: 'Yes', description: 'Shohei Ohtani', price: 365 },
1412
+ ],
1413
+ },
1414
+ ],
1415
+ },
1416
+ ],
1417
+ }),
1418
+ };
1419
+ }
1420
+
1421
+ throw new Error(`Unexpected fetch URL: ${asString}`);
1422
+ };
1423
+
1424
+ try {
1425
+ const result = await scanner.getPlayerMarketOdds('batter_home_runs', 'Shohei Ohtani', {
1426
+ book: 'FanDuel',
1427
+ });
1428
+
1429
+ assert.equal(result.entries.length, 1);
1430
+ assert.equal(result.entries[0].book, 'FanDuel');
1431
+ assert.equal(result.entries[0].oddsInput, '350');
1432
+ } finally {
1433
+ global.fetch = originalFetch;
1434
+ }
1435
+ });
1436
+
1437
  test('direct player odds lookups reuse cached Odds API entries within the ttl window', async () => {
1438
  const scanner = new MarketScanner({
1439
  client: {},