QUOTEZ
QUOTEZ
에이전트를 위한 시장 데이터. 구성이 아닌 설계에 의해 읽기 전용.
MetaTrader 5 시장 데이터를 LLM 에이전트가 호출할 수 있는 타입화된 읽기 전용 도구로 노출하는 MCP 서버입니다. Python 3.11 이상, 하나의 런타임 종속성, stdio 전송. 배지는 3.13에서 멈추는데, 이는 분류기가 거기까지이기 때문입니다. CI는 3.14 레그도 실행하며, 이는 권고 사항으로 표시되어 있으며, 3.14는 충분히 오랫동안 녹색이어서 희망이 아닌 약속이 되면 배지에 합류합니다.
에이전트는 당신이 건네주는 도구만큼만 좋으며, 시장 데이터는 조잡한 도구가 실제 피해를 입히는 곳입니다. 모델은 도구가 반환하는 모든 것을 사실로 재진술하므로, 단위, 시간대, 출처가 없는 페이로드는 누군가가 행동할 수 있는 가격에 대한 확신에 찬 문장이 됩니다. QUOTEZ는 텍스트 덩어리 대신 생성된 출력 스키마, 모든 곳에서 UTC, 모든 페이로드에 synthetic 플래그, 코드에 쓰기 경로가 없음으로 응답합니다.
이것은 피해를 입힐 수 없도록 구축된 하나의 도구로, 에이전트 전체가 도구를 신뢰할 수 있는지 여부보다 더 작고 확인 가능한 질문입니다. 그 더 큰 질문은 QUELLZ의 몫입니다.
범위와 한계
읽기 전용:
order_send없음,order_check없음,symbol_select없음, 모든 종류의 쓰기 없음.실시간 MetaTrader 데이터는 Windows와 실행 중인 터미널이 필요합니다. 휠은 win_amd64 전용입니다.
기본 소스는 생성된 데이터를 재생하고 모든 페이로드에
synthetic: true를 레이블링합니다.시간은 UTC이며 모든 막대는 해당 간격의 왼쪽 가장자리인 시작가로 레이블링됩니다.
예시 에이전트 세션
실제 출력, 붙여넣기가 아닙니다. uv run python examples/agent_session.py로 재생성하십시오. tests/test_readme.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}
]
}
>>> 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.빠른 시작
하나의 명령, 구성할 것 없음, MetaTrader 설치 불필요:
uvx --from git+https://github.com/PNX89/QUOTEZ quotez --source replayQUOTEZ는 PyPI에 게시되지 않았으므로 git 형태가 설치입니다. 참조를 고정하려면 @main, 태그 또는 커밋을 추가하십시오. uv의 종속성 문서를 참조하십시오. 그러면 멈춘 것처럼 보이는데, 이는 표준 출력이 JSON-RPC 와이어이고 호스트가 이를 구동하기 때문입니다. 호스트 없이 작동하는 것을 보려면 저장소를 클론하고 예시 세션을 실행하십시오. 이 세션은 동일한 서버를 프로세스 내 클라이언트에서 구동합니다:
git clone https://github.com/PNX89/QUOTEZ && cd QUOTEZ
uv run python examples/agent_session.pyWindows에서, 이미 실행 중이고 로그인된 터미널을 대상으로:
uvx --from "quotez[mt5] @ git+https://github.com/PNX89/QUOTEZ" quotez --source mt5콘솔 스크립트는 플래그를 받는 유일한 진입점이며, 플래그가 환경 변수보다 우선합니다. mcp run src/quotez/server.py는 모듈 수준의 mcp 전역을 통해 이 서버도 제공하지만, 아무것도 전달하지 않으므로 해당 경로는 변수를 읽습니다.
플래그 | 환경 변수 | 기본값 | 의미 |
|
|
|
|
|
| 비어 있음 | 쉼표로 구분된 화이트리스트, 대소문자 구분 안 함. 비어 있으면 소스가 가진 모든 것을 노출 |
|
|
| 한 번 호출로 반환할 수 있는 최대 막대 수, 1~5000 |
|
|
| 로깅 임계값. 레코드는 항상 stderr로 이동합니다. 표준 출력은 와이어이기 때문입니다. |
호스트에 연결하기
호스트들은 구성 키에 대해 일치하지 않으며, mcpServers와 servers를 잘못 사용하는 것이 서버가 나타나지 않는 일반적인 이유입니다.
호스트 | 파일 | 키 |
Claude Desktop | macOS에서 |
|
Cursor |
|
|
VS Code |
|
|
Claude Code | 파일 없음, CLI 사용 |
|
{
"mcpServers": {
"quotez": {
"command": "/absolute/path/to/uv",
"args": ["tool", "run", "--from", "git+https://github.com/PNX89/QUOTEZ",
"quotez", "--source", "replay"]
}
}
}command는 which uv의 절대 경로여야 합니다. 호스트는 거의 빈 PATH로 서버를 생성하므로, uv만 적는 것이 서버가 조용히 연결에 실패하는 가장 흔한 이유입니다.
도구
8개의 도구가 이 순서로 등록되며, 이는 tools/list가 반환하는 순서입니다. 클라이언트는 그 목록을 캐시하므로 순서는 의도적으로 고정됩니다. 하나의 리소스 symbols://list는 application/json과 동일한 악기 유니버스를 제공합니다.
도구 | 인수 | 반환 | 접근 | 재생 소스 | MetaTrader 소스 |
|
|
| 읽기 | 4개의 생성된 악기 |
|
|
|
| 읽기 | 마지막 저장된 막대에서 파생 |
|
|
|
| 읽기 | M1을 로컬에서 롤업 |
|
|
|
| 읽기 | M1을 로컬에서 롤업 |
|
|
|
| 읽기 |
|
|
| 없음 |
| 읽기 | 자리 표시자 수치, |
|
| 없음 |
| 읽기 | 항상 비어 있음 |
|
| 없음 |
| 읽기 | 항상 비어 있음 |
|
list_symbols는 자체 구문을 발명하는 대신 MetaTrader 자체 그룹 필터 구문을 사용합니다: 패턴의 시작과 끝에 * 와일드카드, 쉼표로 구분된 조건, 부정을 위한 !. 포함은 제외보다 먼저 와야 하므로, "*, !*USD*"는 USD 악기를 제외한 모든 것이고 "!*USD*, *"는 모든 것과 일치합니다. Mt5Source는 문자열을 symbols_get에 전달합니다. 재생 소스는 quotez.groups를 통해 동일한 구문을 실행하므로 둘 다 필터를 동일하게 응답합니다.
모든 도구는 Pydantic 모델을 반환하므로, SDK는 반환 주석에서 outputSchema를 파생하고, structuredContent를 채우며, 서버를 떠나기 전에 페이로드를 검증합니다. BaseModel은 래핑되지 않은 상태로 사용되므로, get_bars가 {"result": ...} 대신 bars 키가 있는 객체를 반환하는 이유입니다.
작동 방식
flowchart LR
host["MCP host<br/>Claude Desktop, Cursor, VS Code"]
server["quotez.server<br/>8 tools, 1 resource"]
proto["MarketDataSource<br/>Protocol"]
replay["ReplaySource<br/>bundled CSVs, any OS"]
mt5["Mt5Source<br/>Windows only, lazy import"]
term["MetaTrader 5 terminal"]
host -- "JSON-RPC over stdio" --> server
server --> proto
proto --> replay
proto --> mt5
mt5 -- "read calls only" --> termMarketDataSource는 전체 서버가 작성된 이음매입니다. 그 위에는 아무것도 MetaTrader5를 임포트하지 않으며, Mt5Source는 모듈 임포트 시가 아니라 첫 사용 시 개인 헬퍼 내에서 확장을 해결하므로, import quotez는 휠이 없는 곳에서도 작동합니다. 이것이 ReplaySource를 모의 객체 대신 일급 구현으로 만드는 이유입니다: 도구 계층은 둘을 구분할 수 없으므로, 전체 스위트는 터미널이 설치되지 않은 상태에서 실제 코드 경로를 실행합니다.
번들 데이터는 4개의 생성된 악기(SYNTH_FX_ALPHA, SYNTH_FX_BETA, SYNTH_IDX_GAMMA, SYNTH_MTL_DELTA), 각각 3600개의 M1 막대, 2026-06-01부터 2026-06-12까지 평일 08:00~14:00 UTC, 9개의 세션 중단(8개는 야간, 1개는 주말)이 포함되어 있습니다. 간격이 없는 시리즈는 집계 버그를 숨기는 시리즈이기 때문입니다. scripts/generate_replay_data.py는 시드된 random.Random에서 파일을 한 번 생성했으며 출력은 커밋되었습니다. CSV는 importlib.resources를 통해 읽히며, Path(__file__).parent를 사용하지 않습니다. 이는 체크아웃에서는 작동하지만 uvx가 수행하는 압축된 설치에서는 깨집니다.
도구와 리소스는 같은 것이 아닙니다
도구는 모델이 호출하기로 결정하는 것입니다. 리소스는 애플리케이션이 로드하기로 결정하는 것입니다. get_bars는 모델 주도적입니다: 추론 중간에 심볼, 시간대, 개수를 선택합니다. symbols://list는 애플리케이션 주도적입니다: 호스트는 모델이 아무것도 결정하기 전에 한 번 유니버스를 컨텍스트에 고정합니다. 이것이 list_symbols의 우연한 중복이 아닌 이유이며, list_symbols는 모델이 의도적으로 실행하는 필터링된 검색입니다.
명백한 다음 리소스인 bars://{symbol}/{timeframe}는 의도적으로 구축되지 않았습니다: 동일한 데이터에 대해 get_bars를 중복하며, 자리 표시자가 있는 URI는 리소스 템플릿이므로 resources/list를 resources/templates/list로 남기고 많은 호스트에서 제대로 표시되지 않거나 전혀 표시되지 않습니다. 테스트는 리소스 템플릿이 등록되지 않았음을 단언합니다.
시간대 집계
재생 소스는 하나의 기본 시간대 M1을 저장하며, quotez.aggregate는 M5, M15, M30, H1, H4 및 D1을 롤업합니다. 하나의 저장된 복사본, 하나의 롤업, 자체적으로 테스트 가능합니다. 이는 실패 모드가 조용하기 때문에 중요합니다: 잘못된 집계는 영원히 그럴듯한 숫자를 반환하며 절대 예외를 발생시키지 않습니다.
MetaTrader 소스는 아무것도 롤업하지 않습니다. 터미널은 이미 모든 기간을 보유하고 있으므로 직접 시간대를 요청받습니다. M1에서 다시 파생하는 것은 더 느리고 운영자가 열어둔 차트와 일치하지 않을 것입니다. 따라서 두 소스는 D1, H4 및 spread에 대해 동일한 호출에 약간 다르게 응답하며, 이는 한계(Limitations)에 있으며 여러분이 찾도록 남겨두지 않습니다.
롤업의 불변성, 각각은 테스트 이름입니다:
M1이 유일한 기본 시간대(timeframe)입니다. 그보다 큰 모든 시간대는 이로부터 파생됩니다.
버킷(bucket)은 벽시계(wall clock) 기준이며, 에포크 초(epoch second)를 바닥 나눗셈(floor division)하여 계산되며, 절대 N개의 행을 위치적으로 그룹화하지 않습니다.
대상(target)은 60초의 정수 배입니다. 그 외의 값은
InvalidRequest를 발생시킵니다.OHLC는 첫 번째 시가(first open), 최대 고가(max high), 최소 저가(min low), 마지막 종가(last close)입니다.
tick_volume은 합산됩니다.spread는 그렇지 않습니다. 이는 호가(quote)의 시점 속성(point in time property)이므로, 집계된 봉(bar)은null을 보고합니다.봉은 UTC 기준 왼쪽 가장자리(left edge)로 레이블이 지정됩니다.
완성되지 않은 마지막 버킷(trailing bucket)은 부분 봉(partial bar)으로 내보내지지 않고 버려집니다. 버킷은 입력에 해당 버킷의 종료 시점 이후의 봉이 있을 때만 내보내집니다.
빈 입력은 빈 리스트를 반환합니다.
불변 조건 2(Invariant 2)는 그 자체로 테스트를 받을 자격이 있습니다. 위치적 그룹화(positional grouping)는 간격 없는 시리즈(gapless series)에서는 벽시계 버킷팅과 일치하지만, 구멍(hole)이 생기는 순간 불일치합니다. 즉, 360개의 봉 세션을 4개씩 그룹화하면 금요일 종가와 월요일 시가가 하나의 봉에 포함되어 4시간 캔들(candle)이 됩니다. 불변 조건 7은 이와 짝을 이루는데, 세션 종료는 데이터가 소진되는 것과 같은 사건이 아니기 때문입니다.
안전 설계(Safety design)
이 주장은 구조적(structural)이며 설정 가능한(configurable) 것이 아닙니다. 이 코드베이스에는 쓰기 경로(write path)가 없습니다. src/quotez/ 어디에도 order_send, order_check, symbol_select, MarketWatch 변형, 파일 쓰기가 없습니다. 어떤 설정으로도 쓰기를 활성화할 수 없습니다. 활성화할 대상 자체가 없기 때문입니다.
두 개의 테스트가 이를 유지하며, 두 번째 테스트가 의미 있는 것입니다. 첫 번째 테스트는 패키지에서 해당 세 가지 MetaTrader 호출을 grep합니다. 저렴하고 모든 파일을 대상으로 하며, 런타임에 조합된 이름으로도 만족됩니다. 두 번째 테스트는 mt5source.py의 AST를 탐색하여 긍정 속성(positive property)을 대신 단언합니다. 즉, 이 패키지가 터미널 모듈에서 읽어오는 속성 집합이 정확히 자체 독스트링(docstring)에 명명된 읽기 호출과 7개의 시간대 상수이며, getattr을 통해 접근되거나 두 번째 변수에 재바인딩된 것이 없다는 것입니다. _mt5()는 전체 MetaTrader5 모듈을 반환하므로, 수백 개의 속성 중 세 개의 이름이 없다는 것만으로는 거의 증명되지 않습니다. 이 탐색을 검증하기 위해 의도적으로 잘못된 5개의 코드 조각(snippet)을 검사하여, 탐색 자체가 실패해야 할 때 실패하는지 확인합니다.
모든 도구는 ToolAnnotations(read_only_hint=True, open_world_hint=False)로 선언됩니다. 이 선언은 클라이언트에 대한 예의일 뿐 그 이상은 아닙니다. MCP 사양은 클라이언트에게 신뢰할 수 있는 서버에서 오지 않은 도구 주석(tool annotation)을 신뢰하지 말라고 지시합니다. read_only_hint=True는 도구를 설명할 뿐, 클라이언트를 제한하지 않으며, 검토자가 확인할 수 있는 속성은 플래그의 존재 여부보다는 호출 자체의 부재입니다. 이를 사양 자체의 도구에 대한 보안 고려 사항(Security Considerations for tools)에 매핑하면, 이 서버가 충족하지 않는 요구 사항을 포함한 표는 다음과 같습니다.
사양 요구 사항(Specification requirement) | QUOTEZ | 위치(Where) |
모든 도구 입력 검증(Validate all tool inputs) | 예(Yes) | 타입 힌트, |
적절한 접근 제어 구현(Implement proper access controls) | 예(Yes) | 심볼 화이트리스트는 모든 도구와 리소스에 적용되며, 게터(getter)에만 적용되지 않습니다. |
도구 호출 속도 제한(Rate limit tool invocations) | 아니오(No) | 구현되지 않았으며, 제한 사항(Limitations)에 나열되어 있습니다. stdio 서버는 정확히 하나의 호스트의 자식 프로세스이므로, 호스트가 속도 제한을 소유합니다. |
도구 출력 정화(Sanitize tool outputs) | 예(Yes) | 계정 로그인은 마지막 네 자리로 마스킹되고, 브로커, 서버 및 계정 소유자 이름은 절대 반환되지 않으며, |
차단된 심볼은 SymbolNotFound로 보고되며, 오타가 발생했을 때의 메시지인 "Symbol 'X' is not available on this server."와 동일한 메시지가 표시됩니다. "허용되지 않음"이라는 별도의 메시지는 운영자가 노출하지 않기로 선택한 상품에 대한 발견 오라클(discovery oracle)이 될 수 있습니다.
오류는 두 가지 채널 중 하나를 사용하며, 더 똑똑한 모델이 실패를 피할 수 있었는지 여부에 따라 선택됩니다. 철자가 틀린 심볼은 그럴 수 있으므로, SymbolNotFound와 InvalidRequest는 일반 예외(ordinary exception)이며, 이는 모델이 읽고 재시도할 수 있는 도구 오류(tool error)가 됩니다. 실행 중이 아닌 터미널은 그럴 수 없으므로, SourceUnavailable은 MCPError로 발생하며, 결과가 전혀 없는 프로토콜 오류(protocol error)입니다. 여기서는 오류 문자열을 반환하지 않습니다. 반환된 문자열은 is_error=False를 가지며 성공적인 응답으로 읽힙니다. 테스트는 모든 도구를 잘못된 입력으로 호출하고 플래그를 단언합니다.
설계 결정(Design decisions)
mcp>=2.0.0,<3 및 MCPServer, v1 핀과 FastMCP가 아닙니다. SDK는 여전히 마이그레이션하지 않은 사람들을 위해 mcp>=1.28,<2를 제공하지만, v1 시대 서버는 3초 만에 스스로를 드러냅니다. from mcp.server.fastmcp import FastMCP. 마이그레이션 가이드에 이름 변경 사항이 있습니다. 저수준 Server는 대안이었지만 더 이상 반환 값을 자동으로 래핑하지 않으므로, 8개의 도구에 대해 JSON Schema를 직접 작성해야 했습니다.
타입이 지정된 Pydantic 반환, 텍스트 블롭(text blob)이 아닙니다. 대부분의 공개 MCP 서버는 산문(prose)을 반환하고 모델이 이를 구문 분석하도록 둡니다. 여기서 반환 주석(return annotation)은 출력 스키마이므로, 타입이 지정되면 비용이 들지 않고 서버에서 페이로드가 나가기 전에 검증을 제공합니다.
두 개의 봉 도구, 선택적 인수가 있는 하나가 아닙니다. JSON Schema는 상호 배타성(mutual exclusivity)을 표현할 수 없으므로, 단일 get_bars(count or start..end)는 "둘 중 하나지만 둘 다는 아님"이라는 제약을 산문으로 모델에 전가하게 됩니다. 두 개의 도구는 완전히 유효한 두 개의 스키마를 가지며, "둘 다 제공됨, 둘 다 제공되지 않음" 오류 클래스는 존재하지 않습니다.
생성된 데이터(Generated data), 실제 피드(real feed)가 아닙니다. 라이선스 결정이지 선호도가 아닙니다. MetaTrader 내보내기는 브로커의 라이선스 피드이며, 지수 및 주식 CFD의 경우 기초 자산은 거래소 라이선스입니다. Yahoo의 도움말 페이지는 명시적으로 "Yahoo Finance에 표시되거나 제공되는 정보를 재배포해서는 안 됩니다"라고 제한하며, 개발자 API 약관은 별도로 접근 권한 판매 또는 서브라이선스를 제한합니다. HistData의 FAQ는 재배포 권한을 전혀 부여하지 않으며, 데이터에 보증이 없으며, 침묵은 라이선스가 아니라고만 명시합니다. 이 중 어떤 것이라도 MIT 저장소에 커밋하면 재라이선스할 권리가 없는 데이터를 재라이선스하는 것입니다.
표준 라이브러리(Standard library), pandas나 numpy가 아닙니다. 번들 CSV 규모에서는 csv와 datetime, 데이터클래스(dataclasses)로 충분하며 트리는 감사 가능한 상태를 유지합니다. 하지만 그 트리를 정직하게 명명할 가치가 있습니다. 즉, mcp 2.x는 anyio, httpx2, jsonschema, mcp-types, opentelemetry-api, pydantic, pyjwt(암호화 확장 포함), python-multipart, sse-starlette, starlette, typing-extensions, typing-inspection 및 uvicorn을 가져오는 하나의 직접 종속성이며, Windows에서는 pywin32도 추가됩니다. 암호화 확장은 cryptography, cffi 및 pycparser를 뒤따라 가져옵니다. 이는 v1보다 더 큰 설치 공간이며, 테스트는 커밋된 uv.lock을 읽고 이 목록이 더 이상 일치하지 않으면 실패합니다. 트리를 명명하기 위해 존재하는 문단이 트리의 대부분만 명명한다면 아무 가치가 없기 때문입니다.
run_backtest 도구 없음. 백테스트(backtest)는 계산량이 무제한이며, MarketDataSource 이상이 필요하고 QUACKZ를 중복하게 되므로, 두 개는 두 개의 집중된 프로젝트가 아닌 두 개의 절반짜리 프로젝트로 읽힐 것입니다. 같은 이유로 여기의 안전장치(guardrail)는 도메인 로컬(domain local)입니다. 즉, 입력 검증, 제한된 쿼리, 고정된 상품 범위(instrument universe), 부작용 없음입니다. 일반 에이전트 안전장치는 QUELLZ에 속하며, 다섯 번 재발명되지 않아야 합니다.
제한 사항(Limitations)
실시간 MetaTrader 경로를 실행하는 지속적 통합(CI) 실행기가 어디에도 없습니다. 비 Windows 휠(wheel)이 없으며, 터미널이나 브로커 계정이 있는 실행기도 없습니다. Windows 작업은 확장이 임포트되고
Mt5Source가 누락된 터미널을 깔끔하게 보고한다는 것만 증명하며, 그게 전부입니다.Mt5Source의 필드 매핑은 여기서 가장 적게 실행되는 코드이며, 가짜 모듈 테스트(fake module test)로 다루어집니다.MetaTrader5는 Windows 전용이며 소스 배포판을 게시하지 않으므로,pip install quotez[mt5]는 macOS와 Linux에서 의도적으로 아무 작업도 하지 않습니다. 테스트는 환경 마커(environment marker)가 그렇게 유지되도록 단언합니다.initialize()는 터미널이 이미 실행 중이 아니면 실행하고, 전체 작업은timeout인수로 제한되며 기본값은 60000밀리초로 문서화되어 있습니다. 페이지는 실행 자체에 대한 수치를 제시하지 않으므로, 60초를 측정된 시작 시간이 아닌 호출의 상한으로 간주하십시오. QUOTEZ는 연결을 호출당 한 번이 아닌 서버 수명 주기(lifespan) 동안 한 번 열므로, 비용이 발생하더라도 첫 번째 도구 호출이 중단된 것처럼 보이지 않고 시작 시 발생합니다.두 소스는 D1 또는 H4 버킷이 시작되는 위치에 대해 일치하지 않습니다. 리플레이 롤업(replay roll up)은 에포크 초를 바닥 처리하므로, D1은 00:00 UTC에, H4는 00, 04, 08, 12, 16 및 20 UTC에 시작됩니다. MetaTrader 터미널은 D1과 H4를 브로커의 서버 일(server day)에 맞추며, 일반적으로 UTC+2 또는 UTC+3이므로, 동일한
get_bars(symbol, "D1")는 어떤 소스가 구성되었는지에 따라 다른 시작 시간과 다른 OHLC를 가진 캔들을 반환합니다. 여기서는 터미널의 M1을 리샘플링하여 이를 숨기지 않습니다. 운영자 자신의 차트와 일치하지 않는 봉은 문서화된 오프셋보다 더 나쁘기 때문입니다.같은 이유로,
spread는 M1 이상의 모든 리플레이 봉에서 null이고 모든 MetaTrader 봉에서 설정됩니다. 롤업은 의도적으로 이를 지웁니다. 터미널은 모든 시간대에서 자체 값을 보고하며, QUOTEZ는 소스가 제공한 데이터를 버리지 않고 그대로 전달합니다.copy_rates_from_pos및copy_rates_range는 터미널의 "차트의 최대 봉 수(Max. bars in chart)" 설정에 의해 자동으로 제한되므로, 서버 자체 제한 내의 요청이라도 여전히 부족하게 반환될 수 있으며 MetaTrader API에서는 이에 대해 아무 말도 하지 않습니다.get_bars는 터미널이 아직 구축 중인 봉을 건너뛰므로, 가장 최신 봉은 항상 종료된(closed) 것입니다.get_bars_range는 그렇지 않습니다. 범위는 호출자의 것이기 때문입니다. 현재 구간 내에 있는end는 해당 구간의 부분 봉을 반환합니다.symbol_info()는 알 수 없는 심볼에 대해 예외를 발생시키는 대신None을 반환하며, 오류 시symbols_get()도 마찬가지입니다. 여기 모든 호출 지점에서 확인하지만, 이는 래핑되는 API의 형태입니다.MetaTrader는 봉 및 틱(tick) 시간을 이동 없이 UTC로 저장하는 반면, 순진한(naive) Python
datetime은 로컬 시간대에 대해 해석됩니다. copy_rates_range 문서에 명시되어 있습니다. 모든 발신 타임스탬프는tz=UTC로 구축되며 순진한 입력은 거부되지만, 이것이 전체 시리즈를 조용히 한 시간 이동시키는 함정입니다.속도 제한 없음. stdio 서버는 하나의 호스트의 자식 프로세스이며, 호스트가 이를 소유합니다.
리플레이 데이터는 샘플 규모이며 생성된 것입니다. 4개 상품, 각각 3600개의 M1 봉, 10거래일. 도구를 시연하고 집계를 테스트하며, 연구 데이터 세트나 시장이 아닙니다.
버전 0.1.0은 읽기 전용이며 stdio 전용이고, 프롬프트(prompts) 기능, SSE 또는 스트리밍 가능 HTTP 전송, OAuth가 없습니다.
왜 이걸 만들었는가(Why I built this)
저는 인덱스 데이터에 대해 워크 포워드 리서치를 실행하고, FX 및 금속 쪽을 위해 MetaTrader 터미널을 유지하고 있어서, 이 두 부분 모두 이미 제 책상 위에 있었습니다. 이 글을 쓰게 된 계기는 에이전트가 잘못 입력된 도구의 숫자를 마치 사실인 양 다시 말하는 것을 보면서였습니다. 단위도, 시간대도, 출처도 없이요. 시장 데이터에서 이는 단순한 외형적 문제가 아닙니다: 종가 대신 시가로 표시된 봉, 또는 타임스탬프가 조용히 현지 시간으로 변경된 경우, 올바르게 보이는 답을 주지만 한 시간 차이가 납니다. 따라서 이는 주로 출처와 도구가 주장할 수 있는 것에 대한 결정이며, 약간의 집계 코드로 감싸져 있습니다.
Development
uv sync --dev
uv run pytest
uv run ruff check .
uv run ruff format --check .
uv run mypy251개의 테스트, 네트워크 없음, 몇 초 소요, macOS, Linux 및 Windows에서 동일합니다. 그 숫자는 실제 수집 실행에 대해 검증된 것입니다. README에 있는 숫자는 아무도 업데이트하지 않는 숫자이기 때문입니다.
License
MIT. LICENSE를 참조하십시오.
Q...Z 도구 세트의 일부로, 스스로를 알리지 않는 실패를 위한 다섯 가지 도구:
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server exposing the Backtest360 engine API as tools for AI agents.
Connect any MCP client to MetaTrader 4/5 to read prices, manage positions, and place trades.
Agent-native crypto market-data over MCP+REST: order flow, whales, liquidations, calibrated scores
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/PNX89/QUOTEZ'
If you have feedback or need assistance with the MCP directory API, please join our Discord server