| Bài 3.1: Kiến thức nền tảng MQL5 chuyên sâu

Được viết bởi thanhdt vào ngày 25/04/2026 lúc 23:15 | 38 lượt xem

Phần đầu tiên của khóa học tập trung vào việc làm chủ ngôn ngữ MQL5 – trái tim của mọi hệ thống giao dịch trên MT5:

  • Giới thiệu ngôn ngữ lập trình MQL5 cho MT5.
  • Cách viết Expert Advisor (EA) chuyên nghiệp theo tiêu chuẩn ngành.
  • Quản lý lệnh và đối tượng thị trường (Market Objects) trên MT5.
  • Thiết lập môi trường phát triển (IDE) và kỹ năng Debug mã nguồn hiệu quả.

| Đối tượng phù hợp với khóa học Lập trình MT5 Hedging

Được viết bởi thanhdt vào ngày 25/04/2026 lúc 23:15 | 37 lượt xem

Khóa học “Lập trình MT5 nâng cao – Hedging tự động hóa” được thiết kế đặc biệt cho những ai muốn làm chủ công nghệ giao dịch:

Khóa học này dành cho ai?

  • Trader chuyên nghiệp: Đã sử dụng MT5, có kiến thức MQL5 cơ bản và muốn nâng cấp lên hệ thống tự động hóa chuyên nghiệp.
  • Nhà phát triển EA: Muốn tự xây dựng Bot Hedging riêng cho tài khoản cá nhân, không còn phụ thuộc vào các EA công cộng trên mạng.
  • Sinh viên & Nhà đầu tư Quant: Những người muốn chuyển sang mảng Algo Trading/Quant, cần nền tảng toán học kết hợp lập trình MT5 thực chiến.

🌟 Lợi ích: Bạn sẽ không chỉ học cách viết code, mà còn học cách thiết kế logic toán học cho hedging, giúp loại bỏ hoàn toàn yếu tố cảm xúc trong giao dịch.

| Vì sao nên học Lập trình MT5 nâng cao – Hedging tự động hóa?

Được viết bởi thanhdt vào ngày 25/04/2026 lúc 23:15 | 35 lượt xem

Ngày nay, khi thị trường forex, CFD hay crypto biến động mạnh và khó đoán, nhiều trader nhận ra rằng hệ thống tự động hóa – đặc biệt là hedging tự động trên MT5 – là chìa khóa để giảm rủi ro và duy trì chiến lược ổn định theo thời gian.

1. Giao dịch theo cảm xúc → Máy làm thay bạn

Nhiều trader thậm chí đã có kinh nghiệm vài năm, nhưng vẫn thua lỗ vì: đặt lệnh theo FOMO/FUD, không tuân thủ SL/TP, hoặc quản lý khối lượng sai cách. Một hệ thống hedging tự động trên MT5 sẽ:

  • Luôn tuân thủ quy tắc đã được lập trình (điểm vào, khối lượng, SL/TP, logic đóng lệnh).
  • Không bao giờ “chửi vốn” hay bị tâm lý khi thị trường đảo ngược đột ngột.
  • Hoạt động 24/5, bền bỉ và chính xác tuyệt đối.

2. Hedging không còn là “đánh cược”

Hedging định lượng khác hoàn toàn với việc “mở hai lệnh ngược chiều cho yên tâm”. Khóa học tập trung vào:

  • Xây dựng logic hedging theo vùng: Hedge ở vùng giá break, vùng over-sold/over-bought hoặc vùng trung bình.
  • Tự động hóa quản lý rủi ro: Khối lượng theo % vốn, SL động, trail theo ATR hoặc hỗ trợ/kháng cự.
  • Backtest chuyên sâu: Kiểm tra hiệu suất trên dữ liệu lịch sử trước khi chạy thực tế.

3. Kết hợp MQL5 + Toán học + Quản lý vốn

Đây là bước chuyển mình từ “người viết EA nhỏ lẻ” sang lập trình viên hệ thống đầu tư tự động thực sự:

  • Nâng cấp kỹ năng lập trình MT5 chuyên nghiệp: Quản lý danh sách lệnh, lọc lệnh theo symbol, magic, type.
  • Kết hợp phân tích dữ liệu và toán học để tối ưu chiến lược thay vì “mò” tham số.
  • Tự động gắn label, ghi log và thiết lập cảnh báo thông minh.

| Nhị Quái V9.2.1 Pro: 6 Tuyến Phòng Thủ Toàn Diện Cho Nhà Đầu Tư Quant

Được viết bởi thanhdt vào ngày 25/04/2026 lúc 17:26 | 48 lượt xem

🛡️ 6 Tuyến Phòng Thủ Của Nhị Quái V9

Hệ thống bảo vệ đa tầng giúp nhà đầu tư kiểm soát rủi ro tuyệt đối:

  • Lớp 1: Giãn Step Thông Minh (Dynamic Step) – Tự động giãn khoảng cách Grid khi thị trường biến động mạnh.
  • Lớp 2: Hồi phục Thông minh (Smart Recovery) – Thuật toán tối ưu Lot Size để thoát lệnh nhanh.
  • Lớp 3: Chốt lời ròng (Realized Basket TP) – Quản lý lợi nhuận theo cụm giúp bảo vệ Margin.
  • Lớp 4: Bộ lọc Xu hướng & Khoảng cách (EMA Filter) – Chỉ giao dịch khi đúng xu hướng EMA.
  • Lớp 5: Watchdog (Hard Drawdown Cut) – Dừng giao dịch khẩn cấp khi chạm ngưỡng rủi ro.
  • Lớp 6: Tấm khiên cuối cùng (Auto Lockdown/Hedge) – Tự động Hedge 1:1 bảo vệ tài khoản tuyệt đối.

