Skip to content

Add public_user_profile to Crypto API (resolve model_id by name)#1

Closed
lingster wants to merge 1 commit into
masterfrom
crypto-public-user-profile
Closed

Add public_user_profile to Crypto API (resolve model_id by name)#1
lingster wants to merge 1 commit into
masterfrom
crypto-public-user-profile

Conversation

@lingster

Copy link
Copy Markdown
Owner

Problem

submission_scores (and diagnostics, staking, etc.) require a model_id,
but the Crypto API had no way to resolve a model name → model_id.
public_user_profile existed only on NumerAPI (Classic) and SignalsAPI,
so there was no supported path to map the usernames shown on the crypto
leaderboard to the UUIDs the rest of the API expects.

Fix

The v3UserProfile GraphQL field accepts a tournament argument that
disambiguates a model name within a tournament. The old Classic/Signals
implementations ignored it — meaning a name shared across tournaments could
resolve to the wrong model's id (verified: quixotic15 returns a
different id with vs. without tournament=12).

This unifies all three tournaments into a single
base_api.Api.public_user_profile that passes tournament=self.tournament_id:

  • CryptoAPI gains public_user_profile (tournament 12) — the missing piece
  • ✅ Signals / Classic now resolve names within their own tournament (11 / 8)
  • ✅ duplicated overrides in numerapi.py and signalsapi.py removed (DRY)

Return shape is unchanged (id, username, startDate, bio, nmrStaked).

Usage

import numerapi
capi = numerapi.CryptoAPI()
model_id = capi.public_user_profile("nosaailgbmmean")["id"]
scores = capi.submission_scores(model_id)

Testing (red/green TDD)

  • New tests in test_cryptoapi.py and test_signalsapi.py assert the model
    is resolved within the API's own tournament and that string fields are
    converted. Written failing first, then made to pass.
  • Full suite: 45 passed (live-API tests deselected). pyflakes clean.

Independently verified against the live API + Numerai MCP

check result
MCP v3_user_profile (no tournament) for a crypto model null (reproduces the bug)
MCP v3UserProfile(tournament: 12) 2d844064-...
CryptoAPI().public_user_profile(...)['id'] 2d844064-... (matches)
submission_scores(model_id) 70,083 rows of real data
Signals / Classic regression resolve to expected ids

🤖 Generated with Claude Code

CryptoAPI had no way to resolve a model name (the "username" shown on the
crypto leaderboard) to a model_id, which is required by submission_scores,
diagnostics, staking, etc. public_user_profile existed only on the Classic
and Signals APIs.

The v3UserProfile GraphQL field accepts a `tournament` argument that
disambiguates a model name within a given tournament. The previous Classic
and Signals implementations ignored it, so a name shared across tournaments
could resolve to the wrong model's id (verified: "quixotic15" returns a
different id with vs without tournament=12).

This unifies all three into a single base_api.Api.public_user_profile that
passes `tournament=self.tournament_id`, so:
  - CryptoAPI gains public_user_profile (tournament 12)
  - Signals/Classic resolve names within their own tournament (11 / 8)
  - the duplicated overrides in numerapi.py and signalsapi.py are removed (DRY)

Verified end-to-end against the live API and the Numerai MCP: a fresh crypto
leaderboard name resolves to its model_id and that id drives submission_scores.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 25bca132e8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread numerapi/base_api.py
data = self.raw_query(query, arguments)["data"]["v3UserProfile"]
# convert strings to python objects
utils.replace(data, "startDate", utils.parse_datetime_string)
utils.replace(data, "nmrStaked", utils.parse_float_string)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve Classic nmrStaked return type

For NumerAPI.public_user_profile callers, this new shared conversion changes nmrStaked from the raw GraphQL string returned by the previous Classic implementation into a Decimal. That is a public API/serialization change unrelated to adding Crypto support; for example existing Classic users doing json.dumps(api.public_user_profile(...)) or string-based persistence/comparisons can now fail or behave differently. Keep the conversion scoped to APIs that already returned Decimal, or make the Classic behavior an explicit compatibility break.

Useful? React with 👍 / 👎.

@lingster

Copy link
Copy Markdown
Owner Author

Superseded by upstream PR numerai#128.

@lingster lingster closed this Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant