Questions and answers about EA using martingale method

 

I am creating a trading EA based on the martingale method. However, the following order is not being calculated according to martingale to offset the loss from the previous order. I would greatly appreciate your help, as there seems to be an error in my EA. Thanks !


//+------------------------------------------------------------------+
//| CustomSellSignal.mq5                                             |
//| Tên của bạn                                                      |
//| Công ty của bạn                                                  |
//+------------------------------------------------------------------+
#property copyright "Tên của bạn"
#property link      "Trang web của bạn"
#property version   "1.02"
#property strict

// Tham số đầu vào
input int    sma_length = 12;        // Chu kỳ của Đường Trung Bình Đơn Giản (SMA)
input int    max_bars_before_cancel = 5; // Số lượng nến trước khi hủy lệnh
input double martingale_multiplier = 2; // Hệ số martingale
ulong last_order_ticket = 0;      // Số hiệu của lệnh gần nhất

// Khai báo handle của chỉ báo đường trung bình
int sma_handle;

// Khai báo các biến chứa dữ liệu nến
double n1_open, n1_close, n1_low, n1_high;
double n2_low, n2_close, n2_open, n2_high;
double n3_low, n3_close, n3_open, n3_high;
double n4_low, n4_close, n4_open, n4_high;
double n5_low, n5_close, n5_open, n5_high;

// Khai báo các biến cho giao dịch
double entry_level, stop_loss_level, take_profit_level;
bool condition_sell;

// Khai báo yêu cầu và kết quả giao dịch
MqlTradeRequest request;
MqlTradeResult result;

// Khai báo mảng để theo dõi các lệnh chờ
datetime order_placed_time[];
ulong order_ticket[];
int order_placed_bar_index[];

//+------------------------------------------------------------------+
//| Hàm khởi tạo Expert Advisor                                      |
//+------------------------------------------------------------------+
int OnInit()
{
    // Tạo chỉ báo đường trung bình
    sma_handle = iMA(NULL, 0, sma_length, 0, MODE_SMA, PRICE_CLOSE);
    if (sma_handle == INVALID_HANDLE)
    {
        Print("Không thể tạo handle cho chỉ báo SMA");
        return INIT_FAILED;
    }

    // Khởi tạo các mảng
    ArraySetAsSeries(order_placed_time, true);
    ArraySetAsSeries(order_ticket, true);
    ArraySetAsSeries(order_placed_bar_index, true);

    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Hàm hủy Expert Advisor                                           |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    // Giải phóng handle của chỉ báo đường trung bình
    IndicatorRelease(sma_handle);
}

// Biến cờ để kiểm tra xem lệnh đã được đặt hay chưa
bool order_placed = false;
datetime last_time = 0; // Theo dõi thời gian của nến cuối

// Khai báo biến toàn cục cho rủi ro và số tiền thua lỗ
double risk_amount = 10.0; // Khởi tạo với giá trị mặc định
double last_loss_amount = 0; // Biến lưu số tiền thua lỗ

// Khai báo biến toàn cục để theo dõi số lần lệnh thua
int loss_streak = 0;

// Biến lưu trữ tổng số tiền lỗ trước đó
double total_loss = 0.0; // Khởi tạo với giá trị 
// Hàm tính toán risk_amount
void CalculateRiskAmount()
{
    // Chọn toàn bộ lịch sử
    if (HistorySelect(0, TimeCurrent()))
    {
        int closedOrdersCount = HistoryOrdersTotal();
        Print("Số lệnh đã đóng: ", closedOrdersCount);
        
        if (closedOrdersCount > 0)
        {
            if (HistoryOrderSelect(closedOrdersCount - 1))
            {
                double last_order_profit = HistoryDealGetDouble(HistoryOrderGetInteger(closedOrdersCount - 0, ORDER_TICKET), DEAL_PROFIT);
                Print("Lợi nhuận lệnh gần nhất: ", last_order_profit);
                
                if (last_order_profit < 0) 
                {
                    // Lệnh thua
                    last_loss_amount = MathAbs(last_order_profit);
                    risk_amount = last_loss_amount * martingale_multiplier; // Áp dụng martingale
                    loss_streak++; // Tăng số lần thua
                    Print("Cập nhật risk_amount: ", risk_amount, " với martingale_multiplier: ", martingale_multiplier);
                } 
                else 
                {
                    // Lệnh thắng
                    risk_amount = 10; // Reset về 10 USD
                    loss_streak = 0; // Reset số lần thua
                    Print("Reset risk_amount về 10");
                }
            }
        }
        else
        {
            Print("Không có lệnh nào đã đóng trong lịch sử.");
        }
    }
}