💻 Mã nguồn MQL5 (V9.2.1 Pro)

Anh/Chị có thể tham khảo mã nguồn chi tiết dưới đây:

//+------------------------------------------------------------------+
//|                                  Bot_Nhi_Quai_V9.2.1_Pro_23_04_1.mq5 |
//|                                  Copyright 2026, NQ              |
//|                    VERSION: 9.2.1 PRO (ULTRA STABLE + SMART RECOVERY)|
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, NQ"
#property link      "https://google.com"
#property version   "9.22"
#property strict

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Arrays\ArrayInt.mqh>

void ReportSymbolSpec() {
    Print("=== KIỂM TRA THÔNG SỐ SÀN (9.21.1 - PRO SMART) ===");
    Print("Symbol: ", _Symbol);
    if(HistorySelect(TimeCurrent()-3600*24, TimeCurrent())) {
        double total_comm = 0, total_vol = 0;
        for(int i=HistoryDealsTotal()-1; i>=0; i--) {
            ulong t = HistoryDealGetTicket(i);
            if(HistoryDealGetString(t, DEAL_SYMBOL) == _Symbol) {
                total_comm += HistoryDealGetDouble(t, DEAL_COMMISSION);
                total_vol += HistoryDealGetDouble(t, DEAL_VOLUME);
            }
        }
        if(total_vol > 0) {
            Print("--- DỮ LIỆU THỰC TẾ (24H QUA) ---");
            Print("Tổng Volume đã đánh: ", NormalizeDouble(total_vol, 2));
            Print("Tổng Phí Hoa Hồng: ", NormalizeDouble(total_comm, 2));
            Print("=> Phí trung bình: ", NormalizeDouble(MathAbs(total_comm/total_vol), 2), " USD / 1.0 Lot");
        }
    }
    Print("======================================");
}

//--- INPUT PARAMETERS ---
input group "=== GENERAL SETTINGS ==="
input string   InpBotName        = "NHI QUAI V9.2.1 PRO";
input string   InpStoragePrefix  = "NHỊ QUÁI V9"; 
input string   InpStartTime      = "00:00";
input string   InpEndTime        = "23:59";
input double   InpMaxSpread      = 50.0;
input double   InpSlippageAllow  = 50.0;
input int      InpMaxPositions   = 500;
input double   InpMaxPriceLimit  = 1000000.0;

input group "=== BUY CLUSTER SETTINGS ==="
input bool     InpBuyEnable      = true;
input double   InpBuyLot         = 0.01;
input double   InpBuyStep        = 5.0;
input double   InpBuyX           = 5.0;
input double   InpBuyMinEqui1    = 8000.0;            
input double   InpBuyMinEqui2    = 8000.0;            
input double   InpBuyMaxLot      = 5.0;               
input int      InpBuyMaxOrders   = 15;                 
input int      InpBuyMagic       = 2111;

input group "=== SELL CLUSTER SETTINGS ==="
input bool     InpSellEnable     = true;
input double   InpSellLot        = 0.01;
input double   InpSellStep       = 5.0;
input double   InpSellX          = 5.0;
input double   InpSellMinEqui1   = 8000.0;            
input double   InpSellMinEqui2   = 8000.0;            
input double   InpSellMaxLot     = 5.0;               
input int      InpSellMaxOrders  = 15;                 
input int      InpSellMagic      = 2112;

input group "=== NHỊ QUÁI (BASKET TP) SETTINGS ==="
input double   InpBuyBasketTP    = 5.0;
input double   InpBuyTPMult      = 1.0;
input double   InpBuyProfitOffset = 0.0;           
input double   InpSellBasketTP   = 5.0;
input double   InpSellTPMult     = 1.0;
input double   InpSellProfitOffset = 0.0;          
input double   InpBasketSafety   = 5.0;

input group "=== WATCHDOG SETTINGS ==="
input double   InpMinProfit      = 5.0;
input double   InHarvestLockNet  = -500.0;         
input double   InpMaxDrawdownCut = 0.0;         
input int      InpCooldownMinutes= 240;            
input bool     InpShowMarkers    = true;

input group "=== CAU HINH HEDGE (GIA TANG) ==="
input bool     InpDynamicStep    = true;           
input double   InpMinStepDistance = 5.0;          

input group "=== DCA DIRECTIONAL SETTINGS ==="
input bool     InpDCAEnable      = true;           
input double   InpDCATarget      = 5.0;           
input double   InpLotMultiplier  = 1.5;            

input group "=== TREND PREDICTION (SMART FILTER) ==="
input bool     InpUseTrendFilter = false;           
input int      InpMAPeriod       = 200;            
input ENUM_TIMEFRAMES InpMATF    = PERIOD_H1;      
input int      InpMAMethod       = MODE_EMA;       
input int      InpMAAppliedPrice = PRICE_CLOSE;    
input double   InpMADistanceLimit = 15.0;          

