Skip to main content
Glama

BotSpot: AI Trading, Backtests and Bots

Run isolated Python data analysis

run_data_analysis

Run complete Agent-generated Python in an ephemeral isolated runtime with pandas, NumPy, SciPy, and statsmodels. A retryable failed attempt below 3 is unfinished: validate the next full request using the returned failed analysisRunId and incremented attempt, then execute its NEW validatedProgram. Failed attempt 2 requires the third execution before a final failure answer; stop immediately for a concrete non-retryable safety/access error. For coverage limitations, state the returned first/last timestamps. Quantify a gap through today only when calculated against the explicit request clock; never guess the elapsed days from old observations or an example. Preserve full aware timestamps returned by price bars when publishing the comparison window. Do not convert them to date-only strings and then claim price clocks were unavailable. Keep market-price endpoints separate from account-observation and retrieval clocks. Declare the exact read-only broker, bounded internal-data, BotSpot public-data, and allowlisted HTTPS capabilities the program needs. For edits of a saved chart, first inspect_analysis_artifact with includeProgram=true and reuse its full calculation datasets; fetch only missing data. Reopening unchanged charts uses displaySavedChart=true without this execution tool. The runtime receives only a short-lived capability token: broker credentials stay in trusted server-side connectors and are never exposed to generated Python. SDK data calls return mapping-compatible payloads: use payload['bars'], payload['positions'], or payload['records'] for documented row collections. For single-symbol broker history, declare capabilities.broker.operations=['historical_prices'] and capabilities.broker.brokerCredentialIds=[the exact brokerCredentialId UUID returned by list_broker_credentials]. For two or more broker symbols requiring fresh reads and sharing asset type, quote currency, and contract terms, including pair comparisons, declare only historical_prices_many and call broker.history_many once; pass asset_type, quote_symbol, expiration, strike, right, exchange, and market as needed, then read payload['barsBySymbol']. For different asset types or distinct option strikes/futures expiries, declare historical_prices and call broker.history separately with each full contract identity. Crypto and forex require an explicit quote_symbol; futures history retains expiration and exchange. broker.quotes also accepts asset_type, quote_symbol, expiration, strike, right, exchange, and market; option quotes require the full contract terms. Never treat a crypto pair, option leg, or futures contract as a stock symbol. history_many batches complete coverage with at most four parallel reads; set batch_size at or below the runtime maxSymbols limit. Request/row/byte quotas still apply, and batchAsOf preserves the individual read timestamps. A chart with one broker symbol plus public macro data remains a single-symbol broker request and uses broker.history with historical_prices. Calculate user-defined series and conditions as pure pandas functions, and evaluate every item at the requested as-of boundary. When the user asks to find a current setup, only mark an item qualified when the condition remains active at the latest completed observation. Emit honest zero-result analyses and never create placeholder items, rows, or actions. A broker-backed call must follow list_broker_credentials in the current turn; generic source wording, labels, provider names, and placeholders are never credential IDs. For an ordinary single-result chart request, persist the complete source rows with dataset.emit, call chart.emit exactly once, and do not call analysis.emit. For table/statistic-only output, emit the requested table or statistics without a dummy chart or unrelated dataset; retain provenance for every fetched source. Emit tables with table.emit(name='...', rows=[...], columns=[...]). Use a reusable AnalysisDocument only for selectable, ranked, user-revisable results, or when a later action field must resolve from an immutable semantic element. In that branch, call dataset.emit for every full calculation dataset, then call analysis.emit exactly once with schemaVersion=1, type='analysis', sourceIds, items, views, actions, skipped, and errors. The full dataset is the durable computation source and must contain stable field definitions and primary keys. Never make sampled chart rows the source of a later value or trade. Every analysis item must reference its own dataset, semantic elements, view, and optional action by opaque ID. Each chart must declare its datasetId plus displaySampling method and sourceRowCount. Semantic elements must include structured derivations that resolve against full datasets. Do not route or alter behavior based on indicator names or user wording. chart.emit accepts only the documented runtime chart fields, never final-response source, metadata, analysis, sources, or runtime fields. The serialized chart object must be at most 256,000 UTF-8 bytes. When the user requests a cadence and range, retain every returned observation at that cadence and set displaySampling.method='none'; never sample daily observations and label the result daily. Only sample when the user did not request complete cadence, and disclose the sampling method. When comparing movement across unlike units with an indexed-to-100 transformation, index every requested numeric series, including macro and public-data series, and use source-based keys ending in _indexed. Resolve a requested session and timezone before matching account observations. Validate actual returned endpoint dates and bar completion times: an earlier available bar does not prove coverage of the requested day. Preserve a user-selected sparse account window as a labeled estimate with funding uncertainty, and omit relative-performance statistics when the benchmark covers a different interval. Portfolio comparisons use the analysisDatasetId returned by get_portfolio_series with capabilities.internalData.datasetIds and internal_data.get; tool names are not provenance IDs. Use intraday benchmark history for account observation times and align each account observation to the latest completed benchmark bar at or before it, preserving the acquisition prefix for the baseline. Matching calendar dates or plotting all raw bars inside the overall window does not perform this alignment. Derive chart captions and statistics from the same executed rows, including the current broker reading and its actual clock basis; a discovery preview can contain fewer observations. Capture each provenance source-ID delta immediately after its fetch and before the next fetch. Never derive multiple source lists after multiple queries from one old provenance snapshot, and never use a dataset ID as a chart sourceIds fallback. When the user did not request cadence or complete observations, a sampled display may be used while retaining the complete full-precision dataset. Build sampled mappings with an explicit loop over indices and source_row=full_rows[index], not a nested tuple/list comprehension. Use explicit profile, time-scale mode, interpolation, transforms, marks, panes, pane appearance, axes, reference lines, reference bands, event windows, hover fields, data-driven bar colors, controls, units, frequencies, timestamps, and source IDs. Use session time for exchange-session comparisons, calendar time for economic and mixed-frequency series, and ordinal time only for non-temporal categories. Never silently forward-fill or interpolate a lower-frequency series. The renderer uses only this declarative contract and never infers meaning from labels. OHLC market data uses candlesticks by default at every requested range; use a price line only when OHLC is unavailable or the user explicitly requests one. An event window has exactly id, paneId, xStart, xEnd, optional semanticElementId, label, and style; it never has axisId or seriesId. A marker has exactly id, paneId, seriesId, x, placement, shape, color, and label, with optional semanticElementId, value, and unit. Event-window endpoints and marker timestamps must be retained chart x values. Derive regimes and crossovers from full calculation rows before display sampling, close the final regime at the newest displayed observation, and select bounded visuals newest-first before returning them oldest-to-newest. Never keep the oldest bounded windows or markers while dropping newer ones. Set analysis.title for a new definition. To revise an existing analysis, pass its definitionId and current parentRevisionId; every edit creates an immutable revision. Corrections of the same completed analysis use that existing definition and current parent revision, so the corrected display replaces the earlier one while history remains available. Independent analyses retain separate definitions. Include only capability groups used by the program. Every present capability array must be non-empty; for example, a broker-only program must omit safeHttp rather than send safeHttp.domains=[]. Runtime gateway limits: {"maxRequests":40,"maxResponseBytes":8000000,"maxRows":50000,"maxSymbols":50}. Operator-approved safe HTTP domains: []; an empty list means direct HTTP is unavailable. For the initial call, explicitly pass attempt=1 and omit previousAnalysisRunId. An MCP input-schema rejection creates no analysis run, so correct it as another initial attempt=1 call. For a repair, pass only the analysisRunId returned by the immediately preceding persisted status=failed result and increment attempt; never use a completed prior run as a repair target. At most three persisted attempts are allowed. Set responseMode='final' only when this completed standalone chart or table is the last requested action, so the canonical artifact can be returned directly without another model copy. Set responseMode='continue' when any later tool action remains, including quote lookup, analysis inspection, resolution, or trade approval work.

