{"id":"d143b9cd00768146","slug":"estimating-electability-from-prediction-markets","trashed":false,"description":"","likes":1,"publish_level":"public","forks":0,"fork_of":null,"has_importers":false,"update_time":"2020-03-14T19:21:18.087Z","first_public_version":null,"paused_version":null,"publish_time":"2020-01-15T19:49:39.209Z","publish_version":292,"latest_version":292,"thumbnail":"93241c57c2c24e9848fc0c9605afd7b7e3d2a2c772afc6111dee0d3ea45a3d72","default_thumbnail":"93241c57c2c24e9848fc0c9605afd7b7e3d2a2c772afc6111dee0d3ea45a3d72","roles":[],"sharing":null,"owner":{"id":"4a29764d3c5ac978","avatar_url":"https://avatars.observableusercontent.com/avatar/c2ab36a2b36058e9d5ad6cab5c830958647aa34d40616ae28603a9a9e5d0064a","login":"joshuahhh","name":"Joshua Horowitz","bio":"","home_url":"http://joshuahhh.com","type":"team","tier":"starter_2024"},"creator":{"id":"ddc378ed3cec53e0","avatar_url":"https://avatars.observableusercontent.com/avatar/c2ab36a2b36058e9d5ad6cab5c830958647aa34d40616ae28603a9a9e5d0064a","login":"joshuahhh","name":"Joshua Horowitz","bio":"","home_url":"http://joshuahhh.com","tier":"public"},"authors":[{"id":"ddc378ed3cec53e0","avatar_url":"https://avatars.observableusercontent.com/avatar/c2ab36a2b36058e9d5ad6cab5c830958647aa34d40616ae28603a9a9e5d0064a","name":"Joshua Horowitz","login":"joshuahhh","bio":"","home_url":"http://joshuahhh.com","tier":"public","approved":true,"description":""}],"collections":[],"files":[],"comments":[],"commenting_lock":null,"suggestion_from":null,"suggestions_to":[],"version":292,"title":"Estimating \"electability\" from prediction markets","license":null,"copyright":"","nodes":[{"id":163,"value":"md`\n# Estimating \"electability\" from prediction markets\n## *(or, taking prediction markets too seriously)*\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":0,"value":"md`\nThere is a PredictIt market for [\"Who will win the 2020 Democratic presidential nomination?\"](https://www.predictit.org/markets/detail/3633/Who-will-win-the-2020-Democratic-presidential-nomination) and another one for [\"Who will win the 2020 U.S. presidential election?\"](https://www.predictit.org/markets/detail/3698/Who-will-win-the-2020-US-presidential-election). This is interesting, because there is a straightforward relationship between these events.\n\nFor a Democratic candidate ${tex`X`},\n\n${tex.block`\\Pr(X\\textrm{ wins general}) = \\Pr(X\\textrm{ wins general} \\mid X\\textrm{ wins primary})\\Pr(X\\textrm{ wins primary}).`}\n\n\nThe two markets I mentioned give us (sketchy, borderline-meaningless) estimates for ${tex`\\Pr(X\\textrm{ wins primary})`} and ${tex`\\Pr(X\\textrm{ wins general})`}. So we can compute:\n\n${tex.block`\\Pr(X\\textrm{ wins general} \\mid X\\textrm{ wins primary}) = \\frac{\\Pr(X\\textrm{ wins general})}{\\Pr(X\\textrm{ wins primary})}`}\n\nI think this is what pundits mean when they talk about \"electibility\" – what are ${tex`X`}'s chances against the Republican opponent?\n\nSo let's do the math and see what comes out.\n\n*Disclaimer: This is just for fun. Prices of contracts in prediction markets [may](https://www.nber.org/papers/w12200) or [may not](https://www.nber.org/papers/w10359) correspond to probabilities in a meaningful way.  Small prices are extremely distorted by transaction fees. PredictIt bettors probably have no idea what they're doing.*\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":213,"value":"md`\n## Primary election\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":2,"value":"primaryData = {\n  const req = await fetch(`https://cors-anywhere.herokuapp.com/https://www.predictit.org/api/Public/GetMarketChartData/3633?timespan=${timespan}&maxContracts=5&showHidden=true`, {headers: {'Content-Type': 'application/json'}})\n  return req.json()\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":4,"value":"vegalite({\n  width: 600,\n  height: 400,\n  data: {\n    values: primaryData\n  },\n  mark: \"line\",\n  encoding: {\n    x: {field: \"date\", type: \"temporal\"},\n    y: {field: \"openSharePrice\", type: \"quantitative\"},\n    color: {field: \"contractName\", type: \"nominal\"},\n  }\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":216,"value":"md`\n## General election\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":22,"value":"generalData = {\n  const req = await fetch(`https://cors-anywhere.herokuapp.com/https://www.predictit.org/api/Public/GetMarketChartData/3698?timespan=${timespan}&maxContracts=6&showHidden=true`, {headers: {'Content-Type': 'application/json'}})\n  return req.json()\n}","pinned":false,"mode":"js","data":null,"name":null},{"id":24,"value":"vegalite({\n  width: 600,\n  height: 400,\n  data: {\n    values: generalData\n  },\n  transform: [\n    {filter: \"datum.contractName != 'Trump'\"}\n  ],\n  mark: \"line\",\n  encoding: {\n    x: {field: \"date\", type: \"temporal\"},\n    y: {field: \"openSharePrice\", type: \"quantitative\"},\n    color: {field: \"contractName\", type: \"nominal\"},\n  }\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":221,"value":"md`\n## \"Electability\"\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":223,"value":"md`\nThis is computed as \\`\\`generalData\\`\\` / \\`\\`primaryData\\`\\`, basically.\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":282,"value":"electabilityData = sql`\n  SELECT\n    contractName,\n    date,\n    generalData.openSharePrice / primaryData.openSharePrice AS p\n  FROM\n    ${{generalData}}\n  JOIN\n    ${{primaryData}} USING contractName, date\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":118,"value":"vegalite({\n  width: 600,\n  height: 400,\n  data: {\n    values: electabilityData\n  },\n  layer: [{\n    mark: \"line\",\n    encoding: {\n      x: {field: \"date\", type: \"temporal\"},\n      y: {field: \"p\", type: \"quantitative\"},\n      color: {field: \"contractName\", type: \"nominal\"},\n    },\n  }]\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":191,"value":"md`\nThis is extremely noisy. Let's use a moving average to smooth it out.\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":101,"value":"windowSize = 4","pinned":false,"mode":"js","data":null,"name":null},{"id":270,"value":"md`\n(I think that means a 5-day trailing average?)\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":44,"value":"vegalite({\n  width: 600,\n  height: 400,\n  data: {\n    values: electabilityData\n  },\n  \"transform\": [{\n    \"frame\": [-windowSize, 0],\n    \"window\": [\n      {\n        \"field\": \"p\",\n        \"op\": \"mean\",\n        \"as\": \"p_rolling_mean\"\n      }\n    ]\n  }],\n  layer: [{\n    mark: \"line\",\n    encoding: {\n      x: {field: \"date\", type: \"temporal\"},\n      y: {field: \"p_rolling_mean\", type: \"quantitative\"},\n      color: {field: \"contractName\", type: \"nominal\"},\n    },\n  }]\n})","pinned":false,"mode":"js","data":null,"name":null},{"id":253,"value":"md`\nThere you go!\n\nWhat to make of it? Beats me.\n\n(Just remember that thing I said about small prices being extremely distorted.)\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":245,"value":"html`<div style=\"height: 12em\"/>`","pinned":false,"mode":"js","data":null,"name":null},{"id":228,"value":"md`\n## Parameters\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":204,"value":"md`\nWe grab data for the past 90 days. PredictIt's API only accepts a few options here. You can try \"24h\", \"7d\", etc.\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":107,"value":"timespan = \"90d\"","pinned":false,"mode":"js","data":null,"name":null},{"id":198,"value":"md`\n## Libraries\n`","pinned":false,"mode":"js","data":null,"name":null},{"id":37,"value":"_ = require(\"lodash\")","pinned":false,"mode":"js","data":null,"name":null},{"id":7,"value":"vegalite = require(\"@observablehq/vega-lite@0.2\")","pinned":false,"mode":"js","data":null,"name":null},{"id":280,"value":"import {sql} from \"@joshuahhh/sql\"","pinned":false,"mode":"js","data":null,"name":null}],"resolutions":[],"schedule":null,"last_view_time":null}