/* Imports */
import fs from "fs";
import axios from "axios";
import https from "https";
import { calculateStars } from "../utils/stars.js";
import { upsert } from "../database/mongo-wrapper.js";
/* Definitions */
let endpoint = process.env.SECRET_BETFAIR_ENDPOINT;
/* Utilities */
let arraysEqual = (a, b) => {
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;
};
let mergeRunners = (runnerCatalog, runnerBook) => {
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,
});
let response = await axios({
url: endpoint,
method: "GET",
headers: {
"Content-Type": "text/html",
},
httpsAgent: agent,
}).then((response) => response.data);
return response;
}
async function whipIntoShape(data) {
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) {
let predictions = await whipIntoShape(data);
// console.log(JSON.stringify(predictions, null, 4))
let results = predictions.map((prediction) => {
/* if(Math.floor(Math.random() * 10) % 20 ==0){
console.log(JSON.stringify(prediction, null, 4))
} */
let id = `betfair-${prediction.marketId}`;
let normalizationFactor = prediction.options
.filter((option) => option.status == "ACTIVE" && option.totalMatched > 0)
.map((option) => option.lastPriceTraded)
.map((x) => 1 / x)
.reduce((a, b) => a + b, 0);
let options = prediction.options
.filter((option) => option.status == "ACTIVE" && option.totalMatched > 0)
.map((option) => ({
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;
}
let result = {
id: id,
title: title,
url: `https://www.betfair.com/exchange/plus/politics/market/${prediction.marketId}`,
platform: "Betfair",
description: description,
options: options,
timestamp: new Date().toISOString(),
qualityindicators: {
stars: calculateStars("Betfair", { volume: prediction.totalMatched }),
volume: prediction.totalMatched,
},
};
return result;
});
return results; //resultsProcessed
}
/* Body */
export async function betfair() {
let data = await fetchPredictions();
let results = await processPredictions(data); // somehow needed
// console.log(results.map(result => ({title: result.title, description: result.description})))
// let string = JSON.stringify(results, null, 2)
// fs.writeFileSync('polyprediction-questions.json', string);
await upsert(results, "betfair-questions");
console.log("Done");
}
// betfair()