# ai.quantifyme/quantifyme

> Describe a trading strategy in plain English and deploy a live signal model in one call. No signup.

- name: ai.quantifyme/quantifyme
- version: 1.0.0
- connection class: R0 (autonomous)
- trust: 75/100 flags: no-repository
- quality: 66/100 (needs work)
- owner: not claimed
- descriptor: https://api.protogrid.dev/v1/servers/ai.quantifyme%2Fquantifyme
- tools: https://api.protogrid.dev/v1/servers/ai.quantifyme%2Fquantifyme/tools

**An agent can connect right now, no human step.** Remote endpoint, no authentication, reachable on the last probe.

## Connection (mcpServers)

```json
{
  "mcpServers": {
    "quantifyme": {
      "type": "http",
      "url": "https://mcp.quantifyme.ai/mcp"
    }
  }
}
```


## Trust

- hygiene: 80
- liveness: 99
- freshness: 65
- provenance: 55
- drivers: +dns-namespace +website +reachable +uptime-97% ~updated-153d-ago -no-repository
- Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed.

## Quality 66/100 (needs work)

### protocol: 75 (weight 25)

- warn `protocol.modern`: newest supported version is 2025-11-25; 2026-07-28 not supported, older versions are deprecated until 2027-07-28
- n/a `protocol.stateless`: only applies to 2026-07-28 servers
- pass `protocol.transport`: streamable HTTP
- n/a `protocol.list_ttl`: only applies to 2026-07-28 servers

### authorization: n/a (weight 15)

- n/a `auth.prm`, `auth.as_metadata`, `auth.cimd`: no remote uses OAuth
- n/a `auth.secret_in_url`: no templated URL

### tool hygiene: 79 (weight 30)

- pass `tools.descriptions`: every tool has a description
- warn `tools.description_length`: 4 tools have descriptions over 1,024 characters, which crowds the context
- pass `tools.schemas`: every tool has an object input schema
- pass `tools.annotations`: 13 of 13 tools declare readOnlyHint or destructiveHint
- fail `tools.directory_hints`: no tool declares all four of readOnlyHint, destructiveHint, idempotentHint and openWorldHint; missing: one_shot (idempotentHint); link_account (destructiveHint); top_up (destructiveHint); …
- pass `tools.token_cost`: about 4,312 tokens to load every tool
- pass `tools.api_dump`: tools are not a one-to-one API dump

### stability: 25 (weight 15)

- warn `stability.changes`: 7 tool changes in 30 days
- fail `stability.rug_pull`: 1 tools kept their name but changed most of their description in 30 days; review before trusting them

### dependencies: n/a (weight 15)

- n/a `deps.known_vulns`, `deps.mcp_sdk_version`, `deps.resolvable`: no npm or PyPI package

