mt5api 0.0.4__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/local-qa/SKILL.md +1 -1
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/local-qa/scripts/qa.sh +1 -1
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/mt5api/SKILL.md +73 -2
- {mt5api-0.0.4 → mt5api-0.2.0}/.github/workflows/ci.yml +1 -22
- mt5api-0.2.0/.github/workflows/release.yml +44 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/AGENTS.md +4 -2
- {mt5api-0.0.4 → mt5api-0.2.0}/PKG-INFO +33 -8
- {mt5api-0.0.4 → mt5api-0.2.0}/README.md +32 -6
- {mt5api-0.0.4 → mt5api-0.2.0}/docs/api/deployment.md +0 -2
- {mt5api-0.0.4 → mt5api-0.2.0}/docs/api/rest-api.md +21 -11
- {mt5api-0.0.4 → mt5api-0.2.0}/docs/index.md +3 -3
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/config.py +0 -22
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/constants.py +0 -4
- mt5api-0.2.0/mt5api/dependencies.py +236 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/main.py +13 -55
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/middleware.py +1 -54
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/models.py +56 -0
- mt5api-0.2.0/mt5api/routers/__init__.py +16 -0
- mt5api-0.2.0/mt5api/routers/connection.py +72 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/routers/market.py +2 -2
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/routers/trading.py +4 -4
- {mt5api-0.0.4 → mt5api-0.2.0}/pyproject.toml +1 -2
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_config.py +0 -28
- mt5api-0.2.0/tests/test_connection.py +467 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_main.py +22 -27
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_middleware.py +0 -24
- {mt5api-0.0.4 → mt5api-0.2.0}/uv.lock +62 -159
- mt5api-0.0.4/mt5api/dependencies.py +0 -132
- mt5api-0.0.4/mt5api/routers/__init__.py +0 -7
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-analyze/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-checklist/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-clarify/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-constitution/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-implement/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-plan/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-specify/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-tasks/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.agents/skills/speckit-taskstoissues/SKILL.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/agents/codex.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/agents/copilot.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.analyze.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.checklist.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.clarify.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.constitution.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.implement.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.plan.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.specify.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.tasks.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/commands/speckit.taskstoissues.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.claude/settings.json +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.github/FUNDING.yml +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.github/dependabot.yml +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.github/renovate.json +0 -0
- /mt5api-0.0.4/.github/workflows/claude-code.yml → /mt5api-0.2.0/.github/workflows/claude.yml +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.gitignore +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/memory/constitution.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/scripts/bash/check-prerequisites.sh +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/scripts/bash/common.sh +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/scripts/bash/create-new-feature.sh +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/scripts/bash/setup-plan.sh +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/scripts/bash/update-agent-context.sh +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/templates/agent-file-template.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/templates/checklist-template.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/templates/plan-template.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/templates/spec-template.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/.specify/templates/tasks-template.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/CLAUDE.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/LICENSE +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/docs/api/index.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mkdocs.yml +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/__init__.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/__main__.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/auth.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/formatters.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/routers/account.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/routers/calc.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/routers/health.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/routers/history.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/mt5api/routers/symbols.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/041-mt5-rest-api/contracts/openapi.yaml +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/041-mt5-rest-api/data-model.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/041-mt5-rest-api/plan.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/041-mt5-rest-api/quickstart.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/041-mt5-rest-api/research.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/041-mt5-rest-api/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/041-mt5-rest-api/tasks.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/042-mt5-core-client/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/043-mt5-dataframe-client/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/044-mt5-trading-client/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/045-mt5-utils/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/046-mt5-api-service/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/047-api-auth-rate-limit/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/048-api-response-format/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/049-api-routing-models/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/050-api-runtime-deploy/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/051-api-error-logging/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/specs/052-api-dependencies/spec.md +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/__init__.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/conftest.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/mt5_constants.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_account.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_auth.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_calc.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_cli.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_dependencies.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_formatters.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_health.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_history.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_integration.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_lifespan.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_market.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_models.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_symbols.py +0 -0
- {mt5api-0.0.4 → mt5api-0.2.0}/tests/test_trading.py +0 -0
|
@@ -3,8 +3,8 @@ name: mt5api
|
|
|
3
3
|
description: >-
|
|
4
4
|
Query the MT5 API for account info, terminal status, health checks, symbol
|
|
5
5
|
data, market data (OHLCV rates, ticks, market depth), open positions, pending
|
|
6
|
-
orders,
|
|
7
|
-
endpoint.
|
|
6
|
+
orders, trade history, and reconnecting the MT5 terminal with new
|
|
7
|
+
credentials. Use when the user wants to interact with any mt5api endpoint.
|
|
8
8
|
allowed-tools: Bash
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -30,6 +30,16 @@ if [ -n "${MT5API_SECRET_KEY:-}" ]; then
|
|
|
30
30
|
fi
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
Login credentials for `/connection/login` are read from the environment so
|
|
34
|
+
the password is never hard-coded in a command:
|
|
35
|
+
|
|
36
|
+
| Variable | Description | Required for login |
|
|
37
|
+
| ----------------- | ------------------------------------------ | ------------------ |
|
|
38
|
+
| `MT5API_LOGIN` | Trading account login (integer) | yes |
|
|
39
|
+
| `MT5API_PASSWORD` | Trading account password | yes |
|
|
40
|
+
| `MT5API_SERVER` | Trading server name (e.g., `Broker-Demo`) | yes |
|
|
41
|
+
| `MT5API_TIMEOUT` | Connection timeout in milliseconds (`> 0`) | no |
|
|
42
|
+
|
|
33
43
|
## Response Formats
|
|
34
44
|
|
|
35
45
|
All endpoints (except `/health`) return JSON by default. Request Parquet with
|
|
@@ -44,6 +54,11 @@ All endpoints (except `/health`) return JSON by default. Request Parquet with
|
|
|
44
54
|
symbol or skipping DOM data.
|
|
45
55
|
- Empty arrays from `/positions`, `/orders`, `/history/orders`, or
|
|
46
56
|
`/history/deals` are valid results.
|
|
57
|
+
- `/connection/login` reconnects the shared MT5 client to a different account.
|
|
58
|
+
It shuts down the current connection and releases any active market-book
|
|
59
|
+
subscriptions before logging in. Never echo the password back to the user
|
|
60
|
+
and do not log it; the response only confirms `login`, `server`, `timeout`,
|
|
61
|
+
and `connected`.
|
|
47
62
|
|
|
48
63
|
---
|
|
49
64
|
|
|
@@ -77,6 +92,59 @@ curl -s "${AUTH_HEADER[@]}" \
|
|
|
77
92
|
|
|
78
93
|
---
|
|
79
94
|
|
|
95
|
+
## Connection
|
|
96
|
+
|
|
97
|
+
### Reconnect to MT5
|
|
98
|
+
|
|
99
|
+
Shut down the current MT5 client and reconnect with new credentials. Active
|
|
100
|
+
market-book subscriptions are released first. The call is serialized so
|
|
101
|
+
concurrent reconnect attempts do not race. The password is sent only in the
|
|
102
|
+
request body and is never echoed in the response.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Build JSON body from env vars; include timeout only when set
|
|
106
|
+
LOGIN_BODY=$(python3 -c "
|
|
107
|
+
import json, os, sys
|
|
108
|
+
body = {
|
|
109
|
+
'login': int(os.environ['MT5API_LOGIN']),
|
|
110
|
+
'password': os.environ['MT5API_PASSWORD'],
|
|
111
|
+
'server': os.environ['MT5API_SERVER'],
|
|
112
|
+
}
|
|
113
|
+
t = os.environ.get('MT5API_TIMEOUT')
|
|
114
|
+
if t:
|
|
115
|
+
body['timeout'] = int(t)
|
|
116
|
+
print(json.dumps(body))
|
|
117
|
+
")
|
|
118
|
+
curl -s -X POST "${AUTH_HEADER[@]}" \
|
|
119
|
+
-H 'Content-Type: application/json' \
|
|
120
|
+
-d "${LOGIN_BODY}" \
|
|
121
|
+
"${MT5API_URL}/connection/login" | python -m json.tool
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Request body:
|
|
125
|
+
|
|
126
|
+
| Field | Type | Required | Description |
|
|
127
|
+
| -------- | ------ | -------- | ------------------------------------------ |
|
|
128
|
+
| login | int | yes | Trading account login (positive integer) |
|
|
129
|
+
| password | string | yes | Trading account password (never echoed) |
|
|
130
|
+
| server | string | yes | Trading server name (e.g., `Broker-Demo`) |
|
|
131
|
+
| timeout | int | no | Connection timeout in milliseconds (`> 0`) |
|
|
132
|
+
|
|
133
|
+
Successful response (`200`):
|
|
134
|
+
|
|
135
|
+
| Field | Type | Description |
|
|
136
|
+
| --------- | ------ | -------------------------------------------- |
|
|
137
|
+
| login | int | Login that was used to connect |
|
|
138
|
+
| server | string | Trading server that was connected to |
|
|
139
|
+
| timeout | int? | Timeout in milliseconds if one was specified |
|
|
140
|
+
| connected | bool | `true` when the new connection succeeded |
|
|
141
|
+
|
|
142
|
+
On failure, MT5 errors surface as `503 Service Unavailable` with an RFC 7807
|
|
143
|
+
problem-details body. Never include the supplied password in any summary or
|
|
144
|
+
diagnostic you return to the user.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
80
148
|
## Account & Terminal
|
|
81
149
|
|
|
82
150
|
### Account Info
|
|
@@ -323,3 +391,6 @@ Either `(date_from AND date_to)` or `(ticket OR position)` must be provided.
|
|
|
323
391
|
running or reachable.
|
|
324
392
|
9. For historical queries, remind the user that either a date range or a
|
|
325
393
|
ticket/position filter is required.
|
|
394
|
+
10. For `/connection/login`, always send the password in the POST body and
|
|
395
|
+
never repeat it in any reply or log message. If the user asks you to
|
|
396
|
+
reconnect, confirm the target `login`/`server` before sending the request.
|
|
@@ -19,7 +19,6 @@ on:
|
|
|
19
19
|
options:
|
|
20
20
|
- lint-and-test
|
|
21
21
|
- docs-deploy
|
|
22
|
-
- release
|
|
23
22
|
description: Choose the workflow to run
|
|
24
23
|
default: lint-and-test
|
|
25
24
|
permissions:
|
|
@@ -54,10 +53,7 @@ jobs:
|
|
|
54
53
|
python-docs-deploy:
|
|
55
54
|
if: >
|
|
56
55
|
github.event_name == 'push'
|
|
57
|
-
|| (
|
|
58
|
-
github.event_name == 'workflow_dispatch'
|
|
59
|
-
&& (inputs.workflow == 'docs-deploy' || inputs.workflow == 'release')
|
|
60
|
-
)
|
|
56
|
+
|| (github.event_name == 'workflow_dispatch' && inputs.workflow == 'docs-deploy')
|
|
61
57
|
permissions:
|
|
62
58
|
contents: write
|
|
63
59
|
uses: dceoy/gh-actions-for-devops/.github/workflows/python-package-mkdocs-gh-deploy.yml@main # zizmor: ignore[unpinned-uses]
|
|
@@ -66,23 +62,6 @@ jobs:
|
|
|
66
62
|
runs-on: ubuntu-slim
|
|
67
63
|
secrets:
|
|
68
64
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
69
|
-
python-package-release:
|
|
70
|
-
if: >
|
|
71
|
-
github.event_name == 'push'
|
|
72
|
-
|| (
|
|
73
|
-
github.event_name == 'workflow_dispatch'
|
|
74
|
-
&& (inputs.workflow == 'release' || inputs.workflow == 'lint-and-test')
|
|
75
|
-
)
|
|
76
|
-
permissions:
|
|
77
|
-
contents: write
|
|
78
|
-
id-token: write
|
|
79
|
-
uses: dceoy/gh-actions-for-devops/.github/workflows/python-package-release-on-pypi-and-github.yml@main # zizmor: ignore[unpinned-uses]
|
|
80
|
-
with:
|
|
81
|
-
package-path: .
|
|
82
|
-
create-releases: ${{ github.event_name == 'workflow_dispatch' && inputs.workflow == 'release' }}
|
|
83
|
-
secrets:
|
|
84
|
-
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
85
|
-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
86
65
|
dependabot-auto-merge:
|
|
87
66
|
if: >
|
|
88
67
|
github.event_name == 'pull_request' && github.actor == 'dependabot[bot]'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Release
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
permissions:
|
|
6
|
+
contents: read
|
|
7
|
+
defaults:
|
|
8
|
+
run:
|
|
9
|
+
shell: bash -euo pipefail {0}
|
|
10
|
+
working-directory: .
|
|
11
|
+
jobs:
|
|
12
|
+
build-and-release:
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
id-token: write
|
|
16
|
+
uses: dceoy/gh-actions-for-devops/.github/workflows/python-package-release-on-pypi-and-github.yml@main # zizmor: ignore[unpinned-uses]
|
|
17
|
+
with:
|
|
18
|
+
package-path: .
|
|
19
|
+
create-github-release: true
|
|
20
|
+
publish-to-pypi: false
|
|
21
|
+
secrets:
|
|
22
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
23
|
+
publish-to-pypi:
|
|
24
|
+
name: Publish the Python 🐍 distribution 📦 to PyPI
|
|
25
|
+
if: >
|
|
26
|
+
startsWith(github.ref, 'refs/tags/')
|
|
27
|
+
needs:
|
|
28
|
+
- build-and-release
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
environment:
|
|
31
|
+
name: pypi
|
|
32
|
+
url: https://pypi.org/p/${{ needs.build-and-release.outputs.project-name }}
|
|
33
|
+
permissions:
|
|
34
|
+
id-token: write # IMPORTANT: mandatory for trusted publishing
|
|
35
|
+
steps:
|
|
36
|
+
- name: Download all the dists
|
|
37
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
38
|
+
with:
|
|
39
|
+
name: ${{ needs.build-and-release.outputs.distribution-artifact-name }}
|
|
40
|
+
path: dist/
|
|
41
|
+
- name: Publish distribution 📦 to PyPI
|
|
42
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
43
|
+
with:
|
|
44
|
+
verbose: true
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
### Package Structure
|
|
32
32
|
|
|
33
33
|
- `mt5api/`: Main FastAPI package.
|
|
34
|
-
- `main.py`: App wiring, lifespan handling, middleware,
|
|
34
|
+
- `main.py`: App wiring, lifespan handling, middleware, and router registration.
|
|
35
35
|
- `__main__.py`: CLI entry point for launching the API from environment-backed configuration.
|
|
36
36
|
- `config.py`: Environment-backed configuration normalization and validation.
|
|
37
37
|
- `auth.py`: Optional API key authentication helpers.
|
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
- Comprehensive linting with 35+ rule categories (ruff)
|
|
51
51
|
- Test coverage tracking with 100% (pytest-cov)
|
|
52
52
|
- Parametrized tests for input/result matrices using `pytest.mark.parametrize` (pytest)
|
|
53
|
+
- Test doubles (mocks, stubs) using `pytest_mock` for external dependencies (pytest-mock)
|
|
54
|
+
- Pydantic models for data validation and configuration
|
|
53
55
|
|
|
54
56
|
## Documentation Workflow
|
|
55
57
|
|
|
@@ -66,7 +68,7 @@
|
|
|
66
68
|
## Security & Configuration Tips
|
|
67
69
|
|
|
68
70
|
- Do not commit real MT5 credentials or API keys.
|
|
69
|
-
- Configure `MT5API_SECRET_KEY`, `
|
|
71
|
+
- Configure `MT5API_SECRET_KEY`, `MT5API_ROUTER_PREFIX`, and `MT5API_LOG_LEVEL` through environment variables.
|
|
70
72
|
- Keep runtime configuration in the environment instead of hardcoding deployment values.
|
|
71
73
|
- Authentication mode is fixed at process startup; cover both authenticated and unauthenticated behavior when changing auth-related code.
|
|
72
74
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mt5api
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: MetaTrader 5 REST API
|
|
5
5
|
Project-URL: Repository, https://github.com/dceoy/mt5api.git
|
|
6
6
|
Author-email: dceoy <dceoy@users.noreply.github.com>
|
|
@@ -24,7 +24,6 @@ Requires-Dist: pdmt5>=0.2.1
|
|
|
24
24
|
Requires-Dist: pyarrow>=18.0.0
|
|
25
25
|
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
26
26
|
Requires-Dist: python-multipart>=0.0.9
|
|
27
|
-
Requires-Dist: slowapi>=0.1.9
|
|
28
27
|
Requires-Dist: uvicorn[standard]>=0.32.0
|
|
29
28
|
Description-Content-Type: text/markdown
|
|
30
29
|
|
|
@@ -36,8 +35,8 @@ MetaTrader 5 REST API
|
|
|
36
35
|
|
|
37
36
|
mt5api exposes MT5 market data, account info, trading history, and trading
|
|
38
37
|
operations over HTTP. It uses the [`pdmt5`](https://github.com/dceoy/pdmt5)
|
|
39
|
-
client internally and adds optional API-key auth
|
|
40
|
-
|
|
38
|
+
client internally and adds optional API-key auth and JSON/Parquet response
|
|
39
|
+
formatting.
|
|
41
40
|
|
|
42
41
|
The API server must run on Windows. The `MetaTrader5` Python package used by
|
|
43
42
|
`pdmt5` is supported only on Windows, so you must host `mt5api` on a Windows
|
|
@@ -52,7 +51,7 @@ graph TB
|
|
|
52
51
|
|
|
53
52
|
subgraph "Windows Host"
|
|
54
53
|
subgraph "FastAPI Application"
|
|
55
|
-
Middleware["Middleware Stack<br/>
|
|
54
|
+
Middleware["Middleware Stack<br/>Logging · Error Handler"]
|
|
56
55
|
Routers["Routers<br/>health · symbols · market · account · history · calc · trading"]
|
|
57
56
|
Auth["API Key Security Dependency<br/>Security(api_key_header) · verify_api_key"]
|
|
58
57
|
Deps["FastAPI Dependencies<br/>MT5 Client Singleton · Format Negotiation"]
|
|
@@ -75,8 +74,8 @@ graph TB
|
|
|
75
74
|
- REST endpoints for symbols, market data, account info, orders, history,
|
|
76
75
|
calculations, and trading operations
|
|
77
76
|
- JSON and Apache Parquet responses (content negotiation)
|
|
78
|
-
- Optional API key authentication
|
|
79
|
-
- Structured JSON logging
|
|
77
|
+
- Optional API key authentication
|
|
78
|
+
- Structured JSON logging
|
|
80
79
|
- OpenAPI/Swagger docs built into the API
|
|
81
80
|
|
|
82
81
|
## Requirements
|
|
@@ -90,6 +89,20 @@ graph TB
|
|
|
90
89
|
|
|
91
90
|
Install and run the API on the Windows machine where MetaTrader 5 is installed.
|
|
92
91
|
|
|
92
|
+
Install the latest release from PyPI:
|
|
93
|
+
|
|
94
|
+
```console
|
|
95
|
+
pip install mt5api
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Or, when managing the project with `uv`, add it as a dependency:
|
|
99
|
+
|
|
100
|
+
```console
|
|
101
|
+
uv add mt5api
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Alternatively, install from source:
|
|
105
|
+
|
|
93
106
|
```powershell
|
|
94
107
|
git clone https://github.com/dceoy/mt5api.git
|
|
95
108
|
cd mt5api
|
|
@@ -98,12 +111,24 @@ uv sync
|
|
|
98
111
|
|
|
99
112
|
## Running the API on Windows
|
|
100
113
|
|
|
114
|
+
After installing from PyPI:
|
|
115
|
+
|
|
101
116
|
```powershell
|
|
102
117
|
$env:MT5API_SECRET_KEY = "your-secret-api-key" # Optional: omit to disable auth
|
|
103
118
|
$env:MT5API_ROUTER_PREFIX = "/api/v1" # Optional: omit for root-level routes
|
|
104
|
-
|
|
119
|
+
python -m mt5api
|
|
105
120
|
```
|
|
106
121
|
|
|
122
|
+
`python -m mt5api` reads `MT5API_HOST`, `MT5API_PORT`, and `MT5API_LOG_LEVEL`
|
|
123
|
+
from the environment. You can also invoke `uvicorn` directly:
|
|
124
|
+
|
|
125
|
+
```powershell
|
|
126
|
+
uvicorn mt5api.main:app --host 0.0.0.0 --port 8000
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
If you cloned the source tree, prepend `uv run` to either command (for example,
|
|
130
|
+
`uv run uvicorn mt5api.main:app --host 0.0.0.0 --port 8000`).
|
|
131
|
+
|
|
107
132
|
Docs:
|
|
108
133
|
|
|
109
134
|
- Swagger UI: `http://localhost:8000/docs`
|
|
@@ -6,8 +6,8 @@ MetaTrader 5 REST API
|
|
|
6
6
|
|
|
7
7
|
mt5api exposes MT5 market data, account info, trading history, and trading
|
|
8
8
|
operations over HTTP. It uses the [`pdmt5`](https://github.com/dceoy/pdmt5)
|
|
9
|
-
client internally and adds optional API-key auth
|
|
10
|
-
|
|
9
|
+
client internally and adds optional API-key auth and JSON/Parquet response
|
|
10
|
+
formatting.
|
|
11
11
|
|
|
12
12
|
The API server must run on Windows. The `MetaTrader5` Python package used by
|
|
13
13
|
`pdmt5` is supported only on Windows, so you must host `mt5api` on a Windows
|
|
@@ -22,7 +22,7 @@ graph TB
|
|
|
22
22
|
|
|
23
23
|
subgraph "Windows Host"
|
|
24
24
|
subgraph "FastAPI Application"
|
|
25
|
-
Middleware["Middleware Stack<br/>
|
|
25
|
+
Middleware["Middleware Stack<br/>Logging · Error Handler"]
|
|
26
26
|
Routers["Routers<br/>health · symbols · market · account · history · calc · trading"]
|
|
27
27
|
Auth["API Key Security Dependency<br/>Security(api_key_header) · verify_api_key"]
|
|
28
28
|
Deps["FastAPI Dependencies<br/>MT5 Client Singleton · Format Negotiation"]
|
|
@@ -45,8 +45,8 @@ graph TB
|
|
|
45
45
|
- REST endpoints for symbols, market data, account info, orders, history,
|
|
46
46
|
calculations, and trading operations
|
|
47
47
|
- JSON and Apache Parquet responses (content negotiation)
|
|
48
|
-
- Optional API key authentication
|
|
49
|
-
- Structured JSON logging
|
|
48
|
+
- Optional API key authentication
|
|
49
|
+
- Structured JSON logging
|
|
50
50
|
- OpenAPI/Swagger docs built into the API
|
|
51
51
|
|
|
52
52
|
## Requirements
|
|
@@ -60,6 +60,20 @@ graph TB
|
|
|
60
60
|
|
|
61
61
|
Install and run the API on the Windows machine where MetaTrader 5 is installed.
|
|
62
62
|
|
|
63
|
+
Install the latest release from PyPI:
|
|
64
|
+
|
|
65
|
+
```console
|
|
66
|
+
pip install mt5api
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Or, when managing the project with `uv`, add it as a dependency:
|
|
70
|
+
|
|
71
|
+
```console
|
|
72
|
+
uv add mt5api
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Alternatively, install from source:
|
|
76
|
+
|
|
63
77
|
```powershell
|
|
64
78
|
git clone https://github.com/dceoy/mt5api.git
|
|
65
79
|
cd mt5api
|
|
@@ -68,12 +82,24 @@ uv sync
|
|
|
68
82
|
|
|
69
83
|
## Running the API on Windows
|
|
70
84
|
|
|
85
|
+
After installing from PyPI:
|
|
86
|
+
|
|
71
87
|
```powershell
|
|
72
88
|
$env:MT5API_SECRET_KEY = "your-secret-api-key" # Optional: omit to disable auth
|
|
73
89
|
$env:MT5API_ROUTER_PREFIX = "/api/v1" # Optional: omit for root-level routes
|
|
74
|
-
|
|
90
|
+
python -m mt5api
|
|
75
91
|
```
|
|
76
92
|
|
|
93
|
+
`python -m mt5api` reads `MT5API_HOST`, `MT5API_PORT`, and `MT5API_LOG_LEVEL`
|
|
94
|
+
from the environment. You can also invoke `uvicorn` directly:
|
|
95
|
+
|
|
96
|
+
```powershell
|
|
97
|
+
uvicorn mt5api.main:app --host 0.0.0.0 --port 8000
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If you cloned the source tree, prepend `uv run` to either command (for example,
|
|
101
|
+
`uv run uvicorn mt5api.main:app --host 0.0.0.0 --port 8000`).
|
|
102
|
+
|
|
77
103
|
Docs:
|
|
78
104
|
|
|
79
105
|
- Swagger UI: `http://localhost:8000/docs`
|
|
@@ -36,9 +36,7 @@ nssm install mt5api
|
|
|
36
36
|
# Optional: set MT5API_SECRET_KEY only when you want to require X-API-Key headers.
|
|
37
37
|
MT5API_SECRET_KEY=your-secret-api-key
|
|
38
38
|
MT5API_LOG_LEVEL=INFO
|
|
39
|
-
MT5API_RATE_LIMIT=100
|
|
40
39
|
MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS=100
|
|
41
|
-
MT5API_CORS_ORIGINS=*
|
|
42
40
|
MT5API_ROUTER_PREFIX=/api/v1
|
|
43
41
|
```
|
|
44
42
|
|
|
@@ -30,9 +30,7 @@ Set the optional API key and other limits via environment variables:
|
|
|
30
30
|
```powershell
|
|
31
31
|
$env:MT5API_SECRET_KEY = "your-secret-api-key" # Optional: omit to disable auth
|
|
32
32
|
$env:MT5API_LOG_LEVEL = "INFO"
|
|
33
|
-
$env:MT5API_RATE_LIMIT = "100"
|
|
34
33
|
$env:MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS = "100"
|
|
35
|
-
$env:MT5API_CORS_ORIGINS = "*"
|
|
36
34
|
$env:MT5API_ROUTER_PREFIX = "/api/v1" # Optional: omit for root-level routes
|
|
37
35
|
```
|
|
38
36
|
|
|
@@ -70,10 +68,7 @@ disabled and those endpoints are accessible without authorization.
|
|
|
70
68
|
curl -H "X-API-Key: your-secret-api-key" "http://windows-host:8000/symbols"
|
|
71
69
|
```
|
|
72
70
|
|
|
73
|
-
##
|
|
74
|
-
|
|
75
|
-
Rate limiting uses `slowapi` with a default limit of `100/minute`. Set
|
|
76
|
-
`MT5API_RATE_LIMIT` to an integer for a different per-minute cap.
|
|
71
|
+
## Subscription Limits
|
|
77
72
|
|
|
78
73
|
Active market-book subscriptions are capped at `100` symbols by default. Set
|
|
79
74
|
`MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS` to a positive integer to adjust that
|
|
@@ -121,9 +116,9 @@ If `MT5API_ROUTER_PREFIX` is configured, prepend it to each API route below.
|
|
|
121
116
|
- `GET /rates/range` (`symbol`, `timeframe`, `date_from`, `date_to`, `format`)
|
|
122
117
|
- `GET /ticks/from` (`symbol`, `date_from`, `count`, `flags`, `format`)
|
|
123
118
|
- `GET /ticks/range` (`symbol`, `date_from`, `date_to`, `flags`, `format`)
|
|
124
|
-
- `GET /market-book/{symbol}` (`format`) — Market depth (DOM)
|
|
125
|
-
- `POST /market-book/{symbol}/subscribe` — Subscribe to DOM events
|
|
126
|
-
- `POST /market-book/{symbol}/unsubscribe` — Unsubscribe from DOM events
|
|
119
|
+
- `GET /market-book/{symbol}` (`format`) — Market depth (DOM) _(experimental)_
|
|
120
|
+
- `POST /market-book/{symbol}/subscribe` — Subscribe to DOM events _(experimental)_
|
|
121
|
+
- `POST /market-book/{symbol}/unsubscribe` — Unsubscribe from DOM events _(experimental)_
|
|
127
122
|
|
|
128
123
|
### Calculations
|
|
129
124
|
|
|
@@ -167,6 +162,14 @@ structure](https://www.mql5.com/en/docs/constants/structures/mqltraderequest),
|
|
|
167
162
|
with typed validation for core fields such as `action`, `symbol`, `volume`,
|
|
168
163
|
`type`, and `price`.
|
|
169
164
|
|
|
165
|
+
### Connection
|
|
166
|
+
|
|
167
|
+
- `POST /connection/login` (body: `{"login": ..., "password": "...",
|
|
168
|
+
"server": "...", "timeout": ...}`) — Reconnect the MT5 terminal with the
|
|
169
|
+
supplied credentials. Any active market-book subscriptions are released and
|
|
170
|
+
the previous MT5 client is shut down before the new connection is
|
|
171
|
+
established. The supplied password is never echoed in responses or logs.
|
|
172
|
+
|
|
170
173
|
## Response Formatter Utilities
|
|
171
174
|
|
|
172
175
|
If you are extending the API with custom endpoints, use the formatter helpers
|
|
@@ -296,6 +299,14 @@ curl -X POST -H "X-API-Key: your-secret-api-key" -H "Content-Type: application/j
|
|
|
296
299
|
"http://windows-host:8000/order/check"
|
|
297
300
|
```
|
|
298
301
|
|
|
302
|
+
### Reconnect to MT5
|
|
303
|
+
|
|
304
|
+
```console
|
|
305
|
+
curl -X POST -H "X-API-Key: your-secret-api-key" -H "Content-Type: application/json" \
|
|
306
|
+
-d '{"login": 12345678, "password": "s3cret", "server": "MetaQuotes-Demo", "timeout": 60000}' \
|
|
307
|
+
"http://windows-host:8000/connection/login"
|
|
308
|
+
```
|
|
309
|
+
|
|
299
310
|
## Error Responses
|
|
300
311
|
|
|
301
312
|
Errors follow RFC 7807 Problem Details:
|
|
@@ -315,9 +326,8 @@ Errors follow RFC 7807 Problem Details:
|
|
|
315
326
|
Minimum security posture for deployments:
|
|
316
327
|
|
|
317
328
|
- Set `MT5API_SECRET_KEY` to enable API key authentication when needed
|
|
318
|
-
-
|
|
329
|
+
- Configure rate limiting at the reverse proxy or API gateway level
|
|
319
330
|
- Run behind HTTPS in production
|
|
320
|
-
- Restrict CORS origins (`MT5API_CORS_ORIGINS`) for public deployments
|
|
321
331
|
- Restrict access to operational endpoints (`/order/check`,
|
|
322
332
|
`/symbols/{symbol}/select`, `/market-book/{symbol}/subscribe`,
|
|
323
333
|
`/market-book/{symbol}/unsubscribe`) to trusted clients only
|
|
@@ -7,7 +7,7 @@ trading operations.
|
|
|
7
7
|
|
|
8
8
|
mt5api exposes MT5 data and trading operations over HTTP using FastAPI. It
|
|
9
9
|
relies on the underlying MT5 client library for connectivity and adds optional
|
|
10
|
-
authentication
|
|
10
|
+
authentication and response formatting suitable for analytics
|
|
11
11
|
workflows.
|
|
12
12
|
|
|
13
13
|
The API server must run on Windows because the `MetaTrader5` Python package is
|
|
@@ -19,8 +19,8 @@ logged in. API clients can connect from any operating system.
|
|
|
19
19
|
- REST endpoints for symbols, market data, account info, orders, history,
|
|
20
20
|
calculations, and trading operations
|
|
21
21
|
- JSON and Apache Parquet responses
|
|
22
|
-
- Optional API key authentication
|
|
23
|
-
- Structured JSON logging
|
|
22
|
+
- Optional API key authentication
|
|
23
|
+
- Structured JSON logging
|
|
24
24
|
- OpenAPI/Swagger docs built in
|
|
25
25
|
|
|
26
26
|
## Requirements
|
|
@@ -6,18 +6,14 @@ import os
|
|
|
6
6
|
import re
|
|
7
7
|
|
|
8
8
|
from .constants import (
|
|
9
|
-
DEFAULT_API_CORS_ORIGINS,
|
|
10
9
|
DEFAULT_API_HOST,
|
|
11
10
|
DEFAULT_API_LOG_LEVEL,
|
|
12
|
-
DEFAULT_API_RATE_LIMIT,
|
|
13
11
|
DEFAULT_API_ROUTER_PREFIX,
|
|
14
12
|
DEFAULT_MAX_MARKET_BOOK_SUBSCRIPTIONS,
|
|
15
|
-
ENV_MT5API_CORS_ORIGINS,
|
|
16
13
|
ENV_MT5API_HOST,
|
|
17
14
|
ENV_MT5API_LOG_LEVEL,
|
|
18
15
|
ENV_MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS,
|
|
19
16
|
ENV_MT5API_PORT,
|
|
20
|
-
ENV_MT5API_RATE_LIMIT,
|
|
21
17
|
ENV_MT5API_ROUTER_PREFIX,
|
|
22
18
|
ENV_MT5API_SECRET_KEY,
|
|
23
19
|
)
|
|
@@ -81,24 +77,6 @@ def get_configured_api_log_level() -> str:
|
|
|
81
77
|
return os.getenv(ENV_MT5API_LOG_LEVEL, DEFAULT_API_LOG_LEVEL)
|
|
82
78
|
|
|
83
79
|
|
|
84
|
-
def get_configured_api_rate_limit() -> str:
|
|
85
|
-
"""Get the configured API rate limit string.
|
|
86
|
-
|
|
87
|
-
Returns:
|
|
88
|
-
Raw per-minute rate-limit string from configuration.
|
|
89
|
-
"""
|
|
90
|
-
return os.getenv(ENV_MT5API_RATE_LIMIT, str(DEFAULT_API_RATE_LIMIT))
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def get_configured_api_cors_origins() -> str:
|
|
94
|
-
"""Get the configured CORS origins string.
|
|
95
|
-
|
|
96
|
-
Returns:
|
|
97
|
-
Raw CORS origins configuration string.
|
|
98
|
-
"""
|
|
99
|
-
return os.getenv(ENV_MT5API_CORS_ORIGINS, DEFAULT_API_CORS_ORIGINS)
|
|
100
|
-
|
|
101
|
-
|
|
102
80
|
def get_configured_api_router_prefix() -> str:
|
|
103
81
|
"""Get the configured API router prefix.
|
|
104
82
|
|
|
@@ -20,8 +20,6 @@ MAX_MARKET_BOOK_SUBSCRIPTIONS_STATE_KEY = "max_market_book_subscriptions"
|
|
|
20
20
|
ENV_MT5API_HOST = "MT5API_HOST"
|
|
21
21
|
ENV_MT5API_PORT = "MT5API_PORT"
|
|
22
22
|
ENV_MT5API_LOG_LEVEL = "MT5API_LOG_LEVEL"
|
|
23
|
-
ENV_MT5API_RATE_LIMIT = "MT5API_RATE_LIMIT"
|
|
24
|
-
ENV_MT5API_CORS_ORIGINS = "MT5API_CORS_ORIGINS"
|
|
25
23
|
ENV_MT5API_ROUTER_PREFIX = "MT5API_ROUTER_PREFIX"
|
|
26
24
|
ENV_MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS = "MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS"
|
|
27
25
|
ENV_MT5API_SECRET_KEY = "MT5API_SECRET_KEY" # noqa: S105
|
|
@@ -29,8 +27,6 @@ ENV_MT5API_SECRET_KEY = "MT5API_SECRET_KEY" # noqa: S105
|
|
|
29
27
|
DEFAULT_API_HOST = "0.0.0.0" # noqa: S104
|
|
30
28
|
DEFAULT_API_PORT = 8000
|
|
31
29
|
DEFAULT_API_LOG_LEVEL = "INFO"
|
|
32
|
-
DEFAULT_API_RATE_LIMIT = 100
|
|
33
|
-
DEFAULT_API_CORS_ORIGINS = "*"
|
|
34
30
|
DEFAULT_API_ROUTER_PREFIX = ""
|
|
35
31
|
DEFAULT_MAX_MARKET_BOOK_SUBSCRIPTIONS = 100
|
|
36
32
|
MAX_API_PORT = 65535
|