pmt4api 1.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.
- pmt4api/__init__.py +32 -0
- pmt4api/__main__.py +78 -0
- pmt4api/_account.py +253 -0
- pmt4api/_base.py +24 -0
- pmt4api/_coverage.py +186 -0
- pmt4api/_events.py +189 -0
- pmt4api/_market.py +263 -0
- pmt4api/_native/CHANGELOG.md +362 -0
- pmt4api/_native/THIRD-PARTY-NOTICES.txt +7 -0
- pmt4api/_native/docs/ERRORS.md +136 -0
- pmt4api/_native/docs/LICENSING.md +55 -0
- pmt4api/_native/docs/SECURITY.md +38 -0
- pmt4api/_native/wmt4api.dll +0 -0
- pmt4api/_risk.py +66 -0
- pmt4api/_runtime.py +154 -0
- pmt4api/_session.py +171 -0
- pmt4api/_streams.py +238 -0
- pmt4api/_trading.py +384 -0
- pmt4api/_util.py +78 -0
- pmt4api/bars.py +62 -0
- pmt4api/client.py +143 -0
- pmt4api/diagnostics.py +38 -0
- pmt4api/docs/API.md +702 -0
- pmt4api/docs/FROM-CSHARP.md +151 -0
- pmt4api/errors.py +233 -0
- pmt4api/frames.py +21 -0
- pmt4api/models.py +337 -0
- pmt4api/py.typed +0 -0
- pmt4api/servers.py +40 -0
- pmt4api-1.0.0.dist-info/METADATA +389 -0
- pmt4api-1.0.0.dist-info/RECORD +33 -0
- pmt4api-1.0.0.dist-info/WHEEL +4 -0
- pmt4api-1.0.0.dist-info/licenses/LICENSE.txt +29 -0
pmt4api/docs/API.md
ADDED
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
# pmt4api — API reference
|
|
2
|
+
|
|
3
|
+
Generated from the code (`tools/gen_docs.py`); do not edit by hand. Times are naive `datetime` values in the broker's server time. Every call that needs a connection raises `NotConnectedError` when there is none, and every error is a subclass of `pmt4api.WmtError`.
|
|
4
|
+
|
|
5
|
+
## Constructing a client
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
Client(login, password, host, port=443, *, api_key=None, token_url=None, dll_path=None, connect_timeout=None, token_timeout=None, trade_timeout=None, quote_timeout=None, history_timeout=None, bars_timeout=None, no_message_timeout=None, auto_reconnect=False, reconnect_backoff=None, reconnect_max_attempts=None, servers=None, comment_encoding='latin-1', placed_type=None)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
A connection to one MetaTrader 4 account through the licensed core.
|
|
12
|
+
|
|
13
|
+
>>> with Client(login, password, host, port, api_key="wk_...") as c:
|
|
14
|
+
... print(c.quote("EURUSDm"))
|
|
15
|
+
|
|
16
|
+
Credentials and library: `api_key` falls back to the `WMT4API_KEY` environment variable (then `WMTAPI_KEY`)
|
|
17
|
+
and `token_url` to `WMT4API_TOKEN_URL` (the core reads these itself); `dll_path` falls back to
|
|
18
|
+
`WMT4API_DLL`, then to the core bundled in the wheel.
|
|
19
|
+
|
|
20
|
+
Timeouts are in seconds: `connect_timeout` (one connect attempt on one server), `token_timeout` (each licence
|
|
21
|
+
request), `trade_timeout` (a trade confirmation; at least 1 s), `quote_timeout` (waiting for a quote),
|
|
22
|
+
`history_timeout` / `bars_timeout` (downloads), `no_message_timeout` (silence after which the session is
|
|
23
|
+
declared dead and closed: default 30 s, at least 10 s, `0` switches it off; the server answers a ping every few
|
|
24
|
+
seconds, so a longer silence means the link stopped carrying traffic). Every other timeout must be positive; the
|
|
25
|
+
quote, history and bars timeouts are the defaults of `quote`, `history` and `bars`. The
|
|
26
|
+
handshake with the broker has its own fixed 30 s limit, whatever `connect_timeout` says (that one bounds the
|
|
27
|
+
TCP dial of each server).
|
|
28
|
+
|
|
29
|
+
Reconnecting: `auto_reconnect=True` turns on the core's watchdog (exponential backoff, failover across the
|
|
30
|
+
primary server, `servers` and the broker's published list, re-subscription); tune it with `reconnect_backoff`
|
|
31
|
+
(seconds) and `reconnect_max_attempts` (0 = until reconnected or `disconnect()`). Do not poll `connected`
|
|
32
|
+
and call `connect()` in a loop. `servers` are extra `(host, port)` access servers to fall back to.
|
|
33
|
+
|
|
34
|
+
`comment_encoding` is the codepage order comments are written in (default `latin-1`); `placed_type`
|
|
35
|
+
records how orders are placed (`"manual"`, `"expert"`, `"dealer"`; a per-call `placed_type` overrides it).
|
|
36
|
+
|
|
37
|
+
Callbacks run on a dispatcher thread of this client, not on the thread that created it.
|
|
38
|
+
|
|
39
|
+
## Connection and session
|
|
40
|
+
|
|
41
|
+
#### `async aconnect()`
|
|
42
|
+
|
|
43
|
+
Awaitable `connect`; the blocking connect runs on a worker thread.
|
|
44
|
+
|
|
45
|
+
#### `add_server(host, port=443)`
|
|
46
|
+
|
|
47
|
+
Add a backup access server, tried (in order) when the primary one cannot be dialled. Credential
|
|
48
|
+
rejections do not fail over. Takes effect at the next connect.
|
|
49
|
+
|
|
50
|
+
#### `async adisconnect()`
|
|
51
|
+
|
|
52
|
+
Awaitable `disconnect`.
|
|
53
|
+
|
|
54
|
+
#### `can_trade` *(property)*
|
|
55
|
+
|
|
56
|
+
Connected with a trading (not investor) password. The broker may still refuse a particular symbol or
|
|
57
|
+
time; this only says the session is allowed to try. See `is_investor`.
|
|
58
|
+
|
|
59
|
+
#### `company` *(property)*
|
|
60
|
+
|
|
61
|
+
The broker's company name, as the server reports it (empty before the first connect).
|
|
62
|
+
|
|
63
|
+
#### `connect()`
|
|
64
|
+
|
|
65
|
+
Connect, authorise through the licence service and load the account. Returns `self`. Calling it on a
|
|
66
|
+
client that is already connected does nothing (it never opens a second session).
|
|
67
|
+
|
|
68
|
+
Raises `LicenseError` / `TokenServiceError` when the licence is refused or unreachable,
|
|
69
|
+
`LoginRejectedError` when the broker rejects the account or password, and `ConnectError` when
|
|
70
|
+
no access server could be reached within `connect_timeout`.
|
|
71
|
+
|
|
72
|
+
#### `connected` *(property)*
|
|
73
|
+
|
|
74
|
+
Live: false when the socket died (the core notices a closed or reset connection at once and a silent one
|
|
75
|
+
within `no_message_timeout`).
|
|
76
|
+
|
|
77
|
+
#### `core_version` *(property)*
|
|
78
|
+
|
|
79
|
+
The version of the licensed core library in use.
|
|
80
|
+
|
|
81
|
+
#### `disconnect()`
|
|
82
|
+
|
|
83
|
+
Close the session and stop the core's reconnect watchdog for good — also when the link is down and the
|
|
84
|
+
watchdog is mid-way through reconnecting. Harmless when never connected.
|
|
85
|
+
|
|
86
|
+
#### `host` *(property)*
|
|
87
|
+
|
|
88
|
+
The access server this client was created for (it may fail over to another of `server_list`).
|
|
89
|
+
|
|
90
|
+
#### `is_investor` *(property)*
|
|
91
|
+
|
|
92
|
+
The login is the read-only investor password, as the account record reports it (the field the C# client
|
|
93
|
+
reads): every trading call then raises `InvestorModeError` before anything is sent. (Verified on
|
|
94
|
+
trading logins only: no investor password was available to exercise the true case.)
|
|
95
|
+
|
|
96
|
+
#### `login` *(property)*
|
|
97
|
+
|
|
98
|
+
The account login number.
|
|
99
|
+
|
|
100
|
+
#### `port` *(property)*
|
|
101
|
+
|
|
102
|
+
The access-server port.
|
|
103
|
+
|
|
104
|
+
#### `raw` *(property)*
|
|
105
|
+
|
|
106
|
+
The underlying core object, for anything this layer does not wrap. Calls made on it raise the core's own
|
|
107
|
+
exceptions, not pmt4api's.
|
|
108
|
+
|
|
109
|
+
#### `reconnect()`
|
|
110
|
+
|
|
111
|
+
Re-establish a dropped session over the primary server, `servers` and the list the broker published, and
|
|
112
|
+
restore the quote subscriptions. `True` when connected afterwards (also when it already was), `False` when
|
|
113
|
+
every server failed — try again later. A refusal retrying cannot cure (an expired licence, a rejected login)
|
|
114
|
+
also returns `False`: call `connect` to see the reason.
|
|
115
|
+
|
|
116
|
+
#### `server_list` *(property)*
|
|
117
|
+
|
|
118
|
+
The access servers the broker published at the last connect, as `(host, port)`: the pool a reconnect
|
|
119
|
+
fails over across (empty before the first connect).
|
|
120
|
+
|
|
121
|
+
#### `server_time` *(property)*
|
|
122
|
+
|
|
123
|
+
The server's clock (server time, naive): the local UTC clock moved by the server's offset. `None` before
|
|
124
|
+
the first connect.
|
|
125
|
+
|
|
126
|
+
#### `server_utc_offset` *(property)*
|
|
127
|
+
|
|
128
|
+
The server's offset from UTC, in whole hours as the broker configures it; `None` before the first
|
|
129
|
+
connect.
|
|
130
|
+
|
|
131
|
+
#### `servers` *(property)*
|
|
132
|
+
|
|
133
|
+
The extra access servers given with `servers=` / `add_server`, tried after the primary one.
|
|
134
|
+
|
|
135
|
+
#### `trade_build` *(property)*
|
|
136
|
+
|
|
137
|
+
The server's build number for this session.
|
|
138
|
+
|
|
139
|
+
## Symbols, quotes and bars
|
|
140
|
+
|
|
141
|
+
#### `async abars(*args, **kwargs)`
|
|
142
|
+
|
|
143
|
+
Awaitable `bars` (runs on a worker thread; never blocks the event loop).
|
|
144
|
+
|
|
145
|
+
#### `async aquote(symbol, timeout=None)`
|
|
146
|
+
|
|
147
|
+
Awaitable `quote` (runs on a worker thread; never blocks the event loop).
|
|
148
|
+
|
|
149
|
+
#### `bars(symbol, timeframe='H1', *, count=None, start=None, end=None, timeout=None)`
|
|
150
|
+
|
|
151
|
+
OHLC bars, oldest first, in the broker's server time.
|
|
152
|
+
|
|
153
|
+
Give `count` for the latest N bars, or `start` for everything from that time; with neither, the latest
|
|
154
|
+
500. `end` (default: now) is the moment the series is read up to: only bars that had completed by then are
|
|
155
|
+
returned (a bar that opens exactly at `end` is still forming and is not in it), so there is no look-ahead.
|
|
156
|
+
`timeframe` is one of `M1 M5 M15 M30 H1 H4 D1 W1 MN1` (or its length in minutes): the server serves each
|
|
157
|
+
itself. The server limits how far back it goes (about a few days of M1), so a long request may return fewer
|
|
158
|
+
bars than asked for; that is the end of the broker's history. `timeout` (seconds, default: the client's
|
|
159
|
+
`bars_timeout`) bounds the whole call.
|
|
160
|
+
|
|
161
|
+
#### `contract_size(symbol)`
|
|
162
|
+
|
|
163
|
+
The contract size of a symbol (units of the instrument per 1.0 lot).
|
|
164
|
+
|
|
165
|
+
#### `find_symbol(prefix)`
|
|
166
|
+
|
|
167
|
+
The symbol `prefix` names: the exact name if the broker has it, else the only symbol that starts with
|
|
168
|
+
it. `None` when there is none; an `InvalidRequestError` listing the candidates when several do
|
|
169
|
+
(use `find_symbols` and choose).
|
|
170
|
+
|
|
171
|
+
#### `find_symbols(prefix)`
|
|
172
|
+
|
|
173
|
+
Every symbol whose name starts with `prefix` (case-insensitive; brokers add suffixes such as `m` or
|
|
174
|
+
`.s`), exact match first, then shortest name.
|
|
175
|
+
|
|
176
|
+
#### `has_symbol(name)`
|
|
177
|
+
|
|
178
|
+
Whether the broker offers `name` (case-insensitive).
|
|
179
|
+
|
|
180
|
+
#### `is_subscribed(symbol)`
|
|
181
|
+
|
|
182
|
+
Whether `symbol` was subscribed (by `subscribe`, a quote request that had to wait, or the core
|
|
183
|
+
itself for the symbols of open positions). Before the first subscription the server streams a default set
|
|
184
|
+
of symbols, so `quote` also answers for symbols this reports as not subscribed.
|
|
185
|
+
|
|
186
|
+
#### `quote(symbol, timeout=None)`
|
|
187
|
+
|
|
188
|
+
The current quote of one symbol, waiting up to `timeout` seconds (default: the client's `quote_timeout`)
|
|
189
|
+
for the first tick; `NoQuoteError` if none arrives. The price is current: a symbol that is not
|
|
190
|
+
subscribed (while others are) is subscribed first and the call waits for its next tick, so it is never a price
|
|
191
|
+
cached before the feed was narrowed. `time` is the tick's server time.
|
|
192
|
+
|
|
193
|
+
#### `subscribe(*symbols)`
|
|
194
|
+
|
|
195
|
+
Start the live quote feed for the given symbols (names, or lists of names). A name the broker does not
|
|
196
|
+
offer raises `InvalidRequestError` before anything is subscribed.
|
|
197
|
+
|
|
198
|
+
#### `symbol(name)`
|
|
199
|
+
|
|
200
|
+
One symbol's specification. Names carry the broker's suffix (`EURUSDm`, `XAUUSD.s`): find yours with
|
|
201
|
+
`find_symbols`. The lookup ignores case.
|
|
202
|
+
|
|
203
|
+
#### `symbol_groups()`
|
|
204
|
+
|
|
205
|
+
The broker's configured symbol groups (name and description). The core does not say which group a symbol
|
|
206
|
+
belongs to; `SymbolInfo.security_index` is the key of its volume rules.
|
|
207
|
+
|
|
208
|
+
#### `symbols()`
|
|
209
|
+
|
|
210
|
+
Every symbol the broker offers on this account, by name, with its specification.
|
|
211
|
+
|
|
212
|
+
#### `tick_value(symbol, side='ask', timeout=None)`
|
|
213
|
+
|
|
214
|
+
The value, in account currency, of one full price unit per 1.0 lot (as the terminal computes it,
|
|
215
|
+
converting through the account currency's cross rates).
|
|
216
|
+
|
|
217
|
+
This is an *input* to position sizing, not a recipe: see `lots_for_risk`. `side` is `"ask"` (what a
|
|
218
|
+
long position is priced against) or `"bid"` (a short). Waits up to `timeout` seconds (default:
|
|
219
|
+
`quote_timeout`) for a live quote. Raises `InvalidRequestError` when the value cannot be computed (a
|
|
220
|
+
symbol whose profit currency has no conversion rate), never a NaN.
|
|
221
|
+
|
|
222
|
+
#### `unsubscribe(*symbols)`
|
|
223
|
+
|
|
224
|
+
Stop the live quote feed for the given symbols (names, or lists of names). A symbol with an open position
|
|
225
|
+
stays on the feed (its profit and the account's equity are priced from it); with nothing left subscribed the
|
|
226
|
+
server goes back to streaming its default set.
|
|
227
|
+
|
|
228
|
+
## Account, orders and history
|
|
229
|
+
|
|
230
|
+
#### `account(refresh=True)`
|
|
231
|
+
|
|
232
|
+
Account details. With `refresh` (the default) every open position's symbol is quoted once first, so
|
|
233
|
+
`equity`, `profit`, `margin`, `free_margin` and `margin_level` are priced from current ticks. They are
|
|
234
|
+
derived on the client (the server does not push them), as the terminal does; see `equity` for the cheap
|
|
235
|
+
read of one figure.
|
|
236
|
+
|
|
237
|
+
#### `async ahistory(start=None, end=None, timeout=None)`
|
|
238
|
+
|
|
239
|
+
Awaitable `history`. Cancelling the awaiting task abandons the download (the broker connection it
|
|
240
|
+
opened is closed), so `asyncio.wait_for(c.ahistory(...), 10)` does not leave a request running.
|
|
241
|
+
|
|
242
|
+
#### `balance` *(property)*
|
|
243
|
+
|
|
244
|
+
The account balance (closed-trade funds, floating P/L excluded); a cheap read.
|
|
245
|
+
|
|
246
|
+
#### `credit` *(property)*
|
|
247
|
+
|
|
248
|
+
The credit the broker granted; a cheap read.
|
|
249
|
+
|
|
250
|
+
#### `equity` *(property)*
|
|
251
|
+
|
|
252
|
+
Balance + floating P/L + credit, priced from the quotes already cached (it does not subscribe or wait: a
|
|
253
|
+
position whose symbol has not ticked yet counts 0 floating). Use `live_equity` to wait for fresh
|
|
254
|
+
quotes.
|
|
255
|
+
|
|
256
|
+
#### `equity_history(start, timeframe='D1', exclude_same_bars=True)`
|
|
257
|
+
|
|
258
|
+
The balance and equity curve since `start` (`timeframe` is `H1`, `H4` or `D1`).
|
|
259
|
+
|
|
260
|
+
`balance` is exact; the historical `equity` is a reconstruction priced from the symbols' bars. With
|
|
261
|
+
`exclude_same_bars` (the default, as in the C# library) consecutive points with an unchanged balance and
|
|
262
|
+
equity are dropped. Downloads the history and per-symbol bars, so it blocks and costs a licence request.
|
|
263
|
+
|
|
264
|
+
#### `free_margin` *(property)*
|
|
265
|
+
|
|
266
|
+
Equity − margin.
|
|
267
|
+
|
|
268
|
+
#### `history(start=None, end=None, timeout=None, cancel=None)`
|
|
269
|
+
|
|
270
|
+
Closed orders and balance / credit entries between `start` and `end` (default: the last 30 days up to
|
|
271
|
+
now), sorted by close time. Blocks until the server has sent everything, up to `timeout` seconds (default:
|
|
272
|
+
the client's `history_timeout`); set the `cancel` event to abandon the wait early
|
|
273
|
+
(`RequestCancelled`).
|
|
274
|
+
|
|
275
|
+
Naive datetimes are used exactly as given, in the broker's server time; timezone-aware ones are converted to
|
|
276
|
+
it. The default window is computed on the server's clock.
|
|
277
|
+
|
|
278
|
+
Each call opens its own short-lived broker connection and costs one licence request, which the licence
|
|
279
|
+
service rate-limits per minute: fetch once and reuse the result rather than polling.
|
|
280
|
+
|
|
281
|
+
#### `leverage` *(property)*
|
|
282
|
+
|
|
283
|
+
The account leverage (the N in 1:N).
|
|
284
|
+
|
|
285
|
+
#### `live_equity()`
|
|
286
|
+
|
|
287
|
+
Equity priced from FRESH quotes: it subscribes each open position's symbol and waits (up to the client's
|
|
288
|
+
`quote_timeout` per symbol) for a tick. Blocks; the cached read is `equity`.
|
|
289
|
+
|
|
290
|
+
#### `margin` *(property)*
|
|
291
|
+
|
|
292
|
+
The margin the open positions hold, derived on the client like the terminal (Forex by leverage, CFD by
|
|
293
|
+
the symbol's margin divider; a Futures position counts 0 until its formula is verified). May wait for a
|
|
294
|
+
conversion quote.
|
|
295
|
+
|
|
296
|
+
#### `margin_level` *(property)*
|
|
297
|
+
|
|
298
|
+
Equity / margin × 100, as the terminal shows it; 0 when no margin is used.
|
|
299
|
+
|
|
300
|
+
#### `order(ticket)`
|
|
301
|
+
|
|
302
|
+
One open order or position by ticket, or `None` when it is not open.
|
|
303
|
+
|
|
304
|
+
#### `orders()`
|
|
305
|
+
|
|
306
|
+
Everything currently working: open positions and pending orders. Each position's `profit` is re-priced
|
|
307
|
+
from the live quote on every read.
|
|
308
|
+
|
|
309
|
+
#### `pending_orders()`
|
|
310
|
+
|
|
311
|
+
Pending orders only (limits and stops).
|
|
312
|
+
|
|
313
|
+
#### `positions()`
|
|
314
|
+
|
|
315
|
+
Open market positions only (`Buy` / `Sell`).
|
|
316
|
+
|
|
317
|
+
#### `profit` *(property)*
|
|
318
|
+
|
|
319
|
+
The floating P/L of the open positions (equity − balance − credit), from cached quotes.
|
|
320
|
+
|
|
321
|
+
#### `summary(start=None, end=None)`
|
|
322
|
+
|
|
323
|
+
Realized trading result, deposits and withdrawals, from the closed-order ledger (all time by default).
|
|
324
|
+
|
|
325
|
+
Downloads the history, so it blocks and costs one licence request; call it off your UI thread (or use
|
|
326
|
+
`asyncio.to_thread`).
|
|
327
|
+
|
|
328
|
+
#### `update_margin()`
|
|
329
|
+
|
|
330
|
+
Warm the quotes the margin figure is priced from (every open position's symbol).
|
|
331
|
+
|
|
332
|
+
#### `update_profits(symbol=None)`
|
|
333
|
+
|
|
334
|
+
Warm the quotes the equity figures are priced from: every open position's symbol, or just `symbol`.
|
|
335
|
+
Blocks up to `quote_timeout` per symbol.
|
|
336
|
+
|
|
337
|
+
## Sizing and risk
|
|
338
|
+
|
|
339
|
+
#### `lots_for_risk(symbol, entry_price, stop_price, risk_amount, *, lot_step=None, min_lot=None, max_ratio=None, max_equity_share=None, max_lot=None)`
|
|
340
|
+
|
|
341
|
+
The volume that loses `risk_amount` (account currency) if `stop_price` is hit, with the evidence.
|
|
342
|
+
|
|
343
|
+
The value of a price unit comes from `tick_value` and the broker's step / minimum / maximum volume from
|
|
344
|
+
the account's own group (pass one to override it); a size that cannot be justified is refused, not guessed.
|
|
345
|
+
The volume is rounded **down** to the step. Check `ok`: when false, `lots` is 0 and `reason` says which
|
|
346
|
+
check failed. Amounts are in the currency the account reports (no cent-account scaling is applied: check the
|
|
347
|
+
first result against your terminal).
|
|
348
|
+
|
|
349
|
+
#### `order_profit(symbol, open_price, close_price, lots, buy=True)`
|
|
350
|
+
|
|
351
|
+
The P/L, in account currency, of `lots` moving from `open_price` to `close_price`. For reporting a
|
|
352
|
+
completed or hypothetical move; use `lots_for_risk` to size. Raises `InvalidRequestError` when the
|
|
353
|
+
value cannot be computed (no conversion rate yet).
|
|
354
|
+
|
|
355
|
+
#### `required_margin(symbol, lots, side='buy', price=0.0)`
|
|
356
|
+
|
|
357
|
+
The margin needed to open `lots` of `symbol`, computed as the terminal does (`price` 0 = the live
|
|
358
|
+
quote; Forex uses the account leverage, CFD the symbol's margin divider). Raises `InvalidRequestError`
|
|
359
|
+
when it cannot be computed (a Futures symbol, whose formula is not verified, or no conversion rate yet).
|
|
360
|
+
|
|
361
|
+
## Order entry
|
|
362
|
+
|
|
363
|
+
#### `async abuy(*args, **kwargs)`
|
|
364
|
+
|
|
365
|
+
Awaitable `buy`.
|
|
366
|
+
|
|
367
|
+
#### `async acancel(*args, **kwargs)`
|
|
368
|
+
|
|
369
|
+
Awaitable `cancel`.
|
|
370
|
+
|
|
371
|
+
#### `async aclose(*args, **kwargs)`
|
|
372
|
+
|
|
373
|
+
Awaitable `close`.
|
|
374
|
+
|
|
375
|
+
#### `async aclose_all_by(*args, **kwargs)`
|
|
376
|
+
|
|
377
|
+
Awaitable `close_all_by`.
|
|
378
|
+
|
|
379
|
+
#### `async aclose_by(*args, **kwargs)`
|
|
380
|
+
|
|
381
|
+
Awaitable `close_by`.
|
|
382
|
+
|
|
383
|
+
#### `async amodify(*args, **kwargs)`
|
|
384
|
+
|
|
385
|
+
Awaitable `modify`.
|
|
386
|
+
|
|
387
|
+
#### `async aplace_order(*args, **kwargs)`
|
|
388
|
+
|
|
389
|
+
Awaitable `place_order`.
|
|
390
|
+
|
|
391
|
+
#### `async asell(*args, **kwargs)`
|
|
392
|
+
|
|
393
|
+
Awaitable `sell`.
|
|
394
|
+
|
|
395
|
+
#### `buy(symbol, lots, *, price=None, slippage=0, sl=0.0, tp=0.0, comment=None, magic=0, placed_type=None)`
|
|
396
|
+
|
|
397
|
+
Buy at market. `price` defaults to the current ask (an instant-execution symbol fills at it within
|
|
398
|
+
`slippage` points; a market-execution symbol ignores it). `sl` / `tp` are prices (0 = none); `lots` is
|
|
399
|
+
a multiple of 0.01. `comment` (at most 31 characters) is how to tag an order: the core does not transmit a
|
|
400
|
+
magic number, so `magic` other than 0 raises `InvalidRequestError` rather than being ignored.
|
|
401
|
+
`placed_type` is `manual`, `expert`, `dealer` ... (default: the client's).
|
|
402
|
+
|
|
403
|
+
#### `buy_async(symbol, lots, *, price=None, slippage=0, sl=0.0, tp=0.0, comment=None, magic=0, placed_type=None)`
|
|
404
|
+
|
|
405
|
+
Send a market buy and return its request id as soon as the request is on the wire; the outcome arrives
|
|
406
|
+
through `on_order_progress` (and `on_order_update`).
|
|
407
|
+
|
|
408
|
+
#### `cancel(ticket)`
|
|
409
|
+
|
|
410
|
+
Delete a pending order.
|
|
411
|
+
|
|
412
|
+
#### `cancel_async(ticket)`
|
|
413
|
+
|
|
414
|
+
Delete a pending order and return its request id at once; see `cancel`.
|
|
415
|
+
|
|
416
|
+
#### `close(ticket, lots=None, *, price=None, slippage=0)`
|
|
417
|
+
|
|
418
|
+
Close a position at market, completely or (with `lots`) in part; `price` defaults to the current
|
|
419
|
+
bid (buy) / ask (sell). Returns the closing record. After a partial close the remainder may carry a new
|
|
420
|
+
ticket: read `positions`.
|
|
421
|
+
|
|
422
|
+
#### `close_all_by(symbol)`
|
|
423
|
+
|
|
424
|
+
Close every pair of opposite positions of `symbol` against each other (hedged accounts).
|
|
425
|
+
|
|
426
|
+
#### `close_all_by_async(symbol)`
|
|
427
|
+
|
|
428
|
+
`close_all_by`, returning its request id at once.
|
|
429
|
+
|
|
430
|
+
#### `close_async(ticket, lots=None, *, price=None, slippage=0)`
|
|
431
|
+
|
|
432
|
+
Close a position (or part of it) at market and return its request id at once; see `close`.
|
|
433
|
+
|
|
434
|
+
#### `close_by(ticket, opposite_ticket)`
|
|
435
|
+
|
|
436
|
+
Close a position against an opposite position of the same symbol (hedged accounts); the result arrives as
|
|
437
|
+
order updates. Both must be open positions of the same symbol and opposite sides.
|
|
438
|
+
|
|
439
|
+
#### `close_by_async(ticket, opposite_ticket)`
|
|
440
|
+
|
|
441
|
+
`close_by`, returning its request id at once.
|
|
442
|
+
|
|
443
|
+
#### `modify(ticket, *, sl=None, tp=None, price=None, expiration=None)`
|
|
444
|
+
|
|
445
|
+
Change a position's stop-loss / take-profit, or a pending order's price / stops / expiration. Anything
|
|
446
|
+
left as `None` keeps its current value (a pending order's expiration included; `expiration="gtc"` clears
|
|
447
|
+
it). Returns the order as the server now holds it.
|
|
448
|
+
|
|
449
|
+
#### `modify_async(ticket, *, sl=None, tp=None, price=None, expiration=None)`
|
|
450
|
+
|
|
451
|
+
Modify a position or pending order and return its request id at once; see `modify`.
|
|
452
|
+
|
|
453
|
+
#### `place_order(symbol, kind, lots, price, *, sl=0.0, tp=0.0, expiration=None, slippage=0, comment=None, magic=0, placed_type=None)`
|
|
454
|
+
|
|
455
|
+
Place a pending order. `kind` is one of `buy_limit sell_limit buy_stop sell_stop`. `expiration` is
|
|
456
|
+
`None` or `"gtc"` (good till cancelled), a `datetime` (server time, or timezone-aware) or a
|
|
457
|
+
`timedelta` from now.
|
|
458
|
+
|
|
459
|
+
#### `place_order_async(symbol, kind, lots, price, *, sl=0.0, tp=0.0, expiration=None, slippage=0, comment=None, magic=0, placed_type=None)`
|
|
460
|
+
|
|
461
|
+
Place a pending order and return its request id at once; see `place_order`.
|
|
462
|
+
|
|
463
|
+
#### `sell(symbol, lots, *, price=None, slippage=0, sl=0.0, tp=0.0, comment=None, magic=0, placed_type=None)`
|
|
464
|
+
|
|
465
|
+
Sell at market (`price` defaults to the current bid); see `buy`.
|
|
466
|
+
|
|
467
|
+
#### `sell_async(symbol, lots, *, price=None, slippage=0, sl=0.0, tp=0.0, comment=None, magic=0, placed_type=None)`
|
|
468
|
+
|
|
469
|
+
Send a market sell and return its request id at once; see `buy_async`.
|
|
470
|
+
|
|
471
|
+
## Events and streams
|
|
472
|
+
|
|
473
|
+
#### `aorder_progress(*, request_id=None, maxsize=1000)`
|
|
474
|
+
|
|
475
|
+
Async version of `order_progress`.
|
|
476
|
+
|
|
477
|
+
#### `aorder_updates(*, maxsize=1000)`
|
|
478
|
+
|
|
479
|
+
Async version of `order_updates`.
|
|
480
|
+
|
|
481
|
+
#### `aquotes(*symbols, maxsize=10000)`
|
|
482
|
+
|
|
483
|
+
Async version of `quotes` (no timeout; `aclose()` or cancel the task to stop). Call it inside a
|
|
484
|
+
running event loop.
|
|
485
|
+
|
|
486
|
+
#### `events_dropped` *(property)*
|
|
487
|
+
|
|
488
|
+
How many events were dropped because callbacks fell too far behind (see `pmt4api._streams`).
|
|
489
|
+
|
|
490
|
+
#### `on_connect(callback)`
|
|
491
|
+
|
|
492
|
+
Call `callback(event)` after every successful connect: the first one and each automatic or manual
|
|
493
|
+
reconnect (`event.connected` is true).
|
|
494
|
+
|
|
495
|
+
#### `on_disconnect(callback)`
|
|
496
|
+
|
|
497
|
+
Call `callback(event)` once when a session ends. `event.error` is why a link dropped, and `None` when
|
|
498
|
+
you called `disconnect`. With `auto_reconnect` the client then reconnects by itself and
|
|
499
|
+
`on_connect` fires again.
|
|
500
|
+
|
|
501
|
+
#### `on_order_progress(callback)`
|
|
502
|
+
|
|
503
|
+
Call `callback(progress)` as a trade request advances (see `buy_async`). Synchronous calls raise
|
|
504
|
+
their outcome instead, but they also report here under an id this client does not return.
|
|
505
|
+
|
|
506
|
+
#### `on_order_update(callback)`
|
|
507
|
+
|
|
508
|
+
Call `callback(update)` when the server pushes a change to an order or position (opened, modified,
|
|
509
|
+
closed, a pending order placed, filled or deleted, a balance entry).
|
|
510
|
+
|
|
511
|
+
#### `on_quote(callback)`
|
|
512
|
+
|
|
513
|
+
Call `callback(quote)` for every tick of every subscribed symbol. Returns a function that removes it.
|
|
514
|
+
|
|
515
|
+
#### `on_quote_history(callback)`
|
|
516
|
+
|
|
517
|
+
Call `callback(event)` as each chunk of bars of a `bars` download arrives.
|
|
518
|
+
|
|
519
|
+
#### `on_symbols_update(callback)`
|
|
520
|
+
|
|
521
|
+
Call `callback()` when the server pushes a change to the symbol list; read `symbol` again (the
|
|
522
|
+
core keeps the table it loaded at connect, so a changed specification is seen at the next reconnect).
|
|
523
|
+
|
|
524
|
+
#### `order_progress(*, request_id=None, timeout=None, maxsize=1000)`
|
|
525
|
+
|
|
526
|
+
Iterate trade-request progress (attached when called), optionally only that of `request_id`. Ends when
|
|
527
|
+
`timeout` seconds pass without an item.
|
|
528
|
+
|
|
529
|
+
#### `order_updates(*, timeout=None, maxsize=1000)`
|
|
530
|
+
|
|
531
|
+
Iterate order updates (attached when called). Ends when `timeout` seconds pass without one.
|
|
532
|
+
|
|
533
|
+
#### `quotes(*symbols, timeout=None, maxsize=10000)`
|
|
534
|
+
|
|
535
|
+
Iterate live quotes of `symbols` (subscribing them first; with none given, every subscribed symbol).
|
|
536
|
+
Ends when `timeout` seconds pass without a tick. The feed is attached when this is called, not at the first
|
|
537
|
+
`next()`. If the consumer falls behind by more than `maxsize` quotes the oldest are dropped.
|
|
538
|
+
|
|
539
|
+
## Module functions
|
|
540
|
+
|
|
541
|
+
#### `load_servers_ini(source)`
|
|
542
|
+
|
|
543
|
+
The brokers in a terminal's `servers.ini`: each with its name, company, demo flag, main host and
|
|
544
|
+
`(host, port)` access servers. Offline: reads only the file (a path, or the file's bytes).
|
|
545
|
+
|
|
546
|
+
#### `save_servers_ini(records)`
|
|
547
|
+
|
|
548
|
+
The bytes of a `servers.ini` file holding `records` (the inverse of `load_servers_ini`).
|
|
549
|
+
|
|
550
|
+
#### `enable_core_logging(logger_name='pmt4api.core')`
|
|
551
|
+
|
|
552
|
+
Forward the core's log messages (`Logger.OnMsgEx`) and internal diagnostics (`Diag.Sink`) to the Python
|
|
553
|
+
logger `logger_name`. Returns a function that switches it off again. Nothing is forwarded unless this is called,
|
|
554
|
+
and the core is silent by default.
|
|
555
|
+
|
|
556
|
+
#### `to_frame(items)`
|
|
557
|
+
|
|
558
|
+
A `pandas.DataFrame` from a list of the package's value objects (`Bar`, `Order`, `Quote`, ...).
|
|
559
|
+
|
|
560
|
+
A list of bars is indexed by its `time`; anything else keeps a plain integer index.
|
|
561
|
+
|
|
562
|
+
## Data types
|
|
563
|
+
|
|
564
|
+
#### `Quote`
|
|
565
|
+
|
|
566
|
+
A price. `time` is the server time of the tick (use it to judge how old the price is); `high` and `low`
|
|
567
|
+
are the session's range once the server has sent it, and `None` before that.
|
|
568
|
+
|
|
569
|
+
Fields: `symbol`, `bid`, `ask`, `time`, `high`, `low`
|
|
570
|
+
|
|
571
|
+
#### `SymbolInfo`
|
|
572
|
+
|
|
573
|
+
A symbol's specification and trading rules, as the server publishes them.
|
|
574
|
+
|
|
575
|
+
Fields: `name`, `digits`, `point`, `currency`, `profit_mode`, `contract_size`, `margin_divider`, `tick_size`, `execution`, `security_index`, `min_lots`, `max_lots`, `lots_step`, `code`, `raw_tick_value`, `raw_bid_tick_value`, `raw_ask_tick_value`
|
|
576
|
+
|
|
577
|
+
#### `SymbolGroup`
|
|
578
|
+
|
|
579
|
+
One of the broker's configured symbol groups (its name and description).
|
|
580
|
+
|
|
581
|
+
Fields: `name`, `description`
|
|
582
|
+
|
|
583
|
+
#### `AccountInfo`
|
|
584
|
+
|
|
585
|
+
The account at the moment it was read. `equity`, `profit`, `margin`, `free_margin` and `margin_level`
|
|
586
|
+
are derived on the client from the live quotes (the server does not push them), exactly as the terminal does.
|
|
587
|
+
`priced_from` is the server time of the oldest tick those figures were priced from (`None` with no open
|
|
588
|
+
position): minutes old while the market is open means the feed is not delivering — do not trust the equity.
|
|
589
|
+
|
|
590
|
+
Fields: `login`, `name`, `company`, `group`, `currency`, `leverage`, `balance`, `credit`, `equity`, `profit`, `margin`, `free_margin`, `margin_level`, `account_type`, `is_investor`, `priced_from`
|
|
591
|
+
|
|
592
|
+
#### `AccountSummary`
|
|
593
|
+
|
|
594
|
+
Realized totals over a history range (from the closed-order ledger, not the floating P/L of open positions).
|
|
595
|
+
|
|
596
|
+
Fields: `balance`, `credit`, `realized_profit`, `deposit`, `withdrawal`
|
|
597
|
+
|
|
598
|
+
#### `EquityPoint`
|
|
599
|
+
|
|
600
|
+
One sample of the balance and equity curve. `balance_change` is the change of balance since the first point
|
|
601
|
+
(deposits and withdrawals included, so it is not a trading result: use `AccountSummary`).
|
|
602
|
+
|
|
603
|
+
Fields: `time`, `balance`, `equity`, `balance_change`, `unrealized_pl`, `balance_drawdown_raw`, `balance_drawdown_relative`, `equity_drawdown_raw`, `equity_drawdown_relative`
|
|
604
|
+
|
|
605
|
+
#### `LotSizing`
|
|
606
|
+
|
|
607
|
+
The answer of `Client.lots_for_risk`. If `ok` is false, `lots` is 0 and `reason` says why: do not
|
|
608
|
+
trade it. `warnings` can accompany a true `ok` (most often that the broker's minimum volume risks more than
|
|
609
|
+
was asked).
|
|
610
|
+
|
|
611
|
+
Fields: `ok`, `lots`, `expected_loss_at_stop`, `risk_requested`, `minimum_trade_cost`, `ratio`, `reason`, `warnings`
|
|
612
|
+
|
|
613
|
+
#### `Order`
|
|
614
|
+
|
|
615
|
+
One MT4 order: an open position, a pending order, a closed order of the history, or a balance / credit entry.
|
|
616
|
+
|
|
617
|
+
Fields: `ticket`, `symbol`, `order_type`, `lots`, `open_time`, `open_price`, `stop_loss`, `take_profit`, `close_time`, `close_price`, `expiration`, `magic`, `swap`, `commission`, `comment`, `profit`, `rate_open`, `rate_close`, `rate_margin`
|
|
618
|
+
|
|
619
|
+
#### `Bar`
|
|
620
|
+
|
|
621
|
+
Bar(time: 'datetime', open: 'float', high: 'float', low: 'float', close: 'float', volume: 'float')
|
|
622
|
+
|
|
623
|
+
Fields: `time`, `open`, `high`, `low`, `close`, `volume`
|
|
624
|
+
|
|
625
|
+
#### `OrderUpdate`
|
|
626
|
+
|
|
627
|
+
A change the server pushed: `action` is one of `PositionOpen`, `PositionClose`, `PositionModify`,
|
|
628
|
+
`PendingOpen`, `PendingClose`, `PendingModify`, `PendingFill`, `Balance`, `Credit` (a pending order that
|
|
629
|
+
fills arrives as `PositionOpen`).
|
|
630
|
+
|
|
631
|
+
Fields: `action`, `order`
|
|
632
|
+
|
|
633
|
+
#### `OrderProgress`
|
|
634
|
+
|
|
635
|
+
Progress of a trade request, as the request id (the integer `Client.buy_async` and friends return)
|
|
636
|
+
advances through the server: `stage` is `InProcess`, `Accepted`, `Opened`, `Closed`, `Modified`,
|
|
637
|
+
`PendingDeleted`, `ClosedBy`, `MultipleClosedBy`, `Price` or `Exception` (`Rejected` and `Timeout` are
|
|
638
|
+
defined by the core but never raised by it). `order` is set where the server returned one, `error` for an
|
|
639
|
+
`Exception` stage (a pmt4api error such as `ServerError`).
|
|
640
|
+
|
|
641
|
+
Fields: `request_id`, `stage`, `order`, `error`
|
|
642
|
+
|
|
643
|
+
#### `ConnectEvent`
|
|
644
|
+
|
|
645
|
+
A session started (`connected` true: the first connect and every reconnect) or ended (`connected` false;
|
|
646
|
+
`error` is the reason for a drop and `None` when you closed the client yourself).
|
|
647
|
+
|
|
648
|
+
Fields: `connected`, `error`
|
|
649
|
+
|
|
650
|
+
#### `QuoteHistoryEvent`
|
|
651
|
+
|
|
652
|
+
A chunk of bars the server delivered for a bar download (see `Client.on_quote_history`).
|
|
653
|
+
|
|
654
|
+
Fields: `symbol`, `timeframe`, `bars`
|
|
655
|
+
|
|
656
|
+
#### `ServerRecord`
|
|
657
|
+
|
|
658
|
+
A broker of a `servers.ini` file: its name, company, demo flag, main host and (host, port) access servers.
|
|
659
|
+
|
|
660
|
+
Fields: `name`, `company`, `is_demo`, `main_host`, `access`
|
|
661
|
+
|
|
662
|
+
## Errors
|
|
663
|
+
|
|
664
|
+
```
|
|
665
|
+
WmtError
|
|
666
|
+
BusyError
|
|
667
|
+
ConnectError
|
|
668
|
+
ConnectionLostError
|
|
669
|
+
CoreNotFoundError
|
|
670
|
+
InvalidRequestError
|
|
671
|
+
LicenseError
|
|
672
|
+
NoQuoteError
|
|
673
|
+
NotConnectedError
|
|
674
|
+
ProtocolError
|
|
675
|
+
RequestCancelled
|
|
676
|
+
RequestTimeout
|
|
677
|
+
RuntimeNotFoundError
|
|
678
|
+
ServerError
|
|
679
|
+
InvestorModeError
|
|
680
|
+
LoginRejectedError
|
|
681
|
+
RequoteError
|
|
682
|
+
TokenServiceError
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
- `BusyError` — The core allows one request of this kind at a time and one is still running; wait for it and retry.
|
|
686
|
+
- `ConnectError` — No access server could be reached (or none answered within `connect_timeout`).
|
|
687
|
+
- `ConnectionLostError` — An established connection was lost, possibly with a request in flight: whether it was applied is unknown; reconnect and look at `Client.orders` before sending again.
|
|
688
|
+
- `CoreNotFoundError` — The licensed core library (wmt4api.dll) could not be located.
|
|
689
|
+
- `InvalidRequestError` — The request was rejected before it was sent (for example, a symbol the server does not know).
|
|
690
|
+
- `InvestorModeError` — The account was opened with an investor (read-only) password and the request needs trading rights. Nothing was sent.
|
|
691
|
+
- `LicenseError` — The licence service refused the request. `reason` is one of: NoKey, Invalid, Expired, Revoked, RateLimited, LoginNotAllowed, AccountLimitReached, Unknown. `status` is the service's HTTP status and `detail` its own message, for support.
|
|
692
|
+
- `LoginRejectedError` — The broker rejected the login: a wrong account number or password (typically code 65), a disabled or expired login, or an authorisation refusal. Fix the credentials; this is not an SDK fault and is not retried across servers.
|
|
693
|
+
- `NoQuoteError` — No quote was available in time to read or to trade against. Nothing was sent.
|
|
694
|
+
- `NotConnectedError` — The call needs a connection and the client is not connected.
|
|
695
|
+
- `ProtocolError` — The server sent something the core could not decode.
|
|
696
|
+
- `RequestCancelled` — The wait was cancelled by the caller (the `cancel` event of a download was set).
|
|
697
|
+
- `RequestTimeout` — The server did not answer within the requested time. For a trade call this means the request WAS sent and was not confirmed in time: the order may have been accepted; look at `orders()` before sending again. (When nothing was sent, `NoQuoteError` is raised instead.)
|
|
698
|
+
- `RequoteError` — An instant-execution price moved before the fill. `bid` / `ask` are the prices the server now offers: decide again and resend (nothing was filled).
|
|
699
|
+
- `RuntimeNotFoundError` — The .NET runtime needed to host the core could not be started.
|
|
700
|
+
- `ServerError` — The broker's server refused the request (a rejected login or a rejected order). `code_value` is the MT4 return code and `code` its name (`"REQUOTE"`, `"NOT_ENOUGH_MONEY"`, `"INVALID_STOPS"`, ...); both are `None` when the refusal carried no code.
|
|
701
|
+
- `TokenServiceError` — The licence service could not be reached or answered with something unusable (not a licence decision).
|
|
702
|
+
- `WmtError` — Base class of every pmt4api error.
|