Bot Auto Trading

Thuật Toán 3: Tính Toán Độ Lệch Khối Lượng Ròng (Volume Bias) Cho Cụm Vị Thế

01/06/2026 Đặng Trí Thanh 211 lượt xem ~14 phút đọc
Mục lục bài viết
    Thuật Toán 3: Tính Toán Độ Lệch Khối Lượng Ròng (Volume Bias) Cho Cụm Vị Thế

    Giới Thiệu: Tại Sao Cần Đo Lệch Khối Lượng?

    Trong giao dịch lưới (grid trading) và chiến lược hai chiều, robot không chỉ mở lệnh mua mà còn duy trì đồng thời cả lệnh mua và lệnh bán ở nhiều tầng giá khác nhau. Khi thị trường di chuyển mạnh theo một hướng, tổng khối lượng Buy có thể vượt xa tổng khối lượng Sell — hoặc ngược lại. Sự chênh lệch này gọi là Volume Bias (Độ Lệch Khối Lượng Ròng).

    Công thức cơ bản:

    ΔV = V_Buy - V_Sell

    Khi ΔV > 0: Robot đang nghiêng về Buy — có rủi ro nếu giá tiếp tục giảm.
    Khi ΔV < 0: Robot đang nghiêng về Sell — có rủi ro nếu giá tiếp tục tăng.
    Khi ΔV ≈ 0: Trạng thái cân bằng — tài khoản được bảo vệ tốt nhất.

    Thuật toán Volume Bias là một phần cốt lõi trong hệ thống quản trị rủi ro. Khi equity (vốn thực tế) rơi xuống ngưỡng nguy hiểm InpMinEqui2, thuật toán sẽ tự động tính toán ΔV và mở một lệnh đối ứng với khối lượng bằng |ΔV| để đóng băng tài khoản — tức là vô hiệu hóa mọi biến động P&L cho đến khi trader can thiệp.

    Bài viết này sẽ phân tích toàn bộ cơ chế từ lý thuyết đến code MQL5 hoàn chỉnh, bao gồm các trường hợp biên (edge cases) và cách tích hợp với hệ thống Equity Lockdown ở Bài 9 trong series.


    Kiến Trúc Tổng Thể: Volume Bias Trong Hệ Thống Lưới


    VOLUME BIAS ALGORITHM — LUỒNG XỬ LÝ

    OnTick() — Kiểm Tra Equity

    Equity <
    InpMinEqui2?

    NO

    Tiếp tục
    bình thường

    YES

    CalculateVolume(magic,
    &buy_vol, &sell_vol)

    ΔV = buy_vol – sell_vol
    delta_vol = |ΔV|

    _LOCKED
    == 1?

    YES

    Bỏ qua
    (đã khóa)

    NO

    Mở lệnh đối ứng khối lượng |ΔV| → Set _LOCKED=1

    Hình 1: Luồng xử lý thuật toán Volume Bias — từ kiểm tra equity đến mở lệnh đóng băng tài khoản

    Như sơ đồ trên minh họa, thuật toán hoạt động theo 4 bước tuần tự:

    1. Giám sát Equity liên tục trong mỗi tick
    2. Tính toán Volume Bias khi equity chạm ngưỡng nguy hiểm
    3. Kiểm tra trạng thái khóa để tránh mở lệnh lặp
    4. Mở lệnh đối ứng với khối lượng chính xác bằng |ΔV|

    Hàm CalculateVolume: Trái Tim Của Thuật Toán

    Hàm CalculateVolume() là thành phần quan trọng nhất. Nó duyệt qua toàn bộ lệnh đang mở (open positions) và tính tổng khối lượng mua/bán theo magic number.

    Tại Sao Lọc Theo Magic Number?

    Trong một tài khoản thực tế, trader có thể chạy nhiều robot hoặc đặt lệnh thủ công cùng lúc. Nếu không lọc theo magic, hàm sẽ tính cả khối lượng của các EA khác — gây ra sai lệch nghiêm trọng trong quyết định đóng băng tài khoản.

    
    //+------------------------------------------------------------------+
    //| Tính tổng khối lượng Buy và Sell theo magic number               |
    //| Trả về true nếu có ít nhất 1 vị thế, false nếu không có gì      |
    //+------------------------------------------------------------------+
    bool CalculateVolume(long magic_number, double &buy_vol, double &sell_vol)
    {
        buy_vol  = 0.0;
        sell_vol = 0.0;
    
        int total = PositionsTotal();
        if(total == 0) return false;
    
        bool found = false;
    
        for(int i = 0; i < total; i++)
        {
            ulong ticket = PositionGetTicket(i);
            if(ticket == 0) continue;
    
            // Chỉ xử lý các vị thế thuộc EA này
            if(PositionGetInteger(POSITION_MAGIC) != magic_number) continue;
    
            // Chỉ xử lý symbol hiện tại
            if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
    
            double lot = PositionGetDouble(POSITION_VOLUME);
            ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
    
            if(pos_type == POSITION_TYPE_BUY)
            {
                buy_vol  += lot;
                found     = true;
            }
            else if(pos_type == POSITION_TYPE_SELL)
            {
                sell_vol += lot;
                found     = true;
            }
        }
    
        // Làm tròn để tránh lỗi floating-point (ví dụ: 0.3000000001)
        buy_vol  = NormalizeDouble(buy_vol,  2);
        sell_vol = NormalizeDouble(sell_vol, 2);
    
        return found;
    }
    

    Xử Lý Lỗi Floating-Point

    Một vấn đề ẩn thường gặp: khi cộng nhiều giá trị double trong MQL5, kết quả có thể bị lỗi làm tròn nhỏ. Ví dụ, ba lệnh 0.1 lot có thể cho kết quả 0.30000000004 thay vì 0.30. Lệnh NormalizeDouble(value, 2) ở cuối hàm giải quyết vấn đề này bằng cách làm tròn về 2 chữ số thập phân.


    Tính Toán Delta Volume: Công Thức Và Ý Nghĩa

    Công Thức Đầy Đủ

    
    // Sau khi gọi CalculateVolume()
    double delta_vol = buy_vol - sell_vol;    // Có thể âm hoặc dương
    double abs_delta = MathAbs(delta_vol);    // Khối lượng đối ứng cần mở
    

    Bảng Diễn Giải Các Trường Hợp

    Giá trị ΔV Ý nghĩa Lệnh đối ứng cần mở Kết quả
    ΔV = +0.5 Thừa 0.5 lot Buy Bán 0.5 lot Sell Cân bằng ròng = 0
    ΔV = -0.3 Thừa 0.3 lot Sell Mua 0.3 lot Buy Cân bằng ròng = 0
    ΔV = 0.0 Đã cân bằng Không cần mở lệnh Không làm gì
    ΔV rất nhỏ (<0.01) Lỗi làm tròn Bỏ qua Tránh lệnh 0 lot

    Hàm OpenHedgeLock: Mở Lệnh Đóng Băng Tài Khoản

    Sau khi tính được abs_delta, hàm OpenHedgeLock() sẽ thực hiện việc mở lệnh đối ứng. Đây là thời điểm quan trọng nhất — mọi sai sót ở bước này đều có hậu quả nghiêm trọng.

    
    //+------------------------------------------------------------------+
    //| Mở lệnh đối ứng để đóng băng tài khoản                          |
    //| Trả về ticket của lệnh mới, hoặc 0 nếu thất bại                 |
    //+------------------------------------------------------------------+
    ulong OpenHedgeLock(double buy_vol, double sell_vol, long magic_number)
    {
        double delta_vol = buy_vol - sell_vol;
        double abs_delta = NormalizeDouble(MathAbs(delta_vol), 2);
    
        // Edge case 1: Khối lượng quá nhỏ — bỏ qua
        if(abs_delta  max_vol)
        {
            Print("CẢNH BÁO: ΔV=", abs_delta, " vượt giới hạn tối đa ", max_vol,
                  ". Giảm xuống mức tối đa.");
            abs_delta = max_vol;
        }
    
        // Xác định hướng lệnh đối ứng
        ENUM_ORDER_TYPE hedge_type;
        if(delta_vol > 0)
            hedge_type = ORDER_TYPE_SELL;  // Thừa Buy → bán để cân bằng
        else
            hedge_type = ORDER_TYPE_BUY;   // Thừa Sell → mua để cân bằng
    
        // Lấy giá hiện tại
        double price = (hedge_type == ORDER_TYPE_BUY)
                       ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                       : SymbolInfoDouble(_Symbol, SYMBOL_BID);
    
        // Tạo request
        MqlTradeRequest  request = {};
        MqlTradeResult   result  = {};
    
        request.action    = TRADE_ACTION_DEAL;
        request.symbol    = _Symbol;
        request.volume    = abs_delta;
        request.type      = hedge_type;
        request.price     = price;
        request.deviation = 20;  // Slippage cho phép: 20 points
        request.magic     = magic_number;
        request.comment   = "HEDGE_LOCK_" + IntegerToString((int)magic_number);
    
        // Làm tròn giá theo digit của symbol
        request.price = NormalizeDouble(request.price, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
    
        // Gửi lệnh
        if(!OrderSend(request, result))
        {
            int err = GetLastError();
            Print("HedgeLock FAILED. Error: ", err, " | Retcode: ", result.retcode,
                  " | Comment: ", result.comment);
            ResetLastError();
            return 0;
        }
    
        if(result.retcode != TRADE_RETCODE_DONE)
        {
            Print("HedgeLock retcode không OK: ", result.retcode,
                  " | Deal: ", result.deal);
            return 0;
        }
    
        Print("HedgeLock SUCCESS! Ticket=", result.deal,
              " | Type=", EnumToString(hedge_type),
              " | Volume=", abs_delta,
              " | Price=", result.price);
    
        return result.deal;
    }
    

    Tại Sao Cần Kiểm Tra SYMBOL_VOLUME_MIN?

    Mỗi broker có giới hạn khối lượng tối thiểu khác nhau. Một số broker cho phép 0.01 lot, nhưng cũng có broker yêu cầu tối thiểu 0.1 lot. Nếu abs_delta nhỏ hơn giá trị này, lệnh sẽ bị từ chối với lỗi TRADE_RETCODE_INVALID_VOLUME. Kiểm tra trước giúp tránh lỗi không cần thiết.


    Hàm CheckVolumeBias: Điều Phối Toàn Bộ Luồng

    Hàm CheckVolumeBias() là hàm cấp cao nhất, được gọi trong OnTick(). Nó điều phối toàn bộ logic: kiểm tra điều kiện, tính toán, đánh dấu trạng thái, và gọi hàm mở lệnh.

    
    // Ngưỡng equity nguy hiểm (cấu hình bởi người dùng)
    input double InpMinEqui2 = 500.0;  // Ngưỡng equity tối thiểu để trigger Hedge Lock
    
    //+------------------------------------------------------------------+
    //| Kiểm tra và thực thi Volume Bias (gọi trong OnTick)              |
    //+------------------------------------------------------------------+
    void CheckVolumeBias(long magic_number)
    {
        // Kiểm tra 1: Đã bị khóa chưa?
        if(GlobalVariableGet("_LOCKED_" + IntegerToString((int)magic_number)) == 1.0)
        {
            // Tài khoản đã bị đóng băng — không làm gì thêm
            return;
        }
    
        // Kiểm tra 2: Equity còn đủ chưa?
        double current_equity = AccountInfoDouble(ACCOUNT_EQUITY);
        if(current_equity >= InpMinEqui2)
        {
            // Vẫn an toàn — không cần hành động
            return;
        }
    
        // === EQUITY CHẠM NGƯỠNG NGUY HIỂM ===
        Print("⚠️ VOLUME BIAS TRIGGER! Equity=", current_equity,
              " < Threshold=", InpMinEqui2);
    
        // Tính toán volume
        double buy_vol, sell_vol;
        bool has_positions = CalculateVolume(magic_number, buy_vol, sell_vol);
    
        if(!has_positions)
        {
            Print("Không có vị thế nào — không thể hedge.");
            return;
        }
    
        double delta_vol = buy_vol - sell_vol;
        Print("Volume Bias: Buy=", buy_vol, " | Sell=", sell_vol,
              " | ΔV=", delta_vol);
    
        // Trường hợp đặc biệt: đã cân bằng tự nhiên
        if(MathAbs(delta_vol)  0)
        {
            // Đặt cờ khóa toàn cục
            GlobalVariableSet("_LOCKED_" + IntegerToString((int)magic_number), 1.0);
    
            // Lưu thông tin hedge để tham chiếu sau
            GlobalVariableSet("_HEDGE_TICKET_" + IntegerToString((int)magic_number),
                             (double)hedge_ticket);
            GlobalVariableSet("_HEDGE_DELTA_"  + IntegerToString((int)magic_number),
                             delta_vol);
    
            Print("✅ Hedge Lock thành công! Tài khoản đóng băng.");
            Print("   Hedge Ticket: ", hedge_ticket);
            Print("   Delta Vol: ", delta_vol);
            Print("   Equity tại thời điểm lock: ", current_equity);
        }
        else
        {
            Print("❌ Hedge Lock thất bại! Cần can thiệp thủ công ngay lập tức!");
            // Gửi alert cho trader
            Alert("CRITICAL: Hedge Lock thất bại tại equity ", current_equity,
                  "! Kiểm tra ngay!");
            SendNotification("CRITICAL: Hedge Lock thất bại! Equity=" +
                            DoubleToString(current_equity, 2));
        }
    }
    

    Xử Lý Edge Cases: Những Tình Huống Nguy Hiểm

    Trong thực chiến, có nhiều tình huống bất ngờ mà code cần xử lý đúng cách. Dưới đây là bảng tổng hợp các edge cases quan trọng nhất:

    Tình huống Nguyên nhân Cách xử lý Code liên quan
    Mở lệnh hedge 2 lần Equity dao động quanh ngưỡng Kiểm tra _LOCKED GlobalVariable trước GlobalVariableGet("_LOCKED_...")
    ΔV = 0 (đã cân bằng) Lưới đối xứng hoàn hảo Không mở lệnh, vẫn đặt cờ khóa MathAbs(delta) < 0.01
    Volume quá nhỏ ΔV < lot tối thiểu của broker Bỏ qua mở lệnh, vẫn khóa SYMBOL_VOLUME_MIN
    Không có vị thế nào Robot chưa mở lệnh bao giờ Return sớm, không làm gì PositionsTotal() == 0
    Mạng ngắt khi gửi lệnh Lỗi kết nối server Log lỗi, gửi Alert + Push notification Alert() + SendNotification()
    EA restart sau khi đã lock Khởi động lại MetaTrader GlobalVariable được lưu tự động qua restart GV tự persist trên disk

    Tích Hợp Với OnTick: Code Hoàn Chỉnh Trong EA

    Dưới đây là cách tích hợp thuật toán Volume Bias vào EA thực tế, bao gồm cả phần OnInit() để xử lý trường hợp EA restart:

    
    // === CẤU HÌNH ===
    input long   InpMagicNumber = 20240101;  // Magic Number của EA
    input double InpMinEqui2    = 500.0;     // Ngưỡng equity trigger Hedge Lock
    input bool   InpEnableHedge = true;      // Bật/tắt chức năng Hedge Lock
    
    // === BIẾN TOÀN CỤC ===
    string GV_LOCKED; // Key GlobalVariable
    string GV_TICKET;
    string GV_DELTA;
    
    //+------------------------------------------------------------------+
    int OnInit()
    {
        // Khởi tạo tên các GlobalVariables
        GV_LOCKED = "_LOCKED_" + IntegerToString((int)InpMagicNumber);
        GV_TICKET = "_HEDGE_TICKET_" + IntegerToString((int)InpMagicNumber);
        GV_DELTA  = "_HEDGE_DELTA_"  + IntegerToString((int)InpMagicNumber);
    
        // Kiểm tra trạng thái khóa từ lần chạy trước (EA restart)
        if(GlobalVariableCheck(GV_LOCKED) && GlobalVariableGet(GV_LOCKED) == 1.0)
        {
            double saved_delta  = GlobalVariableGet(GV_DELTA);
            double saved_ticket = GlobalVariableGet(GV_TICKET);
    
            Print("⚠️ EA khởi động lại — tài khoản VẪN ĐANG BỊ ĐÓNG BĂNG!");
            Print("   Hedge Ticket: ", (long)saved_ticket);
            Print("   Delta khi lock: ", saved_delta);
            Print("   Cần can thiệp thủ công để mở khóa!");
    
            Alert("Tài khoản vẫn đang bị Hedge Lock từ session trước! Ticket=",
                  (long)saved_ticket);
        }
    
        return(INIT_SUCCEEDED);
    }
    
    //+------------------------------------------------------------------+
    void OnTick()
    {
        // Chỉ kiểm tra Volume Bias nếu được bật
        if(InpEnableHedge)
        {
            CheckVolumeBias(InpMagicNumber);
        }
    
        // Nếu đang bị khóa → không chạy logic giao dịch bình thường
        if(GlobalVariableGet(GV_LOCKED) == 1.0)
        {
            Comment("⛔ TÀI KHOẢN ĐANG BỊ HEDGE LOCK — MỌI GIAO DỊCH MỚI ĐÃ BỊ DỪNG");
            return;
        }
    
        // === LOGIC GIAO DỊCH BÌNH THƯỜNG ===
        // ... (code lưới, gặt X, trailing plowing, v.v.)
    }
    

    Giải Phóng Hedge Lock: Quy Trình Mở Khóa

    Sau khi equity được bổ sung hoặc trader muốn tiếp tục giao dịch, cần có quy trình mở khóa an toàn. Điều này KHÔNG nên tự động hóa — trader phải xem xét tình hình thị trường trước khi quyết định.

    
    //+------------------------------------------------------------------+
    //| Mở khóa Hedge Lock (gọi thủ công bởi trader qua nút trên panel) |
    //+------------------------------------------------------------------+
    bool ReleasehHedgeLock(long magic_number)
    {
        string gv_locked = "_LOCKED_" + IntegerToString((int)magic_number);
        string gv_ticket = "_HEDGE_TICKET_" + IntegerToString((int)magic_number);
    
        // Kiểm tra xác nhận
        if(!GlobalVariableCheck(gv_locked) || GlobalVariableGet(gv_locked) != 1.0)
        {
            Print("Không tìm thấy Hedge Lock để giải phóng.");
            return false;
        }
    
        // Lấy ticket của lệnh hedge
        ulong hedge_ticket = (ulong)GlobalVariableGet(gv_ticket);
    
        if(hedge_ticket > 0)
        {
            // Kiểm tra lệnh hedge vẫn còn tồn tại
            if(PositionSelectByTicket(hedge_ticket))
            {
                double hedge_vol  = PositionGetDouble(POSITION_VOLUME);
                ENUM_POSITION_TYPE hedge_type =
                    (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
    
                Print("Cảnh báo: Lệnh hedge ticket=", hedge_ticket,
                      " vẫn đang mở với vol=", hedge_vol,
                      " type=", EnumToString(hedge_type));
                Print("Hãy đóng lệnh này thủ công trước khi mở khóa.");
                return false;
            }
        }
    
        // Xóa các GlobalVariables
        GlobalVariableDel(gv_locked);
        GlobalVariableDel(gv_ticket);
        GlobalVariableDel("_HEDGE_DELTA_" + IntegerToString((int)magic_number));
    
        Print("✅ Hedge Lock đã được giải phóng. EA tiếp tục giao dịch.");
        return true;
    }
    

    Tại Sao Không Tự Động Mở Khóa?

    Nhiều trader hỏi: “Tại sao không tự động mở khóa khi equity phục hồi?” Câu trả lời là: equity phục hồi không có nghĩa là rủi ro đã qua. Thị trường có thể đang trong giai đoạn điều chỉnh ngắn hạn trước khi tiếp tục xu hướng nguy hiểm. Chỉ trader mới có thể đánh giá được bối cảnh tổng thể và quyết định khi nào an toàn để tiếp tục.


    GlobalVariable: Bộ Nhớ Liên Phiên

    Một tính năng quan trọng của GlobalVariables trong MetaTrader 4/5 là chúng được lưu trên disk và tồn tại qua các lần restart của MetaTrader (không phải của VPS/máy tính). Đây là lý do tại sao chúng được chọn để lưu trạng thái khóa:

    Phương pháp lưu trạng thái Tồn tại qua EA restart? Tồn tại qua MT restart? Tốc độ đọc/ghi
    GlobalVariable ✓ Có ✓ Có (lưu disk) Rất nhanh
    Biến static trong EA ✗ Không ✗ Không Cực nhanh
    File CSV/TXT ✓ Có ✓ Có Chậm hơn
    Comment của lệnh ✓ Có (trên sàn) ✓ Có Phụ thuộc broker

    Backtesting Volume Bias: Kiểm Tra Trước Khi Dùng Thực

    Trước khi deploy EA với tính năng Hedge Lock lên tài khoản thực, cần kiểm tra kỹ trong Strategy Tester. Tuy nhiên, GlobalVariables trong Strategy Tester hoạt động khác với môi trường thực — chúng không được lưu giữa các lần chạy test.

    
    // Hàm test CalculateVolume trong Strategy Tester
    // Chạy trong OnInit() của EA test
    void TestCalculateVolume()
    {
        // Giả lập: EA có 3 lệnh Buy tổng cộng 0.3 lot
        // và 2 lệnh Sell tổng cộng 0.2 lot
        // ΔV phải là +0.1
    
        // Trong Strategy Tester, dùng OrderSend để tạo lệnh test trước
        // Sau đó gọi CalculateVolume và kiểm tra kết quả
    
        double buy_vol, sell_vol;
        CalculateVolume(InpMagicNumber, buy_vol, sell_vol);
    
        Print("Test CalculateVolume:");
        Print("  Buy Volume: ", buy_vol, " (expected: 0.30)");
        Print("  Sell Volume: ", sell_vol, " (expected: 0.20)");
        Print("  Delta: ", buy_vol - sell_vol, " (expected: 0.10)");
    
        if(MathAbs((buy_vol - sell_vol) - 0.10) < 0.001)
            Print("✅ Test PASSED");
        else
            Print("❌ Test FAILED");
    }
    

    Mối Liên Hệ Với Các Thuật Toán Khác Trong Series

    Volume Bias không hoạt động độc lập — nó là một phần của hệ sinh thái thuật toán lớn hơn:

    Kết Nối Với Thuật Toán 1 & 2 (Grid Engine)

    Grid Engine (Thuật toán 1-2) là nguồn tạo ra các vị thế mua/bán. Khi lưới mở rộng theo một hướng không cân đối, Volume Bias sẽ được kích hoạt. Do đó, cần thiết kế Grid Engine với tham số kiểm soát số tầng tối đa để tránh ΔV quá lớn.

    Kết Nối Với Comment String Parser (Thuật Toán 4)

    Khi lệnh hedge được mở, nó cũng cần được ghi comment phù hợp (ví dụ: "HEDGE_LOCK") để khi EA restart, Comment Parser (Thuật toán 4) có thể nhận dạng đây là lệnh hedge, không phải lệnh lưới thông thường.

    Kết Nối Với Equity Lockdown (Bài 9 — Thuật Toán Nâng Cao)

    Volume Bias là phiên bản cơ bản của chiến lược đóng băng tài khoản. Ở Bài 9, Equity Lockdown sẽ mở rộng cơ chế này với nhiều tầng ngưỡng (InpMinEqui1, InpMinEqui2) và logic phức tạp hơn để xử lý nhiều kịch bản khác nhau.


    Cạm Bẫy Phổ Biến Khi Triển Khai

    Cạm Bẫy 1: Quên Kiểm Tra Symbol

    Nếu EA chạy trên EURUSD nhưng tài khoản cũng có lệnh GBPUSD (từ EA khác), hàm CalculateVolume() phải lọc theo _Symbol chứ không chỉ theo magic number. Code trên đã xử lý điều này.

    Cạm Bẫy 2: Magic Number Trùng

    Nếu hai EA dùng chung magic number trên cùng một tài khoản, CalculateVolume() sẽ tính lẫn lộn khối lượng của cả hai EA. Luôn dùng magic number duy nhất cho mỗi EA và mỗi cặp tiền tệ.

    Cạm Bẫy 3: Không Xử Lý Partial Fill

    Ở một số broker, lệnh thị trường (TRADE_ACTION_DEAL) có thể bị khớp một phần (partial fill). Code cần kiểm tra result.volume so với request.volume để đảm bảo khớp đủ.

    
    // Kiểm tra partial fill sau OrderSend
    if(result.retcode == TRADE_RETCODE_DONE &&
       MathAbs(result.volume - abs_delta) > 0.001)
    {
        Print("CẢNH BÁO: Partial fill! Yêu cầu=", abs_delta,
              " Thực tế=", result.volume);
        // Tính toán lại phần còn thiếu và thử mở thêm
    }
    

    Tổng Kết Và Lộ Trình Tiếp Theo

    Thuật toán Volume Bias là một trong những công cụ quản trị rủi ro mạnh mẽ nhất trong giao dịch lưới hai chiều. Điểm mấu chốt cần nhớ:

    • ΔV = V_Buy – V_Sell: Công thức đơn giản nhưng quyết định vận mệnh tài khoản
    • GlobalVariable: Chìa khóa để duy trì trạng thái qua các lần restart
    • Không tự động mở khóa: Trader phải can thiệp thủ công sau khi đánh giá thị trường
    • Edge cases: Kiểm tra kỹ vol tối thiểu, trùng lệnh, partial fill

    Ở Bài 4, chúng ta sẽ khám phá thuật toán tiếp theo trong series: Comment String Parser — cơ chế đọc comment từ các vị thế trên sàn để khôi phục trạng thái tầng lưới sau khi EA bị restart. Đây là thuật toán bổ sung hoàn hảo cho Volume Bias vì nó giải quyết câu hỏi: “Sau khi restart, EA biết mình đang ở tầng nào?”


    Bạn Muốn Triển Khai Thuật Toán Này Vào EA Thực Chiến?

    Khóa học MQL5 Nâng Cao của chúng tôi bao gồm toàn bộ 9 thuật toán trong series này, kèm source code hoàn chỉnh, video giảng dạy chi tiết, và hỗ trợ trực tiếp từ instructor.

    Xem Khóa Học MQL5 Nâng Cao →

    Đặng Trí Thanh

    Đặng Trí Thanh

    Giám đốc Công nghệ · DNT Digital · Giảng viên HNDL Hướng Nghiệp Dữ Liệu
    1.398 Bài viết
    15.4k Người theo dõi
    120k+ Lượt đọc

    Đặng Trí Thanh — Founder & CTO · Hướng Nghiệp Dữ Liệu - DNT Digital. Chuyên đà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.

    Bài viết liên quan

    DNT DIGITAL

    🤖 AI CODE: Vibe Code NEEDED! 🚀 🏦 SSI • DNSE • MT5 • Bitget ⚡

    Zalo 0934145100
    Khóa đào tạo
    Hỗ trợ

    Được học lại miễn phí · Hỗ trợ trọn đời · Cập nhật miễn phí

    Đội ngũ hỗ trợ

    Đặng Trí Thanh
    Đặng Trí Thanh
    Giám đốc Công nghệ DNT Digital
    Zalo 0934145100
    Mộng Cầm
    Mộng Cầm
    Hỗ trợ khách hàng · Huấn luyện viên
    Zalo 0927909257
    Khánh Linh
    Khánh Linh
    Hỗ trợ khách hàng · Huấn luyện viên
    Zalo 0927909582