MT5Service - Mid-Level API OverviewΒΆ
Not just a wrapper! MT5Service eliminates 50-70% of boilerplate code while maintaining full MT5 functionality.
π― What is MT5Service?ΒΆ
MT5Service is a mid-level convenience layer between low-level MT5Account (proto/gRPC) and high-level MT5Sugar (business logic).
Three-Layer Architecture:
MT5Account (Low-Level) β Direct gRPC calls, returns Data wrappers
β
MT5Service (Mid-Level) β Unwraps primitives + convenience shortcuts β YOU ARE HERE
β
MT5Sugar (High-Level) β Complex business logic, smart helpers
What makes it special:
- β
Automatic value unwrapping - no more
.Valueceremony - β ~30 convenience methods - shortcuts for common operations
- β Smart combinations - multiple checks in one call
- β Ergonomic trading API - no manual request building
- β 50-70% code reduction - write less, do more
π Quick ComparisonΒΆ
Account OperationsΒΆ
// β MT5Account (Low-Level) - 2 lines:
var data = await account.AccountInfoDoubleAsync(AccountInfoDoublePropertyType.AccountBalance);
double balance = data.Value;
// β
MT5Service (Mid-Level) - 1 line:
double balance = await service.GetBalanceAsync();
Trading OperationsΒΆ
// β MT5Account (Low-Level) - 9 lines:
var request = new OrderSendRequest
{
Symbol = "EURUSD",
Volume = 0.01,
Operation = TMT5_ENUM_ORDER_TYPE.Tmt5OrderTypeBuy,
StopLoss = 1.0800,
TakeProfit = 1.0900,
Comment = "My trade"
};
var result = await account.OrderSendAsync(request);
// β
MT5Service (Mid-Level) - 1 line:
var result = await service.BuyMarketAsync("EURUSD", 0.01,
stopLoss: 1.0800, takeProfit: 1.0900, comment: "My trade");
Symbol Availability CheckΒΆ
// β MT5Account (Low-Level) - 2 separate calls:
var existsData = await account.SymbolExistAsync("EURUSD");
if (!existsData.Exists) return false;
var syncData = await account.SymbolIsSynchronizedAsync("EURUSD");
bool available = syncData.Synchronized;
// β
MT5Service (Mid-Level) - 1 smart call:
bool available = await service.IsSymbolAvailableAsync("EURUSD");
π¦ What's Inside: 4 Groups of MethodsΒΆ
1οΈβ£ Account Convenience Methods (10 methods)ΒΆ
Direct access to account properties without unwrapping:
// Get key account metrics - 1 line each:
double balance = await service.GetBalanceAsync();
double equity = await service.GetEquityAsync();
double margin = await service.GetMarginAsync();
double freeMargin = await service.GetFreeMarginAsync();
double profit = await service.GetProfitAsync();
// Get account info:
long login = await service.GetLoginAsync();
long leverage = await service.GetLeverageAsync();
string name = await service.GetAccountNameAsync();
string server = await service.GetServerNameAsync();
string currency = await service.GetCurrencyAsync();
Benefits: 50% code reduction, no .Value, readable names
2οΈβ£ Symbol Convenience Methods (7 methods + 1 smart)ΒΆ
Quick access to symbol properties and smart availability check:
// Get current quote:
double bid = await service.GetBidAsync("EURUSD");
double ask = await service.GetAskAsync("EURUSD");
long spread = await service.GetSpreadAsync("EURUSD");
// Volume constraints:
double minVol = await service.GetVolumeMinAsync("EURUSD");
double maxVol = await service.GetVolumeMaxAsync("EURUSD");
double step = await service.GetVolumeStepAsync("EURUSD");
// Smart combination (2 calls β 1 method):
bool available = await service.IsSymbolAvailableAsync("EURUSD");
// Trading permission check:
bool canTrade = await service.IsTradingAllowedAsync();
Benefits: 60%+ code reduction, smart combinations, no enums
3οΈβ£ Trading Convenience Methods (6 methods)ΒΆ
Simplified order placement without manual request building:
// Market orders:
await service.BuyMarketAsync("EURUSD", 0.01, stopLoss: 1.08, takeProfit: 1.09);
await service.SellMarketAsync("GBPUSD", 0.05, stopLoss: 1.26, takeProfit: 1.25);
// Limit orders (price improvement):
await service.BuyLimitAsync("EURUSD", 0.1, price: 1.0850, stopLoss: 1.08, takeProfit: 1.09);
await service.SellLimitAsync("GBPUSD", 0.05, price: 1.2550, stopLoss: 1.26, takeProfit: 1.25);
// Stop orders (breakout):
await service.BuyStopAsync("XAUUSD", 0.01, price: 2010, stopLoss: 2000, takeProfit: 2030);
await service.SellStopAsync("USDJPY", 0.1, price: 149.5, stopLoss: 150, takeProfit: 149);
Benefits: 70%+ code reduction, self-documenting, named parameters
4οΈβ£ History Convenience Methods (3 methods)ΒΆ
Sensible defaults for common history queries:
// Get recent orders:
var lastWeek = await service.GetRecentOrdersAsync(days: 7);
var lastMonth = await service.GetRecentOrdersAsync(days: 30, limit: 500);
// Get today's orders:
var today = await service.GetTodayOrdersAsync();
// Check trading permission:
if (await service.IsTradingAllowedAsync())
{
// Ready to trade
}
Benefits: 84% code reduction, sensible defaults, readable intent
π§ Key Features ExplainedΒΆ
Feature 1: Automatic Value UnwrappingΒΆ
Problem in MT5Account:
Every call returns a Data wrapper object that must be unwrapped:
var balanceData = await account.AccountInfoDoubleAsync(AccountInfoDoublePropertyType.AccountBalance);
double balance = balanceData.Value; // β Must unwrap!
var bidData = await account.SymbolInfoDoubleAsync("EURUSD", SymbolInfoDoubleProperty.SymbolBid);
double bid = bidData.Value; // β Must unwrap!
var existsData = await account.SymbolExistAsync("EURUSD");
bool exists = existsData.Exists; // β Must unwrap!
Solution in MT5Service: Direct primitive returns - no unwrapping needed:
double balance = await service.GetBalanceAsync(); // β
Already unwrapped
double bid = await service.GetBidAsync("EURUSD"); // β
Already unwrapped
bool exists = await service.SymbolExistAsync("EURUSD"); // β
Already unwrapped
Impact:
- β 50% less code for data retrieval
- β
Impossible to forget
.Value - β Cleaner, more readable code
Methods with unwrapping:
- All
AccountInfo*β returnsdouble,long,stringdirectly - All
SymbolInfo*β returnsdouble,long,stringdirectly SymbolsTotalβ returnsintdirectlySymbolExist,SymbolSelect,SymbolIsSynchronizedβ returnsbooldirectly
Feature 2: Smart CombinationsΒΆ
Problem in MT5Account: Common operations require multiple separate calls:
// Check if symbol is ready for trading (2 calls):
var existsData = await account.SymbolExistAsync("BTCUSD");
if (!existsData.Exists)
{
Console.WriteLine("Symbol doesn't exist!");
return false;
}
var syncData = await account.SymbolIsSynchronizedAsync("BTCUSD");
if (!syncData.Synchronized)
{
Console.WriteLine("Symbol not synchronized!");
return false;
}
return true;
Solution in MT5Service: Smart methods combine multiple checks:
// 1 smart call replaces 2 separate calls:
bool available = await service.IsSymbolAvailableAsync("BTCUSD");
if (!available)
{
Console.WriteLine("Symbol not available!");
return false;
}
return true;
Smart methods:
IsSymbolAvailableAsync(symbol)- combinesSymbolExist+SymbolIsSynchronizedIsTradingAllowedAsync()- checksAccountTradeAllowedand returns boolean
Impact:
- β Fewer server round-trips
- β Prevents common mistakes (forgetting one of the checks)
- β Clear intent from method name
Feature 3: Ergonomic Trading APIΒΆ
Problem in MT5Account:
Every order requires manual OrderSendRequest building:
// Want to BUY? Build entire request manually:
var request = new OrderSendRequest
{
Symbol = "EURUSD",
Volume = 0.01,
Operation = TMT5_ENUM_ORDER_TYPE.Tmt5OrderTypeBuy, // Must remember enum
StopLoss = 1.0800,
TakeProfit = 1.0900,
Comment = "My trade",
ExpertId = 12345
};
var result = await account.OrderSendAsync(request);
// Want to SELL? Build another request:
var request2 = new OrderSendRequest
{
Symbol = "GBPUSD",
Volume = 0.05,
Operation = TMT5_ENUM_ORDER_TYPE.Tmt5OrderTypeSell, // Different enum
StopLoss = 1.2600,
TakeProfit = 1.2500
};
var result2 = await account.OrderSendAsync(request2);
Solution in MT5Service: Direct trading methods with named parameters:
// BUY - intent clear from method name:
var result = await service.BuyMarketAsync("EURUSD", 0.01,
stopLoss: 1.0800,
takeProfit: 1.0900,
comment: "My trade",
magic: 12345);
// SELL - intent clear from method name:
var result2 = await service.SellMarketAsync("GBPUSD", 0.05,
stopLoss: 1.2600,
takeProfit: 1.2500);
All 6 trading methods:
BuyMarketAsync()- buy at current askSellMarketAsync()- sell at current bidBuyLimitAsync()- pending buy below current priceSellLimitAsync()- pending sell above current priceBuyStopAsync()- pending buy above current price (breakout)SellStopAsync()- pending sell below current price (breakdown)
Impact:
- β 70-89% code reduction per order
- β Self-documenting (method name = intent)
- β Named parameters show what each value means
- β
Can't set wrong
Operationenum (impossible error)
Feature 4: Sensible DefaultsΒΆ
Problem in MT5Account: Common operations require many parameters:
// Want last week's orders? Specify everything:
var history = await account.OrderHistoryAsync(
from: DateTime.UtcNow.AddDays(-7), // Calculate manually
to: DateTime.UtcNow, // Now
sortMode: BMT5_ENUM_ORDER_HISTORY_SORT_TYPE.Bmt5SortByCloseTimeDesc, // Long enum
pageNumber: 0, // No pagination
itemsPerPage: 100, // Limit
deadline: null, // No deadline
cancellationToken: default); // No cancellation
// 7 parameters just to get last week!
Solution in MT5Service: Sensible defaults for common scenarios:
// Last week's orders - 1 parameter:
var history = await service.GetRecentOrdersAsync(days: 7);
// Today's orders - no parameters:
var today = await service.GetTodayOrdersAsync();
// Custom if needed:
var lastMonth = await service.GetRecentOrdersAsync(days: 30, limit: 500);
Impact:
- β 84% code reduction for history queries
- β
Readable intent (
GetTodayOrdersvs manual date calculation) - β Defaults work for 90% of cases
- β Still customizable when needed
π Overall StatisticsΒΆ
Code Reduction by CategoryΒΆ
| Category | Average Code Reduction | Key Benefit |
|---|---|---|
| Account operations | 50% | No .Value unwrapping |
| Symbol operations | 60%+ | No enums + smart checks |
| Trading operations | 70-89% | No request building |
| History operations | 84% | Sensible defaults |
Methods CountΒΆ
| Category | Thin Wrappers | New Convenience Methods | Total |
|---|---|---|---|
| Account | 4 | 10 | 14 |
| Symbol | 7 | 7 + 1 smart | 15 |
| Trading | 5 | 6 | 11 |
| History | 2 | 2 | 4 |
| Streaming | 5 (pass-through) | 0 | 5 |
| Total | 23 | ~30 | ~53 |
π When to Use Each LayerΒΆ
Use MT5Account (Low-Level) when:ΒΆ
- β Need exotic properties not covered by convenience methods
- β Building custom wrapper/framework on top
- β Require absolute control over proto objects
- β Accessing advanced features not in MT5Service
Example: Accessing SymbolInfoSession* for trading hours
Use MT5Service (Mid-Level) when: β ΒΆ
- β 90% of typical trading scenarios
- β Building trading bots/strategies
- β Rapid development
- β Want clean, readable code
- β Don't need auto-normalization (that's MT5Sugar)
Example: Placing orders, getting quotes, checking balances
Use MT5Sugar (High-Level) when:ΒΆ
- β Need auto-normalization of volumes/prices
- β Want risk-based position sizing
- β Need batch operations
- β Require advanced helpers/validators
Example: OpenPositionWithRisk(symbol, riskPercent: 2.0)
π‘ Complete Example: Trading BotΒΆ
using mt5_term_api;
// Initialize
var account = new MT5Account();
var service = new MT5Service(account);
await account.ConnectByHostPortAsync("mt5.mrpc.pro", 443);
// 1. Check account
double balance = await service.GetBalanceAsync();
double equity = await service.GetEquityAsync();
double freeMargin = await service.GetFreeMarginAsync();
Console.WriteLine($"Balance: ${balance:F2}");
Console.WriteLine($"Equity: ${equity:F2}");
Console.WriteLine($"Free Margin: ${freeMargin:F2}");
// 2. Check trading is allowed
if (!await service.IsTradingAllowedAsync())
{
Console.WriteLine("β Trading not allowed!");
return;
}
// 3. Check symbol
string symbol = "EURUSD";
if (!await service.IsSymbolAvailableAsync(symbol))
{
Console.WriteLine($"β Symbol {symbol} not available!");
return;
}
// 4. Get quote
double bid = await service.GetBidAsync(symbol);
double ask = await service.GetAskAsync(symbol);
Console.WriteLine($"{symbol}: Bid={bid:F5}, Ask={ask:F5}");
// 5. Validate volume
double volume = 0.01;
double minVol = await service.GetVolumeMinAsync(symbol);
double maxVol = await service.GetVolumeMaxAsync(symbol);
double step = await service.GetVolumeStepAsync(symbol);
if (volume < minVol || volume > maxVol)
{
Console.WriteLine($"β Volume out of range [{minVol}, {maxVol}]");
return;
}
// 6. Place order
var result = await service.BuyMarketAsync(symbol, volume,
stopLoss: bid - 0.0050,
takeProfit: bid + 0.0100,
comment: "Bot trade");
if (result.RetCode == 10009)
{
Console.WriteLine($"β
Order opened: #{result.Order}");
}
else
{
Console.WriteLine($"β Order failed: {result.Comment}");
}
// 7. Check today's performance
var today = await service.GetTodayOrdersAsync();
double todayProfit = today.ClosedOrders.Sum(o => o.Profit);
Console.WriteLine($"Today's P/L: ${todayProfit:F2} ({today.ClosedOrders.Count} trades)");
Clean, readable, maintainable! π
π Documentation IndexΒΆ
Method GroupsΒΆ
- Account Convenience Methods - Balance, equity, margin, profit, account info
- Symbol Convenience Methods - Bid, ask, spread, volumes, availability
- Trading Convenience Methods - Market/limit/stop orders simplified
- History Convenience Methods - Recent orders, today's orders, trading permissions
π― Key TakeawaysΒΆ
What MT5Service Does:ΒΆ
- β
Eliminates
.Valueunwrapping - returns primitives directly - β Adds ~30 convenience methods - shortcuts for common operations
- β Smart combinations - multiple checks in one call
- β Ergonomic trading API - no request building
- β Sensible defaults - works for 90% of cases
- β 50-70% code reduction - write less, do more
What MT5Service Does NOT Do:ΒΆ
- β Auto-normalization (that's MT5Sugar)
- β Risk management (that's MT5Sugar)
- β Complex business logic (that's MT5Sugar)
- β Replace MT5Account (it wraps it)
The Bottom Line:ΒΆ
MT5Service is the sweet spot between low-level control and high-level convenience. Use it for 90% of your trading code.
// This is MT5Service:
var balance = await service.GetBalanceAsync();
var result = await service.BuyMarketAsync("EURUSD", 0.01, stopLoss: 1.08, takeProfit: 1.09);
var today = await service.GetTodayOrdersAsync();
Simple. Clean. Fast. π