<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ekocam</title>
    <description>The latest articles on DEV Community by ekocam (@ekocam).</description>
    <link>https://dev.to/ekocam</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4009663%2Fcdbac57b-3cf5-408c-826b-309cd0dadd79.jpg</url>
      <title>DEV Community: ekocam</title>
      <link>https://dev.to/ekocam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ekocam"/>
    <language>en</language>
    <item>
      <title>Polymarket Gamma API endDate Is Not the Resolution Deadline</title>
      <dc:creator>ekocam</dc:creator>
      <pubDate>Thu, 24 Sep 2026 17:27:28 +0000</pubDate>
      <link>https://dev.to/ekocam/polymarket-gamma-api-enddate-is-not-the-resolution-deadline-238o</link>
      <guid>https://dev.to/ekocam/polymarket-gamma-api-enddate-is-not-the-resolution-deadline-238o</guid>
      <description>&lt;p&gt;&lt;em&gt;Checked against the Polymarket Gamma API on 24 September 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short answer.&lt;/strong&gt; OrcaLayer compared the &lt;code&gt;endDate&lt;/code&gt; field with the written rules on 23 Polymarket markets. Polymarket's documentation describes a market's end date as the point when it becomes eligible for resolution. The field did not behave that way on sports markets: on NFL and soccer matches it was the kickoff, on esports the start plus 6 hours, on tennis the original start plus 7 days. The deadline that governs a market is in its &lt;code&gt;description&lt;/code&gt;, and whether it still trades is in &lt;code&gt;closed&lt;/code&gt; and &lt;code&gt;acceptingOrders&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you build on Polymarket data, this changes what your code should read. A bot that stops trading at &lt;code&gt;endDate&lt;/code&gt;, a dashboard that counts down to it, and a model that treats it as the resolution time are all reading a field that means different things on different market types.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is endDate in the Polymarket Gamma API?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;endDate&lt;/code&gt; is a UTC timestamp on every market in the Polymarket Gamma API. The API does not document what it represents, and it is not the resolution deadline. In OrcaLayer's sample it was kickoff on NFL and soccer matches, start plus 6 hours on esports, and original start plus 7 days on tennis. The binding deadline is in &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Every market returned by &lt;code&gt;https://gamma-api.polymarket.com/markets/{id}&lt;/code&gt; carries &lt;code&gt;endDate&lt;/code&gt; at the top level. If you are new to these endpoints, start with our &lt;a href="https://orcalayer.com/blog/polymarket-rest-api-developers" rel="noopener noreferrer"&gt;Polymarket REST API guide for developers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The response usually tells you what kind of market you are looking at. Sports matches carry &lt;code&gt;gameStartTime&lt;/code&gt;, &lt;code&gt;eventStartTime&lt;/code&gt;, &lt;code&gt;gameId&lt;/code&gt; and &lt;code&gt;sportsMarketType&lt;/code&gt; (for example &lt;code&gt;"moneyline"&lt;/code&gt;). Markets that belong to a group carry &lt;code&gt;groupItemTitle&lt;/code&gt;, which can be a label such as &lt;code&gt;"Match Winner"&lt;/code&gt; or a date such as &lt;code&gt;"September 30"&lt;/code&gt;. Closed markets add &lt;code&gt;closedTime&lt;/code&gt; and &lt;code&gt;umaEndDate&lt;/code&gt;. The rules are in plain English in &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Polymarket's own &lt;a href="https://docs.polymarket.com/concepts/resolution" rel="noopener noreferrer"&gt;resolution documentation&lt;/a&gt; puts it plainly: "Always read the resolution rules before trading." The rest of this article shows what happens when code reads &lt;code&gt;endDate&lt;/code&gt; instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Polymarket endDate by market type
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Market type&lt;/th&gt;
&lt;th&gt;Markets&lt;/th&gt;
&lt;th&gt;What endDate was&lt;/th&gt;
&lt;th&gt;What the rules say&lt;/th&gt;
&lt;th&gt;Closed before or after endDate&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Esports (CS2, LoL, Dota 2)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Scheduled start + exactly 6 hours, 4 of 4&lt;/td&gt;
&lt;td&gt;A postponed match must be rescheduled to start within 14 days, or the market resolves 50-50&lt;/td&gt;
&lt;td&gt;All 4 before, by 19 minutes to 3 h 18 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tennis (ATP, ITF)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Original scheduled start + exactly 7 days, 4 of 4&lt;/td&gt;
&lt;td&gt;A winner must be determined within 14 days, or the market resolves 50-50&lt;/td&gt;
&lt;td&gt;All 4 before, by 6.3 to 6.8 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NFL, college football, soccer matches&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Kickoff, 4 of 4&lt;/td&gt;
&lt;td&gt;No fixed deadline: open until the game is completed&lt;/td&gt;
&lt;td&gt;All 4 after, by 2 h 17 min to 4 h 57 min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MLB match&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Start + 7 days&lt;/td&gt;
&lt;td&gt;No fixed deadline&lt;/td&gt;
&lt;td&gt;Before, by about 7 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sports futures&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;A "postponed after" backstop&lt;/td&gt;
&lt;td&gt;Still open&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deadline and price markets&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Matched the rules in 4 of 7&lt;/td&gt;
&lt;td&gt;"By" a date, or a date in the title&lt;/td&gt;
&lt;td&gt;Mixed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The sample is 23 hand-picked markets covering each type, so read each row as an observed pattern, not a platform-wide rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Esports: endDate is the start plus six hours
&lt;/h2&gt;

&lt;p&gt;All four esports matches had an &lt;code&gt;endDate&lt;/code&gt; exactly six hours after &lt;code&gt;gameStartTime&lt;/code&gt;. The Counter-Strike match between QUAZAR and Misa Esports started at 08:00 UTC on 23 September, carried an &lt;code&gt;endDate&lt;/code&gt; of 14:00 UTC, and closed at 13:41 UTC.&lt;/p&gt;

&lt;p&gt;Six hours is a fair guess for when a best-of-three finishes, but the rules for the same market allow far longer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the match is postponed, it must be rescheduled to a start time on or before October 7, 2026 at 11:59 PM ET (14 calendar days after the originally scheduled start of September 23, 2026 at 4:00 AM ET). If, by that deadline, the most recently announced rescheduled start time is on or before the deadline, this market resolves based on the result of the match as played. Otherwise, this market resolves 50-50, regardless of whether the match is subsequently played.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The 14 days apply to the rescheduled start, not to the result. A match rescheduled to start on 7 October can resolve later still, long after &lt;code&gt;endDate&lt;/code&gt; has passed. You can see current esports markets on &lt;a href="https://orcalayer.com/esports" rel="noopener noreferrer"&gt;OrcaLayer's esports page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tennis: seven days after the original schedule, and it does not move
&lt;/h2&gt;

&lt;p&gt;Every tennis match in the sample had an &lt;code&gt;endDate&lt;/code&gt; exactly seven days after its originally scheduled start. Here the 14-day rule applies to the result:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the match is canceled (not played at all), ends in a tie, or a winner has not been determined by October 6, 2026, 11:59 PM ET (14 days after the scheduled start), this market will resolve to 50-50.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Rescheduling is where it goes wrong. In two ATP matches, &lt;code&gt;gameStartTime&lt;/code&gt; was later than the start printed in the rules. The US Open match between Ben Shelton and Carlos Alcaraz was scheduled for 8 September at 15:30 UTC and started on 9 September at 03:00 UTC. Its &lt;code&gt;endDate&lt;/code&gt; was 15 September at 15:30 UTC: seven days after the original slot, not the new one.&lt;/p&gt;

&lt;p&gt;A countdown built on &lt;code&gt;endDate&lt;/code&gt; for a tennis market counts from a schedule that may no longer exist. Take the start from &lt;code&gt;gameStartTime&lt;/code&gt; and the deadline from the rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  NFL and soccer markets: endDate is kickoff, not the end of the game
&lt;/h2&gt;

&lt;p&gt;On the Broncos vs Chiefs NFL game, the SMU vs Louisville college football game, a La Liga match and a Romanian Liga I match, &lt;code&gt;endDate&lt;/code&gt; was equal to kickoff to the second. All four markets closed after it, between 2 h 17 min and 4 h 57 min later, which is how long the games took.&lt;/p&gt;

&lt;p&gt;The rules on these markets set no deadline at all:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the game is postponed, this market will remain open until the game has been completed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A kickoff is the one moment when a match market is certainly not ready to resolve. Code that compares the current time with &lt;code&gt;endDate&lt;/code&gt; would have marked all four of these markets as finished at kickoff, while the games were being played and the markets were still trading.&lt;/p&gt;

&lt;p&gt;Across the 16 closed markets in the sample, 6 closed after their &lt;code&gt;endDate&lt;/code&gt;. Four were these matches. The other two were a Bitcoin price market that closed 14 minutes after its reference time and a Fed rate market, covered below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sports futures: sometimes the event, sometimes the backstop
&lt;/h2&gt;

