pdmt5 0.1.2__tar.gz → 0.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {pdmt5-0.1.2 → pdmt5-0.1.4}/PKG-INFO +149 -30
  2. pdmt5-0.1.4/README.md +402 -0
  3. {pdmt5-0.1.2 → pdmt5-0.1.4}/pdmt5/trading.py +180 -1
  4. {pdmt5-0.1.2 → pdmt5-0.1.4}/pyproject.toml +2 -2
  5. {pdmt5-0.1.2 → pdmt5-0.1.4}/test/test_trading.py +391 -0
  6. {pdmt5-0.1.2 → pdmt5-0.1.4}/uv.lock +1 -1
  7. pdmt5-0.1.2/README.md +0 -283
  8. {pdmt5-0.1.2 → pdmt5-0.1.4}/.claude/settings.json +0 -0
  9. {pdmt5-0.1.2 → pdmt5-0.1.4}/.github/FUNDING.yml +0 -0
  10. {pdmt5-0.1.2 → pdmt5-0.1.4}/.github/copilot-instructions.md +0 -0
  11. {pdmt5-0.1.2 → pdmt5-0.1.4}/.github/dependabot.yml +0 -0
  12. {pdmt5-0.1.2 → pdmt5-0.1.4}/.github/workflows/ci.yml +0 -0
  13. {pdmt5-0.1.2 → pdmt5-0.1.4}/.gitignore +0 -0
  14. {pdmt5-0.1.2 → pdmt5-0.1.4}/CLAUDE.md +0 -0
  15. {pdmt5-0.1.2 → pdmt5-0.1.4}/LICENSE +0 -0
  16. {pdmt5-0.1.2 → pdmt5-0.1.4}/docs/api/dataframe.md +0 -0
  17. {pdmt5-0.1.2 → pdmt5-0.1.4}/docs/api/index.md +0 -0
  18. {pdmt5-0.1.2 → pdmt5-0.1.4}/docs/api/mt5.md +0 -0
  19. {pdmt5-0.1.2 → pdmt5-0.1.4}/docs/api/trading.md +0 -0
  20. {pdmt5-0.1.2 → pdmt5-0.1.4}/docs/api/utils.md +0 -0
  21. {pdmt5-0.1.2 → pdmt5-0.1.4}/docs/index.md +0 -0
  22. {pdmt5-0.1.2 → pdmt5-0.1.4}/mkdocs.yml +0 -0
  23. {pdmt5-0.1.2 → pdmt5-0.1.4}/pdmt5/__init__.py +0 -0
  24. {pdmt5-0.1.2 → pdmt5-0.1.4}/pdmt5/dataframe.py +0 -0
  25. {pdmt5-0.1.2 → pdmt5-0.1.4}/pdmt5/mt5.py +0 -0
  26. {pdmt5-0.1.2 → pdmt5-0.1.4}/pdmt5/utils.py +0 -0
  27. {pdmt5-0.1.2 → pdmt5-0.1.4}/renovate.json +0 -0
  28. {pdmt5-0.1.2 → pdmt5-0.1.4}/test/__init__.py +0 -0
  29. {pdmt5-0.1.2 → pdmt5-0.1.4}/test/test_dataframe.py +0 -0
  30. {pdmt5-0.1.2 → pdmt5-0.1.4}/test/test_init.py +0 -0
  31. {pdmt5-0.1.2 → pdmt5-0.1.4}/test/test_mt5.py +0 -0
  32. {pdmt5-0.1.2 → pdmt5-0.1.4}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pdmt5