//+------------------------------------------------------------------+
//| Hàm thực thi lệnh theo từng tick                                 |
//+------------------------------------------------------------------+
void OnTick()
{
    // Gọi hàm cập nhật risk_amount
    CalculateRiskAmount();

    // Kiểm tra xem có đủ số lượng nến để tính toán hay không
    int bars = iBars(NULL, 0); 
    if (bars < sma_length + max_bars_before_cancel + 1)
    {
        return;
    }

    // Lấy thời gian của nến hiện tại
    datetime current_time = iTime(NULL, 0, 0);

    // Kiểm tra xem nến mới đã bắt đầu hay chưa
    if (current_time != last_time)
    {
        last_time = current_time;
        order_placed = false; // Đặt lại cờ khi bắt đầu nến mới
    }

    // Lấy dữ liệu của các nến
    n1_open = iOpen(NULL, 0, 1);
    n1_close = iClose(NULL, 0, 1);
    n1_low = iLow(NULL, 0, 1);
    n1_high = iHigh(NULL, 0, 1);

    n2_low = iLow(NULL, 0, 2);
    n2_close = iClose(NULL, 0, 2);
    n2_open = iOpen(NULL, 0, 2);
    n2_high = iHigh(NULL, 0, 2);

    n3_low = iLow(NULL, 0, 3);
    n3_close = iClose(NULL, 0, 3);
    n3_open = iOpen(NULL, 0, 3);
    n3_high = iHigh(NULL, 0, 3);

    n4_low = iLow(NULL, 0, 4);
    n4_close = iClose(NULL, 0, 4);
    n4_open = iOpen(NULL, 0, 4);
    n4_high = iHigh(NULL, 0, 4);

    n5_low = iLow(NULL, 0, 5);
    n5_close = iClose(NULL, 0, 5);
    n5_open = iOpen(NULL, 0, 5);
    n5_high = iHigh(NULL, 0, 5);
    
    // Tính toán SMA
    double sma_buffer[];
    if (CopyBuffer(sma_handle, 0, 0, sma_length + 1, sma_buffer) <= 0)
    {
        Print("Không thể lấy dữ liệu SMA");
        return;
    }
   
    double sma_current = sma_buffer[0];
    double sma_previous = sma_buffer[1];
   
    bool price_trend_down = sma_current < sma_previous;

    // Định nghĩa điều kiện bán
    condition_sell = price_trend_down &&
                     n1_close < n1_open && n1_high < n2_high &&
                     n2_close > n2_open && n2_high < n3_high &&
                     n3_close < n3_open &&
                     n4_close < n4_open;

    // Nếu có điều kiện bán và chưa có lệnh nào được đặt
    if (condition_sell && !order_placed)
    {
        // Tính toán mức vào lệnh, dừng lỗ và chốt lời
        entry_level = (n1_high + n1_low) / 2;
        stop_loss_level = n2_high + 2; // Cài đặt mức dừng lỗ ban đầu
        take_profit_level = entry_level - (stop_loss_level - entry_level);

        // Tính toán khoảng cách dừng lỗ
        double stop_loss_distance = MathAbs(stop_loss_level - entry_level);
        
        // Tính khối lượng giao dịch
        double lot_size_calculated = risk_amount / stop_loss_distance / 50; // Đảm bảo lot size được tính toán

        // Gửi lệnh bán giới hạn
        ZeroMemory(request);
        request.action = TRADE_ACTION_PENDING;
        request.symbol = Symbol();
        request.volume = NormalizeDouble(lot_size_calculated, 2);
        request.type = ORDER_TYPE_SELL_LIMIT;
        request.price = NormalizeDouble(entry_level, _Digits);
        request.sl = NormalizeDouble(stop_loss_level, _Digits);
        request.tp = NormalizeDouble(take_profit_level, _Digits);
        request.deviation = 3;
        request.magic = 0;
        request.comment = "Sell Limit Order";
        request.type_filling = ORDER_FILLING_FOK;

        // Gửi lệnh bán giới hạn
        if (!OrderSend(request, result))
        {
            Print("Không thể gửi lệnh bán giới hạn: ", result.retcode);
        }
        else
        {
            Print("Lệnh bán giới hạn được gửi thành công. Số hiệu: ", result.order);
            order_placed = true; // Đặt cờ đã đặt lệnh

            // Lưu số hiệu lệnh, thời gian và chỉ số nến
            ArrayResize(order_ticket, ArraySize(order_ticket) + 1);
            ArrayResize(order_placed_time, ArraySize(order_placed_time) + 1);
            ArrayResize(order_placed_bar_index, ArraySize(order_placed_bar_index) + 1);
            order_ticket[ArraySize(order_ticket) - 1] = result.order;
            order_placed_time[ArraySize(order_placed_time) - 1] = current_time;
            order_placed_bar_index[ArraySize(order_placed_bar_index) - 1] = iBarShift(NULL, 0, current_time, false);
        }
    }

    // Kiểm tra và hủy các đơn hàng nếu cần
    for (int i = 0; i < ArraySize(order_ticket); i++)
    {
        if (order_ticket[i] != 0)
        {
            // Kiểm tra trạng thái của đơn hàng
            if (OrderSelect(order_ticket[i]))
            {
                if (OrderGetInteger(ORDER_STATE) == ORDER_STATE_CANCELED)
                {
                    // Đặt lại ticket nếu đơn hàng bị hủy
                    order_ticket[i] = 0;
                    order_placed_time[i] = 0;
                    order_placed_bar_index[i] = 0;
                }
                else if (OrderGetInteger(ORDER_STATE) == ORDER_STATE_FILLED)
                {
                    // Nếu lệnh đã được thực hiện, cập nhật last_order_ticket
                    last_order_ticket = order_ticket[i];
                    order_placed = false; // Đặt lại cờ khi có lệnh đã được thực hiện
                }
            }
        }
    }
}
Files: