mt5api 0.3.0__tar.gz → 1.0.1__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.
Files changed (116) hide show
  1. mt5api-1.0.1/.agents/skills/pr-feedback-triage/SKILL.md +211 -0
  2. {mt5api-0.3.0 → mt5api-1.0.1}/.github/workflows/ci.yml +15 -0
  3. mt5api-1.0.1/AGENTS.md +70 -0
  4. {mt5api-0.3.0 → mt5api-1.0.1}/PKG-INFO +16 -12
  5. {mt5api-0.3.0 → mt5api-1.0.1}/README.md +14 -10
  6. {mt5api-0.3.0 → mt5api-1.0.1}/docs/api/rest-api.md +2 -2
  7. {mt5api-0.3.0 → mt5api-1.0.1}/docs/index.md +0 -3
  8. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/__main__.py +3 -19
  9. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/config.py +49 -6
  10. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/constants.py +1 -1
  11. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/dependencies.py +7 -14
  12. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/main.py +35 -2
  13. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/middleware.py +82 -2
  14. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/connection.py +3 -3
  15. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/health.py +4 -4
  16. {mt5api-0.3.0 → mt5api-1.0.1}/pyproject.toml +3 -3
  17. {mt5api-0.3.0 → mt5api-1.0.1}/tests/conftest.py +2 -2
  18. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_auth.py +5 -5
  19. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_cli.py +20 -23
  20. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_config.py +78 -0
  21. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_connection.py +60 -33
  22. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_health.py +63 -3
  23. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_main.py +102 -0
  24. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_market.py +9 -3
  25. mt5api-1.0.1/tests/test_middleware.py +221 -0
  26. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_trading.py +3 -1
  27. {mt5api-0.3.0 → mt5api-1.0.1}/uv.lock +118 -115
  28. mt5api-0.3.0/.agents/skills/speckit-analyze/SKILL.md +0 -86
  29. mt5api-0.3.0/.agents/skills/speckit-checklist/SKILL.md +0 -106
  30. mt5api-0.3.0/.agents/skills/speckit-clarify/SKILL.md +0 -99
  31. mt5api-0.3.0/.agents/skills/speckit-constitution/SKILL.md +0 -89
  32. mt5api-0.3.0/.agents/skills/speckit-implement/SKILL.md +0 -78
  33. mt5api-0.3.0/.agents/skills/speckit-plan/SKILL.md +0 -71
  34. mt5api-0.3.0/.agents/skills/speckit-specify/SKILL.md +0 -75
  35. mt5api-0.3.0/.agents/skills/speckit-tasks/SKILL.md +0 -79
  36. mt5api-0.3.0/.agents/skills/speckit-taskstoissues/SKILL.md +0 -131
  37. mt5api-0.3.0/.claude/agents/codex.md +0 -986
  38. mt5api-0.3.0/.claude/agents/copilot.md +0 -1194
  39. mt5api-0.3.0/.claude/commands/speckit.analyze.md +0 -184
  40. mt5api-0.3.0/.claude/commands/speckit.checklist.md +0 -294
  41. mt5api-0.3.0/.claude/commands/speckit.clarify.md +0 -181
  42. mt5api-0.3.0/.claude/commands/speckit.constitution.md +0 -82
  43. mt5api-0.3.0/.claude/commands/speckit.implement.md +0 -135
  44. mt5api-0.3.0/.claude/commands/speckit.plan.md +0 -89
  45. mt5api-0.3.0/.claude/commands/speckit.specify.md +0 -256
  46. mt5api-0.3.0/.claude/commands/speckit.tasks.md +0 -137
  47. mt5api-0.3.0/.claude/commands/speckit.taskstoissues.md +0 -30
  48. mt5api-0.3.0/.claude/settings.json +0 -15
  49. mt5api-0.3.0/.specify/memory/constitution.md +0 -73
  50. mt5api-0.3.0/.specify/scripts/bash/check-prerequisites.sh +0 -166
  51. mt5api-0.3.0/.specify/scripts/bash/common.sh +0 -156
  52. mt5api-0.3.0/.specify/scripts/bash/create-new-feature.sh +0 -297
  53. mt5api-0.3.0/.specify/scripts/bash/setup-plan.sh +0 -61
  54. mt5api-0.3.0/.specify/scripts/bash/update-agent-context.sh +0 -799
  55. mt5api-0.3.0/.specify/templates/agent-file-template.md +0 -28
  56. mt5api-0.3.0/.specify/templates/checklist-template.md +0 -40
  57. mt5api-0.3.0/.specify/templates/plan-template.md +0 -105
  58. mt5api-0.3.0/.specify/templates/spec-template.md +0 -115
  59. mt5api-0.3.0/.specify/templates/tasks-template.md +0 -250
  60. mt5api-0.3.0/AGENTS.md +0 -92
  61. mt5api-0.3.0/specs/041-mt5-rest-api/contracts/openapi.yaml +0 -622
  62. mt5api-0.3.0/specs/041-mt5-rest-api/data-model.md +0 -583
  63. mt5api-0.3.0/specs/041-mt5-rest-api/plan.md +0 -373
  64. mt5api-0.3.0/specs/041-mt5-rest-api/quickstart.md +0 -651
  65. mt5api-0.3.0/specs/041-mt5-rest-api/research.md +0 -689
  66. mt5api-0.3.0/specs/041-mt5-rest-api/spec.md +0 -181
  67. mt5api-0.3.0/specs/041-mt5-rest-api/tasks.md +0 -318
  68. mt5api-0.3.0/specs/042-mt5-core-client/spec.md +0 -97
  69. mt5api-0.3.0/specs/043-mt5-dataframe-client/spec.md +0 -96
  70. mt5api-0.3.0/specs/044-mt5-trading-client/spec.md +0 -94
  71. mt5api-0.3.0/specs/045-mt5-utils/spec.md +0 -90
  72. mt5api-0.3.0/specs/046-mt5-api-service/spec.md +0 -104
  73. mt5api-0.3.0/specs/047-api-auth-rate-limit/spec.md +0 -93
  74. mt5api-0.3.0/specs/048-api-response-format/spec.md +0 -93
  75. mt5api-0.3.0/specs/049-api-routing-models/spec.md +0 -91
  76. mt5api-0.3.0/specs/050-api-runtime-deploy/spec.md +0 -90
  77. mt5api-0.3.0/specs/051-api-error-logging/spec.md +0 -91
  78. mt5api-0.3.0/specs/052-api-dependencies/spec.md +0 -93
  79. mt5api-0.3.0/tests/test_middleware.py +0 -147
  80. {mt5api-0.3.0 → mt5api-1.0.1}/.agents/skills/local-qa/SKILL.md +0 -0
  81. {mt5api-0.3.0 → mt5api-1.0.1}/.agents/skills/local-qa/scripts/qa.sh +0 -0
  82. {mt5api-0.3.0 → mt5api-1.0.1}/.agents/skills/mt5api/SKILL.md +0 -0
  83. {mt5api-0.3.0 → mt5api-1.0.1}/.github/FUNDING.yml +0 -0
  84. {mt5api-0.3.0 → mt5api-1.0.1}/.github/dependabot.yml +0 -0
  85. {mt5api-0.3.0 → mt5api-1.0.1}/.github/renovate.json +0 -0
  86. {mt5api-0.3.0 → mt5api-1.0.1}/.github/workflows/claude.yml +0 -0
  87. {mt5api-0.3.0 → mt5api-1.0.1}/.github/workflows/release.yml +0 -0
  88. {mt5api-0.3.0 → mt5api-1.0.1}/.gitignore +0 -0
  89. {mt5api-0.3.0 → mt5api-1.0.1}/CLAUDE.md +0 -0
  90. {mt5api-0.3.0 → mt5api-1.0.1}/LICENSE +0 -0
  91. {mt5api-0.3.0 → mt5api-1.0.1}/docs/api/deployment.md +0 -0
  92. {mt5api-0.3.0 → mt5api-1.0.1}/docs/api/index.md +0 -0
  93. {mt5api-0.3.0 → mt5api-1.0.1}/mkdocs.yml +0 -0
  94. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/__init__.py +0 -0
  95. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/auth.py +0 -0
  96. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/formatters.py +0 -0
  97. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/models.py +0 -0
  98. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/__init__.py +0 -0
  99. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/account.py +0 -0
  100. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/calc.py +0 -0
  101. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/history.py +0 -0
  102. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/market.py +0 -0
  103. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/symbols.py +0 -0
  104. {mt5api-0.3.0 → mt5api-1.0.1}/mt5api/routers/trading.py +0 -0
  105. {mt5api-0.3.0 → mt5api-1.0.1}/tests/__init__.py +0 -0
  106. {mt5api-0.3.0 → mt5api-1.0.1}/tests/mt5_constants.py +0 -0
  107. {mt5api-0.3.0 → mt5api-1.0.1}/tests/openapi_mt5_constants.py +0 -0
  108. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_account.py +0 -0
  109. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_calc.py +0 -0
  110. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_dependencies.py +0 -0
  111. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_formatters.py +0 -0
  112. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_history.py +0 -0
  113. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_integration.py +0 -0
  114. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_lifespan.py +0 -0
  115. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_models.py +0 -0
  116. {mt5api-0.3.0 → mt5api-1.0.1}/tests/test_symbols.py +0 -0
