Skip to content
Open
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
b428969
add columns to polymarket models
hildobby Dec 9, 2025
836fb35
fix
hildobby Dec 9, 2025
6dbe439
add polymarket link slug
hildobby Dec 9, 2025
6621cfa
fixes
hildobby Dec 9, 2025
60c35bb
create open_positions spell
hildobby Dec 9, 2025
8c74bca
create protocol_tvl spell
hildobby Dec 10, 2025
f25cda4
create users balance changes spell
hildobby Dec 10, 2025
0f9c1ab
fix
hildobby Dec 10, 2025
fe719c6
fix
hildobby Dec 10, 2025
151497e
Merge branch 'main' into polymarket_table_fixes
hildobby Dec 10, 2025
9113b9f
fix
hildobby Dec 10, 2025
01ef68c
fix
hildobby Dec 10, 2025
f898a34
fix
hildobby Dec 10, 2025
e9e44e7
fix
hildobby Dec 10, 2025
11daa3f
fi
hildobby Dec 10, 2025
efa32af
add 1 month filter to user balance changes for CI tests
hildobby Dec 10, 2025
7b143e8
fix
hildobby Dec 10, 2025
85d8be5
fix
hildobby Dec 10, 2025
259287a
fixes
hildobby Dec 10, 2025
351bda9
remove 1 month filter used for tests
hildobby Dec 10, 2025
b025811
more fixes
hildobby Dec 11, 2025
ea14ab4
fixes suggested by cursor - good bot
hildobby Dec 11, 2025
1bcf5af
Merge branch 'main' into polymarket_table_fixes
hildobby Dec 11, 2025
3be098b
fixes
hildobby Dec 12, 2025
c2ce5a4
fix
hildobby Dec 12, 2025
8295e84
fixes
hildobby Dec 12, 2025
c269a9d
Merge branch 'main' into polymarket_table_fixes
hildobby Dec 12, 2025
0c92d76
fix users spell and add 1 month filter to user balances for CI tests
hildobby Dec 12, 2025
b40416f
less restrictive join for open positiosn
hildobby Dec 12, 2025
3fe69d9
fix protocol tvl
hildobby Dec 12, 2025
c6be77f
fix
hildobby Dec 13, 2025
1f9bda4
Merge branch 'main' into polymarket_table_fixes
hildobby Dec 13, 2025
23f755b
ci tests passed, remove 1 month filter
hildobby Dec 14, 2025
35f1eeb
account for 50/50s and filter properly
hildobby Dec 16, 2025
2783ec6
Merge branch 'main' into polymarket_table_fixes
hildobby Dec 16, 2025
6b32759
add price_modifier to market_details, optimise positions and add usd …
hildobby Dec 16, 2025
4185473
Merge branch 'polymarket_table_fixes' of https://github.com/hildobby/…
hildobby Dec 16, 2025
9592bca
optimise balance_changes
hildobby Dec 16, 2025
3942db8
optimise
hildobby Dec 16, 2025
b2127f5
Merge branch 'main' into polymarket_table_fixes
hildobby Dec 29, 2025
e69eb26
fix
hildobby Dec 29, 2025
c45d3aa
fix
hildobby Dec 29, 2025
d775b77
Merge branch 'main' into polymarket_table_fixes
hildobby Jan 9, 2026
b633a4c
Merge branch 'main' into polymarket_table_fixes
hildobby Jan 29, 2026
b35c67b
Merge branch 'main' into polymarket_table_fixes
hildobby Feb 11, 2026
eaa70cd
fix
hildobby Feb 11, 2026
2d09578
fix2test
hildobby Feb 12, 2026
e7a8a76
Merge branch 'main' into polymarket_table_fixes
hildobby Feb 18, 2026
7324138
Merge branch 'main' into polymarket_table_fixes
hildobby Feb 20, 2026
86f5b7e
Merge branch 'main' into polymarket_table_fixes
hildobby Feb 27, 2026
b3318b8
optimise attempt #1
hildobby Feb 27, 2026
b9d73fa
fix
hildobby Feb 27, 2026
1da6695
fix
hildobby Feb 27, 2026
ab14d22
fixes
hildobby Feb 27, 2026
3c2b8b6
fix balance changes
hildobby Mar 1, 2026
47f0c0a
bunch of fixes
hildobby Mar 1, 2026
35d467f
Merge branch 'main' into polymarket_table_fixes
hildobby Mar 1, 2026
0d65573
rework user balances
hildobby Mar 1, 2026
2a36011
Merge branch 'main' into polymarket_table_fixes
hildobby Mar 1, 2026
3190f2a
add incremental run code for users_balance_changes
hildobby Mar 1, 2026
ba03028
optimise positions spell incremental runs
hildobby Mar 1, 2026
65e2258
Merge branch 'main' into polymarket_table_fixes
hildobby Mar 1, 2026
715b398
fix
hildobby Mar 1, 2026
4e7fa7f
market_prices_daily fix attempt
hildobby Mar 2, 2026
98f2b04
optimise old spells a fuck ton
hildobby Mar 2, 2026
990ae43
fix
hildobby Mar 2, 2026
039e4b9
Merge branch 'main' into polymarket_table_fixes
hildobby Mar 2, 2026
4c6e5b7
fix
hildobby Mar 2, 2026
464a8f5
fix
hildobby Mar 2, 2026
1667e5b
fixes
hildobby Mar 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ models:
description: "Concrete outcome being bet on (e.g., Trump wins 2024 election?)"
- name: polymarket_link
description: "Link to the Polymarket site (may be broken for archived markets)"
- name: polymarket_link_slug
description: "Slug for the Polymarket link"
- name: token_outcome
description: "YES or NO token outcome"
- name: neg_risk
Expand All @@ -182,6 +184,10 @@ models:
description: "Unique key of the event or market"
- name: token_outcome_name
description: "Combination of token outcome and question"
- name: maker_asset_id
description: "Maker asset ID"
- name: taker_asset_id
description: "Taker asset ID"

