2022-03-29 15:10:28 +00:00
import axios from "axios" ;
2022-05-10 21:45:02 +00:00
import { QuestionOption } from "../../common/types" ;
2022-05-09 21:15:18 +00:00
import { average } from "../../utils" ;
2022-04-23 19:44:38 +00:00
import { FetchedQuestion , Platform } from "./" ;
2022-03-29 15:10:28 +00:00
/* Definitions */
2022-04-01 20:24:35 +00:00
const platformName = "smarkets" ;
2022-03-29 15:10:28 +00:00
let htmlEndPointEntrance = "https://api.smarkets.com/v3/events/" ;
let VERBOSE = false ;
2022-04-01 20:24:35 +00:00
2022-03-29 15:10:28 +00:00
/* Support functions */
2022-05-10 21:45:02 +00:00
async function fetchEvents ( url : string ) {
const response = await axios ( {
2022-03-29 15:10:28 +00:00
url : htmlEndPointEntrance + url ,
method : "GET" ,
} ) . then ( ( res ) = > res . data ) ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( response ) ;
2022-03-29 15:10:28 +00:00
return response ;
}
2022-05-10 21:45:02 +00:00
async function fetchMarkets ( eventid : string ) {
const response = await axios ( {
2022-03-29 15:10:28 +00:00
url : ` https://api.smarkets.com/v3/events/ ${ eventid } /markets/ ` ,
method : "GET" ,
} )
. then ( ( res ) = > res . data )
. then ( ( res ) = > res . markets ) ;
return response ;
}
2022-05-10 21:45:02 +00:00
async function fetchContracts ( marketid : string ) {
const response = await axios ( {
2022-03-29 15:10:28 +00:00
url : ` https://api.smarkets.com/v3/markets/ ${ marketid } /contracts/ ` ,
method : "GET" ,
} ) . then ( ( res ) = > res . data ) ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( response ) ;
if ( ! ( response . contracts instanceof Array ) ) {
throw new Error ( "Invalid response while fetching contracts" ) ;
}
return response . contracts as any [ ] ;
2022-03-29 15:10:28 +00:00
}
2022-05-10 21:45:02 +00:00
async function fetchPrices ( marketid : string ) {
const response = await axios ( {
2022-03-29 15:10:28 +00:00
url : ` https://api.smarkets.com/v3/markets/ ${ marketid } /last_executed_prices/ ` ,
method : "GET" ,
} ) . then ( ( res ) = > res . data ) ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( response ) ;
if ( ! response . last_executed_prices ) {
throw new Error ( "Invalid response while fetching prices" ) ;
}
return response . last_executed_prices ;
2022-03-29 15:10:28 +00:00
}
export const smarkets : Platform = {
2022-04-01 20:24:35 +00:00
name : platformName ,
label : "Smarkets" ,
color : "#6f5b41" ,
2022-03-29 15:10:28 +00:00
async fetcher() {
let htmlPath =
"?state=new&state=upcoming&state=live&type_domain=politics&type_scope=single_event&with_new_type=true&sort=id&limit=50" ;
let events = [ ] ;
while ( htmlPath ) {
2022-05-10 21:45:02 +00:00
const data = await fetchEvents ( htmlPath ) ;
2022-03-29 15:10:28 +00:00
events . push ( . . . data . events ) ;
htmlPath = data . pagination . next_page ;
}
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( events ) ;
2022-03-29 15:10:28 +00:00
let markets = [ ] ;
2022-05-10 21:45:02 +00:00
for ( const event of events ) {
VERBOSE && console . log ( Date . now ( ) ) ;
VERBOSE && console . log ( event . name ) ;
2022-03-29 15:10:28 +00:00
let eventMarkets = await fetchMarkets ( event . id ) ;
2022-05-10 21:45:02 +00:00
eventMarkets = eventMarkets . map ( ( market : any ) = > ( {
2022-03-29 15:10:28 +00:00
. . . market ,
2022-05-10 21:45:02 +00:00
// smarkets doesn't have separate urls for different markets in a single event
// we could use anchors (e.g. https://smarkets.com/event/886716/politics/uk/uk-party-leaders/next-conservative-leader#contract-collapse-9815728-control), but it's unclear if they aren't going to change
2022-03-29 15:10:28 +00:00
slug : event.full_slug ,
} ) ) ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( "Markets fetched" ) ;
VERBOSE && console . log ( event . id ) ;
VERBOSE && console . log ( eventMarkets ) ;
2022-03-29 15:10:28 +00:00
markets . push ( . . . eventMarkets ) ;
}
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( markets ) ;
2022-03-29 15:10:28 +00:00
let results = [ ] ;
for ( let market of markets ) {
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( "================" ) ;
VERBOSE && console . log ( "Market: " , market ) ;
2022-03-29 15:10:28 +00:00
let contracts = await fetchContracts ( market . id ) ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( "Contracts: " , contracts ) ;
2022-03-29 15:10:28 +00:00
let prices = await fetchPrices ( market . id ) ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( "Prices: " , prices [ market . id ] ) ;
2022-03-29 15:10:28 +00:00
2022-05-10 21:45:02 +00:00
let optionsObj : {
[ k : string ] : QuestionOption ;
} = { } ;
const contractIdToName = Object . fromEntries (
contracts . map ( ( c ) = > [ c . id as string , c . name as string ] )
) ;
for ( const price of prices [ market . id ] ) {
const contractName = contractIdToName [ price . contract_id ] ;
if ( ! contractName ) {
console . warn (
` Couldn't find contract ${ price . contract_id } in contracts data, skipping `
) ;
continue ;
}
2022-03-29 15:10:28 +00:00
optionsObj [ price . contract_id ] = {
2022-05-10 21:45:02 +00:00
name : contractName ,
2022-03-29 15:10:28 +00:00
probability : price.last_executed_price
? Number ( price . last_executed_price )
2022-05-10 21:45:02 +00:00
: undefined ,
2022-03-29 15:10:28 +00:00
type : "PROBABILITY" ,
} ;
}
2022-05-10 21:45:02 +00:00
let options : QuestionOption [ ] = Object . values ( optionsObj ) ;
2022-03-29 15:10:28 +00:00
// monkey patch the case where there are only two options and only one has traded.
if (
options . length == 2 &&
2022-05-10 21:45:02 +00:00
options . map ( ( option ) = > option . probability ) . includes ( undefined )
2022-03-29 15:10:28 +00:00
) {
2022-05-10 21:45:02 +00:00
const nonNullPrice =
2022-03-29 15:10:28 +00:00
options [ 0 ] . probability == null
? options [ 1 ] . probability
: options [ 0 ] . probability ;
2022-05-10 21:45:02 +00:00
if ( nonNullPrice != null ) {
options = options . map ( ( option ) = > {
let probability = option . probability ;
return {
. . . option ,
probability :
probability == null ? 100 - nonNullPrice : probability ,
// yes, 100, because prices are not yet normalized.
} ;
} ) ;
}
2022-03-29 15:10:28 +00:00
}
// Normalize normally
2022-05-10 21:45:02 +00:00
const totalValue = options
2022-03-29 15:10:28 +00:00
. map ( ( element ) = > Number ( element . probability ) )
. reduce ( ( a , b ) = > a + b , 0 ) ;
options = options . map ( ( element ) = > ( {
. . . element ,
probability : Number ( element . probability ) / totalValue ,
} ) ) ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( options ) ;
2022-03-29 15:10:28 +00:00
/ *
2022-05-10 21:45:02 +00:00
if ( contracts . length == 2 ) {
2022-03-29 15:10:28 +00:00
isBinary = true
2022-05-10 21:45:02 +00:00
percentage = ( Number ( prices [ market . id ] [ 0 ] . last_executed_price ) + ( 100 - Number ( prices [ market . id ] [ 1 ] . last_executed_price ) ) ) / 2
2022-03-29 15:10:28 +00:00
percentage = Math . round ( percentage ) + "%"
2022-05-10 21:45:02 +00:00
let contractName = contracts [ 0 ] . name
name = name + ( contractName == "Yes" ? '' : ` ( ${ contracts [ 0 ] . name } ) ` )
2022-03-29 15:10:28 +00:00
}
* /
2022-05-10 21:45:02 +00:00
const id = ` ${ platformName } - ${ market . id } ` ;
const title = market . name ;
const result : FetchedQuestion = {
id ,
title ,
2022-03-29 15:10:28 +00:00
url : "https://smarkets.com/event/" + market . event_id + market . slug ,
description : market.description ,
2022-05-10 21:45:02 +00:00
options ,
2022-04-23 19:44:38 +00:00
timestamp : new Date ( ) ,
2022-05-09 21:15:18 +00:00
qualityindicators : { } ,
2022-03-29 15:10:28 +00:00
} ;
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( result ) ;
2022-03-29 15:10:28 +00:00
results . push ( result ) ;
}
2022-05-10 21:45:02 +00:00
VERBOSE && console . log ( results ) ;
2022-03-29 15:10:28 +00:00
return results ;
} ,
2022-05-09 21:15:18 +00:00
calculateStars ( data ) {
let nuno = ( ) = > 2 ;
let eli = ( ) = > null ;
let misha = ( ) = > null ;
let starsDecimal = average ( [ nuno ( ) ] ) ; //, eli(), misha()])
let starsInteger = Math . round ( starsDecimal ) ;
return starsInteger ;
} ,
2022-03-29 15:10:28 +00:00
} ;