pdmt5 0.1.1__py3-none-any.whl → 0.1.3__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.
pdmt5/trading.py
CHANGED
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from datetime import timedelta
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
6
7
|
|
|
7
8
|
from pydantic import ConfigDict, Field
|
|
8
9
|
|
|
9
10
|
from .dataframe import Mt5DataClient
|
|
10
11
|
from .mt5 import Mt5RuntimeError
|
|
11
12
|
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
import pandas as pd
|
|
15
|
+
|
|
12
16
|
|
|
13
17
|
class Mt5TradingError(Mt5RuntimeError):
|
|
14
18
|
"""MetaTrader5 trading error."""
|
|
@@ -32,6 +36,7 @@ class Mt5TradingClient(Mt5DataClient):
|
|
|
32
36
|
def close_open_positions(
|
|
33
37
|
self,
|
|
34
38
|
symbols: str | list[str] | tuple[str, ...] | None = None,
|
|
39
|
+
dry_run: bool | None = None,
|
|
35
40
|
**kwargs: Any, # noqa: ANN401
|
|
36
41
|
) -> dict[str, list[dict[str, Any]]]:
|
|
37
42
|
"""Close all open positions for specified symbols.
|
|
@@ -39,6 +44,8 @@ class Mt5TradingClient(Mt5DataClient):
|
|
|
39
44
|
Args:
|
|
40
45
|
symbols: Optional symbol or list of symbols to filter positions.
|
|
41
46
|
If None, all symbols will be considered.
|
|
47
|
+
dry_run: Optional flag to enable dry run mode. If None, uses the instance's
|
|
48
|
+
`dry_run` attribute.
|
|
42
49
|
**kwargs: Additional keyword arguments for request parameters.
|
|
43
50
|
|
|
44
51
|
Returns:
|
|
@@ -53,18 +60,22 @@ class Mt5TradingClient(Mt5DataClient):
|
|
|
53
60
|
symbol_list = self.symbols_get()
|
|
54
61
|
self.logger.info("Fetching and closing positions for symbols: %s", symbol_list)
|
|
55
62
|
return {
|
|
56
|
-
s: self._fetch_and_close_position(symbol=s, **kwargs)
|
|
63
|
+
s: self._fetch_and_close_position(symbol=s, dry_run=dry_run, **kwargs)
|
|
64
|
+
for s in symbol_list
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
def _fetch_and_close_position(
|
|
60
68
|
self,
|
|
61
69
|
symbol: str | None = None,
|
|
70
|
+
dry_run: bool | None = None,
|
|
62
71
|
**kwargs: Any, # noqa: ANN401
|
|
63
72
|
) -> list[dict[str, Any]]:
|
|
64
73
|
"""Close all open positions for a specific symbol.
|
|
65
74
|
|
|
66
75
|
Args:
|
|
67
76
|
symbol: Optional symbol filter.
|
|
77
|
+
dry_run: Optional flag to enable dry run mode. If None, uses the instance's
|
|
78
|
+
`dry_run` attribute.
|
|
68
79
|
**kwargs: Additional keyword arguments for request parameters.
|
|
69
80
|
|
|
70
81
|
Returns:
|
|
@@ -96,6 +107,7 @@ class Mt5TradingClient(Mt5DataClient):
|
|
|
96
107
|
"position": p["ticket"],
|
|
97
108
|
**kwargs,
|
|
98
109
|
},
|
|
110
|
+
dry_run=dry_run,
|
|
99
111
|
)
|
|
100
112
|
for p in positions_dict
|
|
101
113
|
]
|
|
@@ -182,3 +194,84 @@ class Mt5TradingClient(Mt5DataClient):
|
|
|
182
194
|
f"Failed to calculate minimum order margins for symbol: {symbol}."
|
|
183
195
|
)
|
|
184
196
|
raise Mt5TradingError(error_message)
|
|
197
|
+
|
|
198
|
+
def calculate_spread_ratio(
|
|
199
|
+
self,
|
|
200
|
+
symbol: str,
|
|
201
|
+
) -> float:
|
|
202
|
+
"""Calculate the spread ratio for a given symbol.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
symbol: Symbol for which to calculate the spread ratio.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
Spread ratio as a float.
|
|
209
|
+
"""
|
|
210
|
+
symbol_info_tick = self.symbol_info_tick_as_dict(symbol=symbol)
|
|
211
|
+
return (
|
|
212
|
+
(symbol_info_tick["ask"] - symbol_info_tick["bid"])
|
|
213
|
+
/ (symbol_info_tick["ask"] + symbol_info_tick["bid"])
|
|
214
|
+
* 2
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
def copy_latest_rates_as_df(
|
|
218
|
+
self,
|
|
219
|
+
symbol: str,
|
|
220
|
+
granularity: str = "M1",
|
|
221
|
+
count: int = 1440,
|
|
222
|
+
index_keys: str | None = "time",
|
|
223
|
+
) -> pd.DataFrame:
|
|
224
|
+
"""Fetch rate (OHLC) data as a DataFrame.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
symbol: Symbol to fetch data for.
|
|
228
|
+
granularity: Time granularity as a timeframe suffix (e.g., "M1", "H1").
|
|
229
|
+
count: Number of bars to fetch.
|
|
230
|
+
index_keys: Optional index keys for the DataFrame.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
pd.DataFrame: OHLC data with time index.
|
|
234
|
+
|
|
235
|
+
Raises:
|
|
236
|
+
Mt5TradingError: If the granularity is not supported by MetaTrader5.
|
|
237
|
+
"""
|
|
238
|
+
try:
|
|
239
|
+
timeframe = getattr(self.mt5, f"TIMEFRAME_{granularity.upper()}")
|
|
240
|
+
except AttributeError as e:
|
|
241
|
+
error_message = (
|
|
242
|
+
f"MetaTrader5 does not support the given granularity: {granularity}"
|
|
243
|
+
)
|
|
244
|
+
raise Mt5TradingError(error_message) from e
|
|
245
|
+
else:
|
|
246
|
+
return self.copy_rates_from_pos_as_df(
|
|
247
|
+
symbol=symbol,
|
|
248
|
+
timeframe=timeframe,
|
|
249
|
+
start_pos=0,
|
|
250
|
+
count=count,
|
|
251
|
+
index_keys=index_keys,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def copy_latest_ticks_as_df(
|
|
255
|
+
self,
|
|
256
|
+
symbol: str,
|
|
257
|
+
seconds: int = 300,
|
|
258
|
+
index_keys: str | None = "time_msc",
|
|
259
|
+
) -> pd.DataFrame:
|
|
260
|
+
"""Fetch tick data as a DataFrame.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
symbol: Symbol to fetch tick data for.
|
|
264
|
+
seconds: Time range in seconds to fetch ticks around the last tick time.
|
|
265
|
+
index_keys: Optional index keys for the DataFrame.
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
pd.DataFrame: Tick data with time index.
|
|
269
|
+
"""
|
|
270
|
+
last_tick_time = self.symbol_info_tick_as_dict(symbol=symbol)["time"]
|
|
271
|
+
return self.copy_ticks_range_as_df(
|
|
272
|
+
symbol=symbol,
|
|
273
|
+
date_from=(last_tick_time - timedelta(seconds=seconds)),
|
|
274
|
+
date_to=(last_tick_time + timedelta(seconds=seconds)),
|
|
275
|
+
flags=self.mt5.COPY_TICKS_ALL,
|
|
276
|
+
index_keys=index_keys,
|
|
277
|
+
)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
pdmt5/__init__.py,sha256=QbSFrsi7_bgFzb-ma4DmmUjR90UvrqKMnRZq1wPRmoI,446
|
|
2
2
|
pdmt5/dataframe.py,sha256=rUWtR23hrXBdBqzJhbOlIemNy73RrjSTZZJUhwoL6io,38084
|
|
3
3
|
pdmt5/mt5.py,sha256=KgxHapIrh5b4L0wIOAQIjfXNZafalihbFrh9fhYHmrI,32254
|
|
4
|
-
pdmt5/trading.py,sha256=
|
|
4
|
+
pdmt5/trading.py,sha256=FsLC_X_bwBnnQ9l54wPA4OlwD2HlO1RnPvOCnMopNNE,10113
|
|
5
5
|
pdmt5/utils.py,sha256=Ll5Q3OE5h1A_sZ_qVEnOPGniFlT6_MmHfuu0zqeLdeU,3913
|
|
6
|
-
pdmt5-0.1.
|
|
7
|
-
pdmt5-0.1.
|
|
8
|
-
pdmt5-0.1.
|
|
9
|
-
pdmt5-0.1.
|
|
6
|
+
pdmt5-0.1.3.dist-info/METADATA,sha256=UpjES_3YPgMHCpmX4da8ox0OlqJ36nE5B-cYNKvv2A8,9029
|
|
7
|
+
pdmt5-0.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
8
|
+
pdmt5-0.1.3.dist-info/licenses/LICENSE,sha256=iABrdaUGOBWLYotFupB_PGe8arV5o7rVhn-_vK6P704,1073
|
|
9
|
+
pdmt5-0.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|