Chiến lược định lượng dừng lỗ và dừng lãi động của giao thoa đường trung bình động kép

EMA SMA
Ngày tạo: 2024-12-11 11:23:54 sửa đổi lần cuối: 2024-12-11 11:23:54
sao chép: 0 Số nhấp chuột: 441
1
tập trung vào
1617
Người theo dõi

Chiến lược định lượng dừng lỗ và dừng lãi động của giao thoa đường trung bình động kép

Tổng quan

Đây là một chiến lược giao dịch định lượng dựa trên tín hiệu giao chéo hai đường cong, đánh giá xu hướng thị trường bằng cách giao chéo giữa chỉ số di chuyển trung bình ((EMA) và chỉ số di chuyển trung bình ((EMA)), đồng thời kết hợp với kiểm soát dừng lỗ động để quản lý rủi ro. Chiến lược này sử dụng quản lý vị trí phần trăm, giao dịch theo mặc định với 10% vốn, để bảo vệ lợi nhuận và kiểm soát rủi ro bằng cách đặt giá dừng và dừng lỗ động.

Nguyên tắc chiến lược

Logic cốt lõi của chiến lược này là nhận biết sự thay đổi xu hướng bằng cách theo dõi chéo của đường trung bình di chuyển chỉ số ((EMA) trong 20 chu kỳ và 50 chu kỳ. Khi EMA nhanh lên vượt qua EMA chậm, hệ thống tạo ra nhiều tín hiệu. Sau mỗi lần mở vị trí, hệ thống sẽ tự động thiết lập giá dừng ((1.3 lần giá vào) và giá dừng ((0.95 lần giá vào) dựa trên giá vào.

Lợi thế chiến lược

  1. Tín hiệu ổn định - sử dụng EMA thay vì chỉ đơn giản là moving average (SMA), có thể phản ứng nhanh hơn với sự thay đổi giá cả, đồng thời có thể lọc một phần tiếng ồn thị trường.
  2. Quản lý rủi ro hoàn hảo - Sử dụng cơ chế dừng lỗ động, giá dừng lỗ sẽ điều chỉnh theo thay đổi của giá vào.
  3. Quản lý tài chính hợp lý - Sử dụng quản lý vị trí tỷ lệ cố định, tránh rủi ro cao khi hoạt động toàn vị trí.
  4. Tự động hóa cao - Tự động hóa từ việc tạo tín hiệu đến quản lý vị trí, giảm sự can thiệp của con người.
  5. Khả năng thích ứng - Chiến lược có thể thích ứng với các môi trường thị trường khác nhau, các tham số có thể được điều chỉnh linh hoạt theo tình hình thực tế.

Rủi ro chiến lược

  1. Mức độ chậm trễ trung bình - EMA có thể phản ứng nhanh hơn, nhưng vẫn có một mức độ chậm trễ nhất định, có thể dẫn đến sự chậm trễ trong thời gian nhập cảnh.
  2. Không áp dụng cho thị trường rung động - Có thể tạo ra các tín hiệu phá vỡ giả thường xuyên khi thị trường dao động ngang.
  3. Đặt dừng lỗ nhân cố định - Đặt dừng lỗ với số nhân cố định, có thể không phù hợp với tất cả các môi trường thị trường.
  4. Rủi ro rút lui - Trong thị trường biến động mạnh, 5% dừng có thể không đủ để đối phó với sự biến động lớn.

Hướng tối ưu hóa chiến lược

  1. Thêm chỉ số biến động - Đề xuất thêm chỉ số ATR để điều chỉnh động số lần dừng lỗ để phù hợp hơn với biến động của thị trường.
  2. Tăng xác nhận xu hướng - có thể kết hợp các chỉ số như RSI, MACD để lọc tín hiệu giao dịch và tăng tỷ lệ thắng.
  3. Quản lý vị trí tối ưu hóa - Có thể điều chỉnh kích thước vị trí theo biến động của thị trường, để kiểm soát rủi ro tinh tế hơn.
  4. Thêm bộ lọc thời gian - Xem xét giới hạn cửa sổ thời gian giao dịch để tránh các khoảng thời gian có biến động lớn.
  5. Cải thiện cơ chế dừng - có thể thực hiện dừng di động, thu được nhiều lợi nhuận hơn khi thị trường tiếp tục tốt hơn.

Tóm tắt

Đây là một chiến lược theo dõi xu hướng được thiết kế hợp lý, logic rõ ràng, nắm bắt xu hướng bằng hai đường cong đồng nhất, sử dụng dừng lỗ động để quản lý rủi ro. Ưu điểm của chiến lược là các quy tắc hoạt động rõ ràng, rủi ro có thể kiểm soát được, phù hợp với khung cơ bản của hệ thống giao dịch trung và dài hạn.

Mã nguồn chiến lược
/*backtest
start: 2019-12-23 08:00:00
end: 2024-12-09 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify

//======================================================================//
//                    ____  _            _  __                          //
//                   |  _ \(_)_ __   ___(_)/ _|_   _                    //
//                   | |_) | | '_ \ / _ \ | |_| | | |                   //
//                   |  __/| | | | |  __/ |  _| |_| |                   //
//                   |_|   |_|_| |_|\___|_|_|  \__, |                   //
//                                             |___/                    //
//======================================================================//

//@version=5
strategy(title="TQQQ EMA Strategy", overlay=true)

//#region —————————————————————————————————————————————————— Common Dependence

p_comm_time_range_to_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
    int start_unix_time = na
    int end_unix_time = na
    int start_time_hour = na
    int start_time_minute = na
    int end_time_hour = na
    int end_time_minute = na
    if str.length(time_range) == 11
        // Format: hh:mm-hh:mm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 3, 5)))
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 6, 8)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 9, 11)))
    else if str.length(time_range) == 9
        // Format: hhmm-hhmm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 2, 4)))
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 5, 7)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 7, 9)))
    start_unix_time := timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), start_time_hour, start_time_minute, 0)
    end_unix_time := timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), end_time_hour, end_time_minute, 0)
    [start_unix_time, end_unix_time]

p_comm_time_range_to_start_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
    int start_time_hour = na
    int start_time_minute = na
    if str.length(time_range) == 11
        // Format: hh:mm-hh:mm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 3, 5)))
    else if str.length(time_range) == 9
        // Format: hhmm-hhmm
        start_time_hour := math.floor(str.tonumber(str.substring(time_range, 0, 2)))
        start_time_minute := math.floor(str.tonumber(str.substring(time_range, 2, 4)))
    timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), start_time_hour, start_time_minute, 0)

p_comm_time_range_to_end_unix_time(string time_range, int date_time = time, string timezone = syminfo.timezone) =>
    int end_time_hour = na
    int end_time_minute = na
    if str.length(time_range) == 11
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 6, 8)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 9, 11)))
    else if str.length(time_range) == 9
        end_time_hour := math.floor(str.tonumber(str.substring(time_range, 5, 7)))
        end_time_minute := math.floor(str.tonumber(str.substring(time_range, 7, 9)))
    timestamp(timezone, year(date_time, timezone), month(date_time, timezone), dayofmonth(date_time, timezone), end_time_hour, end_time_minute, 0)

p_comm_timeframe_to_seconds(simple string tf) =>
    float seconds = 0
    tf_lower = str.lower(tf)
    value = str.tonumber(str.substring(tf_lower, 0, str.length(tf_lower) - 1))
    if str.endswith(tf_lower, 's')
        seconds := value
    else if str.endswith(tf_lower, 'd')
        seconds := value * 86400
    else if str.endswith(tf_lower, 'w')
        seconds := value * 604800
    else if str.endswith(tf_lower, 'm')
        seconds := value * 2592000
    else
        seconds := str.tonumber(tf_lower) * 60
    seconds

p_custom_sources() =>
    [open, high, low, close, volume]

//#endregion —————————————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Ta Dependence


//#endregion —————————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Constants

// Input Groups
string P_GP_1      =      ""

//#endregion —————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Inputs

// Default
int p_inp_1        =      input.int(defval=20, title="Fast EMA Length", group=P_GP_1)
int p_inp_2        =      input.int(defval=50, title="Slow EMA Length", group=P_GP_1)
float p_inp_3      =      input.float(defval=1.3, title="Take Profit Price Multiplier", group=P_GP_1, step=0.01)
float p_inp_4      =      input.float(defval=0.95, title="Stop Loss Price Multiplier", group=P_GP_1, step=0.01)


//#endregion ———————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Price Data



//#endregion ———————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Indicators

p_ind_1      =      ta.ema(close, p_inp_1) // Fast EMA
p_ind_2      =      ta.ema(close, p_inp_2) // Slow EMA


//#endregion ———————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Conditions

p_cond_1      =      (ta.crossover(p_ind_1, p_ind_2))


//#endregion ———————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Strategy

// Strategy Order Variables
string p_st_name_1                       =      "Entry"
string p_st_name_2                       =      "Exit"
var float p_st_name_2_tp                 =      na
var bool p_st_name_2_tp_can_drawing      =      true
var float p_st_name_2_sl                 =      na
var bool p_st_name_2_sl_can_drawing      =      true

// Strategy Global
open_trades_number = strategy.opentrades
pre_bar_open_trades_number = na(open_trades_number[1]) ? 0 : open_trades_number[1]
var p_entry_order_id = 1
p_can_place_entry_order() =>
    strategy.equity > 0
get_entry_id_name(int current_order_id, string name) =>
    "[" + str.tostring(current_order_id) + "] " + name
is_entry_order(string order_id, string name) =>
    str.startswith(order_id, "[") and str.endswith(order_id, "] " + name)
get_open_trades_entry_ids() =>
    int p_open_trades_count = strategy.opentrades
    string[] p_entry_ids = array.new_string(0, "")
    if p_open_trades_count > 0
        for i = 0 to p_open_trades_count - 1
            array.push(p_entry_ids, strategy.opentrades.entry_id(i))
    p_entry_ids

// Entry (Entry)
if p_cond_1 and p_can_place_entry_order()
    p_st_name_1_id = get_entry_id_name(p_entry_order_id, p_st_name_1)
    p_entry_order_id := p_entry_order_id + 1
    string entry_message = ""
    strategy.entry(id=p_st_name_1_id, direction=strategy.long, alert_message=entry_message, comment=p_st_name_1_id)
    
    // TP/SL Exit (Exit)
    float p_st_name_2_limit = close * p_inp_3
    if p_st_name_2_tp_can_drawing
        p_st_name_2_tp_can_drawing := false
        p_st_name_2_tp := p_st_name_2_limit
    float p_st_name_2_stop = close * p_inp_4
    if p_st_name_2_sl_can_drawing
        p_st_name_2_sl_can_drawing := false
        p_st_name_2_sl := p_st_name_2_stop
    string p_st_name_2_alert_message = ""
    strategy.exit(id=p_st_name_1_id + "_0", from_entry=p_st_name_1_id, qty_percent=100, limit=p_st_name_2_limit, stop=p_st_name_2_stop, comment_profit=p_st_name_2 + " - TP", comment_loss=p_st_name_2 + " - SL", alert_message=p_st_name_2_alert_message)
    

if high >= p_st_name_2_tp or (pre_bar_open_trades_number > 0 and open_trades_number == 0)
    p_st_name_2_tp_can_drawing := true
    p_st_name_2_sl_can_drawing := true
    p_st_name_2_tp := na
    p_st_name_2_sl := na
plot(p_st_name_2_tp, title="Exit - TP", color=color.rgb(0, 150, 136, 0), linewidth=1, style = plot.style_circles)
if low <= p_st_name_2_sl or (pre_bar_open_trades_number > 0 and open_trades_number == 0)
    p_st_name_2_sl_can_drawing := true
    p_st_name_2_tp_can_drawing := true
    p_st_name_2_sl := na
    p_st_name_2_tp := na
plot(p_st_name_2_sl, title="Exit - SL", color=color.rgb(244, 67, 54, 0), linewidth=1, style = plot.style_circles)
//#endregion —————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Indicator Plots

// Fast EMA
plot(p_ind_1, "Fast EMA", color.rgb(33, 150, 243, 0), 1)

// Slow EMA
plot(p_ind_2, "Slow EMA", color.rgb(255, 82, 82, 0), 1)

//#endregion ————————————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Custom Plots

//#endregion —————————————————————————————————————————————————————————————


//#region —————————————————————————————————————————————————— Alert

//#endregion ——————————————————————————————————————————————————————