&lt;p&gt;League and tournament winner markets followed no single rule. On Shakhtar Donetsk winning the 2026-27 UEFA Champions League, &lt;code&gt;endDate&lt;/code&gt; was 30 May 2027 at 23:59 UTC, while the rules fall back to "Other" only if the season is "postponed after June 19, 2027, 11:59 PM ET", about twenty days later. The New York Yankees World Series market had an &lt;code&gt;endDate&lt;/code&gt; of 31 October 2026, and its rules allow postponement until 31 December 2026. The Boston Celtics NBA Finals market matched its rules to the minute.&lt;/p&gt;

&lt;p&gt;For futures, the field alone does not tell you whether you are looking at an expected event date or the formal backstop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deadline markets: right in 4 of 7, once wrong by 92 days
&lt;/h2&gt;

&lt;p&gt;Markets that ask whether something happens "by" a date came closest to what most people assume &lt;code&gt;endDate&lt;/code&gt; means. Two of them, "Will Anthropic or OpenAI IPO first?" and the Clarity Act market, matched the deadline in the rules, one with a one-minute offset (05:00 instead of 04:59 UTC). The two Bitcoin price markets also matched, though their rules point to "the date specified in the title" or "the month specified in the title", so the deadline lives in the market name.&lt;/p&gt;

&lt;p&gt;Three did not match:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Will the US confirm that aliens exist by September 30?"&lt;/strong&gt; The rules say "by September 30, 2026, 11:59 PM ET", which is 1 October at 03:59 UTC. &lt;code&gt;endDate&lt;/code&gt; was 1 January 2027 at 04:59 UTC, &lt;strong&gt;92 days later&lt;/strong&gt;. That is exactly the &lt;code&gt;endDate&lt;/code&gt; of the parent event the market belongs to, which runs to the end of 2026, so the market appears to carry its event's date rather than its own. Two other fields in the same response point the right way or the wrong way: &lt;code&gt;groupItemTitle&lt;/code&gt; is &lt;code&gt;"September 30"&lt;/code&gt;, which matches the rules, and &lt;code&gt;hasReviewedDates&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;, which shows that a reviewed flag does not guarantee the date matches the rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Fed rate market for the September 2026 meeting.&lt;/strong&gt; &lt;code&gt;endDate&lt;/code&gt; was 16 September at 00:00 UTC, which is 8 PM ET on 15 September, the evening of the first day of a two-day meeting. The market closed 20 hours after its &lt;code&gt;endDate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The market on the next Russian parliamentary election.&lt;/strong&gt; &lt;code&gt;endDate&lt;/code&gt; was 30 September 2026 at 00:00 UTC. The rules fall back to "Other" only if results are not known by 30 September 2027. The market closed on 21 September.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On grouped date markets, check &lt;code&gt;groupItemTitle&lt;/code&gt; before you trust &lt;code&gt;endDate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why endDate changes, and why the Gamma API returns old values
&lt;/h2&gt;

&lt;p&gt;Two markets returned different &lt;code&gt;endDate&lt;/code&gt; values depending on which snapshot the API served.&lt;/p&gt;

&lt;p&gt;For the aliens market, a response with &lt;code&gt;updatedAt&lt;/code&gt; of 21 September showed &lt;code&gt;endDate&lt;/code&gt; as 1 October 2026 at 03:59 UTC, which matches the rules. A fresh response on 24 September showed 1 January 2027. For the IPO market, a response with &lt;code&gt;updatedAt&lt;/code&gt; of 8 August showed 31 December 2027 at 00:00 UTC, 29 hours before the written deadline, and the fresh response showed 1 January 2028 at 04:59 UTC, which matches the rules. Between those snapshots, the IPO market was corrected and the aliens market moved 92 days away from its own rules.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;updatedAt&lt;/code&gt; will not tell you when that happened. It changes often and in bulk: at one point on 24 September the aliens, IPO, Celtics and Bitcoin markets all carried the same &lt;code&gt;updatedAt&lt;/code&gt; to the microsecond. Store your own fetch time instead.&lt;/p&gt;