- name: polymarket_polygon_users_capital_actions
meta:
Expand Down Expand Up @@ -301,6 +307,8 @@ models:
description: "Negative risk market name from on-chain data"
- name: polymarket_link
description: "Link to the Polymarket event page"
- name: polymarket_link_slug
description: "Slug for the Polymarket link"
- name: market_start_time
description: "Start time of the market"
- name: market_end_time
Expand All @@ -309,7 +317,13 @@ models:
description: "Outcome of the market"
- name: resolved_on_timestamp
description: "Timestamp when the market was resolved"

- name: market_start_time_parsed
description: "Start time of the market parsed as a timestamp"
- name: market_end_time_parsed
description: "End time of the market parsed as a timestamp"
- name: final_price
description: "Final price of the market"

- name: polymarket_polygon_positions_raw
meta:
blockchain: polygon
Expand Down Expand Up @@ -486,4 +500,134 @@ models:
- name: tx_hash
description: "Transaction hash of the wallet creation"

- name: polymarket_polygon_open_positions
meta:
blockchain: polygon
sector: prediction_markets
project: polymarket
contributors: hildobby
config:
tags: ['polygon','prediction_markets','polymarket','positions']
description: "Polymarket: open positions in markets"
data_tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- address
- token_id
columns:
- name: address
description: "The address holding the position"
- name: unique_key
description: "Unique identifier for the market"
- name: token_id
description: "Token ID of the position"
- name: token_outcome
description: "Outcome represented by the token"
- name: token_outcome_name
description: "Name of the outcome represented by the token"
- name: balance
description: "Balance of the position"
- name: question_id
description: "Question ID for the market"
- name: market_question
description: "Question of the market"
- name: market_description
description: "Description of the market"
- name: event_market_name
description: "Name of the event market"
- name: event_market_description
description: "Description of the event market"
- name: active
description: "Whether the market is active"
- name: closed
description: "Whether the market is closed"
- name: accepting_orders
description: "Whether the market is accepting orders"
- name: latest_price
description: "The price of the outcome token at the end of the day"
- name: open_interest
description: "The open interest of the position"
- name: market_outcome
description: "The outcome of the market"
- name: resolved_on_timestamp
description: "Timestamp when the market was resolved"
- name: polymarket_link
description: "Link to the Polymarket event page"
- name: polymarket_link_slug
description: "Slug for the Polymarket link"
- name: market_start_time
description: "Start time of the market"
- name: market_start_time_parsed
description: "Start time of the market parsed as a timestamp"
- name: market_end_time
description: "End time of the market"
- name: market_end_time_parsed
description: "End time of the market parsed as a timestamp"
- name: polymarket_polygon_protocol_tvl
meta:
blockchain: polygon
sector: prediction_markets
project: polymarket
contributors: hildobby
config:
tags: ['polygon','prediction_markets','polymarket','tvl']
description: "Polymarket: protocol TVL"
data_tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- hour
columns:
- name: hour
description: "The hour for which the TVL is valid"
- name: tvl
description: "The TVL of the protocol"
- name: net_flow
description: "The net flow of the protocol"