3
- Version: 0.1.2
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
pdmt5-0.1.4/README.md ADDED
@@ -0,0 +1,402 @@
1
+ # pdmt5
2
+
3
+ Pandas-based data handler for MetaTrader 5
4
+
5
+ [![CI/CD](https://github.com/dceoy/pdmt5/actions/workflows/ci.yml/badge.svg)](https://github.com/dceoy/pdmt5/actions/workflows/ci.yml)
6
+ [![Python Version](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![Platform](https://img.shields.io/badge/platform-Windows-blue.svg)](https://www.microsoft.com/windows)
9
+ [![Version](https://img.shields.io/badge/version-0.1.4-green.svg)](https://github.com/dceoy/pdmt5)
10
+
11
+ ## Overview
12
+
13
+ **pdmt5** is a Python package that provides a pandas-based interface for MetaTrader 5 (MT5), making it easier to work with financial market data in Python. It automatically converts MT5's native data structures into pandas DataFrames, enabling seamless integration with data science workflows.
14
+
15
+ ### Key Features
16
+
17
+ - 📊 **Pandas Integration**: All data returned as pandas DataFrames for easy analysis
18
+ - 🔧 **Type Safety**: Full type hints with strict pyright checking and pydantic validation
19
+ - 🏦 **Comprehensive MT5 Coverage**: Account info, market data, tick data, orders, positions, and more
20
+ - 🚀 **Context Manager Support**: Clean initialization and cleanup with `with` statements
21
+ - 📈 **Time Series Ready**: OHLCV data with proper datetime indexing
22
+ - 🛡️ **Robust Error Handling**: Custom exceptions with detailed MT5 error information
23
+
24
+ ## Requirements
25
+
26
+ - **Operating System**: Windows (required by MetaTrader5 API)
27
+ - **Python**: 3.11 or higher
28
+ - **MetaTrader 5**: Terminal must be installed
29
+
30
+ ## Installation
31
+
32
+ ### From GitHub
33
+
34
+ ```bash
35
+ git clone https://github.com/dceoy/pdmt5.git
36
+ pip install -U --no-cache-dir ./pdmt5
37
+ ```
38
+
39
+ ### Using uv (recommended for development)
40
+
41
+ ```bash
42
+ git clone https://github.com/dceoy/pdmt5.git
43
+ cd pdmt5
44
+ uv sync
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ ```python
50
+ import MetaTrader5 as mt5
51
+ from datetime import datetime
52
+ from pdmt5 import Mt5DataClient, Mt5Config
53
+
54
+ # Configure connection
55
+ config = Mt5Config(
56
+ login=12345678,
57
+ password="your_password",
58
+ server="YourBroker-Server",
59
+ timeout=60000
60
+ )
61
+
62
+ # Use as context manager
63
+ with Mt5DataClient(config=config) as client:
64
+ # Get account information as DataFrame
65
+ account_info = client.account_info_as_df()
66
+ print(account_info)
67
+
68
+ # Get OHLCV data as DataFrame
69
+ rates = client.copy_rates_from_as_df(
70
+ symbol="EURUSD",
71
+ timeframe=mt5.TIMEFRAME_H1,
72
+ date_from=datetime(2024, 1, 1),
73
+ count=100
74
+ )
75
+ print(rates.head())
76
+
77
+ # Get current positions as DataFrame
78
+ positions = client.positions_get_as_df()
79
+ print(positions)
80
+ ```
81
+
82
+ ## Core Components
83
+
84
+ ### Mt5Client
85
+
86
+ The base client wrapper for all MetaTrader5 operations with context manager support:
87
+
88
+ - **Connection Management**:
89
+ - `initialize()` - Establish connection with MT5 terminal (with optional path, login, password, server, timeout)
90
+ - `login()` - Connect to trading account with credentials
91
+ - `shutdown()` - Close MT5 terminal connection
92
+ - Context manager support (`with` statement) for automatic initialization/cleanup
93
+ - **Terminal Information**:
94
+ - `version()` - Get MT5 terminal version, build, and release date
95
+ - `last_error()` - Get last error code and description
96
+ - `account_info()` - Get current trading account information
97
+ - `terminal_info()` - Get terminal status and settings
98
+ - **Symbol Operations**:
99
+ - `symbols_total()` - Get total number of financial instruments
100
+ - `symbols_get()` - Get all symbols or filter by group
101
+ - `symbol_info()` - Get detailed data on specific symbol
102
+ - `symbol_info_tick()` - Get last tick for symbol
103
+ - `symbol_select()` - Show/hide symbol in MarketWatch
104
+ - **Market Depth**:
105
+ - `market_book_add()` - Subscribe to Market Depth events
106
+ - `market_book_get()` - Get current Market Depth data
107
+ - `market_book_release()` - Unsubscribe from Market Depth
108
+ - **Market Data**:
109
+ - `copy_rates_from()` - Get bars from specified date
110
+ - `copy_rates_from_pos()` - Get bars from specified position
111
+ - `copy_rates_range()` - Get bars for date range
112
+ - `copy_ticks_from()` - Get ticks from specified date
113
+ - `copy_ticks_range()` - Get ticks for date range
114
+ - **Order Operations**:
115
+ - `orders_total()` - Get number of active orders
116
+ - `orders_get()` - Get active orders with optional filters
117
+ - `order_calc_margin()` - Calculate required margin
118
+ - `order_calc_profit()` - Calculate potential profit
119
+ - `order_check()` - Check if order can be placed
120
+ - `order_send()` - Send order to trade server
121
+ - **Position Operations**:
122
+ - `positions_total()` - Get number of open positions
123
+ - `positions_get()` - Get open positions with optional filters
124
+ - **Trading History**:
125
+ - `history_orders_total()` - Get number of historical orders
126
+ - `history_orders_get()` - Get historical orders with filters
127
+ - `history_deals_total()` - Get number of historical deals
128
+ - `history_deals_get()` - Get historical deals with filters
129
+
130
+ ### Mt5DataClient
131
+
132
+ Extends Mt5Client with pandas DataFrame and dictionary conversions:
133
+
134
+ - **Enhanced Connection**:
135
+ - `initialize_and_login_mt5()` - Combined initialization and login with retry logic
136
+ - Configurable retry attempts via `retry_count` parameter
137
+ - **DataFrame/Dictionary Conversions**: All methods have both `_as_df` and `_as_dict` variants:
138
+ - `version_as_dict/df()` - MT5 version information
139
+ - `last_error_as_dict/df()` - Last error details
140
+ - `account_info_as_dict/df()` - Account information
141
+ - `terminal_info_as_dict/df()` - Terminal information
142
+ - `symbols_get_as_dicts/df()` - Symbol list with optional group filter
143
+ - `symbol_info_as_dict/df()` - Single symbol information
144
+ - `symbol_info_tick_as_dict/df()` - Last tick data
145
+ - `market_book_get_as_dicts/df()` - Market depth data
146
+ - **OHLCV Data Methods**:
147
+ - `copy_rates_from_as_dicts/df()` - Historical bars from date
148
+ - `copy_rates_from_pos_as_dicts/df()` - Historical bars from position
149
+ - `copy_rates_range_as_dicts/df()` - Historical bars for date range
150
+ - **Tick Data Methods**:
151
+ - `copy_ticks_from_as_dicts/df()` - Historical ticks from date
152
+ - `copy_ticks_range_as_dicts/df()` - Historical ticks for date range
153
+ - **Trading Data Methods**:
154
+ - `orders_get_as_dicts/df()` - Active orders with filters
155
+ - `order_check_as_dict/df()` - Order validation results
156
+ - `order_send_as_dict/df()` - Order execution results
157
+ - `positions_get_as_dicts/df()` - Open positions with filters
158
+ - `history_orders_get_as_dicts/df()` - Historical orders with date/ticket/position filters
159
+ - `history_deals_get_as_dicts/df()` - Historical deals with date/ticket/position filters
160
+ - **Features**:
161
+ - Automatic time conversion to datetime objects
162
+ - Optional DataFrame indexing with `index_keys` parameter
163
+ - Input validation for dates, counts, and positions
164
+ - Pydantic-based configuration via `Mt5Config`
165
+
166
+ ### Mt5TradingClient
167
+
168
+ Advanced trading operations client that extends Mt5DataClient:
169
+
170
+ - **Trading Configuration**:
171
+ - `order_filling_mode` - Order execution mode: "IOC" (default), "FOK", or "RETURN"
172
+ - `dry_run` - Test mode flag for simulating trades without execution
173
+ - **Position Management**:
174
+ - `close_open_positions()` - Close all positions for specified symbol(s)
175
+ - `send_or_check_order()` - Execute or validate orders based on dry_run mode
176
+ - **Market Analysis**:
177
+ - `calculate_minimum_order_margins()` - Calculate minimum required margins for buy/sell orders
178
+ - `calculate_spread_ratio()` - Calculate normalized bid-ask spread ratio
179
+ - **Simplified Data Access**:
180
+ - `fetch_latest_rates_as_df()` - Get recent OHLC data with timeframe strings (e.g., "M1", "H1", "D1")
181
+ - `fetch_latest_ticks_as_df()` - Get tick data for specified seconds around last tick
182
+ - `collect_entry_deals_as_df()` - Filter and collect entry deals (BUY/SELL) from history
183
+ - `fetch_positions_with_metrics_as_df()` - Get open positions with calculated metrics (elapsed time, margin, profit ratios)
184
+ - **Features**:
185
+ - Smart order routing with configurable filling modes
186
+ - Comprehensive error handling with `Mt5TradingError`
187
+ - Support for batch operations on multiple symbols
188
+ - Automatic position closing with proper order type reversal
189
+ - Dry run mode for strategy testing without real trades
190
+
191
+ ### Configuration
192
+
193
+ ```python
194
+ from pdmt5 import Mt5Config
195
+
196
+ config = Mt5Config(
197
+ login=12345678, # MT5 account number
198
+ password="password", # MT5 password
199
+ server="Broker-Server", # MT5 server name
200
+ timeout=60000 # Connection timeout in ms
201
+ )
202
+ ```
203
+
204
+ ## Examples
205
+
206
+ ### Getting Historical Data
207
+
208
+ ```python
209
+ import MetaTrader5 as mt5
210
+ from datetime import datetime
211
+
212
+ with Mt5DataClient(config=config) as client:
213
+ # Get last 1000 H1 bars for EURUSD as DataFrame
214
+ df = client.copy_rates_from_as_df(
215
+ symbol="EURUSD",
216
+ timeframe=mt5.TIMEFRAME_H1,
217
+ date_from=datetime.now(),
218
+ count=1000
219
+ )
220
+
221
+ # Data includes: time, open, high, low, close, tick_volume, spread, real_volume
222
+ print(df.columns)
223
+ print(df.describe())
224
+ ```
225
+
226
+ ### Working with Tick Data
227
+
228
+ ```python
229
+ from datetime import datetime, timedelta
230
+
231
+ with Mt5DataClient(config=config) as client:
232
+ # Get ticks for the last hour as DataFrame
233
+ ticks = client.copy_ticks_from_as_df(
234
+ symbol="EURUSD",
235
+ date_from=datetime.now() - timedelta(hours=1),
236
+ count=10000,
237
+ flags=mt5.COPY_TICKS_ALL
238
+ )
239
+
240
+ # Tick data includes: time, bid, ask, last, volume, flags
241
+ print(ticks.head())
242
+ ```
243
+
244
+ ### Analyzing Positions
245
+
246
+ ```python
247
+ with Mt5DataClient(config=config) as client:
248
+ # Get all open positions as DataFrame
249
+ positions = client.positions_get_as_df()
250
+
251
+ if not positions.empty:
252
+ # Calculate summary statistics
253
+ summary = positions.groupby('symbol').agg({
254
+ 'volume': 'sum',
255
+ 'profit': 'sum',
256
+ 'price_open': 'mean'
257
+ })
258
+ print(summary)
259
+ ```
260
+
261
+ ### Trading Operations
262
+
263
+ ```python
264
+ from pdmt5 import Mt5TradingClient
265
+
266
+ # Create trading client with specific order filling mode
267
+ with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
268
+ # Close all EURUSD positions
269
+ results = trader.close_open_positions(symbols="EURUSD")
270
+
271
+ if results:
272
+ for result in results:
273
+ print(f"Closed position {result['position']} with result: {result['retcode']}")
274
+
275
+ # Using dry run mode for testing
276
+ trader_dry = Mt5TradingClient(config=config, dry_run=True)
277
+ with trader_dry:
278
+ # Test closing positions without actual execution
279
+ test_results = trader_dry.close_open_positions(symbols=["EURUSD", "GBPUSD"])
280
+ ```
281
+
282
+ ### Market Analysis with Mt5TradingClient
283
+
284
+ ```python
285
+ with Mt5TradingClient(config=config) as trader:
286
+ # Calculate spread ratio for EURUSD
287
+ spread_ratio = trader.calculate_spread_ratio("EURUSD")
288
+ print(f"EURUSD spread ratio: {spread_ratio:.5f}")
289
+
290
+ # Get minimum order margins
291
+ margins = trader.calculate_minimum_order_margins("EURUSD")
292
+ print(f"Minimum ask margin: {margins['ask']}")
293
+ print(f"Minimum bid margin: {margins['bid']}")
294
+
295
+ # Get recent OHLC data with custom timeframe
296
+ rates_df = trader.fetch_latest_rates_as_df(
297
+ symbol="EURUSD",
298
+ granularity="M15", # 15-minute bars
299
+ count=100
300
+ )
301
+ print(rates_df.tail())
302
+
303
+ # Get tick data for the last 60 seconds
304
+ ticks_df = trader.fetch_latest_ticks_as_df(
305
+ symbol="EURUSD",
306
+ seconds=60
307
+ )
308
+ print(f"Received {len(ticks_df)} ticks")
309
+
310
+ # Collect entry deals for the last hour
311
+ deals_df = trader.collect_entry_deals_as_df(
312
+ symbol="EURUSD",
313
+ history_seconds=3600
314
+ )
315
+ if not deals_df.empty:
316
+ print(f"Found {len(deals_df)} entry deals")
317
+ print(deals_df[['time', 'type', 'volume', 'price']].head())
318
+
319
+ # Get positions with calculated metrics
320
+ positions_df = trader.fetch_positions_with_metrics_as_df("EURUSD")
321
+ if not positions_df.empty:
322
+ print(f"Open positions with metrics:")
323
+ print(positions_df[['ticket', 'volume', 'profit', 'elapsed_seconds', 'underlier_profit_ratio']].head())
324
+ ```
325
+
326
+ ## Development
327
+
328
+ ### Setup Development Environment
329
+
330
+ ```bash
331
+ # Clone repository
332
+ git clone https://github.com/dceoy/pdmt5.git
333
+ cd pdmt5
334
+
335
+ # Install with uv
336
+ uv sync
337
+
338
+ # Run tests
339
+ uv run pytest test/ -v
340
+
341
+ # Run type checking
342
+ uv run pyright .
343
+
344
+ # Run linting
345
+ uv run ruff check --fix .
346
+ uv run ruff format .
347
+ ```
348
+
349
+ ### Code Quality
350
+
351
+ This project maintains high code quality standards:
352
+
353
+ - **Type Checking**: Strict mode with pyright
354
+ - **Linting**: Comprehensive ruff configuration with 40+ rule categories
355
+ - **Testing**: pytest with coverage tracking (minimum 90%)
356
+ - **Documentation**: Google-style docstrings
357
+
358
+ ## Error Handling
359
+
360
+ The package provides detailed error information:
361
+
362
+ ```python
363
+ from pdmt5 import Mt5RuntimeError
364
+
365
+ try:
366
+ with Mt5DataClient(config=config) as client:
367
+ data = client.copy_rates_from("INVALID", mt5.TIMEFRAME_H1, datetime.now(), 100)
368
+ except Mt5RuntimeError as e:
369
+ print(f"MT5 Error: {e}")
370
+ print(f"Error code: {e.error_code}")
371
+ print(f"Description: {e.description}")
372
+ ```
373
+
374
+ ## Limitations
375
+
376
+ - **Windows Only**: Due to MetaTrader5 API requirements
377
+ - **MT5 Terminal Required**: The MetaTrader 5 terminal must be installed
378
+ - **Single Thread**: MT5 API is not thread-safe
379
+
380
+ ## Contributing
381
+
382
+ Contributions are welcome! Please:
383
+
384
+ 1. Fork the repository
385
+ 2. Create a feature branch
386
+ 3. Ensure tests pass and coverage is maintained
387
+ 4. Submit a pull request
388
+
389
+ See [CLAUDE.md](CLAUDE.md) for development guidelines.
390
+
391
+ ## License
392
+
393
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
394
+
395
+ ## Author
396
+
397
+ Daichi Narushima, Ph.D.
398
+
399
+ ## Acknowledgments
400
+
401
+ - MetaTrader 5 for providing the Python API
402
+ - The pandas community for the excellent data manipulation tools