input group "=== SMART RECOVERY (NEW) ==="
input bool     InpEnableSmartRec = true;           // Kich hoat phuc hoi thong minh
input double   InpMaxRecMult     = 3.0;            // Toi da gap 3 lan Lot DCA
input double   InpTargetRetrace  = 2.0;            // Khoang hoi mong muon (Gia)
input int      InpSmartRecStart  = 3;              // Bat dau tu lenh thu may (Default: 3)

//--- GLOBAL VARIABLES ---
CTrade         m_trade_buy, m_trade_sell;
CSymbolInfo    m_symbol;
CPositionInfo  m_position;

int            m_ma_handle = INVALID_HANDLE;

double         m_buy_p0 = 0, m_sell_p0 = 0;
int            m_buy_reset_count = 0, m_sell_reset_count = 0;
int            m_buy_tp_count_x = 0, m_sell_tp_count_x = 0;
bool           m_buy_hedged = false, m_sell_hedged = false;

int            m_buy_surplus_count = 0, m_sell_surplus_count = 0;
double         m_buy_surplus_lot = 0, m_sell_surplus_lot = 0;
double         m_buy_realized_profit = 0, m_sell_realized_profit = 0; 

ulong          m_pos_buy_tickets[], m_pos_sell_tickets[];
int            m_pos_buy_steps[], m_pos_sell_steps[];
ENUM_POSITION_TYPE m_pos_buy_types[], m_pos_sell_types[];

bool           m_need_history_scan_buy = true;
bool           m_need_history_scan_sell = true;
datetime       m_last_trade_tick[3000];
int            m_last_trade_step[3000];

//--- HELPERS ---
bool IsClusterLocked(int m) { return GlobalVariableCheck(GetGVPrefix(m) + "_Locked"); }
void SetClusterLocked(int m, bool l) { string gv = GetGVPrefix(m) + "_Locked"; if(l) GlobalVariableSet(gv, 1.0); else GlobalVariableDel(gv); }
string GetGVPrefix(int magic) { return InpStoragePrefix + "_" + IntegerToString((int)AccountInfoInteger(ACCOUNT_LOGIN)) + "_" + IntegerToString(magic); }

int OnInit()
{
    if(!m_symbol.Name(_Symbol)) return(INIT_FAILED);
    m_trade_buy.SetExpertMagicNumber(InpBuyMagic);
    m_trade_buy.SetDeviationInPoints((ulong)InpSlippageAllow);
    m_trade_sell.SetExpertMagicNumber(InpSellMagic);
    m_trade_sell.SetDeviationInPoints((ulong)InpSlippageAllow);
    
    m_symbol.RefreshRates();
    double current_bid = m_symbol.Bid();

    string gv_buy_p0 = GetGVPrefix(InpBuyMagic) + "_P0";
    string gv_sell_p0 = GetGVPrefix(InpSellMagic) + "_P0";

    if(GlobalVariableCheck(gv_buy_p0)) { m_buy_p0 = GlobalVariableGet(gv_buy_p0); if(m_buy_p0 < 100 || m_buy_p0 > InpMaxPriceLimit) { m_buy_p0 = current_bid; GlobalVariableSet(gv_buy_p0, m_buy_p0); } }
    else { m_buy_p0 = current_bid; GlobalVariableSet(gv_buy_p0, m_buy_p0); }
    
    if(GlobalVariableCheck(gv_sell_p0)) { m_sell_p0 = GlobalVariableGet(gv_sell_p0); if(m_sell_p0 < 100 || m_sell_p0 > InpMaxPriceLimit) { m_sell_p0 = current_bid; GlobalVariableSet(gv_sell_p0, m_sell_p0); } }
    else { m_sell_p0 = current_bid; GlobalVariableSet(gv_sell_p0, m_sell_p0); }

    string gv_start_buy = GetGVPrefix(InpBuyMagic) + "_StartTime";
    string gv_start_sell = GetGVPrefix(InpSellMagic) + "_StartTime";
    if(!GlobalVariableCheck(gv_start_buy)) GlobalVariableSet(gv_start_buy, (double)TimeCurrent());
    if(!GlobalVariableCheck(gv_start_sell)) GlobalVariableSet(gv_start_sell, (double)TimeCurrent());

    if(GlobalVariableCheck(GetGVPrefix(InpBuyMagic)+"_ResetCount")) m_buy_reset_count = (int)GlobalVariableGet(GetGVPrefix(InpBuyMagic)+"_ResetCount");
    if(GlobalVariableCheck(GetGVPrefix(InpSellMagic)+"_ResetCount")) m_sell_reset_count = (int)GlobalVariableGet(GetGVPrefix(InpSellMagic)+"_ResetCount");
    if(GlobalVariableCheck(GetGVPrefix(InpBuyMagic)+"_HitXCount")) m_buy_tp_count_x = (int)GlobalVariableGet(GetGVPrefix(InpBuyMagic)+"_HitXCount");
    if(GlobalVariableCheck(GetGVPrefix(InpSellMagic)+"_HitXCount")) m_sell_tp_count_x = (int)GlobalVariableGet(GetGVPrefix(InpSellMagic)+"_HitXCount");
    
    for(int i=0; i<3000; i++) { m_last_trade_tick[i] = 0; m_last_trade_step[i] = -999999; }

    if(InpUseTrendFilter) {
        m_ma_handle = iMA(_Symbol, InpMATF, InpMAPeriod, 0, (ENUM_MA_METHOD)InpMAMethod, (ENUM_APPLIED_PRICE)InpMAAppliedPrice);
    }

    EventSetTimer(1);
    return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) { EventKillTimer(); if(m_ma_handle != INVALID_HANDLE) IndicatorRelease(m_ma_handle); }