- name: polymarket_polygon_users_balance_changes
meta:
blockchain: polygon
sector: prediction_markets
project: polymarket
contributors: hildobby
config:
tags: ['polygon','prediction_markets','polymarket','users']
description: "Polymarket: user balance changes"
data_tests:
- dbt_utils.unique_combination_of_columns:
combination_of_columns:
- block_number
- tx_index
- evt_index
- direction
columns:
- name: block_time
description: "The time of the balance change"
- name: block_date
description: "The date of the balance change"
- name: block_month
description: "The month of the balance change"
- name: block_number
description: "The block number of the balance change"
- name: tx_hash
description: "The transaction hash of the balance change"
- name: tx_from
description: "The address that initiated the transaction"
- name: tx_to
description: "The address that received the transaction"
- name: tx_index
description: "The transaction index within the block"
- name: evt_index
description: "The event index of the balance change"
- name: direction
description: "The direction of the balance change"
- name: polymarket_wallet
description: "The Polymarket wallet address"
- name: amount
description: "The amount of the balance change"
- name: "from"
description: "The address from which the balance change occurred"
- name: to
description: "The address to which the balance change occurred"
- name: unique_key
description: "The unique key of the balance change"
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,14 @@ SELECT
WHEN lower(neg_risk) = 'false' THEN get_href('https://polymarket.com/event/' || market_slug, market_slug)
WHEN lower(neg_risk) = 'true' THEN get_href('https://polymarket.com/event/' || replace(replace(replace(lower(neg_risk_market_name), ' ', '-'), '$', ''), '''',''), neg_risk_market_name)
END AS polymarket_link,
CASE
WHEN lower(neg_risk) = 'false' THEN market_slug
WHEN lower(neg_risk) = 'true' THEN replace(replace(replace(lower(neg_risk_market_name), ' ', '-'), '$', ''), '''','')
END AS polymarket_link_slug,
accepting_order_timestamp as market_start_time,
date_parse(SUBSTRING(accepting_order_timestamp FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s') as market_start_time_parsed,
end_date_iso as market_end_time,
date_parse(SUBSTRING(end_date_iso FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s') as market_end_time_parsed,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard timestamp parsing to prevent hard failures on malformed API timestamps.

date_parse(...) will fail the model on unexpected formats. Wrap parsing with try(...) so bad rows become nulls instead of aborting the run.

Proposed resilient parsing
-  date_parse(SUBSTRING(accepting_order_timestamp FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s') as market_start_time_parsed,
+  try(date_parse(SUBSTRING(accepting_order_timestamp FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s')) as market_start_time_parsed,
...
-  date_parse(SUBSTRING(end_date_iso FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s') as market_end_time_parsed,
+  try(date_parse(SUBSTRING(end_date_iso FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s')) as market_end_time_parsed,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
date_parse(SUBSTRING(accepting_order_timestamp FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s') as market_start_time_parsed,
end_date_iso as market_end_time,
date_parse(SUBSTRING(end_date_iso FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s') as market_end_time_parsed,
try(date_parse(SUBSTRING(accepting_order_timestamp FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s')) as market_start_time_parsed,
end_date_iso as market_end_time,
try(date_parse(SUBSTRING(end_date_iso FROM 1 FOR 19), '%Y-%m-%dT%H:%i:%s')) as market_end_time_parsed,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@dbt_subprojects/daily_spellbook/models/_projects/polymarket/polygon/polymarket_polygon_market_details.sql`
around lines 101 - 103, The date_parse calls for accepting_order_timestamp and
end_date_iso (which produce market_start_time_parsed and market_end_time_parsed)
can fail on malformed API timestamps; wrap each date_parse(...) expression in
try(...) so parsing errors return null instead of failing the model — i.e.,
replace the raw date_parse(SUBSTRING(...), '%Y-%m-%dT%H:%i:%s') usages for
accepting_order_timestamp and end_date_iso with try(date_parse(SUBSTRING(...),
'%Y-%m-%dT%H:%i:%s')) to make parsing resilient.

game_start_time,
seconds_delay,
fpmm,
Expand All @@ -113,6 +119,10 @@ left join {{ ref('polymarket_polygon_market_outcomes') }} pm

--these nulls get introduced by the polymarket api responses

SELECT * FROM naming_things
SELECT *,
CASE WHEN outcome = '50/50' THEN 0.5
WHEN LOWER(token_outcome) = outcome THEN 1
WHEN outcome != 'unresolved' THEN 0 END AS final_price
Comment on lines +123 to +125
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Normalize both sides of the outcome comparison for final_price.

LOWER(token_outcome) = outcome is still case-sensitive on outcome; mixed-case outcome values can be incorrectly priced as 0.

Proposed comparison fix
-  WHEN LOWER(token_outcome) = outcome THEN 1
+  WHEN LOWER(token_outcome) = LOWER(outcome) THEN 1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CASE WHEN outcome = '50/50' THEN 0.5
WHEN LOWER(token_outcome) = outcome THEN 1
WHEN outcome != 'unresolved' THEN 0 END AS final_price
CASE WHEN outcome = '50/50' THEN 0.5
WHEN LOWER(token_outcome) = LOWER(outcome) THEN 1
WHEN outcome != 'unresolved' THEN 0 END AS final_price
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@dbt_subprojects/daily_spellbook/models/_projects/polymarket/polygon/polymarket_polygon_market_details.sql`
around lines 123 - 125, The final_price CASE uses LOWER(token_outcome) = outcome
which still compares against a case-sensitive outcome; update the comparison to
normalize both sides (e.g., compare LOWER(token_outcome) to LOWER(outcome)) so
mixed-case outcome values are matched correctly; update the conditional in the
CASE that sets final_price (referencing token_outcome and outcome) accordingly.

FROM naming_things
where token_id is not null
and condition_id is not null
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,23 @@ WITH changed_prices AS (
FROM {{ ref('polymarket_polygon_market_trades_raw') }}
) ranked
WHERE rn = 1
),

--sequences are limited to 10k so just pulling this in from the transactions table, no other relationship
days AS (
SELECT *
FROM UNNEST(
SEQUENCE(CAST('2015-01-01' AS date), DATE(DATE_TRUNC('day', NOW())), INTERVAL '1' day)
) AS foo(day)
),
)

forward_fill AS (
SELECT
CAST(d.day AS timestamp) AS day,
, forward_fill AS (
SELECT d.timestamp AS day,
lp.condition_id,
lp.token_id,
lp.price
FROM days d
FROM {{ ref('utils_days') }} d
LEFT JOIN changed_prices lp
ON d.day >= lp.day
AND (lp.next_update_day IS NULL OR d.day < lp.next_update_day)
),
ON d.timestamp >= lp.day
AND (lp.next_update_day IS NULL OR d.timestamp < lp.next_update_day)
WHERE d.timestamp >= CAST('2015-01-01' AS date)
AND d.timestamp <= DATE(DATE_TRUNC('day', NOW()))
)

-- Join with market details to get market end time and token outcome information
price_correction AS (
, price_correction AS (
SELECT
ff.day,
ff.condition_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ select
md.event_market_name,
md.question,
md.polymarket_link,
md.polymarket_link_slug,
md.token_outcome,
md.neg_risk,
t.asset_id,
Expand All @@ -31,6 +32,8 @@ select
t.maker,
t.taker,
md.unique_key,
md.token_outcome_name
md.token_outcome_name,
t.maker_asset_id,
t.taker_asset_id
from {{ ref('polymarket_polygon_market_trades_raw') }} t
left join {{ ref('polymarket_polygon_market_details') }} md on t.asset_id = md.token_id
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ select
t.takerAmountFilled as taker_amount_raw,
t.contract_address,
t.evt_index,
t.evt_tx_hash as tx_hash
t.evt_tx_hash as tx_hash,
t.makerAssetId AS maker_asset_id,
t.takerAssetID AS taker_asset_id
from {{ source('polymarket_polygon', 'CTFExchange_evt_OrderFilled') }} t
inner join {{ ref('polymarket_polygon_base_ctf_tokens') }} ctf on coalesce(nullif(t.makerAssetId, 0), nullif(t.takerAssetID, 0)) = ctf.token0
{% if is_incremental() %}
Expand Down Expand Up @@ -135,7 +137,9 @@ select
t.takerAmountFilled as taker_amount_raw,
t.contract_address,
t.evt_index,
t.evt_tx_hash as tx_hash
t.evt_tx_hash as tx_hash,
t.makerAssetId AS maker_asset_id,
t.takerAssetID AS taker_asset_id
from {{ source('polymarket_polygon', 'NegRiskCtfExchange_evt_OrderFilled') }} t
inner join {{ ref('polymarket_polygon_base_ctf_tokens') }} ctf on coalesce(nullif(t.makerAssetId, 0), nullif(t.takerAssetID, 0)) = ctf.token0
{% if is_incremental() %}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{{
config(
schema = 'polymarket_polygon',
alias = 'open_positions',
materialized = 'view',
post_hook = '{{ expose_spells(blockchains = \'["polygon"]\',
spell_type = "project",
spell_name = "polymarket",
contributors = \'["hildobby"]\') }}'
)
}}

WITH latest_day AS (
SELECT MAX(day) AS day
FROM {{ ref('polymarket_polygon_positions_raw') }}
)

, open_positions AS (
SELECT
p.address,
mm.unique_key,
p.token_id,
mm.token_outcome,
mm.token_outcome_name,
p.balance,
mm.question_id,
mm.question AS market_question,
mm.market_description,
mm.event_market_name,
mm.event_market_description,
mm.active,
mm.closed,
mm.accepting_orders,
mm.polymarket_link,
mm.polymarket_link_slug,
mm.market_start_time,
mm.market_start_time_parsed,
mm.market_end_time,
mm.market_end_time_parsed,
mm.outcome AS market_outcome,
mm.resolved_on_timestamp,
mm.final_price
FROM {{ ref('polymarket_polygon_positions_raw') }} p
INNER JOIN latest_day ld ON p.day = ld.day
INNER JOIN {{ ref('polymarket_polygon_market_details') }} mm ON p.token_id = mm.token_id
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open positions view includes zero-balance closed positions

Medium Severity

The open_positions CTE joins with positions_raw without filtering out positions where balance = 0. Since positions_raw includes all balances (including zero balances from fully exited positions), the view will return closed positions as "open." The schema describes this as "Polymarket: open positions in markets," but users who have completely sold their positions will still appear in the results. A filter like WHERE p.balance > 0 is needed in the open_positions CTE to match the semantic meaning of the table.

Fix in Cursor Fix in Web


SELECT op.address,
op.unique_key,
token_id,
op.token_outcome,
op.token_outcome_name,
op.balance,
op.balance*(CASE WHEN op.market_end_time_parsed IS NULL
OR p.last_updated <= op.market_end_time_parsed
THEN p.latest_price
ELSE COALESCE(final_price, 0)
END) AS open_interest,
CASE WHEN op.market_end_time_parsed IS NULL
OR p.last_updated <=op.market_end_time_parsed
THEN p.latest_price
ELSE COALESCE(final_price, 0)
END AS latest_price,
op.question_id,
op.market_question,
op.market_description,
op.event_market_name,
op.event_market_description,
op.active,
op.closed,
op.accepting_orders,
op.polymarket_link,
op.polymarket_link_slug,
op.market_start_time,
op.market_start_time_parsed,
op.market_end_time,
op.market_end_time_parsed,
op.market_outcome,
op.resolved_on_timestamp
FROM open_positions op
LEFT JOIN {{ ref('polymarket_polygon_market_prices_latest') }} p USING (token_id)
Loading
Loading