&lt;p&gt;The older values reached us through cached responses. In three cases in the sample, a plain request to &lt;code&gt;/markets/{id}&lt;/code&gt; returned an older snapshot, and adding an unused query parameter returned the current one. If your code reads &lt;code&gt;endDate&lt;/code&gt; once when a market is listed, it may be holding a value the platform has since changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  endDate vs gameStartTime vs closedTime vs umaEndDate
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;What it held in the sample&lt;/th&gt;
&lt;th&gt;Safe use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;endDate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kickoff, start + 6 h, start + 7 days, or a deadline, depending on market type&lt;/td&gt;
&lt;td&gt;A hint, never a deadline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gameStartTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start of the sports event, updated when a match was rescheduled&lt;/td&gt;
&lt;td&gt;Event start&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;closedTime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;When the market actually closed&lt;/td&gt;
&lt;td&gt;After-the-fact close time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;umaEndDate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Identical to &lt;code&gt;closedTime&lt;/code&gt; on all 16 closed markets&lt;/td&gt;
&lt;td&gt;Same as &lt;code&gt;closedTime&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The written rules, including any deadline in ET&lt;/td&gt;
&lt;td&gt;The real deadline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The formats differ. &lt;code&gt;gameStartTime&lt;/code&gt; and &lt;code&gt;closedTime&lt;/code&gt; come as &lt;code&gt;"2026-09-23 08:00:00+00"&lt;/code&gt;, while &lt;code&gt;endDate&lt;/code&gt; and &lt;code&gt;eventStartTime&lt;/code&gt; use &lt;code&gt;"2026-09-23T08:00:00Z"&lt;/code&gt;. &lt;code&gt;datetime.fromisoformat&lt;/code&gt; rejects both forms before Python 3.11, so normalize first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_ts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Parse any Gamma API timestamp into an aware UTC datetime.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;T&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+00:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to tell if a Polymarket market is still trading
&lt;/h2&gt;

&lt;p&gt;Do not use &lt;code&gt;endDate&lt;/code&gt; for this, and do not use &lt;code&gt;active&lt;/code&gt; either. The closed CS2 market in the sample returned &lt;code&gt;"active": true&lt;/code&gt; together with &lt;code&gt;"closed": true&lt;/code&gt; and &lt;code&gt;"acceptingOrders": false&lt;/code&gt;. Read &lt;code&gt;closed&lt;/code&gt; and &lt;code&gt;acceptingOrders&lt;/code&gt;, and for the resolution state read &lt;code&gt;umaResolutionStatus&lt;/code&gt;, which was &lt;code&gt;"resolved"&lt;/code&gt; on that market.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_tradable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;closed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;acceptingOrders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not bulletproof. In January 2026 a public report on Polymarket's Rust SDK repository showed finished Africa Cup of Nations markets still returning &lt;code&gt;active=true&lt;/code&gt;, &lt;code&gt;closed=false&lt;/code&gt; and &lt;code&gt;acceptingOrders=true&lt;/code&gt;, with &lt;code&gt;endDate&lt;/code&gt; equal to kickoff (&lt;a href="https://github.com/Polymarket/rs-clob-client/issues/199" rel="noopener noreferrer"&gt;issue #199&lt;/a&gt;). On our September sample the two flags were reliable, but treat them as the best signal available, not a guarantee.&lt;/p&gt;

&lt;p&gt;Closing and resolving are separate steps. After a market closes, the outcome is proposed to the UMA Optimistic Oracle, and according to Polymarket's documentation an undisputed proposal resolves after a 2-hour challenge period.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to find the real resolution deadline of a Polymarket market
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read &lt;code&gt;description&lt;/code&gt;.&lt;/strong&gt; That is the contract. Sports matches say "on or before … ET" or "by … ET (14 days after the scheduled start)". US match markets say they "remain open until the game has been completed". Futures say "postponed after …".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the title and &lt;code&gt;groupItemTitle&lt;/code&gt;&lt;/strong&gt; on price and date markets. "On September 17" or a &lt;code&gt;groupItemTitle&lt;/code&gt; of &lt;code&gt;"September 30"&lt;/code&gt; is the deadline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take the start from &lt;code&gt;gameStartTime&lt;/code&gt;&lt;/strong&gt;, not from &lt;code&gt;endDate&lt;/code&gt; minus a guess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;closedTime&lt;/code&gt; or &lt;code&gt;umaEndDate&lt;/code&gt;&lt;/strong&gt; to know when a market actually closed. Both are empty until it does.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-fetch before you act.&lt;/strong&gt; Add a cache-busting parameter and store your fetch time next to every value you keep.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Python: parse the resolution deadline from a market description
&lt;/h3&gt;

&lt;p&gt;This parser found the deadline on every market in the sample whose rules state a full date and a clock time in Eastern Time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;zoneinfo&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ZoneInfo&lt;/span&gt;

