Mô phỏng nạp và rút tiền
Tester của MetaTrader 5 cho phép bạn mô phỏng các thao tác nạp và rút tiền. Điều này cho phép bạn thử nghiệm với một số hệ thống quản lý tiền.
bool TesterDeposit(double money)
Hàm TesterDeposit
bổ sung vào tài khoản trong quá trình thử nghiệm với số tiền được nạp trong tham số money. Số tiền được chỉ định bằng đơn vị tiền tệ của khoản nạp thử nghiệm.
bool TesterWithdrawal(double money)
Hàm TesterWithdrawal
thực hiện các khoản rút bằng với money
.
Cả hai hàm đều trả về true
như một dấu hiệu của sự thành công.
Ví dụ, hãy xem xét một Expert Advisor dựa trên chiến lược "carry trade". Đối với nó, chúng ta cần chọn một biểu tượng có swap dương lớn ở một trong các hướng giao dịch, ví dụ, mua AUDUSD. Expert Advisor sẽ mở một hoặc nhiều vị thế theo hướng đã chỉ định. Các vị thế thua lỗ sẽ được giữ để tích lũy swap trên chúng. Các vị thế có lợi nhuận sẽ được đóng khi đạt được một số tiền lợi nhuận định trước trên mỗi lot. Các swap kiếm được sẽ được rút khỏi tài khoản. Mã nguồn có sẵn trong tệp CrazyCarryTrade.mq5
.
Trong các tham số đầu vào, người dùng có thể chọn hướng giao dịch, kích thước của một giao dịch (mặc định là 0, nghĩa là lot tối thiểu), và lợi nhuận tối thiểu trên mỗi lot, tại đó một vị thế có lợi nhuận sẽ được đóng.
enum ENUM_ORDER_TYPE_MARKET
{
MARKET_BUY = ORDER_TYPE_BUY,
MARKET_SELL = ORDER_TYPE_SELL
};
input ENUM_ORDER_TYPE_MARKET Type;
input double Volume;
input double MinProfitPerLot = 1000;
2
3
4
5
6
7
8
9
Đầu tiên, hãy kiểm tra trong trình xử lý OnInit
hiệu suất của các hàm TesterWithdrawal
và TesterDeposit
. Cụ thể, việc cố gắng rút gấp đôi số dư sẽ dẫn đến lỗi 10019.
int OnInit()
{
PRTF(TesterWithdrawal(AccountInfoDouble(ACCOUNT_BALANCE) * 2));
/*
not enough money for 20 000.00 withdrawal (free margin: 10 000.00)
TesterWithdrawal(AccountInfoDouble(ACCOUNT_BALANCE)*2)=false / MQL_ERROR::10019(10019)
*/
...
2
3
4
5
6
7
8
Nhưng các lần rút và nạp lại tiếp theo với 100 đơn vị tiền tệ của tài khoản sẽ thành công.
PRTF(TesterWithdrawal(100));
/*
deal #2 balance -100.00 [withdrawal] done
TesterWithdrawal(100)=true / ok
*/
PRTF(TesterDeposit(100)); // trả lại tiền
/*
deal #3 balance 100.00 [deposit] done
TesterDeposit(100)=true / ok
*/
return INIT_SUCCEEDED;
}
2
3
4
5
6
7
8
9
10
11
12
Trong trình xử lý OnTick
, hãy kiểm tra sự sẵn có của các vị thế bằng PositionFilter
và điền mảng values
với lợi nhuận/thua lỗ hiện tại và các swap đã tích lũy của chúng.
void OnTick()
{
const double volume = Volume == 0 ?
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN) : Volume;
ENUM_POSITION_PROPERTY_DOUBLE props[] = {POSITION_PROFIT, POSITION_SWAP};
double values[][2];
ulong tickets[];
PositionFilter pf;
pf.select(props, tickets, values, true);
...
2
3
4
5
6
7
8
9
10
Khi không có vị thế, chúng ta mở một vị thế theo hướng đã định trước.
if(ArraySize(tickets) == 0) // không có vị thế
{
MqlTradeRequestSync request1;
(Type == MARKET_BUY ? request1.buy(volume) : request1.sell(volume));
}
else
{
... // có vị thế - xem hộp tiếp theo
}
2
3
4
5
6
7
8
9
Khi có vị thế, chúng ta duyệt qua chúng trong một vòng lặp và đóng những vị thế có đủ lợi nhuận (đã điều chỉnh theo swap). Đồng thời, chúng ta cũng tính tổng các swap của các vị thế đã đóng và tổng thua lỗ. Vì swap tăng theo thời gian, chúng ta sử dụng chúng như một yếu tố khuếch đại để đóng các vị thế "cũ". Do đó, có thể đóng với thua lỗ.
double loss = 0, swaps = 0;
for(int i = 0; i < ArraySize(tickets); ++i)
{
if(values[i][0] + values[i][1] * values[i][1] >= MinProfitPerLot * volume)
{
MqlTradeRequestSync request0;
if(request0.close(tickets[i]) && request0.completed())
{
swaps += values[i][1];
}
}
else
{
loss += values[i][0];
}
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Nếu tổng thua lỗ tăng, chúng ta định kỳ mở thêm các vị thế, nhưng làm điều đó ít thường xuyên hơn khi có nhiều vị thế hơn, để kiểm soát rủi ro một cách nào đó.
if(loss / ArraySize(tickets) <= -MinProfitPerLot * volume * sqrt(ArraySize(tickets)))
{
MqlTradeRequestSync request1;
(Type == MARKET_BUY ? request1.buy(volume) : request1.sell(volume));
}
...
2
3
4
5
6
Cuối cùng, chúng ta rút swap khỏi tài khoản.
if(swaps >= 0)
{
TesterWithdrawal(swaps);
}
2
3
4
Trong trình xử lý OnDeinit
, chúng ta hiển thị thống kê về các khoản khấu trừ.
void OnDeinit(const int)
{
PrintFormat("Deposit: %.2f Withdrawals: %.2f",
TesterStatistics(STAT_INITIAL_DEPOSIT),
TesterStatistics(STAT_WITHDRAWAL));
}
2
3
4
5
6
Ví dụ, khi chạy Expert Advisor với cài đặt mặc định cho khoảng thời gian từ năm 2021 đến đầu năm 2022, chúng ta nhận được kết quả sau cho AUDUSD:
final balance 10091.19 USD
Deposit: 10000.00 Withdrawals: 197.42
2
Đây là giao diện của báo cáo và biểu đồ.
Báo cáo Expert với các khoản rút từ tài khoản
Do đó, khi giao dịch với lot tối thiểu và sử dụng không quá 1% số tiền nạp trong hơn một năm, chúng ta đã rút được khoảng 200 USD.