@@ -0,0 +1,211 @@
1
+ ---
2
+ name: pr-feedback-triage
3
+ description: Triage pull request review comments into fixes, replies, clarification requests, or open follow-ups while respecting safe execution modes.
4
+ allowed-tools: Bash(git:*), Bash(gh:*), mcp__github__*, Read, Grep, Glob, Edit, MultiEdit, Write
5
+ ---
6
+
7
+ # PR Feedback Triage
8
+
9
+ Triage pull request review feedback, decide what action each thread needs, make focused fixes when allowed, and report or resolve only what is actually handled.
10
+
11
+ ## When to Use
12
+
13
+ - A PR has review comments, requested changes, unresolved review threads, or bot review findings.
14
+ - The user asks to address, respond to, or resolve PR feedback.
15
+ - The user provides a PR URL/number, a branch with an associated PR, or copied comments.
16
+
17
+ Do not use this skill for a first-pass code review with no existing feedback; use a code review skill instead.
18
+
19
+ ## Inputs
20
+
21
+ - Pull request URL or number, or a current branch that has an associated pull request.
22
+ - Repository checkout or platform access sufficient to inspect the PR diff and review feedback.
23
+ - Optional reviewer priorities from the user, such as "only address blocking comments" or "do not reply on the PR platform".
24
+ - Optional operating mode flags: `dry_run`, `no_push`, and `no_reply`.
25
+
26
+ If no PR or review comments are identifiable, ask for the target PR or the copied comments before proceeding.
27
+
28
+ ## Modes
29
+
30
+ - `dry_run`: inspect review feedback and report the triage only. Do not edit files, run write-mode formatters, commit, push, post replies, or resolve review threads.
31
+ - `no_push`: local edits and verification are allowed, but do not push commits or otherwise update the remote branch. Report the local diff or local commits that still need to be pushed. Do not resolve threads whose resolution depends on unpushed local edits.
32
+ - `no_reply`: do not post replies, submit reviews, or resolve review threads. Provide suggested replies and resolution actions in the final report instead.
33
+
34
+ When a mode disables an action, skip that destructive or externally visible action even if normal workflow text would otherwise allow it.
35
+
36
+ ## Preflight
37
+
38
+ 1. Identify the current branch and target PR.
39
+ 2. Check tracked local changes with `git diff --name-only` and `git diff --cached --name-only`. Ignore untracked files unless the review feedback explicitly concerns them.
40
+ 3. Check unpushed commits before relying on remote review feedback.
41
+ 4. If tracked local changes or unpushed commits exist, warn that existing PR comments may not cover the latest local state. In `normal` mode, push only when the user request or repository workflow allows it; otherwise continue with a clearly reported limitation.
42
+
43
+ ## Feedback Collection
44
+
45
+ Gather the complete feedback set before editing:
46
+
47
+ - Fetch unresolved review threads, requested-change reviews, inline comments, copied comments, and PR-level summary comments.
48
+ - Use whichever authenticated GitHub-capable interface is available and reliable. This skill explicitly permits both `gh` and GitHub MCP tools; paginate results and do not inspect only the first page of threads or comments.
49
+ - For bot reviewers that post both summary comments and inline comments, prefer inline comments for actionable triage. Incorporate summary findings only when they contain distinct severity, rationale, or fix instructions not already captured from inline comments.
50
+ - Summary comments may be excluded from triage when they do not add distinct actionable context.
51
+ - Preserve every thread/comment identifier needed to reply or resolve later.
52
+ - Compare each comment with the current diff and file contents because review lines can become outdated.
53
+
54
+ ## Deduplication and Ordering
55
+
56
+ Build one triage record per distinct finding:
57
+
58
+ - Prefer exact review-thread identity when available.
59
+ - For duplicate bot findings appearing in both summary and inline comments, merge by exact issue title first, then by file path plus line range as a fallback.
60
+ - Prefer inline comments for location and current code context.
61
+ - Use summary comments only for distinct severity, category, rationale, or detailed agent prompts that are not already available from inline comments.
62
+ - Preserve the reviewer’s exact issue title and original wording where practical. Do not rename findings in a way that would make replies hard to map back to comments.
63
+ - Preserve the reviewer’s original ordering unless the user asks for priority reordering. Many review bots already order findings by severity.
64
+
65
+ Each triage record should track: original title, reviewer, source IDs, location, current applicability, severity/priority if available, disposition, planned action, verification, reply text if any, resolution decision, platform action attempted, and final platform state.
66
+
67
+ ## Resolution Policy
68
+
69
+ In normal mode, `Resolve conversation` is the default action for any review thread that has been fully handled. A thread is handled when the requested change is implemented and verified, the current code already satisfies the comment, the comment is outdated and no longer applies, or a deliberate deferral/won't-fix response has been posted with a clear reason.
70
+
71
+ Keep a thread open only when it still needs reviewer, maintainer, or product input, the fix is local-only and not pushed, verification is missing for a material change, or the user explicitly requested `dry_run`, `no_push`, or `no_reply` behavior that prevents resolution.
72
+
73
+ When resolving a thread, add a concise reply first only if it provides useful context, such as what changed, why no code change was needed, why a finding was intentionally deferred, or why the original comment is now outdated. Do not add noisy replies for self-evident fixes unless project norms require them.
74
+
75
+ ## Platform Comment Style
76
+
77
+ - Keep every posted reply or comment brief: one sentence by default, two short sentences only when necessary.
78
+ - Do not post PR-level summary or status comments by default. Omit them when they only restate completed fixes, resolved threads, or verification already visible in commits/checks.
79
+ - Avoid templates, long bullet lists, exhaustive status logs, and duplicated explanations in platform comments.
80
+ - For simple fixes, already-addressed findings, or outdated findings, prefer `resolve_only` over adding a reply.
81
+
82
+ ## Platform Action Contract
83
+
84
+ Do not treat triage as complete until every incorporated source ID reaches an explicit terminal state:
85
+
86
+ - `resolved`: a platform resolve action succeeded, or a re-check shows the thread is already resolved.
87
+ - `replied_left_open`: a reply or question was posted and the thread is intentionally left unresolved.
88
+ - `not_resolvable`: the source is a PR-level summary comment or copied comment that has no platform-level resolve action; post a brief reply only when useful.
89
+ - `skipped_by_mode`: `dry_run`, `no_push`, or `no_reply` prevented the external action.
90
+ - `failed_action`: a reply or resolve action was attempted and failed; include the attempted action and failure in the final summary.
91
+
92
+ In normal mode, build and execute a platform action queue after fixes are verified and pushed when needed:
93
+
94
+ - `reply_then_resolve`: use for handled threads where the reviewer needs context before resolution.
95
+ - `resolve_only`: use for self-evident fixes and already-addressed or outdated threads where an extra reply would add noise.
96
+ - `reply_leave_open`: use only for clarification requests, blocked work, or intentionally open follow-ups.
97
+ - `reply_only`: use for PR-level comments or summaries that cannot be resolved, only when a short reply adds value.
98
+
99
+ For duplicate findings, execute the terminal action for every source thread ID, not only the primary triage record. If one finding is represented by three unresolved inline threads, all three must be resolved or explicitly left open.
100
+
101
+ ## GitHub Action Guidance
102
+
103
+ Use whichever authenticated GitHub-capable interface is available and reliable, preferably `gh` or GitHub MCP. Prefer interfaces that expose review-thread resolution state. For GitHub inline review threads, use the thread node ID and the GraphQL `resolveReviewThread` mutation, or an equivalent GitHub MCP resolve-thread tool, rather than assuming that a reply resolves the conversation.
104
+
105
+ A reliable pattern is:
106
+
107
+ 1. Re-fetch review threads and comments immediately before acting.
108
+ 2. Reply to the thread when the action queue says a reply is needed.
109
+ 3. Resolve the review thread by node ID when the terminal state should be `resolved`.
110
+ 4. Re-fetch unresolved review threads after the action queue completes.
111
+ 5. Retry any expected-to-be-resolved thread that is still unresolved once; if it still remains unresolved, mark it `failed_action` instead of claiming completion.
112
+
113
+ Example GraphQL mutation shape:
114
+
115
+ ```graphql
116
+ mutation ($threadId: ID!) {
117
+ resolveReviewThread(input: { threadId: $threadId }) {
118
+ thread {
119
+ id
120
+ isResolved
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ A posted reply alone is sufficient only for `reply_leave_open`, `reply_only`, or `not_resolvable` sources. For handled inline review threads, reply and resolve are separate actions.
127
+
128
+ ## Flow
129
+
130
+ ```mermaid
131
+ flowchart TD
132
+ A[Identify PR and branch state] --> B[Collect all review feedback]
133
+ B --> C[Deduplicate and preserve source IDs]
134
+ C --> D[Inspect current diff and code]
135
+ D --> E{Classify each triage record}
136
+ E -->|Fix| F[Implement minimal change]
137
+ E -->|Answer| G[Prepare concise reply]
138
+ E -->|Clarify| H[Prepare question and leave open]
139
+ E -->|Already addressed or Outdated| I[Prepare evidence]
140
+ E -->|Defer or Won't fix| J[Document reason]
141
+ F --> K[Verify]
142
+ G --> L{Mode}
143
+ H --> L
144
+ I --> L
145
+ J --> L
146
+ K --> L
147
+ L -->|dry_run| M[Report triage only]
148
+ L -->|no_push| N[Report local diff or commits]
149
+ L -->|no_reply| O[Report suggested replies/actions]
150
+ L -->|normal| P[Commit/push if changed]
151
+ P --> R[Execute reply/resolve action queue]
152
+ R --> S[Re-fetch threads and retry unresolved handled threads once]
153
+ M --> Q[Final summary]
154
+ N --> Q
155
+ O --> Q
156
+ S --> Q
157
+ ```
158
+
159
+ ## Compact Workflow
160
+
161
+ 1. **Collect all relevant feedback**
162
+ - Identify the PR and gather unresolved review threads, requested-change reviews, inline comments, copied comments, and PR-level summaries.
163
+ - Paginate all platform calls and keep comment/thread IDs for later replies and resolution.
164
+ - For bot reviews, prioritize inline comments and incorporate summary findings only when they add distinct actionable context.
165
+
166
+ 2. **Classify each triage record**
167
+ - **Fix**: Valid requested change; make the smallest focused edit when not in `dry_run`.
168
+ - **Answer**: No code change needed; prepare a concise explanation.
169
+ - **Clarify**: Ambiguous, conflicting, or missing context; reply with the question and leave unresolved.
170
+ - **Already addressed**: Current code already satisfies it; prepare evidence.
171
+ - **Outdated**: Commented code or issue no longer exists; prepare evidence.
172
+ - **Defer / Won't fix**: Valid concern intentionally not changed now; document a specific reason.
173
+
174
+ 3. **Act according to the classification and mode**
175
+ - Keep edits scoped to the review feedback.
176
+ - Follow reviewer-provided fix instructions literally when they are still applicable; deviate only when the current code proves the instruction is stale or unsafe.
177
+ - In `dry_run`, stop at triage, proposed fixes, suggested replies, and verification plan.
178
+ - In `no_push`, local edits are allowed, but do not push or resolve threads whose fix is only local. Reply or resolve non-code, already-addressed, or outdated threads only when the action does not depend on unpushed work and `no_reply` is not set.
179
+ - In `no_reply`, do not post replies or resolve threads; report suggested replies/actions instead.
180
+ - In normal mode, commit and push changed code when appropriate, then execute the platform action queue for every incorporated source ID.
181
+
182
+ 4. **Verify before claiming completion**
183
+ - For fixes, run appropriate checks or explain why they could not run.
184
+ - Re-inspect the updated diff and comment context to confirm the concern is resolved.
185
+ - Re-fetch review threads after reply/resolve actions and confirm all expected-to-be-resolved thread IDs are resolved.
186
+ - Do not mark a thread resolved if it still needs reviewer, maintainer, or product input.
187
+ - If a resolve or reply operation fails, retry once when safe; then report `failed_action` with the affected source ID and reason.
188
+
189
+ 5. **Finish**
190
+ - Normal mode: commit/push changes when appropriate, post only useful short replies/comments, omit PR-level summaries when they add no value, resolve all handled threads by default, and reconcile the final unresolved set.
191
+ - Safe modes: report the local state and the exact replies/resolution actions a human could take.
192
+
193
+ ## Reply Guidance
194
+
195
+ - Keep inline replies short: one sentence by default, two short sentences only when needed.
196
+ - For fixed findings, mention the concrete change or commit only if it helps the reviewer.
197
+ - For already-addressed or outdated findings, cite the current code path or behavior only as briefly as needed.
198
+ - For deferred or won't-fix findings, provide the reason and any follow-up issue or owner if known.
199
+ - Avoid posting PR-level summary comments unless they communicate a decision, blocker, or requested reviewer action.
200
+ - If a reply or resolve operation fails, continue with the remaining threads and report the failure in the final summary.
201
+
202
+ ## Final Summary Checklist
203
+
204
+ - Mode used: `normal`, `dry_run`, `no_push`, or `no_reply`
205
+ - Counts by disposition: fixed, answered, clarified/left open, already addressed, outdated, deferred/won't-fix
206
+ - Counts by platform terminal state: resolved, replied-left-open, not-resolvable, skipped-by-mode, failed-action
207
+ - Threads resolved, intentionally left open, already resolved, or resolution actions skipped by mode
208
+ - Any expected-to-be-resolved thread that remained unresolved after retry
209
+ - Verification run or planned
210
+ - Commits pushed, local diff/commits, or "none"
211
+ - Remaining open items and who needs to respond
@@ -62,6 +62,19 @@ jobs:
62
62
  runs-on: ubuntu-slim
63
63
  secrets:
64
64
  GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65
+ github-codeql-analysis:
66
+ if: >
67
+ github.event_name == 'push'
68
+ || github.event_name == 'pull_request'
69
+ || (github.event_name == 'workflow_dispatch' && inputs.workflow == 'lint-and-test')
70
+ permissions:
71
+ contents: read
72
+ security-events: write
73
+ actions: read
74
+ uses: dceoy/gh-actions-for-devops/.github/workflows/github-codeql-analysis.yml@main # zizmor: ignore[unpinned-uses]
75
+ with:
76
+ language: >
77
+ ["python"]
65
78
  dependabot-auto-merge:
66
79
  if: >
67
80
  github.event_name == 'pull_request' && github.actor == 'dependabot[bot]'
@@ -73,5 +86,7 @@ jobs:
73
86
  contents: write
74
87
  pull-requests: write
75
88
  actions: read
89
+ checks: read
90
+ statuses: read
76
91
  with:
77
92
  unconditional: true
mt5api-1.0.1/AGENTS.md ADDED
@@ -0,0 +1,70 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure & Module Organization
4
+
5
+ `mt5api/` contains the FastAPI application. Core app setup lives in `main.py`,
6
+ configuration and security in `config.py` and `auth.py`, shared request
7
+ dependencies in `dependencies.py`, middleware in `middleware.py`, response
8
+ serialization in `formatters.py`, and Pydantic/data models in `models.py`.
9
+ Endpoint modules are grouped under `mt5api/routers/` by domain, such as
10
+ `market.py`, `symbols.py`, `account.py`, and `trading.py`. Tests live in
11
+ `tests/` and mirror the package domains with `test_*.py` files. Documentation is
12
+ in `docs/`, with MkDocs configured by `mkdocs.yml`; local agent skills are under
13
+ `skills/`.
14
+
15
+ ## Build, Test, and Development Commands
16
+
17
+ - `uv sync --group dev`: install runtime and development dependencies.
18
+ - `uv run python -m mt5api`: start the API using environment configuration.
19
+ - `uv run uvicorn mt5api.main:app --host 0.0.0.0 --port 8000`: run the app
20
+ directly for local API testing.
21
+ - `uv run pytest`: run the full test suite with coverage settings from
22
+ `pyproject.toml`.
23
+ - `uv run ruff check .` and `uv run ruff format --check .`: lint and verify
24
+ formatting.
25
+ - `uv run pyright`: run strict static type checking.
26
+ - `uv run mkdocs serve`: preview documentation locally.
27
+ - `.agents/skills/local-qa/scripts/qa.sh`: run the repository QA workflow after
28
+ any file update. This wraps formatting, linting, type checks, tests, Markdown
29
+ formatting, and workflow/security checks.
30
+
31
+ The API server runtime requires Windows with MetaTrader 5 installed and logged
32
+ in. Non-Windows systems are suitable for editing docs and most mocked tests.
33
+
34
+ ## Coding Style & Naming Conventions
35
+
36
+ Target Python 3.11+. Use Ruff formatting with an 88-character line length and
37
+ Google-style docstrings. Keep type annotations complete; Pyright runs in strict
38
+ mode. Use `snake_case` for functions, variables, and modules; `PascalCase` for
39
+ classes and Pydantic models; and uppercase names for constants.
40
+
41
+ ## Testing Guidelines
42
+
43
+ Pytest discovers `tests/test_*.py`, `*_test.py`, `Test*` classes, and `test_*`
44
+ functions. Coverage is branch-aware and configured to fail below 100%, so add or
45
+ adjust focused tests with each behavior change. Prefer mocked MT5/pdmt5
46
+ interactions unless a test explicitly requires a Windows MT5 terminal.
47
+
48
+ ## Design Principles
49
+
50
+ Apply KISS, DRY, and YAGNI when changing code. Prefer the simplest direct
51
+ implementation that satisfies the current requirement. Remove duplication when
52
+ it improves clarity or prevents drift, but avoid abstractions that do not serve
53
+ an immediate need. Keep changes small, focused, and easy to review.
54
+
55
+ ## Commit & Pull Request Guidelines
56
+
57
+ History uses short imperative subjects and occasional Conventional Commit
58
+ prefixes, for example `refactor: delegate MT5 constant parsing...` or
59
+ `Add checks and statuses read permissions...`. Keep commits scoped to one
60
+ logical change. Before committing or opening a PR, run
61
+ `.agents/skills/local-qa/scripts/qa.sh`. Pull requests should describe the
62
+ behavior change, list verification commands, link related issues when
63
+ applicable, and call out any runtime impact for Windows/MT5 users.
64
+
65
+ ## Security & Configuration Tips
66
+
67
+ Do not commit credentials, terminal account details, or real API keys. Configure
68
+ runtime values through environment variables such as `MT5API_SECRET_KEY`,
69
+ `MT5API_ROUTER_PREFIX`, `MT5API_HOST`, `MT5API_PORT`, and
70
+ `MT5API_LOG_LEVEL`.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mt5api
3
- Version: 0.3.0
3
+ Version: 1.0.1
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>
@@ -18,9 +18,9 @@ Classifier: Topic :: Office/Business :: Financial :: Investment
18
18
  Requires-Python: <3.14,>=3.11
19
19
  Requires-Dist: fastapi>=0.115.0
20
20
  Requires-Dist: httpx>=0.27.0
21
- Requires-Dist: pdmt5>=0.3.0
21
+ Requires-Dist: pdmt5>=1.1.1
22
22
  Requires-Dist: pyarrow>=18.0.0
23
- Requires-Dist: python-multipart>=0.0.9
23
+ Requires-Dist: python-multipart>=0.0.31
24
24
  Requires-Dist: uvicorn[standard]>=0.32.0
25
25
  Description-Content-Type: text/markdown
26
26
 
@@ -30,14 +30,18 @@ MetaTrader 5 REST API
30
30
 
31
31
  [![CI/CD](https://github.com/dceoy/mt5api/actions/workflows/ci.yml/badge.svg)](https://github.com/dceoy/mt5api/actions/workflows/ci.yml)
32
32
 
33
- mt5api exposes MT5 market data, account info, trading history, and trading
34
- operations over HTTP. It is a FastAPI/HTTP adapter over
35
- [`pdmt5`](https://github.com/dceoy/pdmt5), which provides the core MT5 client,
36
- dataframe/trading primitives, and canonical MT5 constant parsing. mt5api adds
37
- optional API-key auth and JSON/Parquet response formatting.
33
+ mt5api exposes MT5 market data, account info, trading history, trading state,
34
+ order validation, and operational terminal endpoints over HTTP. It is a
35
+ FastAPI/HTTP adapter over [`pdmt5`](https://github.com/dceoy/pdmt5), which
36
+ provides the core MT5 client, dataframe/order primitives, and canonical MT5
37
+ constant parsing. mt5api adds optional API-key auth and JSON/Parquet response
38
+ formatting.
38
39
 
39
- [`mt5cli`](https://github.com/dceoy/mt5cli) is a sibling CLI/batch adapter for
40
- the same pdmt5 stack; it is not a dependency of mt5api.
40
+ The exposed operational surface is deliberately narrow: mt5api validates trade
41
+ requests, manages terminal-side subscriptions and MarketWatch visibility, and
42
+ supports reconnecting the terminal to a different MT5 account via
43
+ `POST /connection/login`, but it does not expose live order-send endpoints or
44
+ implement strategy orchestration.
41
45
 
42
46
  The API server must run on Windows. pdmt5 connects through the MetaTrader 5
43
47
  Python API, which is supported only on Windows, so you must host `mt5api` on a
@@ -72,8 +76,8 @@ graph TB
72
76
 
73
77
  ## Features
74
78
 
75
- - REST endpoints for symbols, market data, account info, orders, history,
76
- calculations, and trading operations
79
+ - REST endpoints for symbols, market data, account info, orders, positions,
80
+ history, margin/profit calculations, order validation, and terminal operations
77
81
  - JSON and Apache Parquet responses (content negotiation)
78
82
  - Optional API key authentication
79
83
  - Structured JSON logging
@@ -4,14 +4,18 @@ MetaTrader 5 REST API
4
4
 
5
5
  [![CI/CD](https://github.com/dceoy/mt5api/actions/workflows/ci.yml/badge.svg)](https://github.com/dceoy/mt5api/actions/workflows/ci.yml)
6
6
 
7
- mt5api exposes MT5 market data, account info, trading history, and trading
8
- operations over HTTP. It is a FastAPI/HTTP adapter over
9
- [`pdmt5`](https://github.com/dceoy/pdmt5), which provides the core MT5 client,
10
- dataframe/trading primitives, and canonical MT5 constant parsing. mt5api adds
11
- optional API-key auth and JSON/Parquet response formatting.
12
-
13
- [`mt5cli`](https://github.com/dceoy/mt5cli) is a sibling CLI/batch adapter for
14
- the same pdmt5 stack; it is not a dependency of mt5api.
7
+ mt5api exposes MT5 market data, account info, trading history, trading state,
8
+ order validation, and operational terminal endpoints over HTTP. It is a
9
+ FastAPI/HTTP adapter over [`pdmt5`](https://github.com/dceoy/pdmt5), which
10
+ provides the core MT5 client, dataframe/order primitives, and canonical MT5
11
+ constant parsing. mt5api adds optional API-key auth and JSON/Parquet response
12
+ formatting.
13
+
14
+ The exposed operational surface is deliberately narrow: mt5api validates trade
15
+ requests, manages terminal-side subscriptions and MarketWatch visibility, and
16
+ supports reconnecting the terminal to a different MT5 account via
17
+ `POST /connection/login`, but it does not expose live order-send endpoints or
18
+ implement strategy orchestration.
15
19
 
16
20
  The API server must run on Windows. pdmt5 connects through the MetaTrader 5
17
21
  Python API, which is supported only on Windows, so you must host `mt5api` on a
@@ -46,8 +50,8 @@ graph TB
46
50
 
47
51
  ## Features
48
52
 
49
- - REST endpoints for symbols, market data, account info, orders, history,
50
- calculations, and trading operations
53
+ - REST endpoints for symbols, market data, account info, orders, positions,
54
+ history, margin/profit calculations, order validation, and terminal operations
51
55
  - JSON and Apache Parquet responses (content negotiation)
52
56
  - Optional API key authentication
53
57
  - Structured JSON logging
@@ -316,8 +316,8 @@ Errors follow RFC 7807 Problem Details:
316
316
  {
317
317
  "type": "/errors/validation-error",
318
318
  "title": "Request Validation Failed",
319
- "status": 400,
320
- "detail": "count must be positive (got: -10)",
319
+ "status": 422,
320
+ "detail": "Request validation error details",
321
321
  "instance": "/rates/from"
322
322
  }
323
323
  ```
