pdmt5 0.1.3__py3-none-any.whl → 0.1.4__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
@@ -214,7 +214,7 @@ class Mt5TradingClient(Mt5DataClient):
214
214
  * 2
215
215
  )
216
216
 
217
- def copy_latest_rates_as_df(
217
+ def fetch_latest_rates_as_df(
218
218
  self,
219
219
  symbol: str,
220
220
  granularity: str = "M1",
@@ -251,7 +251,7 @@ class Mt5TradingClient(Mt5DataClient):
251
251
  index_keys=index_keys,
252
252
  )
253
253
 
254
- def copy_latest_ticks_as_df(
254
+ def fetch_latest_ticks_as_df(
255
255
  self,
256
256
  symbol: str,
257
257
  seconds: int = 300,
@@ -275,3 +275,97 @@ class Mt5TradingClient(Mt5DataClient):
275
275
  flags=self.mt5.COPY_TICKS_ALL,
276
276
  index_keys=index_keys,
277
277
  )
278
+
279
+ def collect_entry_deals_as_df(
280
+ self,
281
+ symbol: str,
282
+ history_seconds: int = 3600,
283
+ index_keys: str | None = "ticket",
284
+ ) -> pd.DataFrame:
285
+ """Collect entry deals as a DataFrame.
286
+
287
+ Args:
288
+ symbol: Symbol to collect entry deals for.
289
+ history_seconds: Time range in seconds to fetch deals around the last tick.
290
+ index_keys: Optional index keys for the DataFrame.
291
+
292
+ Returns:
293
+ pd.DataFrame: Entry deals with time index.
294
+ """
295
+ last_tick_time = self.symbol_info_tick_as_dict(symbol=symbol)["time"]
296
+ deals_df = self.history_deals_get_as_df(
297
+ date_from=(last_tick_time - timedelta(seconds=history_seconds)),
298
+ date_to=(last_tick_time + timedelta(seconds=history_seconds)),
299
+ symbol=symbol,
300
+ index_keys=index_keys,
301
+ )
302
+ if deals_df.empty:
303
+ return deals_df
304
+ else:
305
+ return deals_df.pipe(
306
+ lambda d: d[
307
+ d["entry"]
308
+ & d["type"].isin({self.mt5.DEAL_TYPE_BUY, self.mt5.DEAL_TYPE_SELL})
309
+ ]
310
+ )
311
+
312
+ def fetch_positions_with_metrics_as_df(
313
+ self,
314
+ symbol: str,
315
+ ) -> pd.DataFrame:
316
+ """Fetch open positions as a DataFrame with additional metrics.
317
+
318
+ Args:
319
+ symbol: Symbol to fetch positions for.
320
+
321
+ Returns:
322
+ pd.DataFrame: DataFrame containing open positions with additional metrics.
323
+ """
324
+ positions_df = self.positions_get_as_df(symbol=symbol)
325
+ if positions_df.empty:
326
+ return positions_df
327
+ else:
328
+ symbol_info_tick = self.symbol_info_tick_as_dict(symbol=symbol)
329
+ ask_margin = self.order_calc_margin(
330
+ action=self.mt5.ORDER_TYPE_BUY,
331
+ symbol=symbol,
332
+ volume=1,
333
+ price=symbol_info_tick["ask"],
334
+ )
335
+ bid_margin = self.order_calc_margin(
336
+ action=self.mt5.ORDER_TYPE_SELL,
337
+ symbol=symbol,
338
+ volume=1,
339
+ price=symbol_info_tick["bid"],
340
+ )
341
+ return (
342
+ positions_df.assign(
343
+ elapsed_seconds=lambda d: (
344
+ symbol_info_tick["time"] - d["time"]
345
+ ).dt.total_seconds(),
346
+ underlier_increase_ratio=lambda d: (
347
+ d["price_current"] / d["price_open"] - 1
348
+ ),
349
+ buy=lambda d: (d["type"] == self.mt5.POSITION_TYPE_BUY),
350
+ sell=lambda d: (d["type"] == self.mt5.POSITION_TYPE_SELL),
351
+ )
352
+ .assign(
353
+ buy_i=lambda d: d["buy"].astype(int),
354
+ sell_i=lambda d: d["sell"].astype(int),
355
+ )
356
+ .assign(
357
+ sign=lambda d: (d["buy_i"] - d["sell_i"]),
358
+ margin=lambda d: (
359
+ (d["buy_i"] * ask_margin + d["sell_i"] * bid_margin)
360
+ * d["volume"]
361
+ ),
362
+ )
363
+ .assign(
364
+ signed_volume=lambda d: (d["volume"] * d["sign"]),
365
+ signed_margin=lambda d: (d["margin"] * d["sign"]),
366
+ underlier_profit_ratio=lambda d: (
367
+ d["underlier_increase_ratio"] * d["sign"]
368
+ ),
369
+ )
370
+ .drop(columns=["buy_i", "sell_i", "sign", "underlier_increase_ratio"])
371
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdmt5
3
- Version: 0.1.3
3
+ Version: 0.1.4
4
4
  Summary: Pandas-based data handler for MetaTrader 5
5
5
  Project-URL: Repository, https://github.com/dceoy/pdmt5.git
6
6
  Author-email: dceoy <dceoy@users.noreply.github.com>
@@ -29,6 +29,7 @@ Pandas-based data handler for MetaTrader 5
29
29
  [![Python Version](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
30
30
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
31
31
  [![Platform](https://img.shields.io/badge/platform-Windows-blue.svg)](https://www.microsoft.com/windows)
32
+ [![Version](https://img.shields.io/badge/version-0.1.4-green.svg)](https://github.com/dceoy/pdmt5)
32
33
 
33
34
  ## Overview
34
35
 
@@ -78,14 +79,13 @@ config = Mt5Config(
78
79
  login=12345678,
79
80
  password="your_password",
80
81
  server="YourBroker-Server",
81
- timeout=60000,
82
- portable=False
82
+ timeout=60000
83
83
  )
84
84
 
85
85
  # Use as context manager
86
86
  with Mt5DataClient(config=config) as client:
87
87
  # Get account information as DataFrame
88
- account_info = client.get_account_info_as_df()
88
+ account_info = client.account_info_as_df()
89
89
  print(account_info)
90
90
 
91
91
  # Get OHLCV data as DataFrame
@@ -98,7 +98,7 @@ with Mt5DataClient(config=config) as client:
98
98
  print(rates.head())
99
99
 
100
100
  # Get current positions as DataFrame
101
- positions = client.get_positions_as_df()
101
+ positions = client.positions_get_as_df()
102
102
  print(positions)
103
103
  ```
104
104
 
@@ -106,34 +106,110 @@ with Mt5DataClient(config=config) as client:
106
106
 
107
107
  ### Mt5Client
108
108
 
109
- The base client for MT5 operations with context manager support:
110
-
111
- - **Connection Management**: `initialize()`, `login()`, `shutdown()`
112
- - **Account & Terminal Info**: Access account details and terminal information
113
- - **Symbol Operations**: Get symbol information and market data
114
- - **Trading Operations**: Execute orders, manage positions and deals
115
- - **History Access**: Retrieve historical orders and deals
109
+ The base client wrapper for all MetaTrader5 operations with context manager support:
110
+
111
+ - **Connection Management**:
112
+ - `initialize()` - Establish connection with MT5 terminal (with optional path, login, password, server, timeout)
113
+ - `login()` - Connect to trading account with credentials
114
+ - `shutdown()` - Close MT5 terminal connection
115
+ - Context manager support (`with` statement) for automatic initialization/cleanup
116
+ - **Terminal Information**:
117
+ - `version()` - Get MT5 terminal version, build, and release date
118
+ - `last_error()` - Get last error code and description
119
+ - `account_info()` - Get current trading account information
120
+ - `terminal_info()` - Get terminal status and settings
121
+ - **Symbol Operations**:
122
+ - `symbols_total()` - Get total number of financial instruments
123
+ - `symbols_get()` - Get all symbols or filter by group
124
+ - `symbol_info()` - Get detailed data on specific symbol
125
+ - `symbol_info_tick()` - Get last tick for symbol
126
+ - `symbol_select()` - Show/hide symbol in MarketWatch
127
+ - **Market Depth**:
128
+ - `market_book_add()` - Subscribe to Market Depth events
129
+ - `market_book_get()` - Get current Market Depth data
130
+ - `market_book_release()` - Unsubscribe from Market Depth
131
+ - **Market Data**:
132
+ - `copy_rates_from()` - Get bars from specified date
133
+ - `copy_rates_from_pos()` - Get bars from specified position
134
+ - `copy_rates_range()` - Get bars for date range
135
+ - `copy_ticks_from()` - Get ticks from specified date
136
+ - `copy_ticks_range()` - Get ticks for date range
137
+ - **Order Operations**:
138
+ - `orders_total()` - Get number of active orders
139
+ - `orders_get()` - Get active orders with optional filters
140
+ - `order_calc_margin()` - Calculate required margin
141
+ - `order_calc_profit()` - Calculate potential profit
142
+ - `order_check()` - Check if order can be placed
143
+ - `order_send()` - Send order to trade server
144
+ - **Position Operations**:
145
+ - `positions_total()` - Get number of open positions
146
+ - `positions_get()` - Get open positions with optional filters
147
+ - **Trading History**:
148
+ - `history_orders_total()` - Get number of historical orders
149
+ - `history_orders_get()` - Get historical orders with filters
150
+ - `history_deals_total()` - Get number of historical deals
151
+ - `history_deals_get()` - Get historical deals with filters
116
152
 
117
153
  ### Mt5DataClient
118
154
 
119
- Extends Mt5Client with pandas DataFrame conversions:
120
-
121
- - **DataFrame Methods**: All data methods have `_as_df` variants returning DataFrames
122
- - **Dictionary Methods**: All data methods have `_as_dict` variants returning dictionaries
123
- - **Account Operations**: `get_account_info()`, `get_terminal_info()`
124
- - **Market Data**: `copy_rates_*()` methods for OHLCV data
125
- - **Tick Data**: `copy_ticks_*()` methods for tick-level data
126
- - **Trading Info**: `get_orders()`, `get_positions()`, `get_deals()`
127
- - **Symbol Info**: `get_symbols()`, `get_symbol_info()`
155
+ Extends Mt5Client with pandas DataFrame and dictionary conversions:
156
+
157
+ - **Enhanced Connection**:
158
+ - `initialize_and_login_mt5()` - Combined initialization and login with retry logic
159
+ - Configurable retry attempts via `retry_count` parameter
160
+ - **DataFrame/Dictionary Conversions**: All methods have both `_as_df` and `_as_dict` variants:
161
+ - `version_as_dict/df()` - MT5 version information
162
+ - `last_error_as_dict/df()` - Last error details
163
+ - `account_info_as_dict/df()` - Account information
164
+ - `terminal_info_as_dict/df()` - Terminal information
165
+ - `symbols_get_as_dicts/df()` - Symbol list with optional group filter
166
+ - `symbol_info_as_dict/df()` - Single symbol information
167
+ - `symbol_info_tick_as_dict/df()` - Last tick data
168
+ - `market_book_get_as_dicts/df()` - Market depth data
169
+ - **OHLCV Data Methods**:
170
+ - `copy_rates_from_as_dicts/df()` - Historical bars from date
171
+ - `copy_rates_from_pos_as_dicts/df()` - Historical bars from position
172
+ - `copy_rates_range_as_dicts/df()` - Historical bars for date range
173
+ - **Tick Data Methods**:
174
+ - `copy_ticks_from_as_dicts/df()` - Historical ticks from date
175
+ - `copy_ticks_range_as_dicts/df()` - Historical ticks for date range
176
+ - **Trading Data Methods**:
177
+ - `orders_get_as_dicts/df()` - Active orders with filters
178
+ - `order_check_as_dict/df()` - Order validation results
179
+ - `order_send_as_dict/df()` - Order execution results
180
+ - `positions_get_as_dicts/df()` - Open positions with filters
181
+ - `history_orders_get_as_dicts/df()` - Historical orders with date/ticket/position filters
182
+ - `history_deals_get_as_dicts/df()` - Historical deals with date/ticket/position filters
183
+ - **Features**:
184
+ - Automatic time conversion to datetime objects
185
+ - Optional DataFrame indexing with `index_keys` parameter
186
+ - Input validation for dates, counts, and positions
187
+ - Pydantic-based configuration via `Mt5Config`
128
188
 
129
189
  ### Mt5TradingClient
130
190
 
131
- Advanced trading operations interface that extends Mt5DataClient:
132
-
133
- - **Position Management**: `close_open_positions()` - Close positions by symbol
134
- - **Order Filling Modes**: IOC (Immediate or Cancel), FOK (Fill or Kill), or RETURN
135
- - **Dry Run Mode**: Test trading logic without executing real trades
136
- - **Full Trading Operations**: Includes all Mt5DataClient capabilities plus trading features
191
+ Advanced trading operations client that extends Mt5DataClient:
192
+
193
+ - **Trading Configuration**:
194
+ - `order_filling_mode` - Order execution mode: "IOC" (default), "FOK", or "RETURN"
195
+ - `dry_run` - Test mode flag for simulating trades without execution
196
+ - **Position Management**:
197
+ - `close_open_positions()` - Close all positions for specified symbol(s)
198
+ - `send_or_check_order()` - Execute or validate orders based on dry_run mode
199
+ - **Market Analysis**:
200
+ - `calculate_minimum_order_margins()` - Calculate minimum required margins for buy/sell orders
201
+ - `calculate_spread_ratio()` - Calculate normalized bid-ask spread ratio
202
+ - **Simplified Data Access**:
203
+ - `fetch_latest_rates_as_df()` - Get recent OHLC data with timeframe strings (e.g., "M1", "H1", "D1")
204
+ - `fetch_latest_ticks_as_df()` - Get tick data for specified seconds around last tick
205
+ - `collect_entry_deals_as_df()` - Filter and collect entry deals (BUY/SELL) from history
206
+ - `fetch_positions_with_metrics_as_df()` - Get open positions with calculated metrics (elapsed time, margin, profit ratios)
207
+ - **Features**:
208
+ - Smart order routing with configurable filling modes
209
+ - Comprehensive error handling with `Mt5TradingError`
210
+ - Support for batch operations on multiple symbols
211
+ - Automatic position closing with proper order type reversal
212
+ - Dry run mode for strategy testing without real trades
137
213
 
138
214
  ### Configuration
139
215
 
@@ -144,8 +220,7 @@ config = Mt5Config(
144
220
  login=12345678, # MT5 account number
145
221
  password="password", # MT5 password
146
222
  server="Broker-Server", # MT5 server name
147
- timeout=60000, # Connection timeout in ms
148
- portable=False # Use portable mode
223
+ timeout=60000 # Connection timeout in ms
149
224
  )
150
225
  ```
151
226
 
@@ -194,7 +269,7 @@ with Mt5DataClient(config=config) as client:
194
269
  ```python
195
270
  with Mt5DataClient(config=config) as client:
196
271
  # Get all open positions as DataFrame
197
- positions = client.get_positions_as_df()
272
+ positions = client.positions_get_as_df()
198
273
 
199
274
  if not positions.empty:
200
275
  # Calculate summary statistics
@@ -227,6 +302,50 @@ with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
227
302
  test_results = trader_dry.close_open_positions(symbols=["EURUSD", "GBPUSD"])
228
303
  ```
229
304
 
305
+ ### Market Analysis with Mt5TradingClient
306
+
307
+ ```python
308
+ with Mt5TradingClient(config=config) as trader:
309
+ # Calculate spread ratio for EURUSD
310
+ spread_ratio = trader.calculate_spread_ratio("EURUSD")
311
+ print(f"EURUSD spread ratio: {spread_ratio:.5f}")
312
+
313
+ # Get minimum order margins
314
+ margins = trader.calculate_minimum_order_margins("EURUSD")
315
+ print(f"Minimum ask margin: {margins['ask']}")
316
+ print(f"Minimum bid margin: {margins['bid']}")
317
+
318
+ # Get recent OHLC data with custom timeframe
319
+ rates_df = trader.fetch_latest_rates_as_df(
320
+ symbol="EURUSD",
321
+ granularity="M15", # 15-minute bars
322
+ count=100
323
+ )
324
+ print(rates_df.tail())
325
+
326
+ # Get tick data for the last 60 seconds
327
+ ticks_df = trader.fetch_latest_ticks_as_df(
328
+ symbol="EURUSD",
329
+ seconds=60
330
+ )
331
+ print(f"Received {len(ticks_df)} ticks")
332
+
333
+ # Collect entry deals for the last hour
334
+ deals_df = trader.collect_entry_deals_as_df(
335
+ symbol="EURUSD",
336
+ history_seconds=3600
337
+ )
338
+ if not deals_df.empty:
339
+ print(f"Found {len(deals_df)} entry deals")
340
+ print(deals_df[['time', 'type', 'volume', 'price']].head())
341
+
342
+ # Get positions with calculated metrics
343
+ positions_df = trader.fetch_positions_with_metrics_as_df("EURUSD")
344
+ if not positions_df.empty:
345
+ print(f"Open positions with metrics:")
346
+ print(positions_df[['ticket', 'volume', 'profit', 'elapsed_seconds', 'underlier_profit_ratio']].head())
347
+ ```
348
+
230
349
  ## Development
231
350
 
232
351
  ### Setup Development Environment
@@ -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=FsLC_X_bwBnnQ9l54wPA4OlwD2HlO1RnPvOCnMopNNE,10113
4
+ pdmt5/trading.py,sha256=qZFORyBlSQNp_DQPeuEIqFHPAnVrCJK_6GhFRc5vDR8,13683
5
5
  pdmt5/utils.py,sha256=Ll5Q3OE5h1A_sZ_qVEnOPGniFlT6_MmHfuu0zqeLdeU,3913
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,,
6
+ pdmt5-0.1.4.dist-info/METADATA,sha256=XFIW5O6a7bePMxnDVc7MG6mnkXwNTY_53_mVb_BJxnY,14678
7
+ pdmt5-0.1.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ pdmt5-0.1.4.dist-info/licenses/LICENSE,sha256=iABrdaUGOBWLYotFupB_PGe8arV5o7rVhn-_vK6P704,1073
9
+ pdmt5-0.1.4.dist-info/RECORD,,
File without changes