Input Schema

NameRequiredDescriptionDefault
codeYesComplete generated Python program. Use only preinstalled packages and botspot_analysis SDK functions for data access.
attemptNo
analysisNoStable analysis identity. Omit definitionId and parentRevisionId for the first revision; include both when revising an existing analysis.
capabilitiesYesExact read-only capabilities the Python program may use. Include only groups actually used by the code. Every present group requires a non-empty array; omit unused broker, publicData, internalData, and safeHttp groups entirely.
responseModeNoSet final only when this completed standalone chart or table is the last requested action. Use continue when another tool action must follow, including quote or trade approval work.continue
previousAnalysisRunIdNoUse only the analysisRunId returned by the immediately preceding persisted status=failed result. Input-schema rejection creates no run ID, and completed run IDs are never repair targets.

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observed

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare a non-read-only, non-idempotent, open-world execution with destructiveHint=false; the description adds a great deal beyond that — ephemeral isolated runtime, short-lived capability token with broker credentials never exposed to generated Python, at-most-three persisted attempts, and hard gateway quotas (40 requests, 8MB, 50k rows, 50 symbols) plus a 256,000-byte chart cap. The only shortfall is that it never states what a successful run returns or how failures surface, beyond the status=failed repair contract.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a ~1,500-word unstructured block with no headings or grouping, mixing runtime facts, retry policy, chart-rendering contracts, provenance rules, and sampling semantics into undifferentiated prose. The core purpose is front-loaded in sentence one, but large stretches are agent-policy rules ('Never make sampled chart rows the source of a later value') that a tool definition is a poor place to carry.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool of this complexity — 6 params, deep nested capabilities object, no output schema — the description leaves nothing an agent needs unstated: quotas, capability declarations, retry lifecycle, artifact emission patterns, and chart size limits are all covered. Whatever else is wrong here, coverage is not the gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so the schema already carries most parameter documentation, but the description still adds real meaning: when to omit previousAnalysisRunId (initial call, input-schema rejection), how attempt increments across repairs, and how capability groups map to broker/history/history_many SDK calls. It goes beyond a restatement, though many of those rules are about program content rather than the parameters themselves.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence names a specific verb and resource — executing complete agent-generated Python in an ephemeral isolated runtime with a named package set — which no sibling tool does (generate_other_code produces code, query_data queries data). It also distinguishes itself from inspect_analysis_artifact and displaySavedChart for adjacent chart-editing/reopening cases.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing rules are given throughout: use inspect_analysis_artifact with includeProgram=true before editing saved charts, use displaySavedChart=true for reopening unchanged charts, and set responseMode='final' only when this artifact is the last requested action. Retry/failure branching (attempt<3 unfinished, attempt 2 requires third execution, stop on non-retryable safety errors) is spelled out rather than implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.