- tools: 13, about 4,312 tokens to load them all
- tool set hash: 683d409dd36b59437ff0ddf920b65e6e
- tools last changed: 2026-10-11T08:40:52.834Z
- badge: [![protogrid quality](https://protogrid.dev/badge/ai.quantifyme/quantifyme.svg)](https://protogrid.dev/servers/ai.quantifyme/quantifyme)
- Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed.

### Tool changes

- 2026-10-11 `list_models` changed (description)
  - before: List the user's trained models with pre-computed train/test stats.
  - after: List the user's trained models with pre-computed train/test stats. `acting_as` names the identity listed: the linked account or a trial user (#1962).
- 2026-10-11 `link_account` changed (description)
  - before: Link this chat to the user's existing QuantifyMe account. Call this when the user says they already have a QuantifyMe account, or asks why their models are missing / where a model went, or wants what they deploy here to show up in their own dashboard. By default this connector works with NO signup: it mints an anonymous trial account per chat, so models deployed here belong to that throwaway identity rather than to the user's real one. This returns a short-lived URL; once the user opens it and approves, every later call in THIS chat acts as their account and deploys land in their own model list. Give the user the `link_url` to open. Nothing else is required from them.
  - after: Link this chat to the user's existing QuantifyMe account. Call this when the user says they already have a QuantifyMe account, or asks why their models are missing / where a model went, or wants what they deploy here to show up in their own dashboard. By default this connector works with NO signup: it mints an anonymous trial account per MCP session, so models deployed here belong to that throwaway identity rather than to the user's real one. This returns a short-lived URL; once the user opens it and approves, every later call that carries the same OAuth bearer or the same MCP session acts as their account and deploys land in their own model list. A client that opens a new MCP session on every turn must link again in that session; every answer's `acting_as` line says which identity was used. Give the user the `link_url` to open. Nothing else is required from them.
- 2026-10-05 `stream_test` changed (description)
  - before: Diagnostic: test whether LIVE data streaming works in this client. Renders a widget with three panels — a JS timer (baseline), a WebSocket to the live price feed, and an HTTP poll of /quote — each showing a live value + status, so you can see exactly which streaming mechanisms the client's widget sandbox actually permits. Use when a live/ticking chart isn't moving. Args: symbol: G7 pair to stream (default EURUSD).
  - after: Diagnostic: test whether LIVE data streaming works in this client. Renders a widget with three panels: a JS timer (baseline), the WebSocket panel (not offered: the feed needs a credential and none is sent to a widget), and an HTTP poll of /quote, each showing a live value + status, so you can see which streaming mechanisms the client's widget sandbox permits. Use when a live/ticking chart isn't moving. Args: symbol: G7 pair to stream (default EURUSD).
- 2026-10-05 `find_strategy` changed (description)
  - before: Find an existing PROVEN strategy that matches a plain-English idea, so you can offer the user a choice — deploy the existing one, or generate a fresh custom one. Mirrors the quantifyme.ai landing experience: "Found <X> by @<author> (WR/PF) — Use it / Generate fresh". CALL THIS FIRST when a user describes a strategy idea. Then present the match (if any) and ASK which they want: • Use it → one_shot(community_id=<match.community_id>) — deploys the exact proven strategy (free, no generation). • Generate fresh → one_shot(prompt="<their description>") — Claude writes a brand-new custom strategy for them. If there's no match, just offer to generate fresh. Args: description: the user's strategy idea in plain English (e.g. "buy EURUSD 15min when RSI < 30, sell when RSI > 70"). symbol: optional pair to constrain the match (EURUSD, USDJPY, GBPUSD, USDCHF, USDCAD, AUDUSD, NZDUSD). timeframe: optional granularity to constrain the match (1min/5min/15min/1h). Returns: dict with: - match: the best existing strategy, or null. When present: {community_id, title, username, wr, pf, ret, n_trades, symbol, timeframe}. Pass community_id to one_shot to deploy it unchanged. - description: echoed back — pass as one_shot(prompt=...) to generate fresh. - suggestion: a ready-to-show sentence offering the user the choice.
  - after: Find an existing PROVEN strategy that matches a plain-English idea, so you can offer the user a choice — deploy the existing one, or generate a fresh custom one. Mirrors the quantifyme.ai landing experience: "Found <X> by @<author> (WR/PF) — Use it / Generate fresh". Use this when a user wants to browse for an existing strategy. A vague deploy request does NOT need it: one_shot(prompt=...) deploys the best curated preset or a fresh build. A community strategy is another user's code, so it deploys only after the user has seen its author and code (get_strategy_code with the match's community_id) and picked it. Present the match (if any) and ASK: • Use it → one_shot(community_id=<match.community_id>) — deploys the exact strategy they picked (no generation). • Generate fresh → one_shot(prompt="<their description>") — Claude writes a brand-new custom strategy for them. If there's no match, just offer to generate fresh. Args: description: the user's strategy idea in plain English (e.g. "buy EURUSD 15min when RSI < 30, sell when RSI > 70"). symbol: optional pair to constrain the match (EURUSD, USDJPY, GBPUSD, USDCHF, USDCAD, AUDUSD, NZDUSD). timeframe: optional granularity to constrain the match (1min/5min/15min/1h). Returns: dict with: - match: the best existing strategy, or null. When present: {community_id, title, username, wr, pf, ret, n_trades, symbol, timeframe}. Pass community_id to one_shot to deploy it unchanged. - description: echoed back — pass as one_shot(prompt=...) to generate fresh. - suggestion: a ready-to-show sentence offering the user the choice.
- 2026-10-05 `top_up` changed (description) **meaning changed**
  - before: Fund your QuantifyMe credits with crypto (USDC) — no signup, no human, no card. The agent-native funding rail. SIMULATED in this build (no real charge) and capped at $100 for the POC. Returns your new credit balance.
  - after: Simulated crypto top-up for a QuantifyMe DEV server only: no money moves, so it never makes an account paid and grants at most up to the free credit cap ($100 per call). quantifyme.ai refuses it (#1098) and answers with how to pay for real: send USDC on Base to your deposit address (GET /api/v1/wallet/deposit_address). Returns your new credit balance.
- 2026-10-05 `get_deploy_result` changed (description)
  - before: Wait for a `one_shot` deploy to finish and return its final result. `one_shot` returns a job_token immediately and the LIVE CARD already streams progress and renders the interactive backtest chart itself. Call this ONCE with the token to get the final numbers as TEXT so you can summarize them — it does NOT render another card (no need for get_model_chart). It BLOCKS until the deploy finishes (or ~2.5 min); on timeout it returns ok:false + pending:true — call it again with the same token. IMPORTANT: if `source == "community"`, the deploy used a PRE-EXISTING strategy by `@author` — tell the user that, share the `live_url` as the Live dashboard link, and ask whether they'd like to GENERATE A CUSTOM strategy instead. Use the `note` field as your guide. Args: job_token: the token returned by `one_shot`. Returns: dict with: ok, stem, model, live_url, symbol, timeframe, channels (list), stats:{ret, wr, pf, n, mdd} (out-of-sample test-split metrics — SHOW THESE), source ("community" | "generated"), author (community username if any), author_url + strategy_url (render @author and "pre-existing strategy" as those Markdown links), community_id, suggest_custom (bool), and note (a ready instruction — follow it). On failure: {ok:false, error} (or {pending:true}).
  - after: Wait for a `one_shot` deploy to finish and return its final result. `one_shot` returns a job_token immediately and the LIVE CARD already streams progress and renders the interactive backtest chart itself. Call this ONCE with the token to get the final numbers as TEXT so you can summarize them — it does NOT render another card (no need for get_model_chart). It BLOCKS until the deploy finishes (or ~2.5 min); on timeout it returns ok:false + pending:true — call it again with the same token. IMPORTANT: if `source == "community"`, the deploy used a PRE-EXISTING strategy by `@author` (the user picked it) - tell the user that, share the `live_url` as the Live dashboard link, and ask whether they'd like to GENERATE A CUSTOM strategy instead. A `suggestion` is a community strategy that matched a vague request; it was NOT deployed; offer it, and deploy it only after the user sees its author and code and picks it. Use the `note` field as your guide. Args: job_token: the token returned by `one_shot`. Returns: dict with: ok, stem, model, live_url, symbol, timeframe, channels (list), stats:{ret, wr, pf, n, mdd} (out-of-sample test-split metrics — SHOW THESE), source ("preset" | "generated" | "community"), author (community username if any), author_url + strategy_url (render @author and "pre-existing strategy" as those Markdown links), community_id, suggest_custom (bool), suggestion ({community_id, title, author} or null: offered, not deployed), and note (a ready instruction - follow it). On failure: {ok:false, error} (or {pending:true}).
- 2026-10-05 `one_shot` changed (description)
  - before: End-to-end deploy: generate strategy → train → deploy live. One of `prompt` (free-form NL), `preset` (curated winning strategy), or `community_id` (copy a published community strategy) is required. If more than one is passed, precedence is community_id > preset > prompt. Args: prompt: Natural-language strategy description (e.g. "Buy when RSI < 30, sell > 70"). symbol: Currency pair to backtest on. One of: EURUSD, USDJPY, GBPUSD, USDCHF, USDCAD, AUDUSD, NZDUSD. Default EURUSD. timeframe: Candle granularity. One of: 1min, 5min, 15min, 1h. Default 15min. claude_model: Which Claude variant to use for code generation. "sonnet" (default — best quality, 1/day free) or "haiku" (faster, 3/day free). Ignored when `preset` is set (no generation needed). preset: Curated winning-strategy slug. Skips Claude generation entirely — deploys a pre-saved strategy known to backtest well on the chosen symbol. Available slugs: ema_cross_fast, momentum, scalper_stack, sma_only, trend_ema, volatility, bb_squeeze, all_mix, pivot_kid_ema. Not every slug exists for every symbol — call list_models afterwards to confirm what deployed. community_id: Copy-trade a published community strategy. Pass the `id` of an entry from `browse_community`. Loads that exact strategy code, skips Claude generation, then trains + deploys it. `symbol`/`timeframe` still apply to the backtest+deploy. webhook_url: Optional webhook to receive live signals. telegram_chat_id: Optional Telegram chat ID for signal delivery. Returns IMMEDIATELY (the deploy runs in the background so the live card can stream progress) with: - job_token (str): pass to get_deploy_result to fetch the final result. - poll_url (str): the card polls this for live progress; you can ignore it. - pending (bool): always true here — the deploy is still running. - symbol, timeframe (str). Call this EXACTLY ONCE per request. Pass the user's words as `prompt`; do not pre-pick presets/community strategies — the server routes (vague → a proven community strategy, specific rules → a fresh generation). NEXT STEP (always): call get_deploy_result(job_token) ONCE — it blocks until the deploy finishes and returns the out-of-sample stats + `stem` + `source`/`author` as TEXT so you can summarize. The live card already shows the chart, so you do NOT need get_model_chart. If source='community', tell the user it used a pre-existing strategy by @author and offer to generate a custom one.
  - after: End-to-end deploy: generate strategy → train → deploy live. One of `prompt` (free-form NL), `preset` (curated winning strategy), or `community_id` (copy a published community strategy) is required. If more than one is passed, precedence is community_id > preset > prompt. Args: prompt: Natural-language strategy description (e.g. "Buy when RSI < 30, sell > 70"). symbol: Currency pair to backtest on. One of: EURUSD, USDJPY, GBPUSD, USDCHF, USDCAD, AUDUSD, NZDUSD. Default EURUSD. timeframe: Candle granularity. One of: 1min, 5min, 15min, 1h. Default 15min. claude_model: Which Claude variant to use for code generation. "sonnet" (default — best quality, 1/day free) or "haiku" (faster, 3/day free). Ignored when `preset` is set (no generation needed). preset: Curated winning-strategy slug. Skips Claude generation entirely — deploys a pre-saved strategy known to backtest well on the chosen symbol. Available slugs: ema_cross_fast, momentum, scalper_stack, sma_only, trend_ema, volatility, bb_squeeze, all_mix, pivot_kid_ema. Not every slug exists for every symbol — call list_models afterwards to confirm what deployed. community_id: Copy-trade a published community strategy. Pass the `id` of an entry from `browse_community`. Loads that exact strategy code, skips Claude generation, then trains + deploys it. `symbol`/`timeframe` still apply to the backtest+deploy. webhook_url: Optional webhook to receive live signals. telegram_chat_id: Optional Telegram chat ID for signal delivery. Returns IMMEDIATELY (the deploy runs in the background so the live card can stream progress) with: - job_token (str): pass to get_deploy_result to fetch the final result. - poll_url (str): the card polls this for live progress; you can ignore it. - pending (bool): always true here — the deploy is still running. - symbol, timeframe (str). Call this EXACTLY ONCE per request. Pass the user's words as `prompt`; do not pre-pick presets/community strategies - the server routes (vague → the best curated preset for the market, or a fresh build when there is none; specific rules → a fresh generation). A community strategy deploys only after the user has seen its author and code (get_strategy_code) and picked it: then pass its `community_id`. NEXT STEP (always): call get_deploy_result(job_token) ONCE — it blocks until the deploy finishes and returns the out-of-sample stats + `stem` + `source`/`author` as TEXT so you can summarize. The live card already shows the chart, so you do NOT need get_model_chart. If source='community', tell the user it used a pre-existing strategy by @author and offer to generate a custom one. If the result carries a `suggestion`, you may offer that community strategy.

Full history: https://api.protogrid.dev/v1/servers/ai.quantifyme%2Fquantifyme/changes

## Remotes

- https://mcp.quantifyme.ai/mcp (streamable-http, auth none, reachable true, uptime30d 0.973913)

## Packages

_none_

## Tools (13)

- `browse_community`: Browse the public community leaderboard of published strategies, ranked
    by a composite performance score (best first). No signup or key needed.

    Copy-trade flow: call this to find a top strategy, then pass its `id` to
    `one_shot` as `community_id` to deploy a live signal model running that
    exact strategy in one call.

    Args:
      limit: How many top entries to return (default 20, max 200).
      sort: Ranking metric, best-first — one of "composite" (default),
        "ret" (total return), "wr" (win rate), "sharpe", "n_trades". Mirrors
        the quantifyme.ai/community page's sortable columns, so an agent can
        pick the top strategy by the metric it cares about in one call. The
        sorted entries keep their `id`, so the winner is directly deployable
        via one_shot(community_id=...).

    Returns:
      dict with:
        - scripts (list[dict]): ranked entries, best first. Each has:
            id (int — pass to one_shot as community_id), username, title,
            description, created_at, score, and metrics {total_ret,
            sharpe_strat, win_rate, n_trades, mdd, profit_factor}. SHOW the
            top few with their win_rate / total_ret so the user can pick one.
        - count (int).
        - metric (str): the sort key applied.
    
- `find_strategy`: Find an existing PROVEN strategy that matches a plain-English idea, so you
    can offer the user a choice — deploy the existing one, or generate a fresh
    custom one. Mirrors the quantifyme.ai landing experience: "Found <X> by
    @<author> (WR/PF) — Use it / Generate fresh".

    Use this when a user wants to browse for an existing strategy. A vague deploy
    request does NOT need it: one_shot(prompt=...) deploys the best curated preset
    or a fresh build. A community strategy is another user's code, so it deploys
    only after the user has seen its author and code (get_strategy_code with the
    match's community_id) and picked it. Present the match (if any) and ASK:
      • Use it          → one_shot(community_id=<match.community_id>) — deploys the
                          exact strategy they picked (no generation).
      • Generate fresh  → one_shot(prompt="<their description>") — Claude writes a
                          brand-new custom strategy for them.
    If there's no match, just offer to generate fresh.

    Args:
      description: the user's strategy idea in plain English (e.g. "buy EURUSD
        15min when RSI < 30, sell when RSI > 70").
      symbol: optional pair to constrain the match (EURUSD, USDJPY, GBPUSD,
        USDCHF, USDCAD, AUDUSD, NZDUSD).
      timeframe: optional granularity to constrain the match (1min/5min/15min/1h).

    Returns:
      dict with:
        - match: the best existing strategy, or null. When present:
            {community_id, title, username, wr, pf, ret, n_trades, symbol,
             timeframe}. Pass community_id to one_shot to deploy it unchanged.
        - description: echoed back — pass as one_shot(prompt=...) to generate fresh.
        - suggestion: a ready-to-show sentence offering the user the choice.
    
- `generate_strategy`: Generate Python strategy code (no training/deploy). Use when the user wants raw code.

    Args:
      features: NL description of features (e.g. "RSI 14, Bollinger Bands").
      signals: NL description of signal logic (e.g. "Buy when RSI < 30").
      model: ML model name (default Random Forest).
      risk: NL risk rules (e.g. "0.5% stop loss").
      description: Optional one-line summary; treated as PRIMARY USER REQUEST.
      symbol: Currency pair the code should target. One of: EURUSD, USDJPY,
        GBPUSD, USDCHF, USDCAD, AUDUSD, NZDUSD. Default EURUSD.
      timeframe: Candle granularity. One of: 1min, 5min, 15min, 1h. Default 15min.
      claude_model: "sonnet" (default) or "haiku" (faster, higher daily cap).
    
- `get_deploy_result`: Wait for a `one_shot` deploy to finish and return its final result.

    `one_shot` returns a job_token immediately and the LIVE CARD already streams
    progress and renders the interactive backtest chart itself. Call this ONCE with
    the token to get the final numbers as TEXT so you can summarize them — it does
    NOT render another card (no need for get_model_chart). It BLOCKS until the deploy
    finishes (or ~2.5 min); on timeout it returns ok:false + pending:true — call it
    again with the same token.

    IMPORTANT: if `source == "community"`, the deploy used a PRE-EXISTING strategy by
    `@author` (the user picked it) - tell the user that, share the `live_url` as the
    Live dashboard link, and ask whether they'd like to GENERATE A CUSTOM strategy
    instead. A `suggestion` is a community strategy that matched a vague request; it
    was NOT deployed; offer it, and deploy it only after the user sees its author and
    code and picks it. Use the `note` field as your guide.

    Args:
      job_token: the token returned by `one_shot`.

    Returns:
      dict with: ok, stem, model, live_url, symbol, timeframe, channels (list),
      stats:{ret, wr, pf, n, mdd} (out-of-sample test-split metrics — SHOW THESE),
      source ("preset" | "generated" | "community"), author (community username if
      any), author_url + strategy_url (render @author and "pre-existing strategy" as
      those Markdown links), community_id, suggest_custom (bool), suggestion
      ({community_id, title, author} or null: offered, not deployed), and note (a
      ready instruction - follow it). On failure: {ok:false, error} (or {pending:true}).
    
- `get_model_chart`: Visualize a trained model's backtest — a cumulative-return chart + trade log + stats.

    Use after `one_shot` / `list_models` with the model's `stem` to SHOW the user how it
    traded (the "is it actually any good" view). In ChatGPT this renders an interactive
    widget. In Claude, render an interactive **artifact** from this tool's structured
    output: a line chart of the cumulative return plus a table of the trades.

    Args:
      stem: The model stem (e.g. "14_EURUSD_15min_Model_24") from `list_models` / `one_shot`.

    Returns:
      dict with: ok, stem, symbol, timeframe, stats {ret, wr, pf, n, mdd, sharpe},
      and trades [{type, entry_time, exit_time, entry_price, exit_price, pnl,
      pnl_pct, exit_reason, period}] (most recent ~200). exit_reason is one of
      TP / SL / close_only / signal / end. ret/mdd/wr are fractions; pnl_pct is percent.
    
- `get_quote`: Get the latest price for a G7 FX pair — a quick "what's it at now" check.

    Useful for context before deploying a strategy. The price is the close of
    the most recent 1-minute bar from the platform's market feed (not a raw
    live tick); FX markets close on weekends, so the `stale` flag marks a bar
    that is more than 15 minutes old.

    Args:
      symbol: G7 pair — one of EURUSD, USDJPY, GBPUSD, USDCHF, USDCAD, AUDUSD,
        NZDUSD. Default EURUSD.

    Returns:
      dict with: symbol, price (latest close), time (bar timestamp, UTC),
      change + change_pct (vs the prior 1-min bar), stale (bool).
    
- `get_strategy_code`: Get the actual Python code behind a community leaderboard strategy.

    Use after `browse_community`: pass an entry's `id` here to read its real
    `feature_engineering()` + `strategy_config()` source so the user can
    inspect or tweak it. To deploy it unchanged, pass the same id to
    `one_shot` as `community_id`. Read-only, no signup needed.

    Args:
      community_id: The `id` of a community entry (from `browse_community`).

    Returns:
      dict with: id, title, username, description, symbol, timeframe,
      metrics {total_ret, win_rate, profit_factor, n_trades, mdd, sharpe_strat},
      and `code` (the full Python source). SHOW the code to the user, and offer
      to deploy it via one_shot(community_id=...) or tweak it first.
    
- `link_account`: Link this chat to the user's existing QuantifyMe account.

    Call this when the user says they already have a QuantifyMe account, or
    asks why their models are missing / where a model went, or wants what they
    deploy here to show up in their own dashboard.

    By default this connector works with NO signup: it mints an anonymous trial
    account per MCP session, so models deployed here belong to that throwaway
    identity rather than to the user's real one. This returns a short-lived URL;
    once the user opens it and approves, every later call that carries the same
    OAuth bearer or the same MCP session acts as their account and deploys land
    in their own model list. A client that opens a new MCP session on every turn
    must link again in that session; every answer's `acting_as` line says which
    identity was used.

    Give the user the `link_url` to open. Nothing else is required from them.
    
- `list_deployed`: List the user's currently deployed (live) models.
- `list_models`: List the user's trained models with pre-computed train/test stats.
    `acting_as` names the identity listed: the linked account or a trial user (#1962).
- `one_shot`: End-to-end deploy: generate strategy → train → deploy live.

    One of `prompt` (free-form NL), `preset` (curated winning strategy), or
    `community_id` (copy a published community strategy) is required. If more
    than one is passed, precedence is community_id > preset > prompt.

    Args:
      prompt: Natural-language strategy description (e.g. "Buy when RSI < 30, sell > 70").
      symbol: Currency pair to backtest on. One of: EURUSD, USDJPY, GBPUSD,
        USDCHF, USDCAD, AUDUSD, NZDUSD. Default EURUSD.
      timeframe: Candle granularity. One of: 1min, 5min, 15min, 1h. Default 15min.
      claude_model: Which Claude variant to use for code generation.
        "sonnet" (default — best quality, 1/day free) or "haiku" (faster, 3/day free).
        Ignored when `preset` is set (no generation needed).
      preset: Curated winning-strategy slug. Skips Claude generation entirely
        — deploys a pre-saved strategy known to backtest well on the chosen
        symbol. Available slugs: ema_cross_fast, momentum, scalper_stack,
        sma_only, trend_ema, volatility, bb_squeeze, all_mix, pivot_kid_ema.
        Not every slug exists for every symbol — call list_models afterwards
        to confirm what deployed.
      community_id: Copy-trade a published community strategy. Pass the `id`
        of an entry from `browse_community`. Loads that exact strategy code,
        skips Claude generation, then trains + deploys it. `symbol`/`timeframe`
        still apply to the backtest+deploy.
      webhook_url: Optional webhook to receive live signals.
      telegram_chat_id: Optional Telegram chat ID for signal delivery.

    Returns IMMEDIATELY (the deploy runs in the background so the live card can
    stream progress) with:
        - job_token (str): pass to get_deploy_result to fetch the final result.
        - poll_url (str): the card polls this for live progress; you can ignore it.
        - pending (bool): always true here — the deploy is still running.
        - symbol, timeframe (str).

    Call this EXACTLY ONCE per request. Pass the user's words as `prompt`; do not
    pre-pick presets/community strategies - the server routes (vague → the best
    curated preset for the market, or a fresh build when there is none; specific
    rules → a fresh generation). A community strategy deploys only after the user
    has seen its author and code (get_strategy_code) and picked it: then pass its
    `community_id`.

    NEXT STEP (always): call get_deploy_result(job_token) ONCE — it blocks until the
    deploy finishes and returns the out-of-sample stats + `stem` + `source`/`author`
    as TEXT so you can summarize. The live card already shows the chart, so you do
    NOT need get_model_chart. If source='community', tell the user it used a
    pre-existing strategy by @author and offer to generate a custom one. If the
    result carries a `suggestion`, you may offer that community strategy.
    
- `stream_test`: Diagnostic: test whether LIVE data streaming works in this client.

    Renders a widget with three panels: a JS timer (baseline), the WebSocket
    panel (not offered: the feed needs a credential and none is sent to a
    widget), and an HTTP poll of /quote, each showing a live value + status, so
    you can see which streaming mechanisms the client's widget sandbox permits.
    Use when a live/ticking chart isn't moving.

    Args:
      symbol: G7 pair to stream (default EURUSD).
    
- `top_up`: Simulated crypto top-up for a QuantifyMe DEV server only: no money moves,
    so it never makes an account paid and grants at most up to the free credit
    cap ($100 per call). quantifyme.ai refuses it (#1098) and answers with how to
    pay for real: send USDC on Base to your deposit address
    (GET /api/v1/wallet/deposit_address). Returns your new credit balance.