void OnTick()
{
    if(!IsTradingTime()) return;
    if(!m_symbol.RefreshRates() || m_symbol.Spread()*m_symbol.Point() > InpMaxSpread) return;
    string pos_sym = _Symbol;
    
    string gv_cooldown = InpStoragePrefix + "_" + IntegerToString((int)AccountInfoInteger(ACCOUNT_LOGIN)) + "_CooldownUntil";
    if(GlobalVariableCheck(gv_cooldown)) {
        datetime cooldown_until = (datetime)GlobalVariableGet(gv_cooldown);
        if(TimeCurrent() < cooldown_until) return;
        else GlobalVariableDel(gv_cooldown);
    }

    CacheAllPositions();
    if(InpBuyEnable) ProcessCluster(InpBuyMagic);
    if(InpSellEnable) ProcessCluster(InpSellMagic);
}

void OnTimer() { if(TimeCurrent() % 5 == 0) DrawDashboard(); }
void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { m_need_history_scan_buy = true; m_need_history_scan_sell = true; } }

void ProcessCluster(int magic)
{
    CheckClusterBasketTP(magic);
    double p0 = (magic == InpBuyMagic) ? m_buy_p0 : m_sell_p0;
    double base_step = (magic == InpBuyMagic) ? InpBuyStep : InpSellStep;
    double step_s = base_step;
    double pr_ref = m_symbol.Bid();

    int b_total = 0, s_total = 0; CountTotalOrders(magic, b_total, s_total);
    int cur_s = (int)MathRound((pr_ref - p0) / base_step);
    double equity_live = AccountInfoDouble(ACCOUNT_EQUITY);
    double min_eq1 = (magic == InpBuyMagic) ? InpBuyMinEqui1 : InpSellMinEqui1;
    double min_eq2 = (magic == InpBuyMagic) ? InpBuyMinEqui2 : InpSellMinEqui2;

    if(InpDynamicStep) {
        int g_orders = (magic == InpBuyMagic) ? b_total : s_total;
        if(g_orders >= 3 && g_orders < 6) step_s *= 2.0;    // Bat dau tu lenh 4 (khi dang co 3 lenh)
        else if(g_orders >= 6) step_s *= 3.0;               // Bat dau tu lenh 7 (khi dang co 6 lenh)
    }

    if(MathAbs(cur_s) > 20) {
        string prefix = GetGVPrefix(magic); double new_p0 = pr_ref;
        GlobalVariableSet(prefix + "_P0", new_p0);
        if(magic == InpBuyMagic) m_buy_p0 = new_p0; else m_sell_p0 = new_p0;
        cur_s = 0; p0 = new_p0;
    }
    UpdateTraversedRange(magic, cur_s);

    bool trigger_hedge = (min_eq2 > 0 && equity_live <= min_eq2);
    if(trigger_hedge) {
        CheckDynamicHedge(magic); 
        if(!IsClusterLocked(magic)) { SetClusterLocked(magic, true); Print("!!! LOCKDOWN !!! ", magic); }
        if(magic == InpBuyMagic) m_buy_hedged = true; else m_sell_hedged = true;
        return;
    }
    
    if(IsClusterLocked(magic)) {
        double bv=0, sv=0; CalculateVolume(magic, bv, sv); double delta = MathAbs(NormalizeDouble(bv - sv, 2));
        if(delta > 0.01 || (bv == 0 && sv == 0)) { SetClusterLocked(magic, false); if(magic == InpBuyMagic) m_buy_hedged = false; else m_sell_hedged = false; }
        else { if(magic == InpBuyMagic) m_buy_hedged = true; else m_sell_hedged = true; return; }
    } else { if(magic == InpBuyMagic) m_buy_hedged = false; else m_sell_hedged = false; }

    bool trigger_stop = (min_eq1 > 0 && equity_live <= min_eq1);
    if(trigger_stop) return;

    double buy_lot = NormalizeLot(((magic==InpBuyMagic)?InpBuyLot:InpSellLot) * MathPow(InpLotMultiplier, b_total));
    double sell_lot = NormalizeLot(((magic==InpBuyMagic)?InpBuyLot:InpSellLot) * MathPow(InpLotMultiplier, s_total));

    // --- SMART RECOVERY LOGIC (V9.2.1 Integration) ---
    if(InpEnableSmartRec) {
        double floating = 0; 
        for(int i=0; i<PositionsTotal(); i++) if(m_position.SelectByIndex(i) && m_position.Magic() == magic && m_position.Symbol() == _Symbol) floating += (m_position.Profit() + m_position.Swap() + m_position.Commission());
        
        if(floating < 0) {
            double target_p = ((magic == InpBuyMagic ? InpBuyBasketTP : InpSellBasketTP) * (magic == InpBuyMagic ? InpBuyTPMult : InpSellTPMult)) + InpBasketSafety;
            double req_p = target_p - floating;
            double point_val = m_symbol.TickValue() / m_symbol.TickSize();
            
            if(b_total >= InpSmartRecStart && b_total > s_total) {
                double opt_lot = req_p / (InpTargetRetrace * point_val);
                if(opt_lot > buy_lot) buy_lot = MathMin(opt_lot, buy_lot * InpMaxRecMult);
            } else if(s_total >= InpSmartRecStart && s_total > b_total) {
                double opt_lot = req_p / (InpTargetRetrace * point_val);
                if(opt_lot > sell_lot) sell_lot = MathMin(opt_lot, sell_lot * InpMaxRecMult);
            }
            buy_lot = NormalizeLot(buy_lot); sell_lot = NormalizeLot(sell_lot);
        }
    }

    double last_entry_price = 0;
    for(int i=PositionsTotal()-1; i>=0; i--) if(m_position.SelectByIndex(i) && m_position.Magic() == magic && StringCompare(m_position.Symbol(), _Symbol, false) == 0) { last_entry_price = m_position.PriceOpen(); break; }
    double dist_real = (last_entry_price > 0) ? MathAbs(pr_ref - last_entry_price) : 999999;
    double mandatory_dist = (InpDynamicStep && step_s > InpMinStepDistance) ? step_s : InpMinStepDistance;
    if(mandatory_dist > 0 && dist_real < mandatory_dist && last_entry_price > 0) return;

    CTrade *trade = (magic == InpBuyMagic) ? &m_trade_buy : &m_trade_sell;
    int targets[2]; targets[0] = 0; targets[1] = cur_s;
    
    int trend_dir = 0; bool is_panic = false;
    if(InpUseTrendFilter && m_ma_handle != INVALID_HANDLE) {
        double ma[]; if(CopyBuffer(m_ma_handle, 0, 0, 1, ma) > 0) {
            trend_dir = (pr_ref > ma[0]) ? 1 : -1;
            if(InpMADistanceLimit > 0 && MathAbs(pr_ref - ma[0]) >= InpMADistanceLimit) is_panic = true;
        }
    }

    for(int i=0; i<2; i++) {
        int s = targets[i];
        if(MathAbs(s - (pr_ref - p0) / base_step) > 0.65) continue; 
        int b_c, s_c; CountOrdersAtStep(magic, s, b_c, s_c);
        if(TimeCurrent() - m_last_trade_tick[magic % 3000] < 2) continue;

        string c = InpBotName + ((magic == InpBuyMagic) ? "_B_S" : "_S_S") + IntegerToString(s);
        bool allow_b = !is_panic; bool allow_s = !is_panic;
        if(InpUseTrendFilter && trend_dir != 0) { if(trend_dir == -1 && b_total >= 3) allow_b = false; if(trend_dir == 1 && s_total >= 3) allow_s = false; }
        if(InpBuyMaxOrders > 0 && b_total >= InpBuyMaxOrders) allow_b = false;
        if(InpSellMaxOrders > 0 && s_total >= InpSellMaxOrders) allow_s = false;
        if(magic == InpBuyMagic) allow_s = false; else allow_b = false;
        
        if(IsClusterLocked(magic)) { allow_b = false; allow_s = false; }

        if(allow_b && b_c < (s == 0 ? 2 : 1)) {
            if(s != 0 && pr_ref < p0 && b_c < 1) { if(trade.Buy(buy_lot,_Symbol,0,0,0,c)) { m_last_trade_tick[magic%3000]=TimeCurrent(); AddCacheTicket(magic,trade.ResultOrder(),s,POSITION_TYPE_BUY); break; } }
            if(s != 0 && pr_ref > p0 && b_c < 2) { if(trade.Buy(buy_lot,_Symbol,0,0,0,c)) { m_last_trade_tick[magic%3000]=TimeCurrent(); AddCacheTicket(magic,trade.ResultOrder(),s,POSITION_TYPE_BUY); break; } }
            if(s == 0 && b_c < 2) { if(trade.Buy(buy_lot,_Symbol,0,0,0,c)) { m_last_trade_tick[magic%3000]=TimeCurrent(); AddCacheTicket(magic,trade.ResultOrder(),s,POSITION_TYPE_BUY); break; } }
        }
        if(allow_s && s_c < (s == 0 ? 2 : 1)) {
            if(s != 0 && pr_ref > p0 && s_c < 1) { if(trade.Sell(sell_lot,_Symbol,0,0,0,c)) { m_last_trade_tick[magic%3000]=TimeCurrent(); AddCacheTicket(magic,trade.ResultOrder(),s,POSITION_TYPE_SELL); break; } }
            if(s != 0 && pr_ref < p0 && s_c < 2) { if(trade.Sell(sell_lot,_Symbol,0,0,0,c)) { m_last_trade_tick[magic%3000]=TimeCurrent(); AddCacheTicket(magic,trade.ResultOrder(),s,POSITION_TYPE_SELL); break; } }
            if(s == 0 && s_c < 2) { if(trade.Sell(sell_lot,_Symbol,0,0,0,c)) { m_last_trade_tick[magic%3000]=TimeCurrent(); AddCacheTicket(magic,trade.ResultOrder(),s,POSITION_TYPE_SELL); break; } }
        }
    }
}

void CheckClusterBasketTP(int magic) {
    string gv_start = GetGVPrefix(magic) + "_StartTime"; datetime start_time = GlobalVariableCheck(gv_start) ? (datetime)GlobalVariableGet(gv_start) : 0;
    if(magic == InpBuyMagic ? m_need_history_scan_buy : m_need_history_scan_sell) {
        double realized = 0; if(HistorySelect(start_time, TimeCurrent())) {
            for(int i=HistoryDealsTotal()-1; i>=0; i--) { ulong t = HistoryDealGetTicket(i); if(HistoryDealGetString(t, DEAL_SYMBOL) == _Symbol && HistoryDealGetInteger(t, DEAL_MAGIC) == magic) realized += (HistoryDealGetDouble(t, DEAL_PROFIT) + HistoryDealGetDouble(t, DEAL_SWAP) + HistoryDealGetDouble(t, DEAL_COMMISSION)); }
        }
        realized += (magic == InpBuyMagic ? InpBuyProfitOffset : InpSellProfitOffset);
        if(magic == InpBuyMagic) { m_buy_realized_profit = realized; m_need_history_scan_buy = false; } else { m_sell_realized_profit = realized; m_need_history_scan_sell = false; }
    }
    double floating = 0; for(int i=PositionsTotal()-1; i>=0; i--) if(m_position.SelectByIndex(i) && m_position.Magic() == magic && StringCompare(m_position.Symbol(), _Symbol, false) == 0) floating += (m_position.Profit() + m_position.Swap() + m_position.Commission());
    double total_net = (magic == InpBuyMagic ? m_buy_realized_profit : m_sell_realized_profit) + floating;
    double target = ((magic == InpBuyMagic ? InpBuyBasketTP : InpSellBasketTP) * (magic == InpBuyMagic ? InpBuyTPMult : InpSellTPMult)) + InpBasketSafety;
    if(total_net >= target && target > 0) ResetCluster(magic);
}

