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.
Files changed (32) hide show
  1. {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/workflows/ci.yml +1 -1
  2. {pdmt5-0.1.5 → pdmt5-0.1.7}/PKG-INFO +36 -40
  3. {pdmt5-0.1.5 → pdmt5-0.1.7}/README.md +35 -39
  4. pdmt5-0.1.7/docs/api/trading.md +396 -0
  5. {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/trading.py +75 -43
  6. {pdmt5-0.1.5 → pdmt5-0.1.7}/pyproject.toml +1 -1
  7. {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_trading.py +160 -53
  8. {pdmt5-0.1.5 → pdmt5-0.1.7}/uv.lock +1 -1
  9. pdmt5-0.1.5/docs/api/trading.md +0 -217
  10. {pdmt5-0.1.5 → pdmt5-0.1.7}/.claude/settings.json +0 -0
  11. {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/FUNDING.yml +0 -0
  12. {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/copilot-instructions.md +0 -0
  13. {pdmt5-0.1.5 → pdmt5-0.1.7}/.github/dependabot.yml +0 -0
  14. {pdmt5-0.1.5 → pdmt5-0.1.7}/.gitignore +0 -0
  15. {pdmt5-0.1.5 → pdmt5-0.1.7}/CLAUDE.md +0 -0
  16. {pdmt5-0.1.5 → pdmt5-0.1.7}/LICENSE +0 -0
  17. {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/dataframe.md +0 -0
  18. {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/index.md +0 -0
  19. {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/mt5.md +0 -0
  20. {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/api/utils.md +0 -0
  21. {pdmt5-0.1.5 → pdmt5-0.1.7}/docs/index.md +0 -0
  22. {pdmt5-0.1.5 → pdmt5-0.1.7}/mkdocs.yml +0 -0
  23. {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/__init__.py +0 -0
  24. {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/dataframe.py +0 -0
  25. {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/mt5.py +0 -0
  26. {pdmt5-0.1.5 → pdmt5-0.1.7}/pdmt5/utils.py +0 -0
  27. {pdmt5-0.1.5 → pdmt5-0.1.7}/renovate.json +0 -0
  28. {pdmt5-0.1.5 → pdmt5-0.1.7}/test/__init__.py +0 -0
  29. {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_dataframe.py +0 -0
  30. {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_init.py +0 -0
  31. {pdmt5-0.1.5 → pdmt5-0.1.7}/test/test_mt5.py +0 -0
  32. {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@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.5
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
- - `update_open_position_sltp()` - Modify stop loss and take profit levels for open positions
199
- - **Market Analysis**:
200
- - `calculate_minimum_order_margins()` - Calculate minimum required margins for buy/sell orders
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 with specific order filling mode
291
- with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
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 an open position
303
- if positions := trader.positions_get_as_df(symbol="EURUSD"):
304
- position_ticket = positions.iloc[0]['ticket']
305
- update_result = trader.update_open_position_sltp(
306
- symbol="EURUSD",
307
- position_ticket=position_ticket,
308
- sl=1.0950, # New stop loss
309
- tp=1.1050 # New take profit
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
- new_side="SELL",
317
- new_volume=0.2
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(symbols="EURUSD")
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 margins
351
- margins = trader.calculate_minimum_order_margins("EURUSD")
352
- print(f"Minimum ask margin: {margins['ask']}")
353
- print(f"Minimum bid margin: {margins['bid']}")
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
- - `update_open_position_sltp()` - Modify stop loss and take profit levels for open positions
176
- - **Market Analysis**:
177
- - `calculate_minimum_order_margins()` - Calculate minimum required margins for buy/sell orders
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 with specific order filling mode
268
- with Mt5TradingClient(config=config, order_filling_mode="IOC") as trader:
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 an open position
280
- if positions := trader.positions_get_as_df(symbol="EURUSD"):
281
- position_ticket = positions.iloc[0]['ticket']
282
- update_result = trader.update_open_position_sltp(
283
- symbol="EURUSD",
284
- position_ticket=position_ticket,
285
- sl=1.0950, # New stop loss
286
- tp=1.1050 # New take profit
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
- new_side="SELL",
294
- new_volume=0.2
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(symbols="EURUSD")
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 margins
328
- margins = trader.calculate_minimum_order_margins("EURUSD")
329
- print(f"Minimum ask margin: {margins['ask']}")
330
- print(f"Minimum bid margin: {margins['bid']}")
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
+ ```