Ước tính lợi nhuận của một hoạt động giao dịch: OrderCalcProfit
Một trong những hàm của API MQL5, OrderCalcProfit
, cho phép bạn đánh giá trước kết quả tài chính của một hoạt động giao dịch nếu các điều kiện dự kiến được đáp ứng. Ví dụ, sử dụng hàm này, bạn có thể tìm ra số tiền lợi nhuận khi đạt mức Take Profit
và số tiền lỗ khi Stop Loss
được kích hoạt.
bool OrderCalcProfit(ENUM_ORDER_TYPE action, const string symbol, double volume,
double openPrice, double closePrice, double &profit)
2
Hàm này tính toán lợi nhuận hoặc lỗ bằng đơn vị tiền tệ của tài khoản dựa trên môi trường thị trường hiện tại và các tham số được truyền vào.
Loại lệnh được chỉ định trong tham số action
. Chỉ cho phép các lệnh thị trường ORDER_TYPE_BUY
hoặc ORDER_TYPE_SELL
từ liệt kê ENUM_ORDER_TYPE
. Tên của công cụ tài chính và khối lượng của nó được truyền trong các tham số symbol
và volume
. Giá vào thị trường và giá thoát được thiết lập bởi các tham số openPrice
và closePrice
, tương ứng. Biến profit
được truyền bằng tham chiếu làm tham số cuối cùng, và giá trị lợi nhuận sẽ được ghi vào đó.
Hàm trả về một chỉ báo thành công (true
) hoặc lỗi (false
).
Công thức tính toán kết quả tài chính được sử dụng bên trong OrderCalcProfit
phụ thuộc vào loại ký hiệu.
Định danh | Công thức |
---|---|
SYMBOL_CALC_MODE_FOREX | (ClosePrice - OpenPrice) * ContractSize * Lots |
SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE | (ClosePrice - OpenPrice) * ContractSize * Lots |
SYMBOL_CALC_MODE_CFD | (ClosePrice - OpenPrice) * ContractSize * Lots |
SYMBOL_CALC_MODE_CFDINDEX | (ClosePrice - OpenPrice) * ContractSize * Lots |
SYMBOL_CALC_MODE_CFDLEVERAGE | (ClosePrice - OpenPrice) * ContractSize * Lots |
SYMBOL_CALC_MODE_EXCH_STOCKS | (ClosePrice - OpenPrice) * ContractSize * Lots |
SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX | (ClosePrice - OpenPrice) * ContractSize * Lots |
SYMBOL_CALC_MODE_FUTURES | (ClosePrice - OpenPrice) * Lots * TickPrice / TickSize |
SYMBOL_CALC_MODE_EXCH_FUTURES | (ClosePrice - OpenPrice) * Lots * TickPrice / TickSize |
SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS | (ClosePrice - OpenPrice) * Lots * TickPrice / TickSize |
SYMBOL_CALC_MODE_EXCH_BONDS | Lots * ContractSize * (ClosePrice * FaceValue + AccruedInterest) |
SYMBOL_CALC_MODE_EXCH_BONDS_MOEX | Lots * ContractSize * (ClosePrice * FaceValue + AccruedInterest) |
SYMBOL_CALC_MODE_SERV_COLLATERAL | Lots * ContractSize * MarketPrice * LiqudityRate |
Các ký hiệu sau được sử dụng trong công thức:
Lots
— khối lượng vị thế tính bằng lô (cổ phần hợp đồng)ContractSize
— kích thước hợp đồng (một lô, SYMBOL_TRADE_CONTRACT_SIZE)TickPrice
— giá tick (SYMBOL_TRADE_TICK_VALUE)TickSize
— kích thước tick (SYMBOL_TRADE_TICK_SIZE)MarketPrice
— giá cuối cùng được biết (Bid/Ask) tùy thuộc vào loại giao dịchOpenPrice
— giá mở vị thếClosePrice
— giá đóng vị thếFaceValue
— giá trị danh nghĩa của trái phiếu (SYMBOL_TRADE_FACE_VALUE
)LiqudityRate
— tỷ lệ thanh khoản (SYMBOL_TRADE_LIQUIDITY_RATE
)AccruedInterest
— thu nhập phiếu giảm giá tích lũy (SYMBOL_TRADE_ACCRUED_INTEREST
)
Hàm
OrderCalcProfit
chỉ có thể được sử dụng trong Expert Advisors và scripts. Để tính toán lợi nhuận/lỗ tiềm năng trong indicators, bạn cần triển khai một phương pháp thay thế, ví dụ, tính toán độc lập bằng cách sử dụng các công thức.
Để vượt qua hạn chế trong việc sử dụng các hàm OrderCalcProfit
và OrderCalcMargin
trong indicators, chúng ta đã phát triển một tập hợp các hàm thực hiện tính toán bằng cách sử dụng các công thức từ phần này, cũng như phần Yêu cầu ký quỹ. Các hàm nằm trong tệp tiêu đề MarginProfitMeter.mqh
, bên trong không gian tên chung MPM
(từ "Margin Profit Meter").
Cụ thể, để tính toán kết quả tài chính, điều quan trọng là phải có giá trị của một điểm giá của công cụ cụ thể. Trong các công thức trên, nó gián tiếp tham gia vào sự khác biệt giữa giá mở và giá đóng (ClosePrice - OpenPrice)
.
Hàm tính toán giá trị của một điểm giá PointValue
.
namespace MPM
{
double PointValue(const string symbol, const bool ask = false,
const datetime moment = 0)
{
const double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
const double contract = SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
const ENUM_SYMBOL_CALC_MODE m =
(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
...
2
3
4
5
6
7
8
9
10
Ở đầu hàm, chúng ta yêu cầu tất cả các thuộc tính ký hiệu cần thiết cho việc tính toán. Sau đó, tùy thuộc vào loại ký hiệu, chúng ta thu được lợi nhuận/lỗ bằng đơn vị tiền tệ lợi nhuận của công cụ này. Lưu ý rằng không có trái phiếu ở đây, các công thức của chúng tính đến giá danh nghĩa và thu nhập phiếu giảm giá.
double result = 0;
switch(m)
{
case SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE:
case SYMBOL_CALC_MODE_FOREX:
case SYMBOL_CALC_MODE_CFD:
case SYMBOL_CALC_MODE_CFDINDEX:
case SYMBOL_CALC_MODE_CFDLEVERAGE:
case SYMBOL_CALC_MODE_EXCH_STOCKS:
case SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX:
result = point * contract;
break;
case SYMBOL_CALC_MODE_FUTURES:
case SYMBOL_CALC_MODE_EXCH_FUTURES:
case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS:
result = point * SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)
/ SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
break;
default:
PrintFormat("Unsupported symbol %s trade mode: %s", symbol, EnumToString(m));
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Cuối cùng, chúng ta chuyển đổi số tiền sang đơn vị tiền tệ của tài khoản, nếu nó khác.
string account = AccountInfoString(ACCOUNT_CURRENCY);
string current = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
if(current != account)
{
if(!Convert(current, account, ask, result, moment)) return 0;
}
return result;
}
...
};
2
3
4
5
6
7
8
9
10
11
12
Hàm trợ giúp Convert
được sử dụng để chuyển đổi số tiền. Nó, đến lượt nó, phụ thuộc vào hàm FindExchangeRate
, hàm này tìm kiếm trong tất cả các ký hiệu có sẵn một ký hiệu chứa tỷ giá từ tiền tệ current
sang tiền tệ account
.
bool Convert(const string current, const string account,
const bool ask, double &margin, const datetime moment = 0)
{
string rate;
int dir = FindExchangeRate(current, account, rate);
if(dir == +1)
{
margin *= moment == 0 ?
SymbolInfoDouble(rate, ask ? SYMBOL_BID : SYMBOL_ASK) :
GetHistoricPrice(rate, moment, ask);
}
else if(dir == -1)
{
margin /= moment == 0 ?
SymbolInfoDouble(rate, ask ? SYMBOL_ASK : SYMBOL_BID) :
GetHistoricPrice(rate, moment, ask);
}
else
{
static bool once = false;
if(!once)
{
Print("Can't convert ", current, " -> ", account);
once = true;
}
}
return true;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Hàm FindExchangeRate
tra cứu các ký tự trong Market Watch
và trả về tên của ký hiệu Forex khớp đầu tiên, nếu có nhiều ký hiệu, trong tham số result
. Nếu báo giá tương ứng với thứ tự trực tiếp của các loại tiền tệ current/account
, hàm sẽ trả về +1, và nếu ngược lại, sẽ là account/current
, tức là -1.
int FindExchangeRate(const string current, const string account, string &result)
{
for(int i = 0; i < SymbolsTotal(true); i++)
{
const string symbol = SymbolName(i, true);
const ENUM_SYMBOL_CALC_MODE m =
(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
if(m == SYMBOL_CALC_MODE_FOREX || m == SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE)
{
string base = SymbolInfoString(symbol, SYMBOL_CURRENCY_BASE);
string profit = SymbolInfoString(symbol, SYMBOL_CURRENCY_PROFIT);
if(base == current && profit == account)
{
result = symbol;
return +1;
}
else
if(base == account && profit == current)
{
result = symbol;
return -1;
}
}
}
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Mã đầy đủ của các hàm có thể được tìm thấy trong tệp đính kèm MarginProfitMeter.mqh
.
Hãy kiểm tra hiệu suất của hàm OrderCalcProfit
và nhóm hàm MPM
với một script thử nghiệm ProfitMeter.mq5
: chúng ta sẽ tính toán ước tính lợi nhuận/lỗ cho các giao dịch ảo cho tất cả các ký hiệu của Market Watch
, và chúng ta sẽ thực hiện điều này bằng hai phương pháp: phương pháp tích hợp sẵn và phương pháp của chúng ta.
Trong các tham số đầu vào của script, bạn có thể chọn loại hoạt động Action
(mua hoặc bán), kích thước lô Lot
và thời gian giữ vị thế tính bằng số thanh Duration
. Kết quả tài chính được tính toán cho các báo giá của Duration
thanh cuối cùng của khung thời gian hiện tại.
#property script_show_inputs
input ENUM_ORDER_TYPE Action = ORDER_TYPE_BUY; // Action (only Buy/Sell allowed)
input float Lot = 1;
input int Duration = 20; // Duration (bar number in past)
2
3
4
5
Trong phần thân của script, chúng ta kết nối các tệp tiêu đề và hiển thị tiêu đề với các tham số.
#include <MQL5Book/MarginProfitMeter.mqh>
#include <MQL5Book/Periods.mqh>
void OnStart()
{
// guarantee that the operation will only be a buy or a sell
ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)(Action % 2);
const string text[] = {"buying", "selling"};
PrintFormat("Profits/Losses for %s %s lots"
" of %d symbols in Market Watch on last %d bars %s",
text[type], (string)Lot, SymbolsTotal(true),
Duration, PeriodToString(_Period));
...
2
3
4
5
6
7
8
9
10
11
12
13
Sau đó, trong một vòng lặp qua các ký hiệu, chúng ta thực hiện tính toán theo hai cách và in kết quả để so sánh.
for(int i = 0; i < SymbolsTotal(true); i++)
{
const string symbol = SymbolName(i, true);
const double enter = iClose(symbol, _Period, Duration);
const double exit = iClose(symbol, _Period, 0);
double profit1, profit2; // 2 adopted variables
// standard method
if(!OrderCalcProfit(type, symbol, Lot, enter, exit, profit1))
{
PrintFormat("OrderCalcProfit(%s) failed: %d", symbol, _LastError);
continue;
}
// our own method
const int points = (int)MathRound((exit - enter)
/ SymbolInfoDouble(symbol, SYMBOL_POINT));
profit2 = Lot * points * MPM::PointValue(symbol);
profit2 = NormalizeDouble(profit2,
(int)AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS));
if(type == ORDER_TYPE_SELL) profit2 *= -1;
// output to the log for comparison
PrintFormat("%s: %f %f", symbol, profit1, profit2);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Hãy thử chạy script cho các tài khoản và tập hợp công cụ khác nhau.
Profits/Losses for buying 1.0 lots of 13 symbols in Market Watch on last 20 bars H1
EURUSD: 390.000000 390.000000
GBPUSD: 214.000000 214.000000
USDCHF: -254.270000 -254.270000
USDJPY: -57.930000 -57.930000
USDCNH: -172.570000 -172.570000
USDRUB: 493.360000 493.360000
AUDUSD: 84.000000 84.000000
NZDUSD: 13.000000 13.000000
USDCAD: -97.480000 -97.480000
USDSEK: -682.910000 -682.910000
XAUUSD: -1706.000000 -1706.000000
SP500m: 5300.000000 5300.000000
XPDUSD: -84.030000 -84.030000
2
3
4
5
6
7
8
9
10
11
12
13
14
Lý tưởng nhất, các con số trong mỗi dòng nên khớp nhau.