Polymarket.Activity (Polymarket v0.2.0)

Copy Markdown View Source

Pure normalization and join helpers for Polymarket activity data.

This module operates on plain maps. It does not fetch from the Data API or the CLOB; the caller pipes raw activity events (typically from Polymarket.Data.get_activity/2) and CLOB fills (from PolymarketClob.API.Account.get_trades/3) into these helpers.

All input keys are looked up in both camelCase string form (the shape Polymarket's Data API returns) and snake_case string form (the shape the CLOB and several internal callers use). Atom keys are also accepted as a convenience for in-Elixir construction.

Match semantics

cost_for_order/3, revenue_for_order/3, and redemption_for_market/2 sum USDC sizes across every matching event. This is a deliberate divergence from the bot's extract_activity_cost/3 which returns the first match: GTC orders that partially fill across multiple takers produce multiple activity rows, and summing is the correct total.

All three return nil when no event matches, distinguishing "no activity yet" from "events that summed to 0". The bot uses 0.0 for the same case; the SDK chose nil to keep "missing data" and "actual zero" semantically separate.

Activity ↔ fills join

Polymarket's /activity endpoint identifies each TRADE by transactionHash, not orderHash. To find the activity row for a given CLOB order id, we resolve tx_hash from the fills list first and then match against activity.transactionHash. When no fills list is available, cost_for_order/3 and revenue_for_order/3 fall back to a best-effort match against legacy orderHash / taker_order_id fields. Pass an empty list [] for fills if all you have is the order id and you want the fallback path.

Summary

Functions

Sums fee-inclusive USDC cost across every TRADE BUY event matching order_id. Returns nil when no event matches.

Normalizes a list of raw /activity event maps into typed Polymarket.Activity.Event structs.

Sums REDEEM payouts for condition_id. Returns nil when no event matches.

Sums fee-inclusive USDC revenue across every TRADE SELL event matching order_id. Returns nil when no event matches.

Types

condition_id()

@type condition_id() :: String.t()

order_id()

@type order_id() :: String.t()

raw_event()

@type raw_event() :: map()

raw_fill()

@type raw_fill() :: map()

Functions

cost_for_order(activities, order_id, fills)

@spec cost_for_order([raw_event()], order_id(), [raw_fill()]) :: float() | nil

Sums fee-inclusive USDC cost across every TRADE BUY event matching order_id. Returns nil when no event matches.

Activity is matched to an order id by:

  1. Finding fills whose order_id or taker_order_id equals the requested order_id and collecting their tx_hash/transaction_hash.
  2. Selecting activity events whose transactionHash is in that set AND whose type == "TRADE" AND side == "BUY".

When step 1 yields nothing (e.g. caller did not supply fills), a fallback matches activity rows directly by orderHash or taker_order_id equal to order_id. The fallback is best-effort only — Polymarket has historically populated transactionHash more reliably than orderHash on /activity.

normalize(events)

@spec normalize([raw_event()]) :: [Polymarket.Activity.Event.t()]

Normalizes a list of raw /activity event maps into typed Polymarket.Activity.Event structs.

Unknown event types are still emitted with type: :unknown and the full raw map preserved under :raw, so a caller iterating over a large activity feed never loses events it did not anticipate.

redemption_for_market(activities, condition_id)

@spec redemption_for_market([raw_event()], condition_id()) :: float() | nil

Sums REDEEM payouts for condition_id. Returns nil when no event matches.

Activity rows are matched directly on conditionId / condition_id; no fills join is needed because REDEEM events do not carry a CLOB order id.

revenue_for_order(activities, order_id, fills)

@spec revenue_for_order([raw_event()], order_id(), [raw_fill()]) :: float() | nil

Sums fee-inclusive USDC revenue across every TRADE SELL event matching order_id. Returns nil when no event matches.

Same join semantics as cost_for_order/3.