pdmt5 0.1.5__tar.gz → 0.1.7__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.
- {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/workflows/ci.yml +1 -1
- {pdmt5-0.1.5 → pdmt5-0.1.7}/PKG-INFO +36 -40
- {pdmt5-0.1.5 → pdmt5-0.1.7}/README.md +35 -39
- pdmt5-0.1.7/docs/api/trading.md +396 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/trading.py +75 -43
- {pdmt5-0.1.5 → pdmt5-0.1.7}/pyproject.toml +1 -1
- {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_trading.py +160 -53
- {pdmt5-0.1.5 → pdmt5-0.1.7}/uv.lock +1 -1
- pdmt5-0.1.5/docs/api/trading.md +0 -217
- {pdmt5-0.1.5 → pdmt5-0.1.7}/.claude/settings.json +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/FUNDING.yml +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/copilot-instructions.md +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/dependabot.yml +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/.gitignore +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/CLAUDE.md +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/LICENSE +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/dataframe.md +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/index.md +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/mt5.md +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/utils.md +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/index.md +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/mkdocs.yml +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/__init__.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/dataframe.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/mt5.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/utils.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/renovate.json +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/test/__init__.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_dataframe.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_init.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_mt5.py +0 -0
- {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_utils.py +0 -0
|
@@ -42,7 +42,7 @@ jobs:
|
|
|
42
42
|
- name: Checkout repository
|
|
43
43
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
44
44
|
- name: Set up uv
|
|
45
|
-
uses: astral-sh/setup-uv@
|
|
45
|
+
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
|
|
46
46
|
- name: Install the package
|
|
47
47
|
run: >
|
|
48
48
|
uv sync
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pdmt5
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
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>
|
|
@@ -42,6 +42,8 @@ Pandas-based data handler for MetaTrader 5
|
|
|
42
42
|
- 🚀 **Context Manager Support**: Clean initialization and cleanup with `with` statements
|
|
43
43
|
- 📈 **Time Series Ready**: OHLCV data with proper datetime indexing
|
|
44
44
|
- 🛡️ **Robust Error Handling**: Custom exceptions with detailed MT5 error information
|
|
45
|
+
- 💰 **Advanced Trading Operations**: Position management, margin calculations, and risk analysis tools
|
|
46
|
+
- 🧪 **Dry Run Mode**: Test trading strategies without executing real trades
|
|
45
47
|
|
|
46
48
|
## Requirements
|
|
47
49
|
|
|
@@ -189,15 +191,13 @@ Extends Mt5Client with pandas DataFrame and dictionary conversions:
|
|
|
189
191
|
|
|
190
192
|
Advanced trading operations client that extends Mt5DataClient:
|
|
191
193
|
|
|
192
|
-
- **Trading Configuration**:
|
|
193
|
-
- `order_filling_mode` - Order execution mode: "IOC" (default), "FOK", or "RETURN"
|
|
194
|
-
- `dry_run` - Test mode flag for simulating trades without execution
|
|
195
194
|
- **Position Management**:
|
|
196
195
|
- `close_open_positions()` - Close all positions for specified symbol(s)
|
|
197
196
|
- `place_market_order()` - Place market orders with configurable side, volume, and execution modes
|
|
198
|
-
- `
|
|
199
|
-
- **
|
|
200
|
-
- `
|
|
197
|
+
- `update_sltp_for_open_positions()` - Modify stop loss and take profit levels for open positions
|
|
198
|
+
- **Margin Calculations**:
|
|
199
|
+
- `calculate_minimum_order_margin()` - Calculate minimum required margin for a specific order side
|
|
200
|
+
- `calculate_volume_by_margin()` - Calculate maximum volume for given margin amount
|
|
201
201
|
- `calculate_spread_ratio()` - Calculate normalized bid-ask spread ratio
|
|
202
202
|
- `calculate_new_position_margin_ratio()` - Calculate margin ratio for potential new positions
|
|
203
203
|
- **Simplified Data Access**:
|
|
@@ -210,7 +210,6 @@ Advanced trading operations client that extends Mt5DataClient:
|
|
|
210
210
|
- Comprehensive error handling with `Mt5TradingError`
|
|
211
211
|
- Support for batch operations on multiple symbols
|
|
212
212
|
- Automatic position closing with proper order type reversal
|
|
213
|
-
- Dry run mode for strategy testing without real trades
|
|
214
213
|
|
|
215
214
|
### Configuration
|
|
216
215
|
|
|
@@ -287,8 +286,8 @@ with Mt5DataClient(config=config) as client:
|
|
|
287
286
|
```python
|
|
288
287
|
from pdmt5 import Mt5TradingClient
|
|
289
288
|
|
|
290
|
-
# Create trading client
|
|
291
|
-
with Mt5TradingClient(config=config
|
|
289
|
+
# Create trading client
|
|
290
|
+
with Mt5TradingClient(config=config) as trader:
|
|
292
291
|
# Place a market buy order
|
|
293
292
|
order_result = trader.place_market_order(
|
|
294
293
|
symbol="EURUSD",
|
|
@@ -299,44 +298,33 @@ with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
|
|
|
299
298
|
)
|
|
300
299
|
print(f"Order placed: {order_result['retcode']}")
|
|
301
300
|
|
|
302
|
-
# Update stop loss and take profit for
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
)
|
|
311
|
-
print(f"Position updated: {update_result['retcode']}")
|
|
301
|
+
# Update stop loss and take profit for open positions
|
|
302
|
+
update_results = trader.update_sltp_for_open_positions(
|
|
303
|
+
symbol="EURUSD",
|
|
304
|
+
stop_loss=1.0950, # New stop loss
|
|
305
|
+
take_profit=1.1050 # New take profit
|
|
306
|
+
)
|
|
307
|
+
for result in update_results:
|
|
308
|
+
print(f"Position updated: {result['retcode']}")
|
|
312
309
|
|
|
313
310
|
# Calculate margin ratio for a new position
|
|
314
311
|
margin_ratio = trader.calculate_new_position_margin_ratio(
|
|
315
312
|
symbol="EURUSD",
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
new_position_side="SELL",
|
|
314
|
+
new_position_volume=0.2
|
|
318
315
|
)
|
|
319
316
|
print(f"New position margin ratio: {margin_ratio:.2%}")
|
|
320
317
|
|
|
321
|
-
# Close all EURUSD positions
|
|
322
|
-
results = trader.close_open_positions(
|
|
318
|
+
# Close all EURUSD positions with specific order filling mode
|
|
319
|
+
results = trader.close_open_positions(
|
|
320
|
+
symbols="EURUSD",
|
|
321
|
+
order_filling_mode="FOK" # Fill or Kill
|
|
322
|
+
)
|
|
323
323
|
|
|
324
324
|
if results:
|
|
325
325
|
for symbol, close_results in results.items():
|
|
326
326
|
for result in close_results:
|
|
327
327
|
print(f"Closed position {result.get('position')} with result: {result['retcode']}")
|
|
328
|
-
|
|
329
|
-
# Using dry run mode for testing
|
|
330
|
-
trader_dry = Mt5TradingClient(config=config, dry_run=True)
|
|
331
|
-
with trader_dry:
|
|
332
|
-
# Test placing an order without actual execution
|
|
333
|
-
test_order = trader_dry.place_market_order(
|
|
334
|
-
symbol="GBPUSD",
|
|
335
|
-
volume=0.1,
|
|
336
|
-
order_side="SELL",
|
|
337
|
-
dry_run=True # Override instance setting
|
|
338
|
-
)
|
|
339
|
-
print(f"Test order validation: {test_order['retcode']}")
|
|
340
328
|
```
|
|
341
329
|
|
|
342
330
|
### Market Analysis with Mt5TradingClient
|
|
@@ -347,10 +335,18 @@ with Mt5TradingClient(config=config) as trader:
|
|
|
347
335
|
spread_ratio = trader.calculate_spread_ratio("EURUSD")
|
|
348
336
|
print(f"EURUSD spread ratio: {spread_ratio:.5f}")
|
|
349
337
|
|
|
350
|
-
# Get minimum order
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
print(f"Minimum
|
|
338
|
+
# Get minimum order margin for BUY and SELL
|
|
339
|
+
buy_margin = trader.calculate_minimum_order_margin("EURUSD", "BUY")
|
|
340
|
+
sell_margin = trader.calculate_minimum_order_margin("EURUSD", "SELL")
|
|
341
|
+
print(f"Minimum BUY margin: {buy_margin['margin']} (volume: {buy_margin['volume']})")
|
|
342
|
+
print(f"Minimum SELL margin: {sell_margin['margin']} (volume: {sell_margin['volume']})")
|
|
343
|
+
|
|
344
|
+
# Calculate volume by margin
|
|
345
|
+
available_margin = 1000.0
|
|
346
|
+
max_buy_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "BUY")
|
|
347
|
+
max_sell_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "SELL")
|
|
348
|
+
print(f"Max BUY volume for ${available_margin}: {max_buy_volume}")
|
|
349
|
+
print(f"Max SELL volume for ${available_margin}: {max_sell_volume}")
|
|
354
350
|
|
|
355
351
|
# Get recent OHLC data with custom timeframe
|
|
356
352
|
rates_df = trader.fetch_latest_rates_as_df(
|
|
@@ -19,6 +19,8 @@ Pandas-based data handler for MetaTrader 5
|
|
|
19
19
|
- 🚀 **Context Manager Support**: Clean initialization and cleanup with `with` statements
|
|
20
20
|
- 📈 **Time Series Ready**: OHLCV data with proper datetime indexing
|
|
21
21
|
- 🛡️ **Robust Error Handling**: Custom exceptions with detailed MT5 error information
|
|
22
|
+
- 💰 **Advanced Trading Operations**: Position management, margin calculations, and risk analysis tools
|
|
23
|
+
- 🧪 **Dry Run Mode**: Test trading strategies without executing real trades
|
|
22
24
|
|
|
23
25
|
## Requirements
|
|
24
26
|
|
|
@@ -166,15 +168,13 @@ Extends Mt5Client with pandas DataFrame and dictionary conversions:
|
|
|
166
168
|
|
|
167
169
|
Advanced trading operations client that extends Mt5DataClient:
|
|
168
170
|
|
|
169
|
-
- **Trading Configuration**:
|
|
170
|
-
- `order_filling_mode` - Order execution mode: "IOC" (default), "FOK", or "RETURN"
|
|
171
|
-
- `dry_run` - Test mode flag for simulating trades without execution
|
|
172
171
|
- **Position Management**:
|
|
173
172
|
- `close_open_positions()` - Close all positions for specified symbol(s)
|
|
174
173
|
- `place_market_order()` - Place market orders with configurable side, volume, and execution modes
|
|
175
|
-
- `
|
|
176
|
-
- **
|
|
177
|
-
- `
|
|
174
|
+
- `update_sltp_for_open_positions()` - Modify stop loss and take profit levels for open positions
|
|
175
|
+
- **Margin Calculations**:
|
|
176
|
+
- `calculate_minimum_order_margin()` - Calculate minimum required margin for a specific order side
|
|
177
|
+
- `calculate_volume_by_margin()` - Calculate maximum volume for given margin amount
|
|
178
178
|
- `calculate_spread_ratio()` - Calculate normalized bid-ask spread ratio
|
|
179
179
|
- `calculate_new_position_margin_ratio()` - Calculate margin ratio for potential new positions
|
|
180
180
|
- **Simplified Data Access**:
|
|
@@ -187,7 +187,6 @@ Advanced trading operations client that extends Mt5DataClient:
|
|
|
187
187
|
- Comprehensive error handling with `Mt5TradingError`
|
|
188
188
|
- Support for batch operations on multiple symbols
|
|
189
189
|
- Automatic position closing with proper order type reversal
|
|
190
|
-
- Dry run mode for strategy testing without real trades
|
|
191
190
|
|
|
192
191
|
### Configuration
|
|
193
192
|
|
|
@@ -264,8 +263,8 @@ with Mt5DataClient(config=config) as client:
|
|
|
264
263
|
```python
|
|
265
264
|
from pdmt5 import Mt5TradingClient
|
|
266
265
|
|
|
267
|
-
# Create trading client
|
|
268
|
-
with Mt5TradingClient(config=config
|
|
266
|
+
# Create trading client
|
|
267
|
+
with Mt5TradingClient(config=config) as trader:
|
|
269
268
|
# Place a market buy order
|
|
270
269
|
order_result = trader.place_market_order(
|
|
271
270
|
symbol="EURUSD",
|
|
@@ -276,44 +275,33 @@ with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
|
|
|
276
275
|
)
|
|
277
276
|
print(f"Order placed: {order_result['retcode']}")
|
|
278
277
|
|
|
279
|
-
# Update stop loss and take profit for
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
)
|
|
288
|
-
print(f"Position updated: {update_result['retcode']}")
|
|
278
|
+
# Update stop loss and take profit for open positions
|
|
279
|
+
update_results = trader.update_sltp_for_open_positions(
|
|
280
|
+
symbol="EURUSD",
|
|
281
|
+
stop_loss=1.0950, # New stop loss
|
|
282
|
+
take_profit=1.1050 # New take profit
|
|
283
|
+
)
|
|
284
|
+
for result in update_results:
|
|
285
|
+
print(f"Position updated: {result['retcode']}")
|
|
289
286
|
|
|
290
287
|
# Calculate margin ratio for a new position
|
|
291
288
|
margin_ratio = trader.calculate_new_position_margin_ratio(
|
|
292
289
|
symbol="EURUSD",
|
|
293
|
-
|
|
294
|
-
|
|
290
|
+
new_position_side="SELL",
|
|
291
|
+
new_position_volume=0.2
|
|
295
292
|
)
|
|
296
293
|
print(f"New position margin ratio: {margin_ratio:.2%}")
|
|
297
294
|
|
|
298
|
-
# Close all EURUSD positions
|
|
299
|
-
results = trader.close_open_positions(
|
|
295
|
+
# Close all EURUSD positions with specific order filling mode
|
|
296
|
+
results = trader.close_open_positions(
|
|
297
|
+
symbols="EURUSD",
|
|
298
|
+
order_filling_mode="FOK" # Fill or Kill
|
|
299
|
+
)
|
|
300
300
|
|
|
301
301
|
if results:
|
|
302
302
|
for symbol, close_results in results.items():
|
|
303
303
|
for result in close_results:
|
|
304
304
|
print(f"Closed position {result.get('position')} with result: {result['retcode']}")
|
|
305
|
-
|
|
306
|
-
# Using dry run mode for testing
|
|
307
|
-
trader_dry = Mt5TradingClient(config=config, dry_run=True)
|
|
308
|
-
with trader_dry:
|
|
309
|
-
# Test placing an order without actual execution
|
|
310
|
-
test_order = trader_dry.place_market_order(
|
|
311
|
-
symbol="GBPUSD",
|
|
312
|
-
volume=0.1,
|
|
313
|
-
order_side="SELL",
|
|
314
|
-
dry_run=True # Override instance setting
|
|
315
|
-
)
|
|
316
|
-
print(f"Test order validation: {test_order['retcode']}")
|
|
317
305
|
```
|
|
318
306
|
|
|
319
307
|
### Market Analysis with Mt5TradingClient
|
|
@@ -324,10 +312,18 @@ with Mt5TradingClient(config=config) as trader:
|
|
|
324
312
|
spread_ratio = trader.calculate_spread_ratio("EURUSD")
|
|
325
313
|
print(f"EURUSD spread ratio: {spread_ratio:.5f}")
|
|
326
314
|
|
|
327
|
-
# Get minimum order
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
print(f"Minimum
|
|
315
|
+
# Get minimum order margin for BUY and SELL
|
|
316
|
+
buy_margin = trader.calculate_minimum_order_margin("EURUSD", "BUY")
|
|
317
|
+
sell_margin = trader.calculate_minimum_order_margin("EURUSD", "SELL")
|
|
318
|
+
print(f"Minimum BUY margin: {buy_margin['margin']} (volume: {buy_margin['volume']})")
|
|
319
|
+
print(f"Minimum SELL margin: {sell_margin['margin']} (volume: {sell_margin['volume']})")
|
|
320
|
+
|
|
321
|
+
# Calculate volume by margin
|
|
322
|
+
available_margin = 1000.0
|
|
323
|
+
max_buy_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "BUY")
|
|
324
|
+
max_sell_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "SELL")
|
|
325
|
+
print(f"Max BUY volume for ${available_margin}: {max_buy_volume}")
|
|
326
|
+
print(f"Max SELL volume for ${available_margin}: {max_sell_volume}")
|
|
331
327
|
|
|
332
328
|
# Get recent OHLC data with custom timeframe
|
|
333
329
|
rates_df = trader.fetch_latest_rates_as_df(
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
# Trading
|
|
2
|
+
|
|
3
|
+
::: pdmt5.trading
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The trading module extends Mt5DataClient with advanced trading operations including position management, order execution, and dry run support for testing trading strategies without actual execution.
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
### Mt5TradingClient
|
|
12
|
+
::: pdmt5.trading.Mt5TradingClient
|
|
13
|
+
options:
|
|
14
|
+
show_bases: false
|
|
15
|
+
|
|
16
|
+
Advanced trading client class that inherits from `Mt5DataClient` and provides specialized trading functionality.
|
|
17
|
+
|
|
18
|
+
### Mt5TradingError
|
|
19
|
+
::: pdmt5.trading.Mt5TradingError
|
|
20
|
+
options:
|
|
21
|
+
show_bases: false
|
|
22
|
+
|
|
23
|
+
Custom runtime exception for trading-specific errors.
|
|
24
|
+
|
|
25
|
+
## Usage Examples
|
|
26
|
+
|
|
27
|
+
### Basic Trading Operations
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import MetaTrader5 as mt5
|
|
31
|
+
from pdmt5 import Mt5TradingClient, Mt5Config
|
|
32
|
+
|
|
33
|
+
# Create configuration
|
|
34
|
+
config = Mt5Config(
|
|
35
|
+
login=123456,
|
|
36
|
+
password="your_password",
|
|
37
|
+
server="broker_server",
|
|
38
|
+
timeout=60000,
|
|
39
|
+
portable=False
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Create client with dry run mode for testing
|
|
43
|
+
client = Mt5TradingClient(config=config, dry_run=True)
|
|
44
|
+
|
|
45
|
+
# Use as context manager
|
|
46
|
+
with client:
|
|
47
|
+
# Get current positions as DataFrame
|
|
48
|
+
positions_df = client.get_positions_as_df()
|
|
49
|
+
print(f"Open positions: {len(positions_df)}")
|
|
50
|
+
|
|
51
|
+
# Close positions for specific symbol
|
|
52
|
+
results = client.close_open_positions("EURUSD")
|
|
53
|
+
print(f"Closed positions: {results}")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Production Trading
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# Create client for live trading (dry_run=False)
|
|
60
|
+
client = Mt5TradingClient(config=config, dry_run=False)
|
|
61
|
+
|
|
62
|
+
with client:
|
|
63
|
+
# Close all positions for multiple symbols
|
|
64
|
+
results = client.close_open_positions(["EURUSD", "GBPUSD", "USDJPY"])
|
|
65
|
+
|
|
66
|
+
# Close all positions (all symbols)
|
|
67
|
+
all_results = client.close_open_positions()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Order Filling Modes
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
with Mt5TradingClient(config=config) as client:
|
|
74
|
+
# Use IOC (Immediate or Cancel) - default
|
|
75
|
+
results_ioc = client.close_open_positions(
|
|
76
|
+
symbols="EURUSD",
|
|
77
|
+
order_filling_mode="IOC"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# Use FOK (Fill or Kill)
|
|
81
|
+
results_fok = client.close_open_positions(
|
|
82
|
+
symbols="GBPUSD",
|
|
83
|
+
order_filling_mode="FOK"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Use RETURN (Return if not filled)
|
|
87
|
+
results_return = client.close_open_positions(
|
|
88
|
+
symbols="USDJPY",
|
|
89
|
+
order_filling_mode="RETURN"
|
|
90
|
+
)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Custom Order Parameters
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
with client:
|
|
97
|
+
# Close positions with custom parameters and order filling mode
|
|
98
|
+
results = client.close_open_positions(
|
|
99
|
+
"EURUSD",
|
|
100
|
+
order_filling_mode="IOC", # Specify per method call
|
|
101
|
+
comment="Closing all EURUSD positions",
|
|
102
|
+
deviation=10 # Maximum price deviation
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Error Handling
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from pdmt5.trading import Mt5TradingError
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
with client:
|
|
113
|
+
results = client.close_open_positions("EURUSD")
|
|
114
|
+
except Mt5TradingError as e:
|
|
115
|
+
print(f"Trading error: {e}")
|
|
116
|
+
# Handle specific trading errors
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Checking Order Status
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
with client:
|
|
123
|
+
# Check order (note: send_or_check_order is an internal method)
|
|
124
|
+
# For trading operations, use the provided methods like close_open_positions
|
|
125
|
+
|
|
126
|
+
# Example: Check if we can close a position
|
|
127
|
+
positions = client.get_positions_as_df()
|
|
128
|
+
if not positions.empty:
|
|
129
|
+
# Close specific position
|
|
130
|
+
results = client.close_open_positions("EURUSD")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Position Management Features
|
|
134
|
+
|
|
135
|
+
The Mt5TradingClient provides intelligent position management:
|
|
136
|
+
|
|
137
|
+
- **Automatic Position Reversal**: Automatically determines the correct order type to close positions
|
|
138
|
+
- **Batch Operations**: Close multiple positions for one or more symbols
|
|
139
|
+
- **Dry Run Support**: Test trading logic without executing real trades
|
|
140
|
+
- **Flexible Filtering**: Close positions by symbol, group, or all positions
|
|
141
|
+
- **Custom Parameters**: Support for additional order parameters like comment, deviation, etc.
|
|
142
|
+
|
|
143
|
+
## Dry Run Mode
|
|
144
|
+
|
|
145
|
+
Dry run mode is essential for testing trading strategies:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
# Test mode - validates orders without execution
|
|
149
|
+
test_client = Mt5TradingClient(config=config, dry_run=True)
|
|
150
|
+
|
|
151
|
+
# Production mode - executes real orders
|
|
152
|
+
prod_client = Mt5TradingClient(config=config, dry_run=False)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
In dry run mode:
|
|
156
|
+
- Orders are validated using `order_check()` instead of `order_send()`
|
|
157
|
+
- No actual trades are executed
|
|
158
|
+
- Full validation of margin requirements and order parameters
|
|
159
|
+
- Same return structure as live trading for easy testing
|
|
160
|
+
|
|
161
|
+
## Return Values
|
|
162
|
+
|
|
163
|
+
The `close_open_positions()` method returns a dictionary with symbols as keys:
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
{
|
|
167
|
+
"EURUSD": [
|
|
168
|
+
{
|
|
169
|
+
"retcode": 10009, # Trade done
|
|
170
|
+
"deal": 123456,
|
|
171
|
+
"order": 789012,
|
|
172
|
+
"volume": 1.0,
|
|
173
|
+
"price": 1.1000,
|
|
174
|
+
"comment": "Request executed",
|
|
175
|
+
...
|
|
176
|
+
}
|
|
177
|
+
],
|
|
178
|
+
"GBPUSD": [...]
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Best Practices
|
|
183
|
+
|
|
184
|
+
1. **Always use dry run mode first** to test your trading logic
|
|
185
|
+
2. **Handle Mt5TradingError exceptions** for proper error management
|
|
186
|
+
3. **Check return codes** to verify successful execution
|
|
187
|
+
4. **Use context managers** for automatic connection handling
|
|
188
|
+
5. **Log trading operations** for audit trails
|
|
189
|
+
6. **Validate positions exist** before attempting to close them
|
|
190
|
+
7. **Consider market hours** and trading session times
|
|
191
|
+
|
|
192
|
+
## Common Return Codes
|
|
193
|
+
|
|
194
|
+
- `TRADE_RETCODE_DONE` (10009): Trade operation completed successfully
|
|
195
|
+
- `TRADE_RETCODE_TRADE_DISABLED`: Trading disabled for the account
|
|
196
|
+
- `TRADE_RETCODE_MARKET_CLOSED`: Market is closed
|
|
197
|
+
- `TRADE_RETCODE_NO_MONEY`: Insufficient funds
|
|
198
|
+
- `TRADE_RETCODE_INVALID_VOLUME`: Invalid trade volume
|
|
199
|
+
|
|
200
|
+
## Margin Calculation Methods
|
|
201
|
+
|
|
202
|
+
The trading client provides advanced margin calculation capabilities:
|
|
203
|
+
|
|
204
|
+
### Calculate Minimum Order Margin
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
with client:
|
|
208
|
+
# Calculate minimum margin required for BUY order
|
|
209
|
+
min_margin_buy = client.calculate_minimum_order_margin("EURUSD", "BUY")
|
|
210
|
+
print(f"Minimum volume: {min_margin_buy['volume']}")
|
|
211
|
+
print(f"Minimum margin: {min_margin_buy['margin']}")
|
|
212
|
+
|
|
213
|
+
# Calculate minimum margin required for SELL order
|
|
214
|
+
min_margin_sell = client.calculate_minimum_order_margin("EURUSD", "SELL")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Calculate Volume by Margin
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
with client:
|
|
221
|
+
# Calculate maximum volume for given margin amount
|
|
222
|
+
available_margin = 1000.0 # USD
|
|
223
|
+
max_volume_buy = client.calculate_volume_by_margin("EURUSD", available_margin, "BUY")
|
|
224
|
+
max_volume_sell = client.calculate_volume_by_margin("EURUSD", available_margin, "SELL")
|
|
225
|
+
|
|
226
|
+
print(f"Max BUY volume for ${available_margin}: {max_volume_buy}")
|
|
227
|
+
print(f"Max SELL volume for ${available_margin}: {max_volume_sell}")
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Calculate New Position Margin Ratio
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
with client:
|
|
234
|
+
# Calculate margin ratio for potential new position
|
|
235
|
+
margin_ratio = client.calculate_new_position_margin_ratio(
|
|
236
|
+
symbol="EURUSD",
|
|
237
|
+
new_position_side="BUY",
|
|
238
|
+
new_position_volume=1.0
|
|
239
|
+
)
|
|
240
|
+
print(f"New position would use {margin_ratio:.2%} of account equity")
|
|
241
|
+
|
|
242
|
+
# Check if adding position would exceed risk limits
|
|
243
|
+
if margin_ratio > 0.1: # 10% risk limit
|
|
244
|
+
print("Position size too large for risk management")
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Market Order Placement
|
|
248
|
+
|
|
249
|
+
Place market orders with flexible configuration:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
with client:
|
|
253
|
+
# Place a BUY market order
|
|
254
|
+
result = client.place_market_order(
|
|
255
|
+
symbol="EURUSD",
|
|
256
|
+
volume=1.0,
|
|
257
|
+
order_side="BUY",
|
|
258
|
+
order_filling_mode="IOC", # Immediate or Cancel
|
|
259
|
+
order_time_mode="GTC", # Good Till Cancelled
|
|
260
|
+
dry_run=False, # Set to True for testing
|
|
261
|
+
comment="My buy order"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
# Place a SELL market order with FOK filling
|
|
265
|
+
result = client.place_market_order(
|
|
266
|
+
symbol="EURUSD",
|
|
267
|
+
volume=0.5,
|
|
268
|
+
order_side="SELL",
|
|
269
|
+
order_filling_mode="FOK", # Fill or Kill
|
|
270
|
+
dry_run=True # Test mode
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
print(f"Order result: {result}")
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Stop Loss and Take Profit Management
|
|
277
|
+
|
|
278
|
+
Update SL/TP for existing positions:
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
with client:
|
|
282
|
+
# Update SL/TP for all EURUSD positions
|
|
283
|
+
results = client.update_sltp_for_open_positions(
|
|
284
|
+
symbol="EURUSD",
|
|
285
|
+
stop_loss=1.0950,
|
|
286
|
+
take_profit=1.1100,
|
|
287
|
+
dry_run=False
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# Update only specific positions by ticket
|
|
291
|
+
results = client.update_sltp_for_open_positions(
|
|
292
|
+
symbol="EURUSD",
|
|
293
|
+
stop_loss=1.0950,
|
|
294
|
+
tickets=[123456, 789012], # Specific position tickets
|
|
295
|
+
dry_run=True
|
|
296
|
+
)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Market Data and Analysis Methods
|
|
300
|
+
|
|
301
|
+
### Spread Analysis
|
|
302
|
+
|
|
303
|
+
```python
|
|
304
|
+
with client:
|
|
305
|
+
# Calculate spread ratio for symbol
|
|
306
|
+
spread_ratio = client.calculate_spread_ratio("EURUSD")
|
|
307
|
+
print(f"EURUSD spread ratio: {spread_ratio:.6f}")
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### OHLC Data Retrieval
|
|
311
|
+
|
|
312
|
+
```python
|
|
313
|
+
with client:
|
|
314
|
+
# Fetch latest rate data as DataFrame
|
|
315
|
+
rates_df = client.fetch_latest_rates_as_df(
|
|
316
|
+
symbol="EURUSD",
|
|
317
|
+
granularity="M1", # 1-minute bars
|
|
318
|
+
count=1440, # Last 24 hours
|
|
319
|
+
index_keys="time"
|
|
320
|
+
)
|
|
321
|
+
print(f"Latest rates: {rates_df.tail()}")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Tick Data Analysis
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
with client:
|
|
328
|
+
# Fetch recent tick data
|
|
329
|
+
ticks_df = client.fetch_latest_ticks_as_df(
|
|
330
|
+
symbol="EURUSD",
|
|
331
|
+
seconds=300, # Last 5 minutes
|
|
332
|
+
index_keys="time_msc"
|
|
333
|
+
)
|
|
334
|
+
print(f"Tick count: {len(ticks_df)}")
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Position Analytics with Enhanced Metrics
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
with client:
|
|
341
|
+
# Get positions with additional calculated metrics
|
|
342
|
+
positions_df = client.fetch_positions_with_metrics_as_df("EURUSD")
|
|
343
|
+
|
|
344
|
+
if not positions_df.empty:
|
|
345
|
+
print("Position metrics:")
|
|
346
|
+
print(f"Total signed volume: {positions_df['signed_volume'].sum()}")
|
|
347
|
+
print(f"Total signed margin: {positions_df['signed_margin'].sum()}")
|
|
348
|
+
print(f"Average profit ratio: {positions_df['underlier_profit_ratio'].mean():.4f}")
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Deal History Analysis
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
with client:
|
|
355
|
+
# Collect entry deals for analysis
|
|
356
|
+
deals_df = client.collect_entry_deals_as_df(
|
|
357
|
+
symbol="EURUSD",
|
|
358
|
+
history_seconds=3600, # Last hour
|
|
359
|
+
index_keys="ticket"
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
if not deals_df.empty:
|
|
363
|
+
print(f"Entry deals found: {len(deals_df)}")
|
|
364
|
+
print(f"Deal types: {deals_df['type'].value_counts()}")
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## Integration with Mt5DataClient
|
|
368
|
+
|
|
369
|
+
Since Mt5TradingClient inherits from Mt5DataClient, all data retrieval methods are available:
|
|
370
|
+
|
|
371
|
+
```python
|
|
372
|
+
with Mt5TradingClient(config=config) as client:
|
|
373
|
+
# Get current positions as DataFrame
|
|
374
|
+
positions_df = client.get_positions_as_df()
|
|
375
|
+
|
|
376
|
+
# Analyze positions
|
|
377
|
+
if not positions_df.empty:
|
|
378
|
+
# Calculate total exposure
|
|
379
|
+
total_volume = positions_df['volume'].sum()
|
|
380
|
+
|
|
381
|
+
# Close losing positions
|
|
382
|
+
losing_positions = positions_df[positions_df['profit'] < 0]
|
|
383
|
+
for symbol in losing_positions['symbol'].unique():
|
|
384
|
+
client.close_open_positions(symbol)
|
|
385
|
+
|
|
386
|
+
# Risk management with margin calculations
|
|
387
|
+
for symbol in ["EURUSD", "GBPUSD", "USDJPY"]:
|
|
388
|
+
# Calculate current margin usage
|
|
389
|
+
current_ratio = client.calculate_new_position_margin_ratio(symbol)
|
|
390
|
+
print(f"{symbol} current margin ratio: {current_ratio:.2%}")
|
|
391
|
+
|
|
392
|
+
# Calculate maximum safe position size
|
|
393
|
+
safe_margin = 500.0 # USD
|
|
394
|
+
max_safe_volume = client.calculate_volume_by_margin(symbol, safe_margin, "BUY")
|
|
395
|
+
print(f"{symbol} max safe volume: {max_safe_volume}")
|
|
396
|
+
```
|