&lt;span class="n"&gt;MONTHS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;January|February|March|April|May|June|July|August|September|October|November|December&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;DEADLINE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b(?:on or before|by|after) ((?:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MONTHS&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) \d{{1,2}}, \d{{4}}),? (?:at )?(\d{{1,2}}:\d{{2}} ?[AP]M) E[DS]?T\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rule_deadlines_utc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return every ET deadline stated in a Polymarket market description, in UTC.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clock&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;DEADLINE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strptime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%B %d, %Y %I:%M%p&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tzinfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;ZoneInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;America/New_York&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;astimezone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ZoneInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UTC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;America/New_York&lt;/code&gt; rather than a fixed offset: ET is UTC-4 until 1 November 2026 and UTC-5 after, so a hard-coded offset will be an hour wrong for several months of every year. The parser returns nothing on US match markets, because their rules contain no deadline, and nothing on price markets, where the date is in the title. It does not handle "noon", "p.m." or abbreviated months, and it does not tell a start deadline from a result deadline, so read the sentence around each match.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this sample does not tell you
&lt;/h2&gt;

&lt;p&gt;Twenty-three markets show that &lt;code&gt;endDate&lt;/code&gt; means different things on different market types. They do not show how often each case occurs across Polymarket, or that every esports market uses exactly six hours. Valorant is not in the sample, and there is a single MLB game.&lt;/p&gt;

&lt;p&gt;We did not establish why the aliens market moved, or whether that change was deliberate. All markets here come from the international Polymarket Gamma API. Polymarket US is a separate exchange with its own contract rules, and nothing in this article applies to it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data: 23 markets fetched one by one from &lt;code&gt;gamma-api.polymarket.com/markets/{id}&lt;/code&gt; on 24 September 2026. The full sample is downloadable as &lt;a href="https://orcalayer.com/data/polymarket-enddate-sample-2026-09-24.json" rel="noopener noreferrer"&gt;JSON&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://orcalayer.com/blog/polymarket-api-enddate" rel="noopener noreferrer"&gt;orcalayer.com&lt;/a&gt;. OrcaLayer is an independent Polymarket analytics provider, not affiliated with Polymarket.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>python</category>
      <category>webdev</category>
      <category>crypto</category>
    </item>
    <item>
      <title>Giving Claude live Polymarket data with an MCP server</title>
      <dc:creator>ekocam</dc:creator>
      <pubDate>Sat, 25 Jul 2026 19:05:56 +0000</pubDate>
      <link>https://dev.to/ekocam/giving-claude-live-polymarket-data-with-an-mcp-server-5e5e</link>
      <guid>https://dev.to/ekocam/giving-claude-live-polymarket-data-with-an-mcp-server-5e5e</guid>
      <description>&lt;p&gt;Large language models are good at reasoning about numbers and bad at knowing them. Ask Claude which Polymarket wallets are actually profitable and you will get a confident answer assembled from training data that was already stale when the model shipped.&lt;/p&gt;

&lt;p&gt;The Model Context Protocol fixes that by letting the model call your data directly. This post walks through a working example: a small MCP server that puts live Polymarket whale analytics into Claude Desktop, Cursor, or any other MCP client.&lt;/p&gt;

&lt;p&gt;The server is open source and MIT licensed, so you can read the whole thing: &lt;a href="https://github.com/orcalayer/orcalayer-mcp" rel="noopener noreferrer"&gt;github.com/orcalayer/orcalayer-mcp&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP actually does
&lt;/h2&gt;

&lt;p&gt;An MCP server exposes three kinds of capability to a model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt; the model can call, with typed arguments and structured results&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts&lt;/strong&gt; the user can pick from a menu, which orchestrate several tools at once&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources&lt;/strong&gt; the model can read directly as context, without spending a tool call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That third one matters more than people expect. A methodology document loaded as a resource means the model knows how your numbers are defined before it starts interpreting them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;The server is a stdio wrapper over the Python SDK, so there is nothing to deploy. Add it to your &lt;code&gt;claude_desktop_config.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"orcalayer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uvx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"orcalayer-mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows the file lives at &lt;code&gt;%APPDATA%\Claude\claude_desktop_config.json&lt;/code&gt;, on macOS at &lt;code&gt;~/Library/Application Support/Claude/claude_desktop_config.json&lt;/code&gt;. Restart the app after editing.&lt;/p&gt;

&lt;p&gt;That is the whole install. &lt;code&gt;uvx&lt;/code&gt; fetches and runs the package on demand, so there is no virtualenv to manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tools
&lt;/h2&gt;

