Strategi kuantitatif persilangan rata-rata pergerakan ganda stop-profit dan stop-loss dinamis

EMA SMA
Tanggal Pembuatan: 2024-12-11 11:23:54 Akhirnya memodifikasi: 2024-12-11 11:23:54
menyalin: 0 Jumlah klik: 441
1
fokus pada
1617
Pengikut

Strategi kuantitatif persilangan rata-rata pergerakan ganda stop-profit dan stop-loss dinamis

Ringkasan

Ini adalah strategi perdagangan kuantitatif yang didasarkan pada sinyal crossover dua rata-rata, untuk menilai tren pasar melalui persilangan indeks bergerak cepat (EMA) dan indeks bergerak lambat (EMA), sambil mengkombinasikan kontrol stop loss dinamis untuk mengelola risiko. Strategi ini menggunakan manajemen posisi persentase, secara default menggunakan 10% dari dana untuk berdagang, untuk melindungi keuntungan dan mengendalikan risiko dengan menetapkan harga stop loss dan stop loss dinamis.

Prinsip Strategi

Logika inti dari strategi ini adalah untuk mengidentifikasi perubahan tren dengan memantau crossover 20 siklus dan 50 siklus EMA. Ketika EMA cepat naik melewati EMA lambat, sistem menghasilkan beberapa sinyal. Setiap kali membuka posisi, sistem akan secara otomatis mengatur harga stop-loss dan harga stop-loss berdasarkan harga masuk.

Keunggulan Strategis

  1. Stabilitas sinyal yang kuat - menggunakan EMA dan bukan SMA, dapat merespons perubahan harga lebih cepat, sementara juga dapat menyaring sebagian dari kebisingan pasar.
  2. Pengelolaan risiko yang baik - Menggunakan mekanisme stop loss yang dinamis, harga stop loss akan disesuaikan dengan perubahan harga masuk.
  3. Manajemen dana yang masuk akal - Menggunakan manajemen posisi rasio tetap, menghindari risiko tinggi dari operasi posisi penuh.
  4. Tingkat otomatisasi yang tinggi - dari pembuatan sinyal hingga manajemen posisi otomatis, mengurangi intervensi manusia.
  5. Adaptif - Strategi dapat beradaptasi dengan berbagai kondisi pasar, dan parameter dapat disesuaikan secara fleksibel sesuai dengan situasi yang sebenarnya.

Risiko Strategis

  1. Rata-rata ketertinggalan garis - EMA meskipun bereaksi lebih cepat, namun masih ada ketertinggalan tertentu, yang dapat menyebabkan sedikit penundaan waktu masuk.
  2. Tidak berlaku untuk pasar bergoyang-goyang - sinyal palsu yang sering muncul saat pasar bergoyang-goyang.
  3. Stop loss dengan pengganda tetap - Stop loss dengan pengganda tetap mungkin tidak cocok untuk semua situasi pasar.
  4. Risiko penarikan - Dalam pasar yang sangat bergejolak, stop loss 5% mungkin tidak cukup untuk menghadapi fluktuasi besar.

Arah optimasi strategi

  1. Memperkenalkan indikator volatilitas - dianjurkan untuk menambahkan indikator ATR untuk secara dinamis menyesuaikan stop loss multiplier sehingga lebih sesuai dengan fluktuasi pasar.
  2. Peningkatan konfirmasi tren - dapat digabungkan dengan indikator seperti RSI, MACD untuk memfilter sinyal perdagangan, meningkatkan tingkat kemenangan.
  3. Manajemen Posisi yang Dioptimalkan - Dimensi posisi dapat disesuaikan secara dinamis sesuai dengan fluktuasi pasar, sehingga memungkinkan kontrol risiko yang lebih halus.
  4. Tambahkan Filter Waktu - Pertimbangkan untuk menambahkan batasan pada jendela waktu perdagangan, menghindari periode dengan fluktuasi yang lebih besar.
  5. Mekanisme penutupan yang lebih baik - penutupan bergerak dapat dilakukan untuk mendapatkan lebih banyak keuntungan jika kondisi terus membaik.

Meringkaskan

Ini adalah strategi pelacakan tren yang dirancang secara rasional dan logis, menangkap tren dengan cara melintas di dua garis yang sama, menggunakan stop loss dinamis untuk mengelola risiko. Keuntungan dari strategi ini adalah bahwa aturan operasinya jelas, risiko dapat dikendalikan, dan cocok sebagai kerangka dasar sistem perdagangan jangka menengah dan panjang. Dengan menambahkan lebih banyak kondisi penyaringan dan mengoptimalkan mekanisme stop loss, strategi ini memiliki ruang untuk pengoptimalan yang lebih besar.

Kode Sumber Strategi
/*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 ——————————————————————————————————————————————————————