QUOTEZ
market data an agent can read and cannot act on.
An agent that can read a market can also trade it, unless the tools it is handed cannot. This server hands out prices and nothing else, and no order-placement code exists in it to be tricked into running.
- Tests
- 285
- Python
- 3.11 to 3.13
- Release
- v0.1.0
The demo, as it really ran
$ uv run python examples/agent_session.py
QUOTEZ over an in-memory MCP client, source=replay.
Every price below is generated. This repository bundles no real market data.
>>> list_symbols(group="*FX*")
{
"source": "replay",
"synthetic": true,
"count": 2,
"symbols": [
{"name": "SYNTH_FX_ALPHA", "description": "Synthetic FX pair Alpha", "digits": 5, "point": 1e-05},
{"name": "SYNTH_FX_BETA", "description": "Synthetic FX pair Beta", "digits": 3, "point": 0.001}
]
}
>>> get_quote(symbol="SYNTH_FX_ALPHA")
{
"symbol": "SYNTH_FX_ALPHA",
"time": "2026-06-12T13:59:00Z",
"bid": 1.08044,
"ask": 1.08056,
"spread_points": 12,
"source": "replay",
"synthetic": true
}
>>> get_bars(symbol="SYNTH_FX_ALPHA", timeframe="H1", count=5)
{
"symbol": "SYNTH_FX_ALPHA",
"timeframe": "H1",
"source": "replay",
"synthetic": true,
"count": 5,
"bars": [
{"time": "2026-06-12T08:00:00Z", "open": 1.07985, "high": 1.08231, "low": 1.07978, "close": 1.08125, "tick_volume": 4257, "spread": null},
{"time": "2026-06-12T09:00:00Z", "open": 1.08125, "high": 1.0844, "low": 1.08113, "close": 1.08302, "tick_volume": 2501, "spread": null},
{"time": "2026-06-12T10:00:00Z", "open": 1.08302, "high": 1.08439, "low": 1.08298, "close": 1.08368, "tick_volume": 1643, "spread": null},
{"time": "2026-06-12T11:00:00Z", "open": 1.08368, "high": 1.08395, "low": 1.08036, "close": 1.08097, "tick_volume": 1570, "spread": null},
{"time": "2026-06-12T12:00:00Z", "open": 1.08097, "high": 1.08284, "low": 1.08084, "close": 1.08159, "tick_volume": 2589, "spread": null}
]
}
The remaining 29 lines of the same run
>>> symbol_info(symbol="SYNTH_FX_ALPHA")
{
"name": "SYNTH_FX_ALPHA",
"description": "Synthetic FX pair Alpha",
"digits": 5,
"point": 1e-05,
"spread": 12,
"spread_float": true,
"trade_stops_level": 10,
"trade_freeze_level": 0,
"trade_tick_value": 1.0,
"trade_tick_size": 1e-05,
"trade_contract_size": 100000.0,
"volume_min": 0.01,
"volume_max": 100.0,
"volume_step": 0.01,
"currency_base": "SYA",
"currency_profit": "SYN",
"currency_margin": "SYA",
"source": "replay",
"synthetic": true
}
A symbol that does not exist, to show what the model actually sees:
>>> get_quote(symbol="NOT_A_SYMBOL")
is_error: true
Error executing tool get_quote: Symbol 'NOT_A_SYMBOL' is not available on this server.
Output captured on 2026-08-30. It is committed to the repository and a test fails when it stops matching a live run, so this page cannot quietly drift from the code it describes.
Read it
- Source on GitHub the README carries the argument in full
- The whole toolset what these sixteen repositories argue together, and why there are sixteen
- Release v0.1.0 changelog and tag
The rest of the toolset
- QUACKZ deflating a backtest that only looks good because it was picked out of two hundred
- QUELLZ measuring what prompt-injection containment costs in utility as well as in attack rate
- QUIDZ refusing the outbound payment that would have gone out twice
- QUESTZ stopping a scraper before it writes a CSV from a page that changed shape
- QUIZZ answering what a statistic said at the time, and refusing when it cannot
- QUARANTINEZ treating an outcome the venue never confirmed as terminal rather than as a retry
- QUENCHZ deciding in the open what a tool server gets free while it is still somebody's subprocess
- QUILTZ proving infrastructure code wrong without a cloud account, and saying what that cannot show
- QUAYZ telling a crash loop from an OOMKill, and naming the failure that no single field finds
- QUARRYZ keeping every version a statistical office published, and failing the build when it quietly issues another
- QUASHZ refusing a row whose outcome had not been decided yet when the decision would have been made
- QUALMZ a fixed number of looks at the holdout, where re-running the same configuration does not buy another
- QUEUEZ ordering a feed by its sequence, because on a real recorded session the clock goes backwards
- QUANDARYZ counting the distinct screens a component can settle into when its responses arrive out of order
- QUIETZ watching whether the data arrived rather than whether the server answered