&lt;p&gt;Five tools, four of which need no key at all:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;leaderboard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rank smart-money whales by P&amp;amp;L, win rate or volume&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wallet_overview&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A wallet's profile and performance summary&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;wallet_positions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A wallet's largest open positions&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;markets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search markets where smart whales are clustering&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;whale_alerts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Live feed of recent smart-whale trades&lt;/td&gt;
&lt;td&gt;Premium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For the Premium tool, pass the key through the environment rather than hardcoding it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"orcalayer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uvx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"orcalayer-mcp"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ORCALAYER_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your_key_here"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prompts do the orchestration
&lt;/h2&gt;

&lt;p&gt;The part worth stealing for your own server is the prompt layer. Rather than making the user chain tool calls by hand, ship prompts that encode the workflow you actually want:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prompt&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;analyze_wallet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full wallet analysis: smart money or farmer?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find_divergence&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Markets where smart money disagrees with the current price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hedge_check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Whether a wallet's profit was real alpha or a hedge structure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;territorial_markets_review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ukraine territorial markets with an ISW frontline overlay&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;hedge_check&lt;/code&gt; is the one I would point at if you are building something similar. A wallet that holds both sides of the same market can post a spectacular profit number that means nothing directionally. A naive integration reports that as alpha. Encoding the check as a prompt means the model runs it every time instead of only when the user thinks to ask.&lt;/p&gt;

&lt;p&gt;That is the general lesson: your domain knowledge belongs in the prompts, not in the user's head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources for definitions
&lt;/h2&gt;

&lt;p&gt;Three resources load as plain context:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;orcalayer://methodology&lt;/code&gt; covers how smart money is separated from farmers, hedgers and market makers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;orcalayer://glossary&lt;/code&gt; is a prediction-markets glossary&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;orcalayer://api-reference&lt;/code&gt; is the REST API reference, including auth and rate limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your data has any non-obvious definitions, and analytics data always does, put them in a resource. It costs nothing at query time and stops the model from inventing its own interpretation of your columns.&lt;/p&gt;

&lt;h2&gt;
  
  
  One design note on honest nulls
&lt;/h2&gt;

&lt;p&gt;The Premium stream now tags every event with a &lt;code&gt;settlement_type&lt;/code&gt; of &lt;code&gt;MINT&lt;/code&gt;, &lt;code&gt;MERGE&lt;/code&gt;, &lt;code&gt;COMPLEMENTARY&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;, describing how a match settled rather than what the trader intended.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;null&lt;/code&gt; is deliberate. It means the pipeline could not determine the settlement type, not that the trade was something else. It is tempting to collapse an unknown into a default, and it is almost always the wrong call: a model reading your data cannot tell a real zero from a missing one, so it will treat your guess as fact. Return the honest null and let the caller decide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Which Polymarket wallets have the best win rate right now,
and are any of them just farming near-settled markets?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask that in Claude Desktop with the server connected and it will call &lt;code&gt;leaderboard&lt;/code&gt;, then run the farmer check from the methodology resource, and tell you which of the top names are not what they look like.&lt;/p&gt;

&lt;p&gt;The server is MIT licensed at &lt;a href="https://github.com/orcalayer/orcalayer-mcp" rel="noopener noreferrer"&gt;github.com/orcalayer/orcalayer-mcp&lt;/a&gt;, and the underlying REST API is documented at &lt;a href="https://orcalayer.com/docs/api" rel="noopener noreferrer"&gt;orcalayer.com/docs/api&lt;/a&gt;. Data is for informational purposes only and is not financial advice.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>ai</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A REST API for Polymarket Whale Data: A Developer Guide</title>
      <dc:creator>ekocam</dc:creator>
      <pubDate>Sun, 19 Jul 2026 12:34:32 +0000</pubDate>
      <link>https://dev.to/ekocam/a-rest-api-for-polymarket-whale-data-a-developer-guide-3obi</link>
      <guid>https://dev.to/ekocam/a-rest-api-for-polymarket-whale-data-a-developer-guide-3obi</guid>
      <description>&lt;p&gt;If you want Polymarket whale data in your own code, a dashboard, a trading model, or an AI agent, you need an API, not a website. Here is what the OrcaLayer REST API exposes and how to start.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do developers access a Polymarket REST API?
&lt;/h2&gt;