void CheckDynamicHedge(int m) {
    double bv=0, sv=0; CalculateVolume(m, bv, sv); double delta = NormalizeDouble(bv - sv, 2);
    CTrade *tr = (m == InpBuyMagic) ? &m_trade_buy : &m_trade_sell;
    if(MathAbs(delta) >= 0.01) {
        string comment = "DYN_HEDGE_" + IntegerToString(m);
        if(delta > 0) { if(tr.Sell(MathAbs(delta), _Symbol, 0, 0, 0, comment)) Print(">>> HEDGE: Added Sell ", MathAbs(delta)); }
        else { if(tr.Buy(MathAbs(delta), _Symbol, 0, 0, 0, comment)) Print(">>> HEDGE: Added Buy ", MathAbs(delta)); }
    }
}

void ResetCluster(int magic) {
    CTrade tr; tr.SetExpertMagicNumber(magic); for(int i=PositionsTotal()-1; i>=0; i--) if(m_position.SelectByIndex(i) && m_position.Magic() == magic && StringCompare(m_position.Symbol(), _Symbol, false) == 0) tr.PositionClose(m_position.Ticket());
    string pr = GetGVPrefix(magic); GlobalVariableSet(pr + "_StartTime", (double)TimeCurrent() + 1);
    GlobalVariableDel(pr + "_P0"); GlobalVariableDel(pr + "_LastX");
    double new_p0 = m_symbol.Bid(); GlobalVariableSet(pr + "_P0", new_p0);
    if(magic == InpBuyMagic) { m_buy_p0 = new_p0; m_buy_reset_count++; } else { m_sell_p0 = new_p0; m_sell_reset_count++; }
    m_need_history_scan_buy = true; m_need_history_scan_sell = true;
}

void CheckXProfit(int magic, double p0, double x_sz, double pr) { TP_Logic(magic); int cur_x = (int)MathFloor(MathAbs(pr - p0) / x_sz); string gv = GetGVPrefix(magic) + "_LastX"; int last_x = GlobalVariableCheck(gv) ? (int)GlobalVariableGet(gv) : -1; if(cur_x != last_x) { GlobalVariableSet(gv, (double)cur_x); m_need_history_scan_buy = true; m_need_history_scan_sell = true; } }

void TP_Logic(int magic) {
    int min_s=0, max_s=0; GetTraversedRange(magic, min_s, max_s);
    for(int s = min_s; s <= max_s; s++) {
        int b_cnt=0, s_cnt=0; CountOrdersAtStep(magic, s, b_cnt, s_cnt);
        if(b_cnt >= 2) HarvestSurplusAtStep(magic, s, POSITION_TYPE_BUY, b_cnt - 1);
        if(s_cnt >= 2) HarvestSurplusAtStep(magic, s, POSITION_TYPE_SELL, s_cnt - 1);
    }
}

void HarvestSurplusAtStep(int magic, int s_idx, ENUM_POSITION_TYPE t, int count) {
    int closed = 0; CTrade tr; tr.SetExpertMagicNumber(magic);
    for(int i=PositionsTotal()-1; i>=0; i--) {
        if(m_position.SelectByIndex(i) && StringCompare(m_position.Symbol(), _Symbol, false) == 0 && (m_position.Magic() == InpBuyMagic || m_position.Magic() == InpSellMagic)) {
            if(GetStepFromComment(m_position.Comment()) == s_idx && m_position.PositionType() == t) {
                double net = m_position.Profit() + m_position.Swap() + m_position.Commission();
                if(net >= InpMinProfit) { if(tr.PositionClose(m_position.Ticket())) closed++; }
            }
        }
    }
}

