MT5Service - Trading Operations Methods (Mid-Level API)¶
⚠️ Important: Read This First¶
MT5Service is an architectural layer between high-level (Sugar) and low-level (Account) APIs.
Understanding the 6 Methods:¶
| Method | Direct Use Value | Architectural Role |
|---|---|---|
check_order() |
✅ VERY HIGH - Extracts deeply nested protobuf → OrderCheckResult dataclass (8 fields) | ✅ Used by Sugar |
place_order() |
✅ HIGH - Flattens protobuf → OrderResult dataclass (10 fields) | ✅ Used by Sugar |
modify_order() |
✅ HIGH - Flattens protobuf → OrderResult dataclass (10 fields) | ✅ Used by Sugar |
close_order() |
⚪ LOW - Unpacks data.returned_code from protobuf → int |
✅ Used by Sugar |
calculate_margin() |
⚪ LOW - Unpacks data.margin from protobuf → float |
✅ Used by Sugar |
calculate_profit() |
⚪ LOW - Unpacks data.profit from protobuf → float |
✅ Used by Sugar |
What This Means:¶
Architecture (3 layers):
MT5Sugar (HIGH) → service.place_order() ← Sugar uses Service methods
MT5Service (MID) → account.order_send() ← Service unpacks protobuf + creates dataclasses
MT5Account (LOW) → gRPC call → protobuf Data objects
Value breakdown:
- ✅ VERY HIGH (1 method):
check_order()- extracts deeply nestedmrpc_mql_trade_check_resultstructure - ✅ HIGH (2 methods):
place_order(),modify_order()- flatten 10 protobuf fields into clean dataclass - ⚪ LOW (3 methods): Simple unpacking of single protobuf field (
returned_code,margin,profit)
For direct MT5Service usage:
- ✅ Highly recommended: Use
check_order(),place_order(),modify_order()- significant dataclass conversion value - ⚪ Optional:
close_order(),calculate_margin(),calculate_profit()- minor unpacking value
For MT5Sugar users:
- ✅ All methods work perfectly - the layer serves its architectural purpose
API Layer: MID-LEVEL - wrappers over MT5Account with clean dataclass returns
Implementation:
These methods are implemented in src/pymt5/mt5_service.py, which wraps package/MetaRpcMT5/helpers/mt5_account.py low-level API with dataclass conversion for trading results.
Example files:
examples/2_service/04_service_demo.py- comprehensive demo of all MT5Service methods including trading operations (STEP 5)
Why These Methods Exist¶
Real Value: Protobuf Unpacking + Dataclass Conversion¶
3 methods add VERY HIGH/HIGH value through complex dataclass conversion, 3 methods add LOW value through simple unpacking:
Problem with MT5Account (Low-level):
# MT5Account returns complex protobuf objects
request = trading_helper_pb2.OrderSendRequest()
request.symbol = "EURUSD"
request.volume = 0.1
request.action = 1 # TRADE_ACTION_DEAL
request.type = 0 # ORDER_TYPE_BUY
result_data = await account.order_send(request, None, None)
# result_data is protobuf OrderSendData with 10 nested fields
if result_data.returned_code == 10009: # TRADE_RETCODE_DONE
print(f"Deal: {result_data.deal}, Order: {result_data.order}")
# Must manually access each of 10 protobuf fields
# Checking order requires extracting DEEPLY NESTED structure:
check_response = await account.order_check(request, None, None)
result = check_response.mrpc_mql_trade_check_result # ← Deeply nested!
if result.returned_code == 0:
print(f"Valid! Margin: {result.margin}")
Solution with MT5Service (Mid-level):
# Service creates clean dataclasses - no manual field extraction
request = trading_helper_pb2.OrderSendRequest()
request.symbol = "EURUSD"
request.volume = 0.1
request.action = 1
request.type = 0
result = await service.place_order(request)
# result is OrderResult dataclass with 10 clear fields
if result.returned_code == 10009:
print(f"Deal: {result.deal}, Order: {result.order}")
# Clean dataclass access with type hints
# Check order returns clean dataclass - no nesting:
check = await service.check_order(request)
# check is OrderCheckResult dataclass with 8 fields - already extracted!
if check.returned_code == 0:
print(f"Valid! Margin: {check.margin}")
What MT5Service provides:
-
Complex dataclass conversion (3 methods with HIGH/VERY HIGH value):
-
check_order(): Extracts deeply nestedmrpc_mql_trade_check_result→ OrderCheckResult (8 fields) place_order(): Flattens 10 protobuf fields → OrderResult dataclass-
modify_order(): Flattens 10 protobuf fields → OrderResult dataclass -
Simple unpacking (3 methods with LOW value):
-
close_order(): Unpacksdata.returned_code→ int calculate_margin(): Unpacksdata.margin→ float-
calculate_profit(): Unpacksdata.profit→ float -
Cleaner API:
-
No need to manually access nested protobuf structures
- Type hints for IDE autocomplete
- Clear field names in dataclasses
Architectural purpose:
- ✅ MT5Sugar uses these methods to maintain layered architecture (Sugar → Service → Account)
- ✅ Direct users benefit significantly from dataclass conversion (especially check_order/place_order/modify_order)
All 6 Methods¶
| Method | Returns | Description |
|---|---|---|
place_order() |
OrderResult |
Send market/pending order to broker |
modify_order() |
OrderResult |
Modify existing order or position (SL/TP) |
close_order() |
int |
Close position or delete pending order |
check_order() |
OrderCheckResult |
Validate order before sending |
calculate_margin() |
float |
Calculate required margin for an order |
calculate_profit() |
float |
Calculate potential profit for a trade |
Key Concepts¶
Order Types¶
- Market Order: Executes immediately at current market price (BUY/SELL)
- Pending Order: Executes when price reaches specified level (BUY_LIMIT, SELL_LIMIT, BUY_STOP, SELL_STOP)
Return Codes¶
All trading operations return a return code indicating success/failure:
- 10009 (TRADE_RETCODE_DONE): Success - order placed/modified/closed
- 10004 (TRADE_RETCODE_REQUOTE): Requote - price changed, retry
- 10006 (TRADE_RETCODE_REJECT): Rejected by broker
- 10007 (TRADE_RETCODE_CANCEL): Cancelled by trader
- 10013 (TRADE_RETCODE_INVALID_VOLUME): Invalid volume
- 10014 (TRADE_RETCODE_INVALID_PRICE): Invalid price
- 10015 (TRADE_RETCODE_INVALID_STOPS): Invalid SL/TP
Always check returned_code == 10009 for success!
Pre-Trade Validation¶
Before sending orders, use check_order() to validate:
- Sufficient margin
- Valid volume/price/stops
- Trading allowed
➕ Dataclasses (DTOs)¶
OrderResult¶
@dataclass
class OrderResult:
"""
Result of a trading operation.
ADVANTAGE: Clean dataclass instead of protobuf OrderSendData/OrderModifyData.
"""
returned_code: int # Operation return code (10009 = TRADE_RETCODE_DONE)
deal: int # Deal ticket number (if executed)
order: int # Order ticket number (if placed)
volume: float # Executed volume confirmed by broker
price: float # Execution price confirmed by broker
bid: float # Current Bid price
ask: float # Current Ask price
comment: str # Broker comment or error description
request_id: int # Request ID set by terminal
ret_code_external: int # External return code
Usage:
result = await service.place_order(request)
if result.returned_code == 10009:
print(f"Success! Deal: {result.deal}, Order: {result.order}")
else:
print(f"Failed: {result.comment}")
OrderCheckResult¶
@dataclass
class OrderCheckResult:
"""Result of order validation."""
returned_code: int # Validation code (0 = success)
balance: float # Balance after deal
equity: float # Equity after deal
profit: float # Profit
margin: float # Required margin
margin_free: float # Free margin after
margin_level: float # Margin level after (%)
comment: str # Error description
Usage:
check = await service.check_order(request)
if check.returned_code == 0:
print(f"Valid! Required margin: ${check.margin:.2f}")
else:
print(f"Invalid: {check.comment}")
Method Signatures¶
1) place_order¶
async def place_order(
self,
request: Any, # trading_helper_pb2.OrderSendRequest
deadline: Optional[datetime] = None,
cancellation_event: Optional[Any] = None,
) -> OrderResult
Send market/pending order to broker.
Args:
request: OrderSendRequest protobuf with order parameters
Returns: OrderResult dataclass with deal/order tickets and execution details
Technical: Low-level returns OrderSendData protobuf with nested broker response fields. This wrapper flattens protobuf into OrderResult dataclass with 10 fields.
Check returned_code == 10009 (TRADE_RETCODE_DONE) for successful execution.
OrderSendRequest fields:
request.symbol = "EURUSD" # Symbol
request.volume = 0.1 # Volume in lots
request.action = 1 # TRADE_ACTION_DEAL (market order)
request.type = 0 # ORDER_TYPE_BUY
request.price = 0.0 # 0 for market orders
request.sl = 1.08000 # Stop Loss (optional)
request.tp = 1.09000 # Take Profit (optional)
request.deviation = 20 # Max price deviation in points
request.comment = "My order" # Optional comment
2) modify_order¶
async def modify_order(
self,
request: Any, # trading_helper_pb2.OrderModifyRequest
deadline: Optional[datetime] = None,
cancellation_event: Optional[Any] = None,
) -> OrderResult
Modify existing order or position (SL/TP).
Args:
request: OrderModifyRequest protobuf with modification parameters
Returns: OrderResult with modification details
Technical: Low-level returns OrderModifyData protobuf (same structure as OrderSendData). This wrapper flattens into OrderResult.
Used to:
- Change SL/TP on open positions
- Modify pending order price/SL/TP
OrderModifyRequest fields:
request.order = 12345678 # Ticket number to modify
request.sl = 1.08500 # New Stop Loss
request.tp = 1.09500 # New Take Profit
request.price = 1.08000 # New order price (pending orders only)
3) close_order¶
async def close_order(
self,
request: Any, # trading_helper_pb2.OrderCloseRequest
deadline: Optional[datetime] = None,
cancellation_event: Optional[Any] = None,
) -> int
Close position or delete pending order.
Args:
request: OrderCloseRequest protobuf with ticket to close
Returns: int return code directly (10009 = success)
Technical: Low-level returns OrderCloseData with data.returned_code wrapper. This auto-extracts the int return code.
How it works:
- For positions: Creates opposite market order
- For pending orders: Sends delete request
OrderCloseRequest fields:
request.order = 12345678 # Ticket number to close
request.volume = 0.0 # 0 = close all, or partial volume
4) check_order¶
async def check_order(
self,
request: Any, # trade_functions_pb2.OrderCheckRequest
deadline: Optional[datetime] = None,
cancellation_event: Optional[Any] = None,
) -> OrderCheckResult
Validate order before sending to broker.
Args:
request: OrderCheckRequest protobuf (similar to OrderSendRequest)
Returns: OrderCheckResult dataclass with validation details
Technical: Low-level returns OrderCheckResponse with deeply nested mrpc_mql_trade_check_result. This wrapper extracts 8 validation fields.
Use this before place_order() to:
- Pre-validate margin requirements without sending to broker
- Check if order parameters are valid
- See impact on account (balance, equity, margin)
OrderCheckRequest fields:
request.symbol = "EURUSD"
request.volume = 0.1
request.action = 1 # TRADE_ACTION_DEAL
request.type = 0 # ORDER_TYPE_BUY
request.price = 0.0
returned_code = 0 means valid order
5) calculate_margin¶
async def calculate_margin(
self,
request: Any, # trade_functions_pb2.OrderCalcMarginRequest
deadline: Optional[datetime] = None,
cancellation_event: Optional[Any] = None,
) -> float
Calculate required margin for an order.
Args:
- request: OrderCalcMarginRequest protobuf
Returns: float margin value directly (no Data struct)
Technical: Low-level returns OrderCalcMarginResponse with data.margin wrapper. This auto-extracts margin float.
Use to:
- Check margin requirements before placing order
- Validate if you have enough free margin
- Calculate position sizing
OrderCalcMarginRequest fields:
request.symbol = "EURUSD"
request.volume = 0.1
request.action = 1 # TRADE_ACTION_DEAL
request.type = 0 # ORDER_TYPE_BUY
6) calculate_profit¶
async def calculate_profit(
self,
request: Any, # trade_functions_pb2.OrderCalcProfitRequest
deadline: Optional[datetime] = None,
cancellation_event: Optional[Any] = None,
) -> float
Calculate potential profit for a trade.
Args:
request: OrderCalcProfitRequest protobuf
Returns: float profit value directly (no Data struct)
Technical: Low-level returns OrderCalcProfitResponse with data.profit wrapper. This auto-extracts profit float.
Use to:
- Calculate P&L for hypothetical trade given entry/exit prices and volume
- Validate risk/reward ratio
- Calculate TP target profit
OrderCalcProfitRequest fields:
request.symbol = "EURUSD"
request.volume = 0.1
request.action = 1 # TRADE_ACTION_DEAL
request.type = 0 # ORDER_TYPE_BUY
request.price_open = 1.08000 # Entry price
request.price_close = 1.09000 # Exit price
🔗 Usage Examples¶
Example 1: Placing Market Buy Order¶
from pymt5 import MT5Service
from MetaRpcMT5 import mt5_term_api_trading_helper_pb2 as trading_helper_pb2
async def place_market_buy(service: MT5Service, symbol: str, volume: float):
"""Place a market BUY order."""
# Create request
request = trading_helper_pb2.OrderSendRequest()
request.symbol = symbol
request.volume = volume
request.action = 1 # TRADE_ACTION_DEAL (market order)
request.type = 0 # ORDER_TYPE_BUY
request.price = 0.0 # 0 for market orders
request.deviation = 20 # Max 20 points deviation
request.comment = "Market BUY"
# Send order
result = await service.place_order(request)
# Check result
if result.returned_code == 10009: # TRADE_RETCODE_DONE
print(f"SUCCESS!")
print(f" Deal: {result.deal}")
print(f" Order: {result.order}")
print(f" Price: {result.price}")
print(f" Volume: {result.volume}")
else:
print(f"FAILED: {result.comment}")
print(f" Return code: {result.returned_code}")
return result
Example 2: Placing Order with SL/TP¶
async def place_order_with_stops(
service: MT5Service,
symbol: str,
volume: float,
sl: float,
tp: float
):
"""Place market order with Stop Loss and Take Profit."""
request = trading_helper_pb2.OrderSendRequest()
request.symbol = symbol
request.volume = volume
request.action = 1 # TRADE_ACTION_DEAL
request.type = 0 # ORDER_TYPE_BUY
request.price = 0.0
request.sl = sl # Stop Loss
request.tp = tp # Take Profit
request.deviation = 20
request.comment = "Order with SL/TP"
result = await service.place_order(request)
if result.returned_code == 10009:
print(f"Order placed: {result.order}")
print(f" SL: {sl}, TP: {tp}")
else:
print(f"Failed: {result.comment}")
return result
Example 3: Validating Order Before Placing¶
from MetaRpcMT5 import mt5_term_api_trade_functions_pb2 as trade_functions_pb2
async def safe_place_order(
service: MT5Service,
symbol: str,
volume: float
) -> bool:
"""Validate order before placing."""
# Step 1: Check order
check_request = trade_functions_pb2.OrderCheckRequest()
check_request.symbol = symbol
check_request.volume = volume
check_request.action = 1
check_request.type = 0
check_request.price = 0.0
check_result = await service.check_order(check_request)
if check_result.returned_code != 0:
print(f"Order validation FAILED: {check_result.comment}")
return False
print("Order validation PASSED:")
print(f" Required margin: ${check_result.margin:.2f}")
print(f" Free margin after: ${check_result.margin_free:.2f}")
print(f" Margin level after: {check_result.margin_level:.2f}%")
# Step 2: Place order
order_request = trading_helper_pb2.OrderSendRequest()
order_request.symbol = symbol
order_request.volume = volume
order_request.action = 1
order_request.type = 0
order_request.price = 0.0
order_request.deviation = 20
result = await service.place_order(order_request)
if result.returned_code == 10009:
print(f"Order placed successfully: {result.order}")
return True
else:
print(f"Order placement failed: {result.comment}")
return False
Example 4: Modifying Position SL/TP¶
async def modify_position_stops(
service: MT5Service,
ticket: int,
new_sl: float,
new_tp: float
):
"""Modify Stop Loss and Take Profit of existing position."""
request = trading_helper_pb2.OrderModifyRequest()
request.order = ticket # Ticket to modify
request.sl = new_sl # New Stop Loss
request.tp = new_tp # New Take Profit
result = await service.modify_order(request)
if result.returned_code == 10009:
print(f"Position {ticket} modified successfully")
print(f" New SL: {new_sl}")
print(f" New TP: {new_tp}")
else:
print(f"Modification failed: {result.comment}")
return result
Example 5: Closing Position¶
async def close_position(service: MT5Service, ticket: int):
"""Close an open position."""
request = trading_helper_pb2.OrderCloseRequest()
request.order = ticket
request.volume = 0.0 # 0 = close entire position
return_code = await service.close_order(request)
if return_code == 10009:
print(f"Position {ticket} closed successfully")
return True
else:
print(f"Failed to close position {ticket}, code: {return_code}")
return False
Example 6: Calculating Required Margin¶
async def check_margin_requirement(
service: MT5Service,
symbol: str,
volume: float
):
"""Calculate required margin for a trade."""
request = trade_functions_pb2.OrderCalcMarginRequest()
request.symbol = symbol
request.volume = volume
request.action = 1 # TRADE_ACTION_DEAL
request.type = 0 # ORDER_TYPE_BUY
margin = await service.calculate_margin(request)
print(f"Required margin for {volume} lots of {symbol}: ${margin:.2f}")
# Check if we have enough free margin
from MetaRpcMT5 import mt5_term_api_account_information_pb2 as account_info_pb2
free_margin = await service.get_account_double(
account_info_pb2.ACCOUNT_MARGIN_FREE
)
if free_margin >= margin:
print(f"OK: You have ${free_margin:.2f} free margin")
return True
else:
print(f"INSUFFICIENT: You need ${margin:.2f} but only have ${free_margin:.2f}")
return False
Example 7: Calculating Potential Profit¶
async def calculate_trade_profit(
service: MT5Service,
symbol: str,
volume: float,
entry_price: float,
exit_price: float
):
"""Calculate potential profit for a trade."""
request = trade_functions_pb2.OrderCalcProfitRequest()
request.symbol = symbol
request.volume = volume
request.action = 1 # TRADE_ACTION_DEAL
request.type = 0 # ORDER_TYPE_BUY
request.price_open = entry_price
request.price_close = exit_price
profit = await service.calculate_profit(request)
print(f"Trade Calculation for {symbol}:")
print(f" Volume: {volume} lots")
print(f" Entry: {entry_price}")
print(f" Exit: {exit_price}")
print(f" Profit: ${profit:.2f}")
return profit
Example 8: Complete Safe Trading Flow¶
async def safe_trade_with_validation(
service: MT5Service,
symbol: str,
volume: float,
sl_points: int,
tp_points: int
):
"""Complete safe trading flow with all validations."""
from MetaRpcMT5 import mt5_term_api_market_info_pb2 as market_info_pb2
# Step 1: Get current price
tick = await service.get_symbol_tick(symbol)
print(f"Current price: {tick.ask}")
# Step 2: Calculate SL/TP prices
point = await service.get_symbol_double(
symbol, market_info_pb2.SYMBOL_POINT
)
sl = tick.ask - (sl_points * point)
tp = tick.ask + (tp_points * point)
print(f"Calculated SL: {sl:.5f}, TP: {tp:.5f}")
# Step 3: Calculate required margin
margin_request = trade_functions_pb2.OrderCalcMarginRequest()
margin_request.symbol = symbol
margin_request.volume = volume
margin_request.action = 1
margin_request.type = 0
required_margin = await service.calculate_margin(margin_request)
print(f"Required margin: ${required_margin:.2f}")
# Step 4: Check free margin
from MetaRpcMT5 import mt5_term_api_account_information_pb2 as account_info_pb2
free_margin = await service.get_account_double(
account_info_pb2.ACCOUNT_MARGIN_FREE
)
if free_margin < required_margin:
print(f"INSUFFICIENT MARGIN: Need ${required_margin:.2f}, have ${free_margin:.2f}")
return None
# Step 5: Calculate potential profit
profit_request = trade_functions_pb2.OrderCalcProfitRequest()
profit_request.symbol = symbol
profit_request.volume = volume
profit_request.action = 1
profit_request.type = 0
profit_request.price_open = tick.ask
profit_request.price_close = tp
potential_profit = await service.calculate_profit(profit_request)
print(f"Potential TP profit: ${potential_profit:.2f}")
# Step 6: Validate order
check_request = trade_functions_pb2.OrderCheckRequest()
check_request.symbol = symbol
check_request.volume = volume
check_request.action = 1
check_request.type = 0
check_request.price = 0.0
check_result = await service.check_order(check_request)
if check_result.returned_code != 0:
print(f"Order validation failed: {check_result.comment}")
return None
print("Order validation passed!")
# Step 7: Place order
order_request = trading_helper_pb2.OrderSendRequest()
order_request.symbol = symbol
order_request.volume = volume
order_request.action = 1
order_request.type = 0
order_request.price = 0.0
order_request.sl = sl
order_request.tp = tp
order_request.deviation = 20
order_request.comment = "Safe validated order"
result = await service.place_order(order_request)
if result.returned_code == 10009:
print(f"\nSUCCESS! Order placed:")
print(f" Ticket: {result.order}")
print(f" Price: {result.price}")
print(f" SL: {sl:.5f}, TP: {tp:.5f}")
return result
else:
print(f"\nFAILED: {result.comment}")
return None
When to Use Each Method¶
Use place_order()¶
Use when:
- Opening new positions (market or pending orders)
- Need to specify SL/TP with order
- Ready to send order to broker
Important:
- Always check
returned_code == 10009for success - Use
check_order()first for validation
Use modify_order()¶
Use when:
- Changing SL/TP on open position
- Modifying pending order price
- Adjusting stops based on market conditions
Use close_order()¶
Use when:
- Closing open position
- Deleting pending order
- Emergency exit from trade
Use check_order()¶
Use when:
- Pre-validating order before placing
- Checking margin requirements
- Seeing impact on account before trading
ALWAYS use before place_order() for safety!
Use calculate_margin()¶
Use when:
- Planning position size
- Checking if you have enough margin
- Calculating max position size
Use calculate_profit()¶
Use when:
- Calculating risk/reward ratio
- Setting TP targets
- Analyzing trade potential
Recommendations¶
- Always validate first - Use
check_order()beforeplace_order() - Check return codes -
returned_code == 10009means success - Calculate margin - Ensure sufficient free margin before trading
- Use SL/TP - Always set Stop Loss and Take Profit
- Handle errors - Check
result.commentfor error descriptions - Validate volumes - Check symbol's
VOLUME_MIN,VOLUME_MAX,VOLUME_STEP
Safe trading pattern:
# 1. Calculate margin
margin = await service.calculate_margin(margin_request)
# 2. Check order
check = await service.check_order(check_request)
if check.returned_code != 0:
return
# 3. Place order
result = await service.place_order(order_request)
if result.returned_code == 10009:
print("Success!")
Common Return Codes¶
| Code | Name | Meaning |
|---|---|---|
| 10009 | TRADE_RETCODE_DONE | Success - request completed |
| 10004 | TRADE_RETCODE_REQUOTE | Requote - price changed |
| 10006 | TRADE_RETCODE_REJECT | Request rejected |
| 10013 | TRADE_RETCODE_INVALID_VOLUME | Invalid volume |
| 10014 | TRADE_RETCODE_INVALID_PRICE | Invalid price |
| 10015 | TRADE_RETCODE_INVALID_STOPS | Invalid SL/TP |
| 10016 | TRADE_RETCODE_INVALID_FILL | Invalid filling mode |
| 10018 | TRADE_RETCODE_MARKET_CLOSED | Market is closed |
| 10019 | TRADE_RETCODE_NO_MONEY | Not enough money |
📚 Related Sections¶
- MT5Service Overview - mid-level API overview
- Account Methods (Mid-Level) - checking margin/balance
- Symbol Methods (Mid-Level) - getting prices and symbol specs
- Positions & Orders (Mid-Level) - checking open positions
- Trading Operations (Low-Level) - low-level trading API
- MT5Service API Reference - complete mid-level API reference
Summary¶
Real Value Assessment¶
6 methods with mixed value levels - 3 with HIGH/VERY HIGH value (dataclass conversion), 3 with LOW value (simple unpacking):
| Method | Value Level | What It Does |
|---|---|---|
check_order() |
✅ VERY HIGH | Extracts deeply nested mrpc_mql_trade_check_result → OrderCheckResult (8 fields) |
place_order() |
✅ HIGH | Flattens 10 protobuf fields → OrderResult dataclass |
modify_order() |
✅ HIGH | Flattens 10 protobuf fields → OrderResult dataclass |
close_order() |
⚪ LOW | Unpacks data.returned_code from protobuf → int |
calculate_margin() |
⚪ LOW | Unpacks data.margin from protobuf → float |
calculate_profit() |
⚪ LOW | Unpacks data.profit from protobuf → float |
Why these methods have value:
MT5Account returns protobuf objects:
# Low-level returns:
result_data: OrderSendData = await account.order_send(...) # 10 protobuf fields
check_response: OrderCheckResponse = await account.order_check(...) # Deeply nested!
close_data: OrderCloseData = await account.order_close(...) # data.returned_code wrapper
margin_response: OrderCalcMarginResponse = await account.order_calc_margin(...) # data.margin
MT5Service unpacks and converts:
# Mid-level returns:
result: OrderResult = await service.place_order(...) # Flattened dataclass (10 fields)
check: OrderCheckResult = await service.check_order(...) # Extracted dataclass (8 fields)
code: int = await service.close_order(...) # Unpacked int
margin: float = await service.calculate_margin(...) # Unpacked float
Key advantages:
-
Complex dataclass conversion (HIGH/VERY HIGH value):
-
check_order()- Extracts deeply nested protobuf structure (VERY valuable!) -
place_order(),modify_order()- Flatten 10 fields into clean OrderResult dataclass -
Simple unpacking (LOW value):
-
close_order(),calculate_margin(),calculate_profit()- Simple single-field extraction -
Type hints - Full IDE autocomplete support for all dataclass fields
-
Clear return codes - All methods return standardized codes for error handling
Best practices:
- ✅ ALWAYS use
check_order()beforeplace_order()for safety - it extracts complex validation data - ✅ ALWAYS check
returned_code == 10009for success - ✅ ALWAYS calculate margin before trading
- ✅ ALWAYS use Stop Loss and Take Profit
- ✅ ALWAYS handle errors (check
result.comment)
Bottom line:
- ✅ For direct users: Highly recommend using
check_order(),place_order(),modify_order()- significant dataclass conversion value - ⚪ Optional:
close_order(),calculate_margin(),calculate_profit()- minor unpacking, could call Account directly - ✅ For Sugar users: Methods serve architectural purpose perfectly
- ✅ vs MT5Account: Significant improvement through dataclass conversion, especially for check_order()