PythonMetaTrader5 2.3.2__py3-none-any.whl → 3.0.0__py3-none-any.whl
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.
- PythonMetaTrader5/__init__.py +73 -535
- PythonMetaTrader5/adapters/__init__.py +1 -0
- PythonMetaTrader5/adapters/mt5_mapping.py +92 -0
- PythonMetaTrader5/adapters/mt5_session.py +48 -0
- PythonMetaTrader5/adapters/mt5_terminal.py +224 -0
- PythonMetaTrader5/adapters/system_clock.py +10 -0
- PythonMetaTrader5/application/__init__.py +1 -0
- PythonMetaTrader5/application/batch.py +60 -0
- PythonMetaTrader5/application/entries.py +163 -0
- PythonMetaTrader5/application/execution.py +108 -0
- PythonMetaTrader5/application/magic_scope.py +65 -0
- PythonMetaTrader5/application/ports.py +75 -0
- PythonMetaTrader5/application/trader.py +275 -0
- PythonMetaTrader5/connection.py +52 -0
- PythonMetaTrader5/domain/__init__.py +1 -0
- PythonMetaTrader5/domain/amounts.py +33 -0
- PythonMetaTrader5/domain/errors.py +53 -0
- PythonMetaTrader5/domain/inputs.py +106 -0
- PythonMetaTrader5/domain/market.py +91 -0
- PythonMetaTrader5/domain/orders.py +64 -0
- PythonMetaTrader5/domain/requests.py +32 -0
- PythonMetaTrader5/domain/retcodes.py +81 -0
- PythonMetaTrader5/domain/stops.py +85 -0
- PythonMetaTrader5/domain/symbol.py +158 -0
- PythonMetaTrader5/legacy/__init__.py +1 -0
- PythonMetaTrader5/legacy/arguments.py +52 -0
- PythonMetaTrader5/legacy/broker.py +284 -0
- PythonMetaTrader5/legacy/mt5_namespace.py +56 -0
- PythonMetaTrader5/legacy/views.py +123 -0
- PythonMetaTrader5/py.typed +0 -0
- PythonMetaTrader5/result.py +41 -0
- pythonmetatrader5-3.0.0.dist-info/METADATA +231 -0
- pythonmetatrader5-3.0.0.dist-info/RECORD +36 -0
- {pythonmetatrader5-2.3.2.dist-info → pythonmetatrader5-3.0.0.dist-info}/WHEEL +1 -1
- pythonmetatrader5-3.0.0.dist-info/licenses/LICENSE +16 -0
- pythonmetatrader5-2.3.2.dist-info/METADATA +0 -267
- pythonmetatrader5-2.3.2.dist-info/RECORD +0 -5
- {pythonmetatrader5-2.3.2.dist-info → pythonmetatrader5-3.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PythonMetaTrader5
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: Safe, typed trading layer over the official MetaTrader5 Python API
|
|
5
|
+
Author-email: Wiktor Jelen <wiktorjn@gmail.com>
|
|
6
|
+
License-Expression: CC-BY-NC-4.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/Akinzou/MetaTrader5-Python
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/Akinzou/MetaTrader5-Python/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/Akinzou/MetaTrader5-Python/blob/master/CHANGELOG.md
|
|
10
|
+
Keywords: metatrader5,mt5,trading,forex,algotrading
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: MetaTrader5; sys_platform == "win32"
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
32
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
33
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
34
|
+
Dynamic: license-file
|
|
35
|
+
|
|
36
|
+
# PythonMetaTrader5
|
|
37
|
+
|
|
38
|
+
[](https://github.com/Akinzou/MetaTrader5-Python/actions/workflows/ci.yml)
|
|
39
|
+
[](https://pypi.org/project/PythonMetaTrader5/)
|
|
40
|
+

|
|
41
|
+

|
|
42
|
+
[](https://pepy.tech/projects/pythonmetatrader5)
|
|
43
|
+
[](https://discord.gg/BARYa55KS8)
|
|
44
|
+
|
|
45
|
+
A safe, typed trading layer over the official
|
|
46
|
+
[`MetaTrader5`](https://pypi.org/project/MetaTrader5/) Python package.
|
|
47
|
+
|
|
48
|
+
Built for bots (webhook executors, signal followers) where a trading call must
|
|
49
|
+
**never hang, never retry blindly, and never fail silently**:
|
|
50
|
+
|
|
51
|
+
- **Every trading call returns.** Requotes are retried a bounded number of times
|
|
52
|
+
with a fresh quote; everything else comes back immediately as a typed error.
|
|
53
|
+
(The deprecated `Broker.login(ToEffect=True)` is the one exception: as in
|
|
54
|
+
2.x, it keeps trying until the login works.)
|
|
55
|
+
- **No silent defaults.** Values that MT5 would quietly read as something else
|
|
56
|
+
are refused before sending: `sl=0` ("no stop"), `ticket=0` (possibly "no
|
|
57
|
+
filter"), `volume=True` (one lot), NaN and infinities.
|
|
58
|
+
- **No double fills.** Timeouts and lost connections are never auto-retried:
|
|
59
|
+
the order may already be live.
|
|
60
|
+
- **Typed results.** `Ok(receipt)` or `Err(TradeError)` with an `ErrorKind`
|
|
61
|
+
(`MARKET_CLOSED`, `NO_MONEY`, `INVALID_STOPS`, ...) instead of magic numbers.
|
|
62
|
+
- **Correct prices and lots.** Prices snap to the symbol's tick grid, volumes
|
|
63
|
+
are checked against min/max/step, the filling mode is chosen from the symbol.
|
|
64
|
+
- **Magic numbers.** Tag your bot's trades and close/cancel only those.
|
|
65
|
+
- **SL/TP as prices or distances in points.**
|
|
66
|
+
- **2.x compatible.** The old `Broker` class still works (deprecated).
|
|
67
|
+
|
|
68
|
+
> One connection per process: the official package keeps a single global
|
|
69
|
+
> terminal session, so a second `connect()` (or its failed login) affects the
|
|
70
|
+
> first. Run one process per account.
|
|
71
|
+
>
|
|
72
|
+
> Thread-safe within the library: every terminal call holds one process-wide
|
|
73
|
+
> lock, so a threaded webhook server can share a `Trader`. The MT5 functions
|
|
74
|
+
> re-exported through `PythonMetaTrader5` hold it for each single call (a pair
|
|
75
|
+
> such as `order_send` + `last_error` is not atomic). Calls you make to the
|
|
76
|
+
> `MetaTrader5` module directly bypass it.
|
|
77
|
+
>
|
|
78
|
+
> Requires Windows with a MetaTrader 5 terminal installed (the official
|
|
79
|
+
> `MetaTrader5` package is Windows-only). Enable **Algo Trading** in the terminal.
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install PythonMetaTrader5
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Quick start
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from PythonMetaTrader5 import Err, Ok, Side, Stop, connect
|
|
91
|
+
|
|
92
|
+
match connect(12345678, "password", "MetaQuotes-Demo", magic=1001):
|
|
93
|
+
case Err(error):
|
|
94
|
+
raise SystemExit(f"cannot connect: {error}")
|
|
95
|
+
case Ok(trader):
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
with trader: # shuts the terminal connection down on exit
|
|
99
|
+
result = trader.open_position(
|
|
100
|
+
"EURUSD", Side.BUY, 0.10,
|
|
101
|
+
sl=Stop.points(1000), # 1000 points below the entry price
|
|
102
|
+
tp=1.12500, # a plain float is an absolute price
|
|
103
|
+
comment="webhook #42",
|
|
104
|
+
)
|
|
105
|
+
match result:
|
|
106
|
+
case Ok(receipt):
|
|
107
|
+
print("filled at", receipt.price, "deal", receipt.deal)
|
|
108
|
+
case Err(error):
|
|
109
|
+
print("not opened:", error.kind, error.message)
|
|
110
|
+
|
|
111
|
+
trader.close_positions("EURUSD") # only this bot's (magic 1001) positions
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## API
|
|
115
|
+
|
|
116
|
+
`connect(login, password, server, *, path=None, timeout_ms=60000, magic=0,
|
|
117
|
+
deviation=10, retry=None) -> Result[Trader, TradeError]`
|
|
118
|
+
|
|
119
|
+
`login` must be a positive integer or a string of ASCII digits; `True`,
|
|
120
|
+
`12345678.9` and similar values are rejected rather than coerced.
|
|
121
|
+
|
|
122
|
+
| `Trader` method | Returns |
|
|
123
|
+
|---|---|
|
|
124
|
+
| `open_position(symbol, side, volume, *, sl=None, tp=None, price=None, comment=None)` | `Result[TradeReceipt, TradeError]` |
|
|
125
|
+
| `place_limit_order(symbol, side, volume, price, *, sl=None, tp=None, comment=None)` | `Result[TradeReceipt, TradeError]` |
|
|
126
|
+
| `close_positions(symbol=None, *, ticket=None, magic=<own>, comment=None)` | `Result[list[TradeReceipt], BatchFailure]` |
|
|
127
|
+
| `cancel_pending_orders(symbol=None, *, magic=<own>, kind=None)` | `Result[list[TradeReceipt], BatchFailure]` |
|
|
128
|
+
| `positions(symbol=None, *, ticket=None, magic=None)` | `Result[list[Position], TradeError]` |
|
|
129
|
+
| `pending_orders(symbol=None, *, magic=None, kind=None)` | `Result[list[PendingOrder], TradeError]` |
|
|
130
|
+
| `shutdown()` | `None` |
|
|
131
|
+
|
|
132
|
+
- `side`: `Side.BUY` / `Side.SELL`, or the strings `"buy"`, `"sell"`, `"long"`, `"short"`.
|
|
133
|
+
- `sl` / `tp`: a float is an **absolute price**; `Stop.points(n)` is a distance
|
|
134
|
+
of `n` points from the entry price (`Stop.at_price(p)` is the explicit form).
|
|
135
|
+
For limit orders the distance is measured from the limit price, and for a
|
|
136
|
+
market order with an explicit `price` from that price. A float stop that is
|
|
137
|
+
zero, negative or not finite is rejected (`INVALID_STOPS`); pass `None` for
|
|
138
|
+
no stop. `Stop.points()` / `Stop.at_price()` raise `ValueError` unless the
|
|
139
|
+
value is a positive finite number (bool and str included; a zero stop would
|
|
140
|
+
mean "no stop" to MT5); the sign of a points distance is ignored. A `kind`
|
|
141
|
+
that is not a `StopKind` raises `TypeError`. A stop that resolves outside
|
|
142
|
+
the tick grid's range, or to zero or below, is `INVALID_STOPS` when the
|
|
143
|
+
order is built. For a value that may be bad at runtime, such as
|
|
144
|
+
an ATR that is NaN during warm-up, use
|
|
145
|
+
`Stop.parse(value, StopKind.POINTS)`, which returns `Ok(stop)` /
|
|
146
|
+
`Err(INVALID_STOPS)`.
|
|
147
|
+
- Amounts may be `int`, `float`, `Decimal` or numpy scalars; `bool` and strings
|
|
148
|
+
are refused (the deprecated `Broker` still converts numeric strings).
|
|
149
|
+
- `price` (market orders): send at this price once instead of the live quote.
|
|
150
|
+
- `comment`: at most 29 UTF-16 units: 29 characters, but characters outside
|
|
151
|
+
the BMP, such as most emoji, count as 2 (combined emoji more). The `MetaTrader5` package refuses 30 or more (measured on 5.0.6231; its
|
|
152
|
+
docs say 31). Longer comments, and comments that are not `str`, are rejected
|
|
153
|
+
before sending, not truncated.
|
|
154
|
+
- **`close_positions()` and `cancel_pending_orders()` act only on the trader's
|
|
155
|
+
own `magic`** unless you pass another one (ADR 0011); `magic=None` is still
|
|
156
|
+
"own". To act on the whole account, manual trades included, pass
|
|
157
|
+
`magic=ANY_MAGIC`. A `ticket` is closed whatever its magic. `positions()`
|
|
158
|
+
and `pending_orders()` still list every magic by default.
|
|
159
|
+
- Manual trades have magic 0, the `connect()` default, so set your own `magic`
|
|
160
|
+
for this to protect them. Until then a close/cancel that affects magic-0
|
|
161
|
+
items logs a warning; `magic=0` passed explicitly acknowledges it. On a
|
|
162
|
+
netting account a position keeps the magic of the deal that opened it, so
|
|
163
|
+
merged volume cannot be told apart by magic; a defaulted close/cancel that
|
|
164
|
+
matches nothing logs how many items with other magics it left open.
|
|
165
|
+
- A magic must be an integer from 0 to 2\*\*64-1 (MT5's ulong); `connect()`
|
|
166
|
+
returns `Err(INVALID_ARGUMENT)` otherwise, e.g. for `None`. An empty string
|
|
167
|
+
`""` as symbol is rejected too.
|
|
168
|
+
- `BatchFailure.errors` names every position/order that failed
|
|
169
|
+
(`TradeError.ticket`). `BatchFailure.succeeded` holds the receipts of the
|
|
170
|
+
ones that worked; their `order` / `deal` are the IDs of the closing deal, not
|
|
171
|
+
the position ticket.
|
|
172
|
+
- `ticket` must be a positive integer; `0`, `True` or `"7"` are rejected.
|
|
173
|
+
|
|
174
|
+
### Errors
|
|
175
|
+
|
|
176
|
+
`TradeError(kind, message, retcode=None, receipt=None, ticket=None)`. The
|
|
177
|
+
`receipt` carries the broker's raw answer when there was one. Retry policy:
|
|
178
|
+
|
|
179
|
+
| Server answer | What happens |
|
|
180
|
+
|---|---|
|
|
181
|
+
| market deal (entry or close): done | `Ok(receipt)` |
|
|
182
|
+
| pending order: placed or done | `Ok(receipt)` |
|
|
183
|
+
| market deal: partial fill | `PARTIAL_FILL` with the receipt; part of the deal exists, never re-sent |
|
|
184
|
+
| market deal: placed (queued, not executed) | `OUTCOME_UNKNOWN` with the receipt, never re-sent |
|
|
185
|
+
| requote, price changed, no quotes, too many requests | retried with a fresh quote, up to `RetryPolicy.attempts` (default 3, 0.5 s apart), then `RETRIES_EXHAUSTED` |
|
|
186
|
+
| timeout, no connection, or `order_send` lost in IPC | `OUTCOME_UNKNOWN`, never retried: check `positions()` first |
|
|
187
|
+
| anything else | the matching `ErrorKind`, returned at once |
|
|
188
|
+
| refused before sending: the terminal's symbol data cannot price an order (point 0, NaN tick size, volume step 0, ...) | `BROKEN_SYMBOL_DATA`, the same on every resend: escalate, don't retry. Closing still works on such symbols |
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
from PythonMetaTrader5 import RetryPolicy, connect
|
|
192
|
+
|
|
193
|
+
connect(..., retry=RetryPolicy(attempts=5, delay_seconds=0.2))
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Logging
|
|
197
|
+
|
|
198
|
+
The library logs through the standard `logging` module under the
|
|
199
|
+
`PythonMetaTrader5` logger and never configures handlers itself. Without any
|
|
200
|
+
logging configuration, warnings and errors still reach stderr.
|
|
201
|
+
|
|
202
|
+
## Migrating from 2.x
|
|
203
|
+
|
|
204
|
+
`from PythonMetaTrader5 import Broker` keeps working and emits a
|
|
205
|
+
`DeprecationWarning`. `from PythonMetaTrader5 import *` still brings in the
|
|
206
|
+
`MetaTrader5` functions and constants, as in 2.x. Several 2.x behaviours were unsafe and changed: see
|
|
207
|
+
[MIGRATION.md](MIGRATION.md).
|
|
208
|
+
|
|
209
|
+
## Development
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
python -m venv .venv && .venv\Scripts\activate
|
|
213
|
+
pip install -e ".[dev]"
|
|
214
|
+
ruff check src tests scripts && ruff format --check src tests scripts
|
|
215
|
+
mypy
|
|
216
|
+
pytest --cov
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`tests/contract` compares the unit-test fakes with the installed `MetaTrader5`
|
|
220
|
+
package and is skipped where it is not installed (anywhere but Windows).
|
|
221
|
+
Integration tests trade on a **demo** account and are skipped unless
|
|
222
|
+
`MT5_LOGIN`, `MT5_PASSWORD` and `MT5_SERVER` are set (they refuse to run on a
|
|
223
|
+
live account): `pytest -m integration`.
|
|
224
|
+
|
|
225
|
+
Architecture and decisions: [docs/architecture.md](docs/architecture.md),
|
|
226
|
+
[docs/adr](docs/adr).
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
[CC BY-NC 4.0](LICENSE). Trading carries risk; this software comes without any
|
|
231
|
+
warranty.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
PythonMetaTrader5/__init__.py,sha256=bALjGPZAZJwaduG6zQ_2ifF1yYSlSUwug6iRujTnw58,2761
|
|
2
|
+
PythonMetaTrader5/connection.py,sha256=xA6VhhqNM-oXGh3ieWS8bCr9yAb4aEVtontgDsHwrQ4,1898
|
|
3
|
+
PythonMetaTrader5/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
PythonMetaTrader5/result.py,sha256=Q3RpcspZgb8nEf8Tnm_W4cx9IldyUDIN_DiCwZg5nEQ,956
|
|
5
|
+
PythonMetaTrader5/adapters/__init__.py,sha256=SfTHYRiDD8Qyi9zAtjh1WQJbT2XKL9C58zDM7P-RU0c,67
|
|
6
|
+
PythonMetaTrader5/adapters/mt5_mapping.py,sha256=YYQO_pFSbavKpeir2zGbZyYmMcp_tqssJa0la_VaB2Y,3089
|
|
7
|
+
PythonMetaTrader5/adapters/mt5_session.py,sha256=hoXlaKMdM1INqOE8Cc4bo3S8vvWNivXq_d1jgA0v9YE,1837
|
|
8
|
+
PythonMetaTrader5/adapters/mt5_terminal.py,sha256=OlpWUIR8wYAb7slKcCulni3JiwsQB8574FcOq6oQPpw,9476
|
|
9
|
+
PythonMetaTrader5/adapters/system_clock.py,sha256=h5dDN-xHNREghu0pCfbO5wM7BvawZQ9YDDAm36KpTkM,188
|
|
10
|
+
PythonMetaTrader5/application/__init__.py,sha256=sAbMrgqvIrwVA1TMdDfkVyh3dO9matXRVTiihb91ns4,64
|
|
11
|
+
PythonMetaTrader5/application/batch.py,sha256=krKHiBXU49aaBGmtC82O8L2oNKjUny5hqdC8YNBPR1o,1940
|
|
12
|
+
PythonMetaTrader5/application/entries.py,sha256=8uL4rI7h4iZjEh4nGVpi5UJQBL2Z7pdpXKN7cNKjWuQ,6025
|
|
13
|
+
PythonMetaTrader5/application/execution.py,sha256=uCJlMnvJKCteAvFw8mLBgndoYU_oooBn91VTpWS2P_Y,4208
|
|
14
|
+
PythonMetaTrader5/application/magic_scope.py,sha256=zxUyY_8z-96SCwr3lu-W8AdVqoG_Ug17TQHabnJdwOQ,2429
|
|
15
|
+
PythonMetaTrader5/application/ports.py,sha256=yeJrWLbdh1ncdYxn8c9cNGMdwppReTrigCPPc8OIKoA,2642
|
|
16
|
+
PythonMetaTrader5/application/trader.py,sha256=Ahw1WEleyYGs3V0b59pmBLdf878pHiSJ31r7dyN0PFM,10203
|
|
17
|
+
PythonMetaTrader5/domain/__init__.py,sha256=ZZ7iypJWkoG-nK2y_Dj0CG4IRZETi7IGJ90jY06cak8,57
|
|
18
|
+
PythonMetaTrader5/domain/amounts.py,sha256=ab_shtLiqn1I__9R7LtG_Vrz2hjrKwFqUZ1JE5F4tTo,1475
|
|
19
|
+
PythonMetaTrader5/domain/errors.py,sha256=Or7wDSlBO6Yo6miQiQOnXsInUXR67aMRhLhtZXKSVz8,2013
|
|
20
|
+
PythonMetaTrader5/domain/inputs.py,sha256=g_Z3s3e0H-VlKqNvvBTnXdavkVcKXt9kzE-PYryfcB0,4075
|
|
21
|
+
PythonMetaTrader5/domain/market.py,sha256=rBMc17-Uki3boAvPcDZNNPbYRtFxVFWGrGxoPZaBYrE,2051
|
|
22
|
+
PythonMetaTrader5/domain/orders.py,sha256=QA_AlOENgEZSD0ssP0WYJeJRdOC4zZ4z8-xtyRr0RTI,2399
|
|
23
|
+
PythonMetaTrader5/domain/requests.py,sha256=WngSUCpcSlQGBn8a7pMBV-TKVwNtFFqzRQNMuWZ-F9A,857
|
|
24
|
+
PythonMetaTrader5/domain/retcodes.py,sha256=Zstjn2Z-fbl4LZY7EacvSnYnxKJLxj5tzKoNF2YXDTI,3825
|
|
25
|
+
PythonMetaTrader5/domain/stops.py,sha256=G-eKU1z_LiKTugkfuPbMfoyUpCww1NhB7GqrNDKjTKU,3325
|
|
26
|
+
PythonMetaTrader5/domain/symbol.py,sha256=UnNJETCa7JXXqZrEWXVk07AxSBpOPsptV-aKtbPlJH8,7039
|
|
27
|
+
PythonMetaTrader5/legacy/__init__.py,sha256=g-HN0OW4CQ2xmYPdzjsIKoFJlZQquypd_wbairdEWiw,72
|
|
28
|
+
PythonMetaTrader5/legacy/arguments.py,sha256=bkklwl-9e6-JSY3bdPztwaElLXz8ro0qLieVkqozlbI,1802
|
|
29
|
+
PythonMetaTrader5/legacy/broker.py,sha256=qQC9gCsNQqjpH-AvX6PG6uVxU8Sm5bnziyDChoG_1sg,11168
|
|
30
|
+
PythonMetaTrader5/legacy/mt5_namespace.py,sha256=z-Woo4SnWu7ACk4j9zZ62h5K41cwhAae4ZAwtl4PKRQ,2411
|
|
31
|
+
PythonMetaTrader5/legacy/views.py,sha256=O_vDxru28cIn6j0kqNJerDcyVbRY4oLEnTtSAlA1H08,3260
|
|
32
|
+
pythonmetatrader5-3.0.0.dist-info/licenses/LICENSE,sha256=XDOg33_Bini4gyXwSu3XzYs5Gf3Han6tAojB-dZD5DQ,659
|
|
33
|
+
pythonmetatrader5-3.0.0.dist-info/METADATA,sha256=IUDIfEZPg2tx9fyBQLvdUL1hch2pMAxicnQ1M4U978Y,11658
|
|
34
|
+
pythonmetatrader5-3.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
35
|
+
pythonmetatrader5-3.0.0.dist-info/top_level.txt,sha256=r8xFh3BXAc7RVgR1j6wCYfyk_mm_DaDoGUYFk2IqBLE,18
|
|
36
|
+
pythonmetatrader5-3.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
PythonMetaTrader5
|
|
2
|
+
Copyright (c) Wiktor Jelen
|
|
3
|
+
|
|
4
|
+
This work is licensed under the Creative Commons Attribution-NonCommercial 4.0
|
|
5
|
+
International License (CC BY-NC 4.0).
|
|
6
|
+
|
|
7
|
+
You are free to share and adapt this work for non-commercial purposes, provided
|
|
8
|
+
you give appropriate credit, link to the license, and indicate if changes were
|
|
9
|
+
made.
|
|
10
|
+
|
|
11
|
+
Full legal code: https://creativecommons.org/licenses/by-nc/4.0/legalcode
|
|
12
|
+
Summary: https://creativecommons.org/licenses/by-nc/4.0/
|
|
13
|
+
|
|
14
|
+
THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. TRADING FINANCIAL
|
|
15
|
+
INSTRUMENTS CARRIES RISK; THE AUTHORS ARE NOT LIABLE FOR ANY LOSSES INCURRED
|
|
16
|
+
THROUGH THE USE OF THIS SOFTWARE.
|
|
@@ -1,267 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: PythonMetaTrader5
|
|
3
|
-
Version: 2.3.2
|
|
4
|
-
Summary: Connect MT5 with Python
|
|
5
|
-
Author-email: Wiktor Jelen <wiktorjn@gmail.com>
|
|
6
|
-
License: CC BY-NC 4.0
|
|
7
|
-
Project-URL: Homepage, https://github.com/Akinzou/MetaTrader5-Python
|
|
8
|
-
Project-URL: Bug Tracker, https://github.com/Akinzou/MetaTrader5-Python/issues
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.6
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
Requires-Dist: MetaTrader5
|
|
15
|
-
Requires-Dist: loguru
|
|
16
|
-
Requires-Dist: pyautogui
|
|
17
|
-
|
|
18
|
-
# PythonMetaTrader5 [](https://github.com/Akinzou/MetaTrader5-Python/actions/workflows/python-publish.yml)    [](https://pepy.tech/projects/pythonmetatrader5)
|
|
19
|
-
|
|
20
|
-
[](https://discord.gg/BARYa55KS8)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# MetaTrader5 Python Broker Helper
|
|
24
|
-
|
|
25
|
-
Minimal, production‑ready helper around the official **MetaTrader5** Python package,
|
|
26
|
-
with a single market-entry function and clean handling of **SL/TP as absolute prices or offsets in POINTS**.
|
|
27
|
-
Includes utilities to read positions, close them, and manage pending orders.
|
|
28
|
-
|
|
29
|
-
> Works with: `MetaTrader5`, `loguru`, `pyautogui`
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Features
|
|
34
|
-
|
|
35
|
-
- ✅ One function to open market positions: `OpenPosition(...)`
|
|
36
|
-
- ✅ SL/TP can be passed **as absolute prices** or **offsets in POINTS**
|
|
37
|
-
- ✅ Automatic price normalization to instrument `digits`
|
|
38
|
-
- ✅ Consistent error handling (common MT5 retcodes mapped to messages)
|
|
39
|
-
- ✅ Backward‑compat wrappers: `Buy`, `Sell`, `BuySL`, `SellSL`
|
|
40
|
-
- ✅ Position helpers: `GetPositions`, `GetPosition`, `GetPositionsBySymbol`
|
|
41
|
-
- ✅ Closing and pending orders helpers: `Close`, `SellLimit`, `BuyLimit`, `CancelOrders`
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
## Installation
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
pip install MetaTrader5
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
> Ensure your MetaTrader 5 terminal is running, logged in, and **Algo Trading** is enabled.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## Quick Start
|
|
56
|
-
|
|
57
|
-
```python
|
|
58
|
-
from PythonMetaTrader5 import Broker
|
|
59
|
-
import time
|
|
60
|
-
|
|
61
|
-
# Login to your account
|
|
62
|
-
broker = Broker(96540048, "PASSWORD", "MetaQuotes-Demo")
|
|
63
|
-
time.sleep(1) # small grace period after login
|
|
64
|
-
|
|
65
|
-
# Open BUY with SL/TP given as OFFSETS IN POINTS
|
|
66
|
-
r = broker.OpenPosition(
|
|
67
|
-
"EURUSD", "buy", 0.10,
|
|
68
|
-
sl=1000, sl_type="offset", # 1000 points (≈ 100 pips on 5-digit symbol)
|
|
69
|
-
tp=1500, tp_type="offset"
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
# Read positions for a symbol
|
|
73
|
-
xau_positions = broker.GetPositionsBySymbol("XAUUSD", as_dict=True)
|
|
74
|
-
|
|
75
|
-
# Close all positions on a symbol
|
|
76
|
-
broker.Close("EURUSD")
|
|
77
|
-
|
|
78
|
-
# Cancel pending limit orders on a symbol
|
|
79
|
-
broker.CancelOrders("EURUSD")
|
|
80
|
-
|
|
81
|
-
# Graceful shutdown
|
|
82
|
-
broker.Disconnect()
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## SL/TP Semantics (Important)
|
|
88
|
-
|
|
89
|
-
- `sl_type` / `tp_type`:
|
|
90
|
-
- `"absolute"` → you pass **absolute prices** (e.g., `1.23456`)
|
|
91
|
-
- `"offset"` → you pass **offsets in POINTS** (converted using `symbol_info(symbol).point`)
|
|
92
|
-
|
|
93
|
-
- Offsets are applied from the **current tick price** (`ask` for BUY, `bid` for SELL):
|
|
94
|
-
- BUY : `SL = ask - |sl|*point`, `TP = ask + |tp|*point`
|
|
95
|
-
- SELL: `SL = bid + |sl|*point`, `TP = bid - |tp|*point`
|
|
96
|
-
|
|
97
|
-
- All calculated prices (including absolute inputs) are normalized to the instrument `digits`.
|
|
98
|
-
|
|
99
|
-
> If you get `Wrong SL (10016)`, check `symbol_info(symbol).stops_level` and multiply by `point` to know the minimal allowed distance.
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## API Reference
|
|
104
|
-
|
|
105
|
-
### `class Broker`
|
|
106
|
-
|
|
107
|
-
#### `__init__(self, log, password, server)`
|
|
108
|
-
Initialize MT5, attempt login, and print account info on success.
|
|
109
|
-
|
|
110
|
-
- **log**: login number (int or str)
|
|
111
|
-
- **password**: account password (str)
|
|
112
|
-
- **server**: broker server name (str)
|
|
113
|
-
|
|
114
|
-
#### `login(self, ToEffect=False) -> bool`
|
|
115
|
-
Retrying login loop. If `ToEffect` is `False`, returns immediately on failure.
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
### Market Entry
|
|
120
|
-
|
|
121
|
-
#### `OpenPosition(self, symbol, side, volume, *, sl=None, tp=None, price=None, comment=None, ticket=None, sl_type="absolute", tp_type="absolute")`
|
|
122
|
-
Open a market position.
|
|
123
|
-
|
|
124
|
-
- **symbol**: e.g., `"EURUSD"`
|
|
125
|
-
- **side**: `"buy" | "sell" | "long" | "short"`
|
|
126
|
-
- **volume**: lot size (float)
|
|
127
|
-
- **sl**/**tp**: number (see `sl_type`/`tp_type`)
|
|
128
|
-
- **sl_type**/**tp_type**: `"absolute"` (prices) or `"offset"` (**POINTS**)
|
|
129
|
-
- **price**: optional direct price; if `None`, uses current tick (ask/bid) and retries on transient errors
|
|
130
|
-
- **comment**: optional MT5 order comment
|
|
131
|
-
- **ticket**: existing position id if needed (rarely used for market entry)
|
|
132
|
-
|
|
133
|
-
**Returns**: result of `order_send` (MT5 `TradeResult`)
|
|
134
|
-
|
|
135
|
-
**Examples**:
|
|
136
|
-
```python
|
|
137
|
-
# Absolute prices
|
|
138
|
-
broker.OpenPosition("XAUUSD", "sell", 0.10, sl=2400.0, tp=2380.0, sl_type="absolute", tp_type="absolute")
|
|
139
|
-
|
|
140
|
-
# Offsets in POINTS
|
|
141
|
-
broker.OpenPosition("EURUSD", "buy", 0.10, sl=1000, tp=1500, sl_type="offset", tp_type="offset")
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
### Backward‑Compat Wrappers
|
|
147
|
-
|
|
148
|
-
#### `Buy(self, symbol, volume, price=None, *, comment=None, ticket=None)`
|
|
149
|
-
Market BUY via `OpenPosition`.
|
|
150
|
-
|
|
151
|
-
#### `Sell(self, symbol, volume, price=None, *, comment=None, ticket=None)`
|
|
152
|
-
Market SELL via `OpenPosition`.
|
|
153
|
-
|
|
154
|
-
#### `BuySL(self, symbol, volume, sl, price=None, *, comment=None, ticket=None, sl_type="absolute")`
|
|
155
|
-
BUY with SL specified (absolute or offset in points).
|
|
156
|
-
|
|
157
|
-
#### `SellSL(self, symbol, volume, sl, price=None, *, comment=None, ticket=None, sl_type="absolute")`
|
|
158
|
-
SELL with SL specified (absolute or offset in points).
|
|
159
|
-
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
### Close & Pending Orders
|
|
163
|
-
|
|
164
|
-
#### `Close(self, symbol, *, comment=None, ticket=None) -> bool`
|
|
165
|
-
Iteratively closes all positions for a **ticket** or for a **symbol** (same filtering semantics as `positions_get`). Returns `False` if nothing to close.
|
|
166
|
-
|
|
167
|
-
#### `SellLimit(self, symbol, volume, stoplimit, price=None, comment=None, ticket=None)`
|
|
168
|
-
Create a SELL LIMIT order at `stoplimit`. If current `bid >= stoplimit`, executes a market SELL immediately for consistency.
|
|
169
|
-
|
|
170
|
-
#### `BuyLimit(self, symbol, volume, stoplimit, price=None, comment=None, ticket=None)`
|
|
171
|
-
Create a BUY LIMIT order at `stoplimit`. If current `ask <= stoplimit`, executes a market BUY immediately.
|
|
172
|
-
|
|
173
|
-
#### `CancelOrders(self, symbol)`
|
|
174
|
-
Cancel all BUY/SELL LIMIT pending orders on the given symbol.
|
|
175
|
-
|
|
176
|
-
#### `Disconnect(self)`
|
|
177
|
-
Shutdown MT5 connection.
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
### Positions Helpers
|
|
182
|
-
|
|
183
|
-
#### `GetPositionsBySymbol(self, symbol: str, as_dict: bool = False) -> list`
|
|
184
|
-
Return all open positions for a symbol. If `as_dict=True`, returns a list of plain dictionaries (ready for JSON/GUI).
|
|
185
|
-
|
|
186
|
-
#### `GetPositions(self, symbol=None, *, ticket=None, as_dict: bool = False) -> list`
|
|
187
|
-
Return positions with the same filter style as `Close()`:
|
|
188
|
-
- `ticket` provided → that single position
|
|
189
|
-
- else `symbol` provided → all for that symbol
|
|
190
|
-
- else → all positions
|
|
191
|
-
|
|
192
|
-
#### `GetPosition(self, symbol=None, *, ticket=None, as_dict: bool = False)`
|
|
193
|
-
Return the first matching position (or `None`). Useful when at most one position is expected.
|
|
194
|
-
|
|
195
|
-
**Example**:
|
|
196
|
-
```python
|
|
197
|
-
p = broker.GetPosition(symbol="XAUUSD", as_dict=True)
|
|
198
|
-
if p:
|
|
199
|
-
print("Ticket:", p["ticket"], "Type:", "BUY" if p["type"] == 0 else "SELL", "Profit:", p["profit"])
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
---
|
|
203
|
-
|
|
204
|
-
## Error Handling & Retcodes
|
|
205
|
-
|
|
206
|
-
- Known retcodes are mapped in `RetCodes`:
|
|
207
|
-
- `10027`: Enable Algo Trading in MetaTrader5 app
|
|
208
|
-
- `10018`: Market closed
|
|
209
|
-
- `10016`: Wrong SL
|
|
210
|
-
|
|
211
|
-
- For `10027`, a `Ctrl+E` hotkey is issued via `pyautogui` to toggle Algo Trading.
|
|
212
|
-
- For `10016`, retries are **not** attempted (invalid SL/TP).
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Advanced Examples
|
|
217
|
-
|
|
218
|
-
```python
|
|
219
|
-
# 1) BUY with SL absolute price, TP as offset in points
|
|
220
|
-
broker.OpenPosition(
|
|
221
|
-
"US500", "buy", 1.0,
|
|
222
|
-
sl=5780.0, sl_type="absolute",
|
|
223
|
-
tp=200, tp_type="offset"
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
# 2) SELL with both offsets in points
|
|
227
|
-
broker.OpenPosition(
|
|
228
|
-
"EURUSD", "sell", 0.2,
|
|
229
|
-
sl=800, tp=1200,
|
|
230
|
-
sl_type="offset", tp_type="offset"
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
# 3) Get all positions as dicts and filter by profit
|
|
234
|
-
pos = broker.GetPositions(as_dict=True)
|
|
235
|
-
winners = [p for p in pos if p["profit"] > 0]
|
|
236
|
-
|
|
237
|
-
# 4) Close by ticket
|
|
238
|
-
p = broker.GetPosition(symbol="XAUUSD")
|
|
239
|
-
if p:
|
|
240
|
-
broker.Close("XAUUSD", ticket=p.ticket)
|
|
241
|
-
|
|
242
|
-
# 5) Pending orders
|
|
243
|
-
broker.BuyLimit("EURUSD", 0.10, stoplimit=1.10000)
|
|
244
|
-
broker.SellLimit("EURUSD", 0.10, stoplimit=1.12000)
|
|
245
|
-
broker.CancelOrders("EURUSD")
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
## Notes
|
|
251
|
-
|
|
252
|
-
- Ensure the symbol is visible/active in MT5 Market Watch.
|
|
253
|
-
- Check `stops_level`/`freeze_level` on your broker if SL/TP are rejected:
|
|
254
|
-
```python
|
|
255
|
-
info = symbol_info("EURUSD")
|
|
256
|
-
print(info.point, info.digits, info.stops_level, info.freeze_level, info.volume_min, info.volume_step)
|
|
257
|
-
```
|
|
258
|
-
- `volume` must respect broker `volume_min`/`volume_step`.
|
|
259
|
-
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
## License
|
|
263
|
-
|
|
264
|
-
CC-BY-NC 4.0
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
PythonMetaTrader5/__init__.py,sha256=FQYk4BheVnCjEDqIKFw_i5bR6tTOquydzNtxbKkO9F8,21318
|
|
2
|
-
pythonmetatrader5-2.3.2.dist-info/METADATA,sha256=APqxO1ni0V5HA0gN37blvK0QPYxjnz0kcOFxvB669jc,8814
|
|
3
|
-
pythonmetatrader5-2.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
4
|
-
pythonmetatrader5-2.3.2.dist-info/top_level.txt,sha256=r8xFh3BXAc7RVgR1j6wCYfyk_mm_DaDoGUYFk2IqBLE,18
|
|
5
|
-
pythonmetatrader5-2.3.2.dist-info/RECORD,,
|
|
File without changes
|