Nội dung này phục vụ mục đích giáo dục, không phải lời khuyên đầu tư, tín hiệu giao dịch hoặc mẫu code sẵn sàng dùng tiền thật.

Trả lời ngắn: Một EA có thể tách thành sáu phần: nhận dữ liệu, tạo tín hiệu, giới hạn rủi ro, gửi yêu cầu, quản lý vị thế và ghi lại trạng thái. Tách như vậy giúp biết lỗi xảy ra ở bước nào. Cách chia phần không tự làm chiến lược đúng, yêu cầu được khớp hay hệ thống có lợi nhuận.

Đọc xong, bạn sẽ hiểu:

  • Sáu component làm gì và không được làm gì.
  • Contract nối các component ra sao.
  • Signal khác risk, execution và position state thế nào.
  • Cách audit một EA bằng component card.

1. Sáu component, sáu trách nhiệm

a. Data: tạo snapshot có nguồn gốc

Data layer thu thập và chuẩn hóa dữ liệu mà các khối sau cần: giá, bar, spread, symbol property, account state hoặc time. Output không nên là một đống biến rời; nó nên là snapshot có timestamp, symbol và trạng thái hợp lệ.

Ví dụ giả:

{packet_id: 42, bar: 101, spread: 18, data_ok: true}

Data không tự nói “mua” hay “bán”. Nếu vừa đọc giá vừa tạo signal, boundary đã bị trộn.

b. Signal và Risk trả lời hai câu khác nhau

Signal đánh giá điều kiện strategy và trả WAIT hoặc một candidate action. Risk nhận candidate cùng account/symbol state rồi trả PASS, BLOCK hoặc giới hạn đã được định nghĩa.

Signal hỏi: “Điều kiện strategy có tạo candidate không?”

Risk hỏi: “Candidate này có được phép đi tiếp trong state hiện tại không?”

Signal đúng nhưng spread 18 vượt rule 15 thì risk có thể trả BLOCK_SPREAD. Không sửa signal thành false để che lý do block; hai bằng chứng cần tách.

c. Execution, Position và Observability

Execution chuyển approved action thành trade request, gửi qua API phù hợp và đọc result. Position Management theo dõi position/order đã được xác nhận, không đoán rằng request gửi đi chắc đã fill. Observability gồm log, metric và state giúp người vận hành nhìn event, decision, request và result.

Hình 1 — Một EA dễ kiểm khi mỗi component có đúng một trách nhiệm chính.

Observability không phải strategy thứ bảy. Log không được âm thầm đổi decision; nó chỉ ghi và cảnh báo theo contract.

2. Contract input/output giữ boundary

a. Contract là phiếu giao việc

Contract là quy ước về input, output, error và owner giữa hai component. Hãy tưởng tượng sáu trạm bếp. Phiếu từ trạm trước phải nói rõ món, số bàn và trạng thái. Phiếu “làm tiếp đi” khiến trạm sau phải đoán.

Một contract Data → Signal có thể ghi:

  • Input: event + symbol/timeframe.
  • Output: Snapshot.
  • Error: DATA_STALE, SYMBOL_UNAVAILABLE.
  • Owner: Data component.

Signal không nên tự gọi lại nguồn khác khi snapshot lỗi. Nó trả NO_DECISION với lý do. Nếu mỗi component tự chữa dữ liệu theo cách riêng, cùng packet có thể mang nhiều sự thật.

b. Decision packet giữ một ID

Decision packet là gói dữ liệu, ID và trạng thái đi xuyên pipeline. Packet 42 có thể đổi:

DATA_OK → CANDIDATE → BLOCK_SPREAD → LOGGED

Hoặc:

DATA_OK → WAIT → LOGGED

Hình 2 — Decision packet giữ cùng một ID từ dữ liệu tới bằng chứng.

ID giúp ghép log. Nếu request/result dùng ID khác mà không có mapping, trace bị đứt.

c. Error phải là output hợp lệ

Error không phải ngoại lệ “hiếm nên bỏ”. Data stale, handle lỗi, input sai hoặc server reject đều phải có representation. Một component tốt trả error có cấu trúc, không chỉ false.

Ví dụ false từ execution không cho biết request chưa gửi, bị reject hay timeout. EXEC_REJECTED_VOLUME_STEP rõ hơn và giúp owner đúng xử lý.

3. Trace packet 42 qua pipeline

a. Nhánh WAIT

Event tạo packet 42. Data trả snapshot bar 101, spread 12. Signal kiểm rule và trả WAIT. Khi đó:

  • Risk không cần đánh giá candidate.
  • Execution không được gọi.
  • Position state không đổi.
  • Observability ghi 42 | SIGNAL_WAIT.

“Không có action” vẫn là kết quả đầy đủ. Nếu log chỉ tồn tại khi gửi request, người vận hành sẽ không biết EA im lặng vì WAIT hay vì chết.

b. Nhánh bị Risk chặn

Packet 43 có spread 18; signal trả CANDIDATE. Risk rule tối đa 15 nên trả BLOCK_SPREAD.

Execution không được phép nhận packet blocked. Position state không đổi. Log ghi candidate và block reason. Đây là lý do risk phải đứng trước execution, không phải check sau khi request đã gửi.

c. Nhánh gửi request

Packet 44 đi qua Data, Signal và Risk với output PASS. Execution tạo request. Hai kết quả giả:

  • Server accept: result CONFIRMED, Position Management cập nhật state đã xác nhận.
  • Server reject: result REJECTED, Position Management không dựng position tưởng tượng.

MQL5 cung cấp nhóm trade functions để thao tác order/position và kiểm state. Việc gọi function không thay thế kiểm result. MQL5 Reference — Trade Functions