void CacheAllPositions() {
    ArrayResize(m_pos_buy_tickets, 0); ArrayResize(m_pos_sell_tickets, 0);
    for(int i=0; i<PositionsTotal(); i++) if(m_position.SelectByIndex(i) && StringCompare(m_position.Symbol(), _Symbol, false) == 0) {
        int m = (int)m_position.Magic();
        if(m == InpBuyMagic) { int n=ArraySize(m_pos_buy_tickets); ArrayResize(m_pos_buy_tickets,n+1); ArrayResize(m_pos_buy_steps,n+1); ArrayResize(m_pos_buy_types,n+1); m_pos_buy_tickets[n]=m_position.Ticket(); m_pos_buy_steps[n]=GetStepFromComment(m_position.Comment()); m_pos_buy_types[n]=m_position.PositionType(); }
        else if(m == InpSellMagic) { int n=ArraySize(m_pos_sell_tickets); ArrayResize(m_pos_sell_tickets,n+1); ArrayResize(m_pos_sell_steps,n+1); ArrayResize(m_pos_sell_types,n+1); m_pos_sell_tickets[n]=m_position.Ticket(); m_pos_sell_steps[n]=GetStepFromComment(m_position.Comment()); m_pos_sell_types[n]=m_position.PositionType(); }
    }
}

void CountOrdersAtStep(int magic, int s_idx, int &b, int &s) {
    b = 0; s = 0; int lim = (magic==InpBuyMagic)?ArraySize(m_pos_buy_tickets):ArraySize(m_pos_sell_tickets);
    for(int i=0; i<lim; i++) if((magic==InpBuyMagic?m_pos_buy_steps[i]:m_pos_sell_steps[i]) == s_idx) { if((magic==InpBuyMagic?m_pos_buy_types[i]:m_pos_sell_types[i]) == POSITION_TYPE_BUY) b++; else s++; }
}

int GetStepFromComment(string c) { int cur=0, last=-1; while((cur=StringFind(c,"_S",cur))!=-1){ last=cur; cur+=1; } if(last!=-1){ return (int)StringToInteger(StringSubstr(c,last+2)); } return 0; }
void SetLastStep(int m, int s) { GlobalVariableSet(GetGVPrefix(m)+"_LastStep", (double)s); }
void GetTraversedRange(int m, int &mi, int &ma) { string k_mi=GetGVPrefix(m)+"_MinStep", k_ma=GetGVPrefix(m)+"_MaxStep"; mi=GlobalVariableCheck(k_mi)?(int)GlobalVariableGet(k_mi):0; ma=GlobalVariableCheck(k_ma)?(int)GlobalVariableGet(k_ma):0; }
void UpdateTraversedRange(int m, int s) { string mi=GetGVPrefix(m)+"_MinStep", ma=GetGVPrefix(m)+"_MaxStep"; if(!GlobalVariableCheck(mi)||s<GlobalVariableGet(mi)) GlobalVariableSet(mi, (double)s); if(!GlobalVariableCheck(ma)||s>GlobalVariableGet(ma)) GlobalVariableSet(ma, (double)s); }
void CalculateVolume(int m, double &bv, double &sv) { bv=0; sv=0; for(int i=0;i<PositionsTotal();i++) if(m_position.SelectByIndex(i)&&m_position.Magic()==m){ if(m_position.PositionType()==POSITION_TYPE_BUY) bv+=m_position.Volume(); else sv+=m_position.Volume(); } }
bool IsTradingTime() { MqlDateTime dt; TimeToStruct(TimeCurrent(),dt); string t=StringFormat("%02d:%02d",dt.hour,dt.min); return (t>=InpStartTime && t<=InpEndTime); }
void AddCacheTicket(int m, ulong t, int s, ENUM_POSITION_TYPE ty) { CacheAllPositions(); }
double NormalizeLot(double vol) { double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); if(step <= 0) return vol; double lot = MathRound(vol / step) * step; return NormalizeDouble(lot, 2); }
void CountTotalOrders(int magic, int &b, int &s) { b = 0; s = 0; for(int i=0; i<PositionsTotal(); i++) if(m_position.SelectByIndex(i) && m_position.Magic() == magic && StringCompare(m_position.Symbol(), _Symbol, false) == 0) { if(m_position.PositionType() == POSITION_TYPE_BUY) b++; else s++; } }

void DrawDashboard() {
    double b_f = 0, s_f = 0; for(int i=0; i<PositionsTotal(); i++) if(m_position.SelectByIndex(i) && StringCompare(m_position.Symbol(), _Symbol, false) == 0) { double p = m_position.Profit() + m_position.Swap() + m_position.Commission(); if(m_position.Magic() == InpBuyMagic) b_f += p; else if(m_position.Magic() == InpSellMagic) s_f += p; }
    string t = "=== NHI QUAI V9.2.1 PRO (V23.04_1) ===\n";
    t += StringFormat("Buy Cluster: Float %.2f | %s\n", b_f, (m_buy_hedged?"HEDGED":"NORMAL"));
    t += StringFormat("Sell Cluster: Float %.2f | %s\n", s_f, (m_sell_hedged?"HEDGED":"NORMAL"));
    Comment(t);
}

