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.
Files changed (31) hide show
  1. {pdmt5-0.1.4 → pdmt5-0.1.6}/.claude/settings.json +2 -2
  2. {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/workflows/ci.yml +1 -1
  3. {pdmt5-0.1.4 → pdmt5-0.1.6}/PKG-INFO +59 -13
  4. {pdmt5-0.1.4 → pdmt5-0.1.6}/README.md +58 -12
  5. {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/trading.md +187 -9
  6. {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/trading.py +212 -41
  7. {pdmt5-0.1.4 → pdmt5-0.1.6}/pyproject.toml +1 -1
  8. {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_trading.py +578 -81
  9. {pdmt5-0.1.4 → pdmt5-0.1.6}/uv.lock +1 -1
  10. {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/FUNDING.yml +0 -0
  11. {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/copilot-instructions.md +0 -0
  12. {pdmt5-0.1.4 → pdmt5-0.1.6}/.github/dependabot.yml +0 -0
  13. {pdmt5-0.1.4 → pdmt5-0.1.6}/.gitignore +0 -0
  14. {pdmt5-0.1.4 → pdmt5-0.1.6}/CLAUDE.md +0 -0
  15. {pdmt5-0.1.4 → pdmt5-0.1.6}/LICENSE +0 -0
  16. {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/dataframe.md +0 -0
  17. {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/index.md +0 -0
  18. {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/mt5.md +0 -0
  19. {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/api/utils.md +0 -0
  20. {pdmt5-0.1.4 → pdmt5-0.1.6}/docs/index.md +0 -0
  21. {pdmt5-0.1.4 → pdmt5-0.1.6}/mkdocs.yml +0 -0
  22. {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/__init__.py +0 -0
  23. {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/dataframe.py +0 -0
  24. {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/mt5.py +0 -0
  25. {pdmt5-0.1.4 → pdmt5-0.1.6}/pdmt5/utils.py +0 -0
  26. {pdmt5-0.1.4 → pdmt5-0.1.6}/renovate.json +0 -0
  27. {pdmt5-0.1.4 → pdmt5-0.1.6}/test/__init__.py +0 -0
  28. {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_dataframe.py +0 -0
  29. {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_init.py +0 -0
  30. {pdmt5-0.1.4 → pdmt5-0.1.6}/test/test_mt5.py +0 -0
  31. {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 check --fix . && uv run ruff format . && uv run pyright . && uv run pytest"
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@7edac99f961f18b581bbd960d59d049f04c0002f # v6.4.1
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.4
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
  [![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)
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
- - `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
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 result in results:
296
- print(f"Closed position {result['position']} with result: {result['retcode']}")
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 closing positions without actual execution
302
- test_results = trader_dry.close_open_positions(symbols=["EURUSD", "GBPUSD"])
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 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']}")
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
  [![Python Version](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/downloads/)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
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
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
- - `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
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 result in results:
273
- print(f"Closed position {result['position']} with result: {result['retcode']}")
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 closing positions without actual execution
279
- test_results = trader_dry.close_open_positions(symbols=["EURUSD", "GBPUSD"])
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 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']}")
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
+ ```