@@ -10,9 +10,6 @@ mt5api is a FastAPI/HTTP adapter over
10
10
  dataframe/trading primitives, and canonical MT5 constant parsing. mt5api adds
11
11
  optional authentication, response formatting, and OpenAPI documentation.
12
12
 
13
- [`mt5cli`](https://github.com/dceoy/mt5cli) is a sibling CLI/batch adapter for
14
- the same pdmt5 stack; it is not a dependency of mt5api.
15
-
16
13
  The API server must run on Windows because pdmt5 connects through the MetaTrader
17
14
  5 Python API, which is Windows-only. Run `mt5api` on a Windows host with
18
15
  MetaTrader 5 installed and logged in. API clients can connect from any operating
@@ -11,11 +11,7 @@ from .config import (
11
11
  get_configured_api_log_level,
12
12
  get_configured_api_port,
13
13
  )
14
- from .constants import (
15
- API_APP_IMPORT,
16
- DEFAULT_API_PORT,
17
- MAX_API_PORT,
18
- )
14
+ from .constants import API_APP_IMPORT
19
15
 
20
16
 
21
17
  def _get_host() -> str:
@@ -33,19 +29,7 @@ def _get_port() -> int:
33
29
  Returns:
34
30
  Port number for the API server.
35
31
  """
36
- raw_port = get_configured_api_port()
37
- if raw_port is None:
38
- return DEFAULT_API_PORT
39
-
40
- try:
41
- port_value = int(raw_port)
42
- except ValueError:
43
- return DEFAULT_API_PORT
44
-
45
- if not 1 <= port_value <= MAX_API_PORT:
46
- return DEFAULT_API_PORT
47
-
48
- return port_value
32
+ return get_configured_api_port()
49
33
 
50
34
 
51
35
  def _get_log_level() -> str:
@@ -54,7 +38,7 @@ def _get_log_level() -> str:
54
38
  Returns:
55
39
  Log level string for uvicorn.
56
40
  """
57
- return get_configured_api_log_level().lower()
41
+ return get_configured_api_log_level()
58
42
 
59
43
 
60
44
  def main() -> None:
@@ -8,6 +8,7 @@ import re
8
8
  from .constants import (
9
9
  DEFAULT_API_HOST,
10
10
  DEFAULT_API_LOG_LEVEL,
11
+ DEFAULT_API_PORT,
11
12
  DEFAULT_API_ROUTER_PREFIX,
12
13
  DEFAULT_MAX_MARKET_BOOK_SUBSCRIPTIONS,
13
14
  ENV_MT5API_HOST,
@@ -16,9 +17,21 @@ from .constants import (
16
17
  ENV_MT5API_PORT,
17
18
  ENV_MT5API_ROUTER_PREFIX,
18
19
  ENV_MT5API_SECRET_KEY,
20
+ MAX_API_PORT,
19
21
  )
20
22
 
21
23
  _VALID_API_ROUTER_PREFIX_PATTERN = re.compile(r"^[A-Za-z0-9_-]+(?:/[A-Za-z0-9_-]+)*$")
24
+ _VALID_UVICORN_LOG_LEVELS = {"critical", "error", "warning", "info", "debug", "trace"}
25
+ _LOGGING_LOG_LEVEL_BY_API_LEVEL = {
26
+ "critical": "CRITICAL",
27
+ "error": "ERROR",
28
+ "warning": "WARNING",
29
+ "info": "INFO",
30
+ "debug": "DEBUG",
31
+ "trace": "DEBUG",
32
+ }
33
+ _INVALID_MT5API_PORT_ERROR = "Invalid MT5API_PORT"
34
+ _INVALID_MT5API_LOG_LEVEL_ERROR = "Invalid MT5API_LOG_LEVEL"
22
35
  _INVALID_MT5API_ROUTER_PREFIX_ERROR = "Invalid MT5API_ROUTER_PREFIX"
23
36
  _INVALID_MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS_ERROR = (
24
37
  "Invalid MT5API_MAX_MARKET_BOOK_SUBSCRIPTIONS"
@@ -59,22 +72,52 @@ def get_configured_api_host() -> str:
59
72
  return os.getenv(ENV_MT5API_HOST, DEFAULT_API_HOST)
60
73
 
61
74
 
62
- def get_configured_api_port() -> str | None:
63
- """Get the configured API port string.
75
+ def get_configured_api_port() -> int:
76
+ """Get the configured API port.
64
77
 
65
78
  Returns:
66
- Raw port string from the environment, or ``None`` if unset.
79
+ Port number for the API server.
80
+
81
+ Raises:
82
+ ValueError: If the configured port is not an integer in the TCP port range.
67
83
  """
68
- return os.getenv(ENV_MT5API_PORT)
84
+ raw_port = os.getenv(ENV_MT5API_PORT)
85
+ if raw_port is None:
86
+ return DEFAULT_API_PORT
87
+
88
+ try:
89
+ port = int(raw_port)
90
+ except ValueError as error:
91
+ raise ValueError(_INVALID_MT5API_PORT_ERROR) from error
92
+
93
+ if not 1 <= port <= MAX_API_PORT:
94
+ raise ValueError(_INVALID_MT5API_PORT_ERROR)
95
+
96
+ return port
69
97
 
70
98
 
71
99
  def get_configured_api_log_level() -> str:
72
100
  """Get the configured API log level.
73
101
 
74
102
  Returns:
75
- Log level string from configuration.
103
+ Valid uvicorn log level string from configuration.
104
+
105
+ Raises:
106
+ ValueError: If the configured log level is unsupported.
107
+ """
108
+ log_level = os.getenv(ENV_MT5API_LOG_LEVEL, DEFAULT_API_LOG_LEVEL).strip().lower()
109
+ if log_level not in _VALID_UVICORN_LOG_LEVELS:
110
+ raise ValueError(_INVALID_MT5API_LOG_LEVEL_ERROR)
111
+ return log_level
112
+
113
+
114
+ def get_configured_python_log_level() -> str:
115
+ """Get a stdlib logging-compatible log level for the API logger.
116
+
117
+ Returns:
118
+ Python logging level name derived from the configured API log level.
76
119
  """
77
- return os.getenv(ENV_MT5API_LOG_LEVEL, DEFAULT_API_LOG_LEVEL)
120
+ return _LOGGING_LOG_LEVEL_BY_API_LEVEL[get_configured_api_log_level()]
78
121
 
79
122
 
80
123
  def get_configured_api_router_prefix() -> str:
@@ -6,7 +6,7 @@ API_DESCRIPTION = (
6
6
  "Provides market data, account information, trading history, calculations, "
7
7
  "and safe operational endpoints via HTTP."
8
8
  )
9
- API_VERSION = "1.0.0"
9
+ API_VERSION = "1.0.1"
10
10
  API_DOCS_URL = "/docs"
11
11
  API_REDOC_URL = "/redoc"
12
12
  API_OPENAPI_URL = "/openapi.json"
@@ -80,12 +80,12 @@ def shutdown_mt5_client() -> None:
80
80
  async def replace_mt5_client(config: Mt5Config) -> Mt5DataClient:
81
81
  """Swap the MT5 client singleton with a new connection.
82
82
 
83
- Constructs and initializes the new ``Mt5DataClient`` BEFORE touching the
84
- singleton so a failed reconnect leaves the existing client in place
85
- instead of disconnecting the operator from a working terminal. The new
86
- client is installed atomically; the old client (if any) is shut down on
87
- a best-effort basis after the swap. Callers MUST hold
88
- ``get_mt5_client_lock`` so concurrent reconnect requests do not race.
83
+ Constructs and initializes the new ``Mt5DataClient`` before replacing the
84
+ singleton reference. The MetaTrader5 Python module has process-global
85
+ connection state, so the previous client object must not be shut down after
86
+ successful reconnect because that would close the connection just opened by
87
+ the new client. Callers MUST hold ``get_mt5_client_lock`` so concurrent
88
+ reconnect requests do not race.
89
89
 
90
90
  The raised ``RuntimeError`` deliberately omits the underlying exception
91
91
  text from its message because third-party ``pdmt5``/MetaTrader5
@@ -101,7 +101,7 @@ async def replace_mt5_client(config: Mt5Config) -> Mt5DataClient:
101
101
 
102
102
  Raises:
103
103
  RuntimeError: If the new MT5 client cannot be constructed or
104
- initialized. The previously installed client is preserved.
104
+ initialized.
105
105
  """
106
106
  global _mt5_client # noqa: PLW0603
107
107
 
@@ -113,15 +113,8 @@ async def replace_mt5_client(config: Mt5Config) -> Mt5DataClient:
113
113
  error_message = "Failed to initialize MT5 client"
114
114
  raise RuntimeError(error_message) from e
115
115
 
116
- old_client = _mt5_client
117
116
  _mt5_client = new_client
118
117
 
119
- if old_client is not None:
120
- try:
121
- await asyncio.to_thread(old_client.shutdown)
122
- except Exception:
123
- logger.exception("Failed to shutdown previous MT5 client")
124
-
125
118
  return new_client
126
119
 
127
120