© 2026 Hướng Nghiệp Dữ Liệu | Hệ thống giao dịch tự động chuyên nghiệp.

| Quản lý vốn & Rủi ro thực chiến: Tự động hóa Hedging (Buổi 0.3)

Được viết bởi thanhdt vào ngày 25/04/2026 lúc 11:56 | 36 lượt xem

🛡️

Quản lý vốn & Rủi ro thực chiến: Tự động hóa Hedging

PHẦN 0: PHỤ ĐẠO — Buổi 0.3

Trong giao dịch, quản lý vốn là yếu tố sống còn. Bài học này hướng dẫn xây dựng hệ thống Auto Hedge tự động bảo vệ tài khoản khỏi các cú sụt giảm mạnh (Drawdown) bất ngờ.

📊 Mục tiêu bài học

  • ✅ Kiểm soát Equity thời gian thực.
  • ✅ Thuật toán tính Net Lot đối ứng.
  • ✅ Thông báo khẩn cấp qua Telegram.

💻 Mã nguồn MQL5: Auto Hedge Protection

//+------------------------------------------------------------------+
//|                                     Buoi 0.3_1 Canh bao va Hedge |
//|                                  Copyright 2026, DNT Quant Trade |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade trade;

input double InpMinEquity = 500.0; // Ngưỡng Equity kích hoạt Hedge

void OnTick() {
    double equity = AccountInfoDouble(ACCOUNT_EQUITY);
    if(equity < InpMinEquity) ExecuteAutoHedge(equity);
}

void ExecuteAutoHedge(double currentEquity) {
    double buyLots = 0, sellLots = 0;
    for(int i = PositionsTotal()-1; i >= 0; i--) {
        if(PositionSelectByTicket(PositionGetTicket(i))) {
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) buyLots += PositionGetDouble(POSITION_VOLUME);
            else sellLots += PositionGetDouble(POSITION_VOLUME);
        }
    }
    double net = buyLots - sellLots;
    if(MathAbs(net) > 0.001) {
        if(net > 0) trade.Sell(net, _Symbol);
        else trade.Buy(MathAbs(net), _Symbol);
        Print("🚨 Auto Hedge Activated at $", currentEquity);
    }
}
            

| Hướng dẫn Kết nối MT5 với Telegram: Dashboard & Input tham số (Buổi 0.2)

Được viết bởi thanhdt vào ngày 19/04/2026 lúc 22:03 | 44 lượt xem

Kết nối MT5 với Telegram: Dashboard & Input Tham Số

Buổi 0.2: Infrastructure and Connectivity

Trong bài học này, chúng ta sẽ thực hành cách kết nối MetaTrader 5 với Telegram để gửi thông báo Dashboard tự động. Mã nguồn này cho phép tùy chỉnh Token và ChatID trực tiếp từ bảng tham số (Inputs) mà không cần can thiệp vào code.

🚀 Các bước thực hiện

  • 1
    Tạo Bot Telegram qua @BotFather để lấy API Token.
  • 2
    Lấy Chat ID của bạn (sử dụng bot @userinfobot).
  • 3
    Thêm URL https://api.telegram.org vào danh sách Allow URLs trong MT5.

💻 Mã nguồn MQL5 (Buổi 0.2)

MQL5 Source Code
//+------------------------------------------------------------------+
//|                                                MT5_Telegram.mq5 |
//|                                  Copyright 2026, DNT Quant Trade |
//+------------------------------------------------------------------+
#property version   "1.00"
#property strict

//--- INPUTS
input string InpToken  = "YOUR_BOT_TOKEN"; // Telegram Token
input string InpChatID = "YOUR_CHAT_ID";   // Telegram ChatID

int OnInit() {
   EventSetTimer(10);
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {
   EventKillTimer();
}

void OnTimer() {
   if(IsStopped()) return;

   string accName = AccountInfoString(ACCOUNT_NAME);
   double profit  = AccountInfoDouble(ACCOUNT_PROFIT);
   string timeNow = TimeToString(TimeLocal(), TIME_DATE|TIME_SECONDS);
   
   string dashboard = "=== DASHBOARD TELEGRAM ===\n" +
                      "👤 Account: " + accName + "\n" +
                      "💰 Floating: " + DoubleToString(profit, 2) + "\n" +
                      "⏰ Time: " + timeNow;
   
   Comment(dashboard);
   SendTelegram(dashboard);
}

void SendTelegram(string message) {
   StringReplace(message, "\n", "%0A");
   StringReplace(message, " ", "%20");

   string url = "https://api.telegram.org/bot" + InpToken + 
                "/sendMessage?chat_id=" + InpChatID + "&text=" + message;
   
   char data[], result[];
   string headers;
   WebRequest("GET", url, NULL, NULL, 3000, data, 0, result, headers);
}
            

⚠️ Lưu ý quan trọng:
Đừng quên cấp quyền cho MT5 truy cập URL của Telegram:
Tools -> Options -> Expert Advisors -> Tích chọn Allow WebRequest và thêm https://api.telegram.org.

© 2026 DNT Quant Trade — Kiến tạo tương lai
huongnghiepdulieu.com