&lt;p&gt;Through the OrcaLayer API. It is a plain REST API over the same index the site runs on: over 1.2 billion trades read directly from the Polygon chain, farmer-filtered. Full access is on the Premium tier (19.99 dollars a month) at 600 requests per minute. Some read endpoints, wallet profiles, market search and the leaderboard, need no key at all, so you can prototype before paying anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quickstart
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign up and upgrade to Premium.&lt;/li&gt;
&lt;li&gt;Go to Settings, API Keys, and generate a key. It uses the &lt;code&gt;sk_orca_&lt;/code&gt; prefix and is shown once.&lt;/li&gt;
&lt;li&gt;Call the API:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer sk_orca_XXXXXX"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://orcalayer.com/api/public/v1/whales/leaderboard?limit=10"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication works either as a Bearer token in the &lt;code&gt;Authorization&lt;/code&gt; header or as an &lt;code&gt;x-api-key&lt;/code&gt; header. Premium endpoints under &lt;code&gt;/api/v2&lt;/code&gt; expect &lt;code&gt;x-api-key&lt;/code&gt; specifically. A missing or invalid key returns 401, a non-Premium plan on a Premium endpoint returns 403, and passing the rate limit returns 429 with a &lt;code&gt;Retry-After&lt;/code&gt; header.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the API exposes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Whale leaderboards, farmer-filtered, with win rate, profit and profit factor&lt;/li&gt;
&lt;li&gt;Individual wallet profiles and full trade histories&lt;/li&gt;
&lt;li&gt;Recent whale trades and whale position flips&lt;/li&gt;
&lt;li&gt;Per-market whale activity&lt;/li&gt;
&lt;li&gt;Whale alerts data, the same stream that powers the alerts feed&lt;/li&gt;
&lt;li&gt;ISW Ukraine territory data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The numbers match what the site shows, because it is the same index and the same published methodology, including the farmer filter and NegRisk correction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clients and tooling
&lt;/h2&gt;

&lt;p&gt;You do not have to start from raw REST:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python SDK: &lt;code&gt;pip install orcalayer&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;MCP server for AI agents: &lt;code&gt;uvx orcalayer-mcp&lt;/code&gt;, so Claude or any MCP-capable agent can query whale data directly&lt;/li&gt;
&lt;li&gt;Claude Code agent skill for terminal workflows&lt;/li&gt;
&lt;li&gt;A whale watchlist monitor and a backtest cookbook as ready-made starting points&lt;/li&gt;
&lt;li&gt;OpenAPI spec at &lt;code&gt;https://orcalayer.com/api/openapi.json&lt;/code&gt; for generating typed clients in any language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of them are linked from the API docs at &lt;a href="https://orcalayer.com/docs/api" rel="noopener noreferrer"&gt;orcalayer.com/docs/api&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to build on it
&lt;/h2&gt;

&lt;p&gt;At 600 requests per minute you can poll a watchlist of wallets every few seconds and drive your own alerting, mirror the leaderboard into your own database, backtest wallet-following strategies against real resolved markets, or feed an AI agent live whale context through MCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is there a REST API for Polymarket whale analytics?&lt;/strong&gt;&lt;br&gt;
Yes. The OrcaLayer REST API serves whale leaderboards, wallet profiles and trades, whale alerts, market whale activity and ISW territory data over plain REST. Full access is on the Premium tier at 600 requests per minute; some read endpoints such as wallet profiles, market search and the leaderboard need no key at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I authenticate?&lt;/strong&gt;&lt;br&gt;
Generate a key in Settings, API Keys, then send it as a Bearer token in the &lt;code&gt;Authorization&lt;/code&gt; header or as an &lt;code&gt;x-api-key&lt;/code&gt; header. Keys use the &lt;code&gt;sk_orca_&lt;/code&gt; prefix and are shown only once at creation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a Python SDK?&lt;/strong&gt;&lt;br&gt;
Yes, &lt;code&gt;pip install orcalayer&lt;/code&gt;. There is also an MCP server for AI agents (&lt;code&gt;uvx orcalayer-mcp&lt;/code&gt;), a Claude Code agent skill, a whale watchlist monitor and a backtest cookbook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are the rate limits?&lt;/strong&gt;&lt;br&gt;
Premium runs at 600 requests per minute. Exceeding the limit returns HTTP 429 with a &lt;code&gt;Retry-After&lt;/code&gt; header.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://orcalayer.com/blog/polymarket-rest-api-developers" rel="noopener noreferrer"&gt;orcalayer.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>python</category>
      <category>crypto</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Most "top traders" on Polymarket are farming win rate. I backtested it.</title>
      <dc:creator>ekocam</dc:creator>
      <pubDate>Tue, 30 Jun 2026 13:42:21 +0000</pubDate>
      <link>https://dev.to/ekocam/most-top-traders-on-polymarket-are-farming-win-rate-i-backtested-it-1b8j</link>
      <guid>https://dev.to/ekocam/most-top-traders-on-polymarket-are-farming-win-rate-i-backtested-it-1b8j</guid>
      <description>&lt;p&gt;If you've looked at a "top traders" leaderboard on Polymarket and thought about copy-trading the top wallets, I have some bad news: a lot of those flawless 95%+ win-rate records are farmed, not earned. I pulled the on-chain data and backtested it, and the raw leaderboard turns out to be a pretty bad signal to copy. Here's the breakdown, with reproducible notebooks at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  The farming trick
