Skip to content

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

Open
lingster wants to merge 1 commit into
numerai:masterfrom
lingster:crypto-public-user-profile
Open

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

Conversation

@lingster

Copy link
Copy Markdown

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.

Verified against the live API + Numerai MCP

check result
v3UserProfile (no tournament) for a crypto model null (reproduces the bug)
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 as a string

When this shared method is invoked through NumerAPI, it now converts nmrStaked to Decimal; the removed Classic implementation only converted startDate, so existing callers of NumerAPI.public_user_profile(...) that persist or compare the previously returned stake string will start seeing a different type. If the goal is only to add tournament-scoped lookup, keep this conversion limited to APIs that already returned Decimal or leave the Classic return type unchanged.

Useful? React with 👍 / 👎.

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