Lấy thống kê tài chính kiểm tra: TesterStatistics
Chúng ta thường đánh giá chất lượng của một Expert Advisor dựa trên báo cáo giao dịch, tương tự như báo cáo kiểm tra khi làm việc với tester. Nó chứa một số lượng lớn các biến đặc trưng cho phong cách giao dịch, độ ổn định và tất nhiên là lợi nhuận. Tất cả các số liệu này, với một số ngoại lệ, đều có sẵn cho chương trình MQL thông qua hàm đặc biệt TesterStatistics
. Do đó, nhà phát triển Expert Advisor có khả năng phân tích các biến riêng lẻ trong mã và xây dựng các tiêu chí chất lượng tối ưu hóa kết hợp của riêng họ từ chúng.
double TesterStatistics(ENUM_STATISTICS statistic)
Hàm TesterStatistics
trả về giá trị của biến thống kê được chỉ định, được tính toán dựa trên kết quả của một lần chạy riêng lẻ của Expert Advisor trong tester. Hàm có thể được gọi trong trình xử lý OnDeinit
hoặc OnTester
, điều mà chúng ta sẽ thảo luận sau.
Tất cả các biến thống kê có sẵn được tổng hợp trong liệt kê ENUM_STATISTICS. Một số trong đó đóng vai trò là đặc điểm định tính, tức là các số thực (thường là tổng lợi nhuận, mức sụt giảm, tỷ lệ, v.v.), và phần còn lại là định lượng, tức là số nguyên (ví dụ, số lượng giao dịch). Tuy nhiên, cả hai nhóm đều được kiểm soát bởi cùng một hàm với kết quả double
.
Bảng sau đây hiển thị các chỉ số thực (số tiền và hệ số). Tất cả số tiền được biểu thị bằng đơn vị tiền tệ của khoản tiền gửi.
Định danh | Mô tả |
---|---|
STAT_INITIAL_DEPOSIT | Khoản tiền gửi ban đầu |
STAT_WITHDRAWAL | Số tiền rút khỏi tài khoản |
STAT_PROFIT | Lợi nhuận hoặc lỗ ròng tại cuối kỳ kiểm tra, tổng của STAT_GROSS_PROFIT và STAT_GROSS_LOSS |
STAT_GROSS_PROFIT | Tổng lợi nhuận, tổng của tất cả các giao dịch có lãi (lớn hơn hoặc bằng 0) |
STAT_GROSS_LOSS | Tổng lỗ, tổng của tất cả các giao dịch thua lỗ (nhỏ hơn hoặc bằng 0) |
STAT_MAX_PROFITTRADE | Lợi nhuận tối đa: giá trị lớn nhất trong tất cả các giao dịch có lãi (lớn hơn hoặc bằng 0) |
STAT_MAX_LOSSTRADE | Lỗ tối đa: giá trị nhỏ nhất trong tất cả các giao dịch thua lỗ (nhỏ hơn hoặc bằng 0) |
STAT_CONPROFITMAX | Tổng lợi nhuận tối đa trong một chuỗi giao dịch có lãi (lớn hơn hoặc bằng 0) |
STAT_MAX_CONWINS | Tổng lợi nhuận trong chuỗi giao dịch có lãi dài nhất |
STAT_CONLOSSMAX | Tổng lỗ tối đa trong một chuỗi giao dịch thua lỗ (nhỏ hơn hoặc bằng 0) |
STAT_MAX_CONLOSSES | Tổng lỗ trong chuỗi giao dịch thua lỗ dài nhất |
STAT_BALANCEMIN | Giá trị số dư tối thiểu |
STAT_BALANCE_DD | Mức sụt giảm số dư tối đa bằng tiền |
STAT_BALANCEDD_PERCENT | Mức sụt giảm số dư theo phần trăm, được ghi nhận tại thời điểm mức sụt giảm số dư tối đa bằng tiền (STAT_BALANCE_DD) |
STAT_BALANCE_DDREL_PERCENT | Mức sụt giảm số dư tối đa theo phần trăm |
STAT_BALANCE_DD_RELATIVE | Mức sụt giảm số dư bằng tiền tương đương, được ghi nhận tại thời điểm mức sụt giảm số dư tối đa theo phần trăm (STAT_BALANCE_DDREL_PERCENT) |
STAT_EQUITYMIN | Giá trị vốn chủ sở hữu tối thiểu |
STAT_EQUITY_DD | Mức sụt giảm tối đa bằng tiền |
STAT_EQUITYDD_PERCENT | Mức sụt giảm theo phần trăm, được ghi nhận tại thời điểm mức sụt giảm tối đa của quỹ bằng tiền (STAT_EQUITY_DD) |
STAT_EQUITY_DDREL_PERCENT | Mức sụt giảm tối đa theo phần trăm |
STAT_EQUITY_DD_RELATIVE | Mức sụt giảm bằng tiền được ghi nhận tại thời điểm mức sụt giảm tối đa theo phần trăm (STAT_EQUITY_DDREL_PERCENT) |
STAT_EXPECTED_PAYOFF | Kỳ vọng toán học của thắng lợi (trung bình cộng của tổng lợi nhuận và số lượng giao dịch) |
STAT_PROFIT_FACTOR | Độ sinh lời, là tỷ lệ STAT_GROSS_PROFIT/STAT_GROSS_LOSS (nếu STAT_GROSS_LOSS = 0; độ sinh lời lấy giá trị DBL_MAX) |
STAT_RECOVERY_FACTOR | Hệ số phục hồi: tỷ lệ của STAT_PROFIT/STAT_BALANCE_DD |
STAT_SHARPE_RATIO | Tỷ lệ Sharpe |
STAT_MIN_MARGINLEVEL | Mức ký quỹ tối thiểu đạt được |
STAT_CUSTOM_ONTESTER | Giá trị của tiêu chí tối ưu hóa tùy chỉnh được trả về bởi hàm OnTester |
Bảng sau đây hiển thị các chỉ số nguyên (số lượng).
Định danh | Mô tả |
---|---|
STAT_DEALS | Tổng số giao dịch đã hoàn thành |
STAT_TRADES | Số lượng giao dịch (các giao dịch để thoát khỏi thị trường) |
STAT_PROFIT_TRADES | Các giao dịch có lãi |
STAT_LOSS_TRADES | Các giao dịch thua lỗ |
STAT_SHORT_TRADES | Các giao dịch ngắn |
STAT_LONG_TRADES | Các giao dịch dài |
STAT_PROFIT_SHORTTRADES | Các giao dịch ngắn có lãi |
STAT_PROFIT_LONGTRADES | Các giao dịch dài có lãi |
STAT_PROFITTRADES_AVGCON | Độ dài trung bình của một chuỗi giao dịch có lãi |
STAT_LOSSTRADES_AVGCON | Độ dài trung bình của một chuỗi giao dịch thua lỗ |
STAT_CONPROFITMAX_TRADES | Số lượng giao dịch hình thành STAT_CONPROFITMAX (lợi nhuận tối đa trong chuỗi giao dịch có lãi) |
STAT_MAX_CONPROFIT_TRADES | Số lượng giao dịch trong chuỗi giao dịch có lãi dài nhất STAT_MAX_CONWINS |
STAT_CONLOSSMAX_TRADES | Số lượng giao dịch hình thành STAT_CONLOSSMAX (lỗ tối đa trong chuỗi giao dịch thua lỗ) |
STAT_MAX_CONLOSS_TRADES | Số lượng giao dịch trong chuỗi giao dịch thua lỗ dài nhất STAT_MAX_CONLOSSES |
Hãy thử sử dụng các số liệu được trình bày để tạo ra tiêu chí chất lượng Expert Advisor phức hợp của riêng chúng ta. Để làm điều này, chúng ta cần một ví dụ "thử nghiệm" của chương trình MQL. Hãy lấy Expert Advisor MultiMartingale.mq5 làm điểm khởi đầu, nhưng chúng ta sẽ đơn giản hóa nó: loại bỏ đa tiền tệ, xử lý lỗi tích hợp và lập lịch. Hơn nữa, chúng ta sẽ chọn một chiến lược giao dịch tín hiệu cho nó với một phép tính duy nhất trên thanh, tức là tại giá mở. Điều này sẽ tăng tốc độ tối ưu hóa và mở rộng lĩnh vực cho các thử nghiệm.
Chiến lược sẽ dựa trên các điều kiện quá mua và quá bán được xác định bởi chỉ báo OsMA. Chỉ báo Bollinger Bands được áp dụng lên OsMA sẽ giúp tìm động các ranh giới của biến động dư thừa, tức là các tín hiệu giao dịch.
Khi OsMA quay trở lại trong hành lang, vượt qua ranh giới dưới từ dưới lên, chúng ta sẽ mở giao dịch mua. Khi OsMA vượt qua ranh giới trên theo cùng cách từ trên xuống, chúng ta sẽ bán. Để thoát khỏi vị thế, chúng ta sử dụng đường trung bình động, cũng được áp dụng cho OsMA. Nếu OsMA cho thấy một chuyển động ngược lại (xuống đối với vị thế dài hoặc lên đối với vị thế ngắn) và chạm vào MA, vị thế sẽ được đóng. Chiến lược này được minh họa trong ảnh chụp màn hình sau.
Chiến lược giao dịch dựa trên các chỉ báo OsMA, BBands và MA
Đường dọc màu xanh lam tương ứng với thanh nơi giao dịch mua được mở, vì trên hai thanh trước đó, dải Bollinger dưới đã bị biểu đồ OsMA vượt qua từ dưới lên (nơi này được đánh dấu bằng mũi tên màu xanh lam rỗng trong cửa sổ phụ). Đường dọc màu đỏ là vị trí của tín hiệu ngược lại, vì vậy giao dịch mua đã được đóng và giao dịch bán được mở. Trong cửa sổ phụ, tại vị trí này (hoặc đúng hơn, trên hai thanh trước đó, nơi có mũi tên màu đỏ rỗng), biểu đồ OsMA vượt qua dải Bollinger trên từ trên xuống. Cuối cùng, đường màu xanh lá cây chỉ ra việc đóng giao dịch bán, do biểu đồ bắt đầu tăng lên trên đường MA màu đỏ.
Hãy đặt tên cho Expert Advisor là BandOsMA.mq5
. Các cài đặt chung sẽ bao gồm số ma thuật, khối lượng cố định và khoảng cách dừng lỗ tính bằng điểm. Đối với dừng lỗ, chúng ta sẽ sử dụng TrailingStop
từ ví dụ trước. Không sử dụng chốt lời ở đây.
input group "C O M M O N S E T T I N G S"
sinput ulong Magic = 1234567890;
input double Lots = 0.01;
input int StopLoss = 1000;
2
3
4
Ba nhóm cài đặt dành cho các chỉ báo.
input group "O S M A S E T T I N G S"
input int FastOsMA = 12;
input int SlowOsMA = 26;
input int SignalOsMA = 9;
input ENUM_APPLIED_PRICE PriceOsMA = PRICE_TYPICAL;
input group "B B A N D S S E T T I N G S"
input int BandsMA = 26;
input int BandsShift = 0;
input double BandsDeviation = 2.0;
input group "M A S E T T I N G S"
input int PeriodMA = 10;
input int ShiftMA = 0;
input ENUM_MA_METHOD MethodMA = MODE_SMA;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Trong Expert Advisor MultiMartingale.mq5
, chúng ta không có tín hiệu giao dịch, trong khi hướng mở được người dùng đặt. Ở đây chúng ta có tín hiệu giao dịch, và việc sắp xếp chúng thành một lớp riêng biệt là hợp lý. Trước tiên, hãy mô tả giao diện trừu tượng TradingSignal
.
interface TradingSignal
{
virtual int signal(void);
};
2
3
4
Nó đơn giản như giao diện khác của chúng ta TradingStrategy
. Và điều này là tốt. Các giao diện và đối tượng càng đơn giản, chúng càng có khả năng thực hiện một việc duy nhất, đó là phong cách lập trình tốt vì nó giảm thiểu lỗi và làm cho các dự án phần mềm lớn dễ hiểu hơn. Nhờ tính trừu tượng trong bất kỳ chương trình nào sử dụng TradingSignal
, sẽ có thể thay thế một tín hiệu này bằng tín hiệu khác. Chúng ta cũng có thể thay thế chiến lược. Các chiến lược của chúng ta giờ đây chịu trách nhiệm chuẩn bị và gửi lệnh, còn tín hiệu khởi tạo chúng dựa trên phân tích thị trường.
Trong trường hợp của chúng ta, hãy gói triển khai cụ thể của TradingSignal
vào lớp BandOsMaSignal
. Tất nhiên, chúng ta cần các biến để lưu trữ mô tả của 3 chỉ báo. Các phiên bản chỉ báo được tạo và xóa trong hàm tạo và hàm hủy, tương ứng. Tất cả các tham số sẽ được truyền từ các biến đầu vào. Lưu ý rằng iBands
và iMA
được xây dựng dựa trên trình xử lý hOsMA
.
class BandOsMaSignal: public TradingSignal
{
int hOsMA, hBands, hMA;
int direction;
public:
BandOsMaSignal(const int fast, const int slow, const int signal,
const ENUM_APPLIED_PRICE price,
const int bands, const int shift, const double deviation,
const int period, const int x, ENUM_MA_METHOD method)
{
hOsMA = iOsMA(_Symbol, _Period, fast, slow, signal, price);
hBands = iBands(_Symbol, _Period, bands, shift, deviation, hOsMA);
hMA = iMA(_Symbol, _Period, period, x, method, hOsMA);
direction = 0;
}
~BandOsMaSignal()
{
IndicatorRelease(hMA);
IndicatorRelease(hBands);
IndicatorRelease(hOsMA);
}
...
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Hướng của tín hiệu giao dịch hiện tại được đặt trong biến direction
: 0 — không có tín hiệu (không xác định...
(Tài liệu bị cắt ngắn tại đây, phần còn lại không được cung cấp để dịch tiếp.)
Chúng ta bây giờ có một Expert Advisor sẵn sàng mà chúng ta có thể sử dụng như một công cụ để nghiên cứu tester. Trước tiên, hãy tạo một cấu trúc phụ trợ TesterRecord
để truy vấn và lưu trữ tất cả dữ liệu thống kê.
struct TesterRecord
{
string feature;
double value;
static void fill(TesterRecord &stats[])
{
ResetLastError();
for(int i = 0; ; ++i)
{
const double v = TesterStatistics((ENUM_STATISTICS)i);
if(_LastError) return;
TesterRecord t = {EnumToString((ENUM_STATISTICS)i), v};
PUSH(stats, t);
}
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Trong trường hợp này, trường chuỗi feature
chỉ cần thiết cho đầu ra nhật ký thông tin. Để lưu tất cả các chỉ số (ví dụ, để có thể tạo biểu mẫu báo cáo của riêng bạn sau này), một mảng đơn giản kiểu double
với độ dài phù hợp là đủ.
Sử dụng cấu trúc trong trình xử lý OnDeinit
, chúng ta đảm bảo rằng API MQL5 trả về các giá trị giống như báo cáo của tester.
void OnDeinit(const int)
{
TesterRecord stats[];
TesterRecord::fill(stats);
ArrayPrint(stats, 2);
}
2
3
4
5
6
Ví dụ, khi chạy Expert Advisor trên EURUSD, H1 với khoản tiền gửi 10000 và không có tối ưu hóa nào (với cài đặt mặc định), chúng ta sẽ nhận được khoảng các giá trị sau cho năm 2021 (đoạn trích):
[feature] [value]
[ 0] "STAT_INITIAL_DEPOSIT" 10000.00
[ 1] "STAT_WITHDRAWAL" 0.00
[ 2] "STAT_PROFIT" 6.01
[ 3] "STAT_GROSS_PROFIT" 303.63
[ 4] "STAT_GROSS_LOSS" -297.62
[ 5] "STAT_MAX_PROFITTRADE" 15.15
[ 6] "STAT_MAX_LOSSTRADE" -10.00
...
[27] "STAT_DEALS" 476.00
[28] "STAT_TRADES" 238.00
...
[37] "STAT_CONLOSSMAX_TRADES" 8.00
[38] "STAT_MAX_CONLOSS_TRADES" 8.00
[39] "STAT_PROFITTRADES_AVGCON" 2.00
[40] "STAT_LOSSTRADES_AVGCON" 2.00
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Biết tất cả các giá trị này, chúng ta có thể sáng tạo ra công thức của riêng mình cho số liệu kết hợp về chất lượng Expert Advisor và đồng thời là hàm mục tiêu tối ưu hóa. Nhưng giá trị của chỉ số này trong mọi trường hợp sẽ cần được báo cáo cho tester. Và đó là điều mà hàm OnTester
thực hiện.