Bài viết gần đây
-
-
Dart Cú Pháp Cơ Bản Flutter Buổi 2 | var final const Null Safety
Tháng 7 27, 2026 -
EA MT5 Chậm Vì Multi-Pass | Siêu Cache 1-Pass Buổi 2
Tháng 7 27, 2026 -
Cache & Array MT5 Buổi 2 | Siêu Cache 1-Pass Grid Bot Hedging
Tháng 7 27, 2026 -
Python Dùng Để Làm Gì Trong Tài Chính? (CK, Fintech, Bot Trading)
Tháng 7 26, 2026
| Cache & Array MT5 Buổi 2 | Siêu Cache 1-Pass Grid Bot Hedging
Được viết bởi thanhdt vào ngày 27/07/2026 lúc 23:10 | 40 lượt xem
Nguồn:
Day DataPass/Khoa hoc Bot MT5 Nang cao Hedging Tu dong hoa/PHAN 1. CONG NGHE LOI (Infrastructure) (3 Buoi)/Buoi 2. Ky thuat Cache & Array (Bo nho dem)/Bai giang/Buoi2_Ky_thuat_Cache_Array.md+ bài tậpBuoi2_BaiTap.md.
Khi EA Grid hoặc hedging hai chiều mở hàng chục đến hàng trăm lệnh, một thói quen code tưởng như vô hại — gọi PositionsTotal() rồi lặp lại nhiều lần mỗi Tick — có thể biến VPS thành nút thắt cổ chai. Thị trường ra tin (Nonfarm, CPI), giá giật 50 tick/giây; nếu mỗi tick EA quét sàn bốn lần cho cùng một tập lệnh, CPU có thể bão hòa trước khi logic nhồi lệnh hay chốt lời kịp chạy.
Bài viết trình bày lại Buổi 2 — Kỹ thuật Cache & Array (Bộ nhớ đệm) trong khóa Lập trình MT5 Nâng cao Hedging & Tự động hóa tại Hướng Nghiệp Dữ Liệu. Đây là bài kỹ thuật Infrastructure — giải thích cách robot sao chép trạng thái lệnh vào vùng nhớ riêng, quét một lần (1-Pass), rồi tái sử dụng dữ liệu ở mọi hàm con. Không phải tín hiệu giao dịch, không cam kết lợi nhuận.
Buổi 1 đã giới thiệu Global Variables làm “ổ cứng” lưu P0, Step, trạng thái cụm. Buổi 2 trả lời câu hỏi tiếp theo: làm sao đọc hàng trăm lệnh đang mở mà EA vẫn nhẹ trên VPS?
1. Cache và Array — hai khái niệm nền trước khi tối ưu
1.1. Cache (bộ nhớ đệm) là gì?
Hãy tưởng tượng quản lý siêu thị: mỗi lần sếp hỏi “hôm nay bán được bao nhiêu áo?”, thay vì vào kho đếm lại từng cái, bạn nhìn quyển sổ thu ngân.
Trong MQL5, Cache là các biến do EA tự tạo (cache_total_buy_orders, cache_total_buy_lot…) lưu kết quả vừa quét từ Terminal. Các hàm phía sau đọc Cache thay vì gọi lại API PositionGetDouble() hàng loạt.
1.2. Array (mảng) là gì?
Nếu Cache chỉ lưu một con số tổng, Array giống tủ nhiều ngăn — mỗi ngăn chứa Ticket của một lệnh:
ArrayBuyTickets = [1001, 1002, 1003, ...]
Khi cần đóng toàn bộ cụm Buy, EA lặp mảng và gửi lệnh Close theo từng Ticket — không cần quét lại điều kiện Magic/Symbol mỗi lần.
1.3. Ba cấp dữ liệu trong MT5
| Cấp | Vị trí | Ai quản lý | EA đọc như thế nào |
|---|---|---|---|
| 1 — Server Broker | Máy chủ sàn | Broker | Terminal đồng bộ qua mạng |
| 2 — Terminal RAM | MT5 trên VPS | MetaQuotes | PositionsTotal(), PositionGetTicket() |
| 3 — EA Cache | Biến Global/Static | Lập trình viên | Biến cache_*, ArrayBuyTickets[] |
Gọi API Cấp 2 không gửi request mạng — nhưng vẫn tốn CPU vì Terminal phải duyệt cấu trúc nội bộ. Khi Grid 100 lệnh × 4 vòng lặp × 50 tick/giây, con số phép tính bùng nổ.
Siêu Cache = snapshot Cấp 2 về Cấp 3 một lần, dùng lại nhiều lần trong cùng chu kỳ Tick.
2. Lỗi Multi-Pass — vì sao EA “treo” dù VPS ổn
Code nghiệp dư thường tách logic thành nhiều vòng lặp độc lập:
- Vòng 1: đếm lệnh Buy
- Vòng 2: đếm lệnh Sell
- Vòng 3: tính tổng Lot
- Vòng 4: tính tổng Profit
Ví dụ số: 100 lệnh mở, 4 vòng = 400 phép duyệt mỗi lần tính toán. OnTick() chạy mỗi tick giá; tin mạnh → 50 tick/giây → 20.000 phép/giây.
Hậu quả thực tế:
- MT5 đơ, chart giật
OrderSendtrễ → trượt giá, nhồi lệnh sai Step- Basket TP chạy muộn → floating âm sâu hơn kế hoạch
Đây là lỗi kiến trúc, không phải “VPS yếu”. Nâng cấu hình chỉ che triệu chứng.
graph LR
A["OnTick mỗi 20ms"] --> B["Vòng 1 · đếm Buy"]
A --> C["Vòng 2 · đếm Sell"]
A --> D["Vòng 3 · tổng Lot"]
A --> E["Vòng 4 · tổng Profit"]
B --> F["CPU bão hòa"]
C --> F
D --> F
E --> F
3. Siêu Cache 1-Pass — triển khai MQL5
3.1. Khai báo biến Cache Global
int cache_total_buy_orders = 0;
int cache_total_sell_orders = 0;
double cache_total_buy_lot = 0.0;
double cache_total_sell_lot = 0.0;
double cache_total_buy_profit = 0.0;
double cache_total_sell_profit = 0.0;
Đặt Global (hoặc static trong class) để mọi hàm — CheckTakeProfit(), ProcessCluster(), DrawDashboard() — đọc cùng một nguồn, không truyền 6 tham số qua từng lời gọi.
3.2. Hàm UpdateOrderCache() — quét duy nhất một lần
void UpdateOrderCache()
{
cache_total_buy_orders = 0;
cache_total_sell_orders = 0;
cache_total_buy_lot = 0.0;
cache_total_sell_lot = 0.0;
cache_total_buy_profit = 0.0;
cache_total_sell_profit = 0.0;
int total = PositionsTotal();
for(int i = total - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket <= 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
// Buổi 3 sẽ lọc Magic 2111/2112 — tạm bỏ qua ở demo Buổi 2
long type = PositionGetInteger(POSITION_TYPE);
double volume = PositionGetDouble(POSITION_VOLUME);
double profit = PositionGetDouble(POSITION_PROFIT);
if(type == POSITION_TYPE_BUY)
{
cache_total_buy_orders++;
cache_total_buy_lot += volume;
cache_total_buy_profit += profit;
}
else if(type == POSITION_TYPE_SELL)
{
cache_total_sell_orders++;
cache_total_sell_lot += volume;
cache_total_sell_profit += profit;
}
}
}
Thói quen tốt: duyệt từ total - 1 về 0. Khi đóng lệnh trong vòng lặp, chỉ số không bị lệch (index out of range).
3.3. Vòng đời Cache trong OnTick()
graph TD
A(["Tick giá mới"]) --> B[UpdateOrderCache]
B --> C{Logic giao dịch}
C -->|"Đọc cache"| D["ProcessCluster · TP · Dashboard"]
D --> E{OrderSend hoặc Close?}
E -->|Có| F[UpdateOrderCache lại]
E -->|Không| G(["Kết thúc Tick"])
F --> G
Hai thời điểm bắt buộc gọi UpdateOrderCache():
- Đầu
OnTick()— Profit floating đổi theo giá - Ngay sau
OrderSend/ đóng lệnh thành công — số lệnh thực tế đã thay đổi, Cache cũ sai
Quên bước 2 là bug kinh điển: robot nghĩ còn 5 lệnh Buy trong khi đã mở thêm 1 lệnh → nhồi vượt Step.
3.4. Global Cache vs biến Local — khi nào dùng gì?
Local trong OnTick() |
Global Cache | |
|---|---|---|
| Tốc độ 1-Pass | Nhanh như nhau | Nhanh như nhau |
| Nhiều hàm con | Phải truyền tham số | Đọc trực tiếp |
| Code 500+ dòng | Rối, khó test | “Trạm dữ liệu trung tâm” |
| Unit test | Khó mock | Có thể reset Cache trong test |
Với EA production kiểu Nhị Quái (nhiều module), Global Cache là mặc định hợp lý.
4. Array ticket — đóng cụm lệnh không quét lại sàn
4.1. Cập nhật Cache kèm mảng Ticket
ulong ArrayBuyTickets[];
int buy_ticket_count = 0;
void UpdateCacheWithArray()
{
int total = PositionsTotal();
ArrayResize(ArrayBuyTickets, total);
buy_ticket_count = 0;
for(int i = total - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket <= 0) continue;
if(PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY) continue;
ArrayBuyTickets[buy_ticket_count] = ticket;
buy_ticket_count++;
}
ArrayResize(ArrayBuyTickets, buy_ticket_count);
}
Sau vòng lặp, ArrayResize(..., buy_ticket_count) cắt phần thừa — tiết kiệm RAM khi total lớn nhưng Buy thực tế ít.
4.2. Đóng basket Buy từ mảng
void CloseAllBuyFromArray()
{
for(int i = 0; i < buy_ticket_count; i++)
{
ulong ticket = ArrayBuyTickets[i];
if(!PositionSelectByTicket(ticket)) continue;
// m_trade_buy.PositionClose(ticket); — Buổi 3 gắn CTrade + Magic
}
}
So với Multi-Pass: một lần build mảng, một lần close — O(n) thay vì O(n × số_hành_động).
4.3. Struct + Array of Struct (mở rộng)
Khi cần lưu Ticket và Lot và Profit mở cửa cùng lúc:
struct OrderSnapshot
{
ulong ticket;
double volume;
double profit;
double open_price;
};
OrderSnapshot BuySnapshots[];
Mỗi phần tử mảng là một “hồ sơ lệnh” — phù hợp dashboard Buổi sau và Basket TP cần sort theo Step.
5. Bài tập Buổi 2 — hiển thị Balance/Equity từ Cache
Trong folder bài tập, học viên viết EA hiển thị Balance và Equity lên chart — nhưng không gọi AccountInfoDouble() mỗi dòng vẽ text; thay vào đó cache vào biến Global, chỉ refresh khi Tick mới hoặc khi có deal.
Mục tiêu bài tập:
- Tách Thu thập dữ liệu (Update) khỏi Hiển thị (Draw)
- Quen thói quen “một nguồn sự thật” trước Buổi 3 Magic/Comment
File tham chiếu: Buoi2_0_HienThi_BaLanceEquity_TuCache.mq5
6. Liên hệ với lộ trình 12 buổi MT5 Hedging
| Buổi | Chủ đề Infrastructure | Vai trò Cache |
|---|---|---|
| 1 | Global Variables | Lưu P0, Step, trạng thái cụm |
| 2 | Cache & Array | Đọc lệnh nhanh — nền cho Grid |
| 3 | Magic & Comment | Lọc đúng lệnh bot khi UpdateCache |
| 4+ | Step, X-Level, Surplus | Dùng Cache trong ProcessCluster() |
Không có Buổi 2 vững, Buổi 4 trở đi EA dễ chậm khi lưới dày — dù logic Step đúng.
7. FAQ
Cache có thay Global Variables không?
Không. GV lưu trạng thái chiến thuật qua restart; Cache là snapshot tạm trong phiên chạy, rebuild mỗi Tick.
Cập nhật Cache mỗi Tick có tốn không?
Một lần 1-Pass vẫn rẻ hơn nhiều so với bốn lần quét riêng. Có thể throttle (ví dụ dashboard 500ms) nhưng logic giao dịch nên refresh mỗi Tick.
Array có cần khi mới 5–10 lệnh?
Demo ít lệnh vẫn chạy. Array và Struct trả giá khi scale 50–200 lệnh và cần close-all basket trong vài millisecond.
Liên quan Python PyNhiQuaiBot?
Port sang Python dùng list/dict thay Array — ý tưởng snapshot positions một lần giữ nguyên. Khóa Python Nâng cao Hedging KG 01/08/2026.
8. Tóm tắt
- Multi-Pass = nhân số lần quét lệnh theo số hàm → treo VPS khi tin mạnh
- Siêu Cache 1-Pass = một vòng
for, gom Buy/Sell/Lot/Profit vào biến Global - Array ticket = đóng cụm chính xác, không quét lại điều kiện
- Gọi
UpdateOrderCache()đầu Tick và sau khi giao dịch
Giao dịch tự động có rủi ro drawdown — bài mang tính giáo dục kỹ thuật, không cam kết lợi nhuận.
Liên hệ & đăng ký: Lập trình MT5 Nâng cao Hedging & Tự động hóa · Hotline 0934 145 100 · Zalo 039 791 9841
Khóa MT5 Hedging: Lập trình MT5 Nâng cao Hedging & Tự động hóa · Hotline 0934 145 100
Weekly Digest — Nhận Bản Tin Hàng Tuần
Nhận các bài viết phân tích kỹ thuật chuyên sâu, thuật toán giao dịch tự động (Trading Bot) và các giải pháp công nghệ mới nhất từ Hướng Nghiệp Dữ Liệu.
Đặng Trí Thanh
Giám đốc Công nghệ · DNT Digital · Giảng viên HNDLĐào tạo và triển khai thực chiến Python, MT5 và hệ thống bot auto trading / IB cho học viên và doanh nghiệp.