pdmt5 0.1.4__tar.gz → 0.1.6__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.4 → pdmt5-0.1.6}/.claude/settings.json +2 -2
- {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/workflows/ci.yml +1 -1
- {pdmt5-0.1.4 → pdmt5-0.1.6}/PKG-INFO +59 -13
- {pdmt5-0.1.4 → pdmt5-0.1.6}/README.md +58 -12
- {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/trading.md +187 -9
- {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/trading.py +212 -41
- {pdmt5-0.1.4 → pdmt5-0.1.6}/pyproject.toml +1 -1
- {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_trading.py +578 -81
- {pdmt5-0.1.4 → pdmt5-0.1.6}/uv.lock +1 -1
- {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/FUNDING.yml +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/copilot-instructions.md +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/dependabot.yml +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/.gitignore +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/CLAUDE.md +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/LICENSE +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/dataframe.md +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/index.md +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/mt5.md +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/utils.md +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/index.md +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/mkdocs.yml +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/__init__.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/dataframe.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/mt5.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/utils.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/renovate.json +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/test/__init__.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_dataframe.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_init.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_mt5.py +0 -0
- {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_utils.py +0 -0
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
"hooks": [
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
|
-
"command": "uv run ruff
|
|
9
|
+
"command": "uv run ruff format . && uv run ruff check --fix . && uv run pyright . && uv run pytest"
|
|
10
10
|
}
|
|
11
11
|
]
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
15
|
-
}
|
|
15
|
+
}
|
|
@@ -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.6
|
|
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,7 +29,6 @@ Pandas-based data handler for MetaTrader 5
|
|
|
29
29
|
[](https://www.python.org/downloads/)
|
|
30
30
|
[](https://opensource.org/licenses/MIT)
|
|
31
31
|
[](https://www.microsoft.com/windows)
|
|
32
|
-
[](https://github.com/dceoy/pdmt5)
|
|
33
32
|
|
|
34
33
|
## Overview
|
|
35
34
|
|
|
@@ -43,6 +42,8 @@ Pandas-based data handler for MetaTrader 5
|
|
|
43
42
|
- 🚀 **Context Manager Support**: Clean initialization and cleanup with `with` statements
|
|
44
43
|
- 📈 **Time Series Ready**: OHLCV data with proper datetime indexing
|
|
45
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
|
|
46
47
|
|
|
47
48
|
## Requirements
|
|
48
49
|
|
|
@@ -195,10 +196,13 @@ Advanced trading operations client that extends Mt5DataClient:
|
|
|
195
196
|
- `dry_run` - Test mode flag for simulating trades without execution
|
|
196
197
|
- **Position Management**:
|
|
197
198
|
- `close_open_positions()` - Close all positions for specified symbol(s)
|
|
198
|
-
- `
|
|
199
|
-
-
|
|
200
|
-
|
|
199
|
+
- `place_market_order()` - Place market orders with configurable side, volume, and execution modes
|
|
200
|
+
- `update_sltp_for_open_positions()` - Modify stop loss and take profit levels for open positions
|
|
201
|
+
- **Margin Calculations**:
|
|
202
|
+
- `calculate_minimum_order_margin()` - Calculate minimum required margin for a specific order side
|
|
203
|
+
- `calculate_volume_by_margin()` - Calculate maximum volume for given margin amount
|
|
201
204
|
- `calculate_spread_ratio()` - Calculate normalized bid-ask spread ratio
|
|
205
|
+
- `calculate_new_position_margin_ratio()` - Calculate margin ratio for potential new positions
|
|
202
206
|
- **Simplified Data Access**:
|
|
203
207
|
- `fetch_latest_rates_as_df()` - Get recent OHLC data with timeframe strings (e.g., "M1", "H1", "D1")
|
|
204
208
|
- `fetch_latest_ticks_as_df()` - Get tick data for specified seconds around last tick
|
|
@@ -288,18 +292,52 @@ from pdmt5 import Mt5TradingClient
|
|
|
288
292
|
|
|
289
293
|
# Create trading client with specific order filling mode
|
|
290
294
|
with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
|
|
295
|
+
# Place a market buy order
|
|
296
|
+
order_result = trader.place_market_order(
|
|
297
|
+
symbol="EURUSD",
|
|
298
|
+
volume=0.1,
|
|
299
|
+
order_side="BUY",
|
|
300
|
+
order_filling_mode="IOC", # Immediate or Cancel
|
|
301
|
+
order_time_mode="GTC" # Good Till Cancelled
|
|
302
|
+
)
|
|
303
|
+
print(f"Order placed: {order_result['retcode']}")
|
|
304
|
+
|
|
305
|
+
# Update stop loss and take profit for open positions
|
|
306
|
+
update_results = trader.update_sltp_for_open_positions(
|
|
307
|
+
symbol="EURUSD",
|
|
308
|
+
stop_loss=1.0950, # New stop loss
|
|
309
|
+
take_profit=1.1050 # New take profit
|
|
310
|
+
)
|
|
311
|
+
for result in update_results:
|
|
312
|
+
print(f"Position updated: {result['retcode']}")
|
|
313
|
+
|
|
314
|
+
# Calculate margin ratio for a new position
|
|
315
|
+
margin_ratio = trader.calculate_new_position_margin_ratio(
|
|
316
|
+
symbol="EURUSD",
|
|
317
|
+
new_position_side="SELL",
|
|
318
|
+
new_position_volume=0.2
|
|
319
|
+
)
|
|
320
|
+
print(f"New position margin ratio: {margin_ratio:.2%}")
|
|
321
|
+
|
|
291
322
|
# Close all EURUSD positions
|
|
292
323
|
results = trader.close_open_positions(symbols="EURUSD")
|
|
293
324
|
|
|
294
325
|
if results:
|
|
295
|
-
for
|
|
296
|
-
|
|
326
|
+
for symbol, close_results in results.items():
|
|
327
|
+
for result in close_results:
|
|
328
|
+
print(f"Closed position {result.get('position')} with result: {result['retcode']}")
|
|
297
329
|
|
|
298
330
|
# Using dry run mode for testing
|
|
299
331
|
trader_dry = Mt5TradingClient(config=config, dry_run=True)
|
|
300
332
|
with trader_dry:
|
|
301
|
-
# Test
|
|
302
|
-
|
|
333
|
+
# Test placing an order without actual execution
|
|
334
|
+
test_order = trader_dry.place_market_order(
|
|
335
|
+
symbol="GBPUSD",
|
|
336
|
+
volume=0.1,
|
|
337
|
+
order_side="SELL",
|
|
338
|
+
dry_run=True # Override instance setting
|
|
339
|
+
)
|
|
340
|
+
print(f"Test order validation: {test_order['retcode']}")
|
|
303
341
|
```
|
|
304
342
|
|
|
305
343
|
### Market Analysis with Mt5TradingClient
|
|
@@ -310,10 +348,18 @@ with Mt5TradingClient(config=config) as trader:
|
|
|
310
348
|
spread_ratio = trader.calculate_spread_ratio("EURUSD")
|
|
311
349
|
print(f"EURUSD spread ratio: {spread_ratio:.5f}")
|
|
312
350
|
|
|
313
|
-
# Get minimum order
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
print(f"Minimum
|
|
351
|
+
# Get minimum order margin for BUY and SELL
|
|
352
|
+
buy_margin = trader.calculate_minimum_order_margin("EURUSD", "BUY")
|
|
353
|
+
sell_margin = trader.calculate_minimum_order_margin("EURUSD", "SELL")
|
|
354
|
+
print(f"Minimum BUY margin: {buy_margin['margin']} (volume: {buy_margin['volume']})")
|
|
355
|
+
print(f"Minimum SELL margin: {sell_margin['margin']} (volume: {sell_margin['volume']})")
|
|
356
|
+
|
|
357
|
+
# Calculate volume by margin
|
|
358
|
+
available_margin = 1000.0
|
|
359
|
+
max_buy_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "BUY")
|
|
360
|
+
max_sell_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "SELL")
|
|
361
|
+
print(f"Max BUY volume for ${available_margin}: {max_buy_volume}")
|
|
362
|
+
print(f"Max SELL volume for ${available_margin}: {max_sell_volume}")
|
|
317
363
|
|
|
318
364
|
# Get recent OHLC data with custom timeframe
|
|
319
365
|
rates_df = trader.fetch_latest_rates_as_df(
|
|
@@ -6,7 +6,6 @@ Pandas-based data handler for MetaTrader 5
|
|
|
6
6
|
[](https://www.python.org/downloads/)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
[](https://www.microsoft.com/windows)
|
|
9
|
-
[](https://github.com/dceoy/pdmt5)
|
|
10
9
|
|
|
11
10
|
## Overview
|
|
12
11
|
|
|
@@ -20,6 +19,8 @@ Pandas-based data handler for MetaTrader 5
|
|
|
20
19
|
- 🚀 **Context Manager Support**: Clean initialization and cleanup with `with` statements
|
|
21
20
|
- 📈 **Time Series Ready**: OHLCV data with proper datetime indexing
|
|
22
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
|
|
23
24
|
|
|
24
25
|
## Requirements
|
|
25
26
|
|
|
@@ -172,10 +173,13 @@ Advanced trading operations client that extends Mt5DataClient:
|
|
|
172
173
|
- `dry_run` - Test mode flag for simulating trades without execution
|
|
173
174
|
- **Position Management**:
|
|
174
175
|
- `close_open_positions()` - Close all positions for specified symbol(s)
|
|
175
|
-
- `
|
|
176
|
-
-
|
|
177
|
-
|
|
176
|
+
- `place_market_order()` - Place market orders with configurable side, volume, and execution modes
|
|
177
|
+
- `update_sltp_for_open_positions()` - Modify stop loss and take profit levels for open positions
|
|
178
|
+
- **Margin Calculations**:
|
|
179
|
+
- `calculate_minimum_order_margin()` - Calculate minimum required margin for a specific order side
|
|
180
|
+
- `calculate_volume_by_margin()` - Calculate maximum volume for given margin amount
|
|
178
181
|
- `calculate_spread_ratio()` - Calculate normalized bid-ask spread ratio
|
|
182
|
+
- `calculate_new_position_margin_ratio()` - Calculate margin ratio for potential new positions
|
|
179
183
|
- **Simplified Data Access**:
|
|
180
184
|
- `fetch_latest_rates_as_df()` - Get recent OHLC data with timeframe strings (e.g., "M1", "H1", "D1")
|
|
181
185
|
- `fetch_latest_ticks_as_df()` - Get tick data for specified seconds around last tick
|
|
@@ -265,18 +269,52 @@ from pdmt5 import Mt5TradingClient
|
|
|
265
269
|
|
|
266
270
|
# Create trading client with specific order filling mode
|
|
267
271
|
with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
|
|
272
|
+
# Place a market buy order
|
|
273
|
+
order_result = trader.place_market_order(
|
|
274
|
+
symbol="EURUSD",
|
|
275
|
+
volume=0.1,
|
|
276
|
+
order_side="BUY",
|
|
277
|
+
order_filling_mode="IOC", # Immediate or Cancel
|
|
278
|
+
order_time_mode="GTC" # Good Till Cancelled
|
|
279
|
+
)
|
|
280
|
+
print(f"Order placed: {order_result['retcode']}")
|
|
281
|
+
|
|
282
|
+
# Update stop loss and take profit for open positions
|
|
283
|
+
update_results = trader.update_sltp_for_open_positions(
|
|
284
|
+
symbol="EURUSD",
|
|
285
|
+
stop_loss=1.0950, # New stop loss
|
|
286
|
+
take_profit=1.1050 # New take profit
|
|
287
|
+
)
|
|
288
|
+
for result in update_results:
|
|
289
|
+
print(f"Position updated: {result['retcode']}")
|
|
290
|
+
|
|
291
|
+
# Calculate margin ratio for a new position
|
|
292
|
+
margin_ratio = trader.calculate_new_position_margin_ratio(
|
|
293
|
+
symbol="EURUSD",
|
|
294
|
+
new_position_side="SELL",
|
|
295
|
+
new_position_volume=0.2
|
|
296
|
+
)
|
|
297
|
+
print(f"New position margin ratio: {margin_ratio:.2%}")
|
|
298
|
+
|
|
268
299
|
# Close all EURUSD positions
|
|
269
300
|
results = trader.close_open_positions(symbols="EURUSD")
|
|
270
301
|
|
|
271
302
|
if results:
|
|
272
|
-
for
|
|
273
|
-
|
|
303
|
+
for symbol, close_results in results.items():
|
|
304
|
+
for result in close_results:
|
|
305
|
+
print(f"Closed position {result.get('position')} with result: {result['retcode']}")
|
|
274
306
|
|
|
275
307
|
# Using dry run mode for testing
|
|
276
308
|
trader_dry = Mt5TradingClient(config=config, dry_run=True)
|
|
277
309
|
with trader_dry:
|
|
278
|
-
# Test
|
|
279
|
-
|
|
310
|
+
# Test placing an order without actual execution
|
|
311
|
+
test_order = trader_dry.place_market_order(
|
|
312
|
+
symbol="GBPUSD",
|
|
313
|
+
volume=0.1,
|
|
314
|
+
order_side="SELL",
|
|
315
|
+
dry_run=True # Override instance setting
|
|
316
|
+
)
|
|
317
|
+
print(f"Test order validation: {test_order['retcode']}")
|
|
280
318
|
```
|
|
281
319
|
|
|
282
320
|
### Market Analysis with Mt5TradingClient
|
|
@@ -287,10 +325,18 @@ with Mt5TradingClient(config=config) as trader:
|
|
|
287
325
|
spread_ratio = trader.calculate_spread_ratio("EURUSD")
|
|
288
326
|
print(f"EURUSD spread ratio: {spread_ratio:.5f}")
|
|
289
327
|
|
|
290
|
-
# Get minimum order
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
print(f"Minimum
|
|
328
|
+
# Get minimum order margin for BUY and SELL
|
|
329
|
+
buy_margin = trader.calculate_minimum_order_margin("EURUSD", "BUY")
|
|
330
|
+
sell_margin = trader.calculate_minimum_order_margin("EURUSD", "SELL")
|
|
331
|
+
print(f"Minimum BUY margin: {buy_margin['margin']} (volume: {buy_margin['volume']})")
|
|
332
|
+
print(f"Minimum SELL margin: {sell_margin['margin']} (volume: {sell_margin['volume']})")
|
|
333
|
+
|
|
334
|
+
# Calculate volume by margin
|
|
335
|
+
available_margin = 1000.0
|
|
336
|
+
max_buy_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "BUY")
|
|
337
|
+
max_sell_volume = trader.calculate_volume_by_margin("EURUSD", available_margin, "SELL")
|
|
338
|
+
print(f"Max BUY volume for ${available_margin}: {max_buy_volume}")
|
|
339
|
+
print(f"Max SELL volume for ${available_margin}: {max_sell_volume}")
|
|
294
340
|
|
|
295
341
|
# Get recent OHLC data with custom timeframe
|
|
296
342
|
rates_df = trader.fetch_latest_rates_as_df(
|
|
@@ -47,7 +47,7 @@ with client:
|
|
|
47
47
|
# Get current positions as DataFrame
|
|
48
48
|
positions_df = client.get_positions_as_df()
|
|
49
49
|
print(f"Open positions: {len(positions_df)}")
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
# Close positions for specific symbol
|
|
52
52
|
results = client.close_open_positions("EURUSD")
|
|
53
53
|
print(f"Closed positions: {results}")
|
|
@@ -62,7 +62,7 @@ client = Mt5TradingClient(config=config, dry_run=False)
|
|
|
62
62
|
with client:
|
|
63
63
|
# Close all positions for multiple symbols
|
|
64
64
|
results = client.close_open_positions(["EURUSD", "GBPUSD", "USDJPY"])
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
# Close all positions (all symbols)
|
|
67
67
|
all_results = client.close_open_positions()
|
|
68
68
|
```
|
|
@@ -73,19 +73,19 @@ with client:
|
|
|
73
73
|
# Configure different order filling modes
|
|
74
74
|
# IOC (Immediate or Cancel) - default
|
|
75
75
|
client_ioc = Mt5TradingClient(
|
|
76
|
-
config=config,
|
|
76
|
+
config=config,
|
|
77
77
|
order_filling_mode="IOC"
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
# FOK (Fill or Kill)
|
|
81
81
|
client_fok = Mt5TradingClient(
|
|
82
|
-
config=config,
|
|
82
|
+
config=config,
|
|
83
83
|
order_filling_mode="FOK"
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
# RETURN (Return if not filled)
|
|
87
87
|
client_return = Mt5TradingClient(
|
|
88
|
-
config=config,
|
|
88
|
+
config=config,
|
|
89
89
|
order_filling_mode="RETURN"
|
|
90
90
|
)
|
|
91
91
|
```
|
|
@@ -121,7 +121,7 @@ except Mt5TradingError as e:
|
|
|
121
121
|
with client:
|
|
122
122
|
# Check order (note: send_or_check_order is an internal method)
|
|
123
123
|
# For trading operations, use the provided methods like close_open_positions
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
# Example: Check if we can close a position
|
|
126
126
|
positions = client.get_positions_as_df()
|
|
127
127
|
if not positions.empty:
|
|
@@ -196,6 +196,173 @@ The `close_open_positions()` method returns a dictionary with symbols as keys:
|
|
|
196
196
|
- `TRADE_RETCODE_NO_MONEY`: Insufficient funds
|
|
197
197
|
- `TRADE_RETCODE_INVALID_VOLUME`: Invalid trade volume
|
|
198
198
|
|
|
199
|
+
## Margin Calculation Methods
|
|
200
|
+
|
|
201
|
+
The trading client provides advanced margin calculation capabilities:
|
|
202
|
+
|
|
203
|
+
### Calculate Minimum Order Margin
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
with client:
|
|
207
|
+
# Calculate minimum margin required for BUY order
|
|
208
|
+
min_margin_buy = client.calculate_minimum_order_margin("EURUSD", "BUY")
|
|
209
|
+
print(f"Minimum volume: {min_margin_buy['volume']}")
|
|
210
|
+
print(f"Minimum margin: {min_margin_buy['margin']}")
|
|
211
|
+
|
|
212
|
+
# Calculate minimum margin required for SELL order
|
|
213
|
+
min_margin_sell = client.calculate_minimum_order_margin("EURUSD", "SELL")
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Calculate Volume by Margin
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
with client:
|
|
220
|
+
# Calculate maximum volume for given margin amount
|
|
221
|
+
available_margin = 1000.0 # USD
|
|
222
|
+
max_volume_buy = client.calculate_volume_by_margin("EURUSD", available_margin, "BUY")
|
|
223
|
+
max_volume_sell = client.calculate_volume_by_margin("EURUSD", available_margin, "SELL")
|
|
224
|
+
|
|
225
|
+
print(f"Max BUY volume for ${available_margin}: {max_volume_buy}")
|
|
226
|
+
print(f"Max SELL volume for ${available_margin}: {max_volume_sell}")
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Calculate New Position Margin Ratio
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
with client:
|
|
233
|
+
# Calculate margin ratio for potential new position
|
|
234
|
+
margin_ratio = client.calculate_new_position_margin_ratio(
|
|
235
|
+
symbol="EURUSD",
|
|
236
|
+
new_position_side="BUY",
|
|
237
|
+
new_position_volume=1.0
|
|
238
|
+
)
|
|
239
|
+
print(f"New position would use {margin_ratio:.2%} of account equity")
|
|
240
|
+
|
|
241
|
+
# Check if adding position would exceed risk limits
|
|
242
|
+
if margin_ratio > 0.1: # 10% risk limit
|
|
243
|
+
print("Position size too large for risk management")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Market Order Placement
|
|
247
|
+
|
|
248
|
+
Place market orders with flexible configuration:
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
with client:
|
|
252
|
+
# Place a BUY market order
|
|
253
|
+
result = client.place_market_order(
|
|
254
|
+
symbol="EURUSD",
|
|
255
|
+
volume=1.0,
|
|
256
|
+
order_side="BUY",
|
|
257
|
+
order_filling_mode="IOC", # Immediate or Cancel
|
|
258
|
+
order_time_mode="GTC", # Good Till Cancelled
|
|
259
|
+
dry_run=False, # Set to True for testing
|
|
260
|
+
comment="My buy order"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Place a SELL market order with FOK filling
|
|
264
|
+
result = client.place_market_order(
|
|
265
|
+
symbol="EURUSD",
|
|
266
|
+
volume=0.5,
|
|
267
|
+
order_side="SELL",
|
|
268
|
+
order_filling_mode="FOK", # Fill or Kill
|
|
269
|
+
dry_run=True # Test mode
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
print(f"Order result: {result}")
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Stop Loss and Take Profit Management
|
|
276
|
+
|
|
277
|
+
Update SL/TP for existing positions:
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
with client:
|
|
281
|
+
# Update SL/TP for all EURUSD positions
|
|
282
|
+
results = client.update_sltp_for_open_positions(
|
|
283
|
+
symbol="EURUSD",
|
|
284
|
+
stop_loss=1.0950,
|
|
285
|
+
take_profit=1.1100,
|
|
286
|
+
dry_run=False
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
# Update only specific positions by ticket
|
|
290
|
+
results = client.update_sltp_for_open_positions(
|
|
291
|
+
symbol="EURUSD",
|
|
292
|
+
stop_loss=1.0950,
|
|
293
|
+
tickets=[123456, 789012], # Specific position tickets
|
|
294
|
+
dry_run=True
|
|
295
|
+
)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Market Data and Analysis Methods
|
|
299
|
+
|
|
300
|
+
### Spread Analysis
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
with client:
|
|
304
|
+
# Calculate spread ratio for symbol
|
|
305
|
+
spread_ratio = client.calculate_spread_ratio("EURUSD")
|
|
306
|
+
print(f"EURUSD spread ratio: {spread_ratio:.6f}")
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### OHLC Data Retrieval
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
with client:
|
|
313
|
+
# Fetch latest rate data as DataFrame
|
|
314
|
+
rates_df = client.fetch_latest_rates_as_df(
|
|
315
|
+
symbol="EURUSD",
|
|
316
|
+
granularity="M1", # 1-minute bars
|
|
317
|
+
count=1440, # Last 24 hours
|
|
318
|
+
index_keys="time"
|
|
319
|
+
)
|
|
320
|
+
print(f"Latest rates: {rates_df.tail()}")
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Tick Data Analysis
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
with client:
|
|
327
|
+
# Fetch recent tick data
|
|
328
|
+
ticks_df = client.fetch_latest_ticks_as_df(
|
|
329
|
+
symbol="EURUSD",
|
|
330
|
+
seconds=300, # Last 5 minutes
|
|
331
|
+
index_keys="time_msc"
|
|
332
|
+
)
|
|
333
|
+
print(f"Tick count: {len(ticks_df)}")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Position Analytics with Enhanced Metrics
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
with client:
|
|
340
|
+
# Get positions with additional calculated metrics
|
|
341
|
+
positions_df = client.fetch_positions_with_metrics_as_df("EURUSD")
|
|
342
|
+
|
|
343
|
+
if not positions_df.empty:
|
|
344
|
+
print("Position metrics:")
|
|
345
|
+
print(f"Total signed volume: {positions_df['signed_volume'].sum()}")
|
|
346
|
+
print(f"Total signed margin: {positions_df['signed_margin'].sum()}")
|
|
347
|
+
print(f"Average profit ratio: {positions_df['underlier_profit_ratio'].mean():.4f}")
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Deal History Analysis
|
|
351
|
+
|
|
352
|
+
```python
|
|
353
|
+
with client:
|
|
354
|
+
# Collect entry deals for analysis
|
|
355
|
+
deals_df = client.collect_entry_deals_as_df(
|
|
356
|
+
symbol="EURUSD",
|
|
357
|
+
history_seconds=3600, # Last hour
|
|
358
|
+
index_keys="ticket"
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
if not deals_df.empty:
|
|
362
|
+
print(f"Entry deals found: {len(deals_df)}")
|
|
363
|
+
print(f"Deal types: {deals_df['type'].value_counts()}")
|
|
364
|
+
```
|
|
365
|
+
|
|
199
366
|
## Integration with Mt5DataClient
|
|
200
367
|
|
|
201
368
|
Since Mt5TradingClient inherits from Mt5DataClient, all data retrieval methods are available:
|
|
@@ -204,14 +371,25 @@ Since Mt5TradingClient inherits from Mt5DataClient, all data retrieval methods a
|
|
|
204
371
|
with Mt5TradingClient(config=config) as client:
|
|
205
372
|
# Get current positions as DataFrame
|
|
206
373
|
positions_df = client.get_positions_as_df()
|
|
207
|
-
|
|
374
|
+
|
|
208
375
|
# Analyze positions
|
|
209
376
|
if not positions_df.empty:
|
|
210
377
|
# Calculate total exposure
|
|
211
378
|
total_volume = positions_df['volume'].sum()
|
|
212
|
-
|
|
379
|
+
|
|
213
380
|
# Close losing positions
|
|
214
381
|
losing_positions = positions_df[positions_df['profit'] < 0]
|
|
215
382
|
for symbol in losing_positions['symbol'].unique():
|
|
216
383
|
client.close_open_positions(symbol)
|
|
217
|
-
|
|
384
|
+
|
|
385
|
+
# Risk management with margin calculations
|
|
386
|
+
for symbol in ["EURUSD", "GBPUSD", "USDJPY"]:
|
|
387
|
+
# Calculate current margin usage
|
|
388
|
+
current_ratio = client.calculate_new_position_margin_ratio(symbol)
|
|
389
|
+
print(f"{symbol} current margin ratio: {current_ratio:.2%}")
|
|
390
|
+
|
|
391
|
+
# Calculate maximum safe position size
|
|
392
|
+
safe_margin = 500.0 # USD
|
|
393
|
+
max_safe_volume = client.calculate_volume_by_margin(symbol, safe_margin, "BUY")
|
|
394
|
+
print(f"{symbol} max safe volume: {max_safe_volume}")
|
|
395
|
+
```
|