Position property cần đọc theo account mode và symbol/ticket phù hợp. Tài liệu MQL5 mô tả các property position, nhưng cấu trúc component vẫn do hệ thống thiết kế. MQL5 Reference — Position Properties

4. Sai lầm, giới hạn và rủi ro

a. God module

God module là một hàm/class làm gần như mọi thứ: đọc giá, tính signal, chọn volume, gửi request, sửa position state, vẽ panel và ghi file. Nó tiện lúc demo, nhưng khó test từng contract.

Ba lỗi khác:

  1. Risk rule bị copy ở hai nơi và cho kết quả khác.
  2. Execution tự sửa signal khi request fail.
  3. Position module cập nhật từ “send thành công” thay vì confirmed result.

b. Hidden state và owner mơ hồ

Hidden state là trạng thái ảnh hưởng decision nhưng không nằm trong contract/log: biến global, cache cũ hoặc flag do component khác sửa. Khi packet giống nhau cho output khác mà không giải thích được, state có thể đang ẩn.

Câu chắc chắn: cùng input + cùng state + cùng rule xác định phải tạo cùng decision trong mô hình deterministic.

Câu có điều kiện: nếu component đọc time/network/server state ngoài packet, output có thể khác và dependency đó phải được ghi.

c. Tách component không tự loại lỗi

Quá nhiều lớp cũng gây overhead: object chuyển đổi liên tục, log trùng và boundary giả. Mục tiêu là trách nhiệm rõ, không phải số file. Một EA nhỏ vẫn có thể tách bằng function/struct đơn giản.

Event handling trong MQL5 gồm nhiều handler và queue. Component map phải phù hợp event thật, không ép mọi event qua cùng đường nếu contract khác. MQL5 Reference — Event Handling

d. Điểm dừng

Dừng review nếu:

  • không biết component nào sở hữu data/state;
  • signal gửi request trực tiếp;
  • risk chạy sau execution;
  • result không nối về request ID;
  • position state được đoán;
  • log đổi decision;
  • error chỉ là false không lý do.

Đây là lỗi boundary, không sửa bằng cách đổi input strategy.

5. Checklist và component card

a. Checklist bảy câu

Với từng component, hỏi:

  1. Input type và nguồn là gì?
  2. Output type là gì?
  3. Error nào được phép?
  4. State nào được đọc/ghi?
  5. Side effect nào được phép?
  6. Owner là ai?
  7. Log/metric nào chứng minh?

Sau đó kiểm toàn pipeline: ID có xuyên suốt không, blocked packet có dừng không và confirmed result mới cập nhật position không.

b. Bài tập 10–15 phút

Dùng giấy/Sheets miễn phí, không terminal/account/tiền thật. Tạo bốn cột:

Mẫu đối chiếu đã điền

Component Input giả Output giả Không được tự làm
Data tick/bar snapshot tạo signal
Signal snapshot WAIT/CANDIDATE gửi request
Risk candidate + state PASS/BLOCK giả result
Execution approved action request/result sửa strategy
Position confirmed result position state đoán fill
Observability all events log/metric đổi decision

Hình 3 — Contract tốt nói rõ dữ liệu vào, dữ liệu ra, lỗi và người sở hữu.

Chọn packet 43 và trace: snapshot → candidate → block → log. Nếu bạn vẫn cho execution chạy, quay lại boundary Risk/Execution. Kết quả mong đợi là packet dừng đúng nơi và lý do còn nguyên.

c. Khi nào chưa nên đi tiếp

Nếu một component có hơn một owner, output không có type hoặc error không quan sát được, giữ trạng thái NEEDS DESIGN. Đừng nối account thật để “test cho nhanh”.

6. Tổng kết

a. Năm ý chính

  • Data, Signal, Risk, Execution, Position và Observability có trách nhiệm khác nhau.
  • Contract nói rõ input, output, error và owner.
  • Decision packet dùng một ID để trace.
  • Confirmed result mới được cập nhật position state.
  • Tách component nhằm giảm đoán ngầm, không nhằm tăng số file.

b. Câu hỏi tự kiểm tra

  • Signal và Risk trả lời hai câu khác nhau thế nào?
  • Packet bị BLOCK_SPREAD có đi vào Execution không?
  • Vì sao Position không cập nhật từ “đã send”?
  • Observability có được đổi decision không?

c. Gợi ý đáp án

Xem gợi ý câu 1

Signal tạo candidate; Risk cho phép hoặc chặn candidate theo state. Xem lại mục 1.

Xem gợi ý câu 2

Không; blocked packet phải dừng trước Execution. Xem lại mục 3.

Xem gợi ý câu 3

Send chưa chứng minh server confirmed/fill; cần result. Xem lại mục 3.

Xem gợi ý câu 4

Không; Observability ghi log/metric, không sửa decision. Xem lại mục 1 và mục 5.

d. Thuật ngữ cần nhớ

Thuật ngữ Giải thích ngắn
Data layer Khối tạo snapshot có nguồn gốc.
Signal Logic tạo WAIT hoặc candidate.
Risk Khối cho phép hoặc chặn candidate.
Execution Khối tạo request và đọc result.
Position Management Khối theo dõi position đã xác nhận.
Observability Log/metric/state giúp nhìn hành vi.
Contract Quy ước input, output, error và owner.
Decision packet Gói dữ liệu và ID đi xuyên pipeline.
Hidden state State ảnh hưởng decision nhưng không khai báo.

e. Nguồn tham khảo

Bài trước: EA Engine là gì? #7. Bài tiếp theo: EA Inputs là gì? #9.

Nội dung này phục vụ mục đích giáo dục; không phải lời khuyên đầu tư, tín hiệu giao dịch hay kiến trúc đã xác nhận cho production/live.