&lt;/h2&gt;

&lt;p&gt;It's simple. You only ever buy outcomes that are already basically decided, priced around 95-99c.&lt;/p&gt;

&lt;p&gt;Think of a market like "Will X happen?" sitting at 99c the day before it resolves. You put up 99c to make 1c. You win almost every time. Do this across enough near-decided markets and you end up with a 95%+ win rate and a clean, green, very impressive-looking record.&lt;/p&gt;

&lt;p&gt;But the edge is basically zero, and more importantly for a copy-trader: it's &lt;strong&gt;unfollowable&lt;/strong&gt;. You can't get filled at 99c at any real size, and you're risking 99 to make 1. The win rate is real in the data and useless in practice.&lt;/p&gt;

&lt;p&gt;Raw P&amp;amp;L and win-rate leaderboards reward exactly this behavior. So the wallets that look best are often the ones you least want to copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measuring it properly
&lt;/h2&gt;

&lt;p&gt;A few things matter when you compute this from raw on-chain data, or the numbers come out wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NegRisk consolidation.&lt;/strong&gt; Polymarket's multi-outcome markets settle through a NegRisk adapter. If you don't consolidate the legs, you double-count and P&amp;amp;L inflates. (The public data API's &lt;code&gt;cashPnl&lt;/code&gt; has this problem - I don't use it as cost-basis truth.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FIFO cost basis, per wallet per market.&lt;/strong&gt; Matching sells against buys in order, not averaging blindly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Win rate per resolved market, not per trade.&lt;/strong&gt; A wallet that makes 40 trades in one market that resolves in its favor didn't win 40 times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that in place, I split the leaderboard into two cohorts to copy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Raw top 8&lt;/strong&gt; by cumulative P&amp;amp;L (farmers included).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtered top 8&lt;/strong&gt; - same board with farmers and hedgers removed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then I backtested copying each one as an equal-weight equity curve across resolved markets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgpm7b2dlxux0s0fr8s8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgpm7b2dlxux0s0fr8s8j.png" alt=" " width="799" height="381"&gt;&lt;/a&gt;&lt;br&gt;
Honest read: for most of the window the two curves basically track each other. The filtered cohort only pulls ahead near the end, and not by a huge margin (~33M vs ~27M in this run). I'm not going to oversell "filtering wins on P&amp;amp;L" - that gap is small and probably sample-dependent. Both curves are lumpy too; a few big resolutions carry most of the move, which is kind of the point - these are near-decided markets resolving.&lt;/p&gt;

&lt;p&gt;What I'd actually stand behind: &lt;strong&gt;the raw leaderboard is built on those unfollowable ~99c fills, so copying it is a bad idea regardless of the cumulative number.&lt;/strong&gt; The win rate on those boards is mostly noise. If you're building a copy-trading strategy, "who has the highest win rate" is close to the worst possible wallet-selection signal.&lt;/p&gt;

&lt;p&gt;Small sample (8 per cohort), so take the exact numbers with a grain of salt. The interesting part isn't the dollar figure, it's the mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce it
&lt;/h2&gt;

&lt;p&gt;The notebooks are open source (MIT) so you can re-run this on a different set of wallets or a different time window and check whether the filtered edge holds out of sample - genuinely curious if it does:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/orcalayer/polymarket-backtest-cookbook" rel="noopener noreferrer"&gt;github.com/orcalayer/polymarket-backtest-cookbook&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three notebooks: follow one wallet's resolved bets as an equity curve, follow a smart-money cohort by category, and the raw-vs-filtered comparison above.&lt;/p&gt;

&lt;p&gt;The data comes from OrcaLayer, which is a data layer I build over Polymarket (every trade read straight from the Polygon chain, then classified - farmer filtering, NegRisk-correct win rates, FIFO P&amp;amp;L). The leaderboard endpoint is keyless so the notebooks run free; per-wallet backtests use an API key.&lt;/p&gt;

&lt;p&gt;If you go deeper into prediction-market data, I'd love feedback on the methodology - especially the NegRisk and FIFO handling, which is where most of the subtlety lives.&lt;/p&gt;

</description>
      <category>python</category>
      <category>datascience</category>
      <category>api</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
