/* Imports */ import axios from "axios"; import https from "https"; import { average } from "../../utils"; import { FetchedQuestion, Platform } from "./"; const platformName = "betfair"; /* Definitions */ const endpoint = process.env.SECRET_BETFAIR_ENDPOINT; /* Utilities */ const arraysEqual = (a: string[], b: string[]) => { if (a === b) return true; if (a == null || b == null) return false; if (a.length !== b.length) return false; // If you don't care about the order of the elements inside // the array, you should sort both arrays here. // Please note that calling sort on an array will modify that array. // you might want to clone your array first. for (var i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; }; const mergeRunners = (runnerCatalog: any, runnerBook: any) => { let keys = Object.keys(runnerCatalog); let result = []; for (let key of keys) { result.push({ ...runnerCatalog[key], ...runnerBook[key] }); } return result; }; /* Support functions */ async function fetchPredictions() { const agent = new https.Agent({ rejectUnauthorized: false, }); const response = await axios({ url: endpoint, method: "GET", httpsAgent: agent, }).then((response) => response.data); return response; } async function whipIntoShape(data: any) { let catalogues = data.market_catalogues; let books = data.market_books; let keys1 = Object.keys(catalogues).sort(); let keys2 = Object.keys(books).sort(); // console.log(keys1) // console.log(keys2) let results = []; if (!arraysEqual(keys1, keys2)) { throw new Error( "Betfair: Error in endpoint; Betfair catalogues and books do not match" ); } else { for (let key of keys1) { results.push({ ...catalogues[key], ...books[key], options: mergeRunners(catalogues[key].runners, books[key].runners), }); } } return results; } async function processPredictions(data: any) { let predictions = await whipIntoShape(data); // console.log(JSON.stringify(predictions, null, 4)) let results: FetchedQuestion[] = predictions.map((prediction) => { /* if(Math.floor(Math.random() * 10) % 20 ==0){ console.log(JSON.stringify(prediction, null, 4)) } */ let id = `${platformName}-${prediction.marketId}`; let normalizationFactor = prediction.options .filter( (option: any) => option.status == "ACTIVE" && option.totalMatched > 0 ) .map((option: any) => option.lastPriceTraded) .map((x: any) => 1 / x) .reduce((a: any, b: any) => a + b, 0); let options = prediction.options .filter( (option: any) => option.status == "ACTIVE" && option.totalMatched > 0 ) .map((option: any) => ({ name: option.runnerName, probability: option.lastPriceTraded != 0 ? 1 / option.lastPriceTraded / normalizationFactor : 0, // https://www.aceodds.com/bet-calculator/odds-converter.html type: "PROBABILITY", })); // console.log(prediction.options) let rules = prediction.description.rules .split("Regs.")[1] .replace(/

/g, " ") .replace(/
/g, " ") .replace(//g, " ") .replace(/<\/b>/g, " ") .replace(/\n/g, " ") .trim(); if (rules == undefined) { // console.log(prediction.description) } let title = rules.split("? ")[0] + "?"; let description = rules.split("? ")[1].trim(); if (title.includes("of the named")) { title = prediction.marketName + ": " + title; } const result: FetchedQuestion = { id, title, url: `https://www.betfair.com/exchange/plus/politics/market/${prediction.marketId}`, description, options, qualityindicators: { volume: prediction.totalMatched, }, }; return result; }); return results; //resultsProcessed } export const betfair: Platform = { name: platformName, label: "Betfair", color: "#3d674a", version: "v1", async fetcher() { const data = await fetchPredictions(); const results = await processPredictions(data); return results; }, calculateStars(data) { const volume = data.qualityindicators.volume || 0; let nuno = () => (volume > 10000 ? 4 : volume > 1000 ? 3 : 2); let eli = () => (volume > 10000 ? null : null); let misha = () => null; let starsDecimal = average([nuno()]); //, eli(), misha()]) const firstOption = data.options[0]; // Substract 1 star if probability is above 90% or below 10% if ( firstOption && ((firstOption.probability || 0) < 0.1 || (firstOption.probability || 0) > 0.9) ) { starsDecimal = starsDecimal - 1; } let starsInteger = Math.round(starsDecimal); return starsInteger; }, };