이중 이동 평균 교차 동적 손절매 및 손절매 양적 전략

EMA SMA
생성 날짜: 2024-12-11 11:23:54 마지막으로 수정됨: 2024-12-11 11:23:54
복사: 0 클릭수: 87
1
집중하다
1166
수행원

이중 이동 평균 교차 동적 손절매 및 손절매 양적 전략

개요

이것은 쌍평선 교차 신호에 기반한 양적 거래 전략으로, 빠른 지수 이동 평균 ((EMA) 와 느린 지수 이동 평균 ((EMA) 의 교차로 시장의 추세를 판단하며, 동적 스톱 손실 통제와 결합하여 위험을 관리한다. 전략은 백분율 포지션 관리를 채택하고, 기본으로 10%의 자금을 사용하여 거래하며, 동적 스톱 및 스톱 손실 가격을 설정하여 이익을 보호하고 위험을 제어한다.

전략 원칙

전략의 핵심 논리는 20주기 및 50주기 지수 이동 평균 (EMA) 의 교차를 모니터링하여 트렌드 변화를 식별하는 것입니다. 빠른 EMA가 느린 EMA를 상향으로 넘어가면, 시스템은 여러 신호를 발생시킵니다. 포지션을 열 때마다, 시스템은 자동으로 입시 가격 (입시 가격의 1.3배) 및 중단 가격 (입시 가격의 0.95배) 에 따라 중지 가격을 설정합니다. 이러한 동적 중지 손실 디자인은 다양한 시장 환경에 적응하여 전략의 유연성을 향상시킵니다.

전략적 이점

  1. 신호 안정성 - 간단한 이동 평균 (SMA) 대신 EMA를 사용하여 가격 변화에 더 빠르게 반응 할 수 있으며 시장의 일부 소음을 필터링 할 수 있습니다.
  2. 리스크 관리 - 동적인 스톱 스톱 스로드 메커니즘을 사용하여, 스톱 스로드 가격은 출입 가격의 변화에 따라 조정됩니다.
  3. 재원 관리 합리적인 - 고정 비율 포지션 관리를 사용하여 전체 포지션 운영의 높은 위험을 피한다.
  4. 높은 수준의 자동화 - 신호 생성에서 포지션 관리에 이르기까지 모든 것이 자동화되어 인간의 개입이 줄어들었습니다.
  5. 적응성 - 전략은 다양한 시장 환경에 적응할 수 있으며, 매개 변수는 실제 상황에 따라 유연하게 조정할 수 있습니다.

전략적 위험

  1. 평균선 지연성 - EMA는 반응 속도가 빠르지만, 여전히 약간의 지연성이 존재하여 입시 시기가 약간 늦어질 수 있다.
  2. 흔들리는 시장은 적용되지 않습니다 - 시장이 수평적으로 흔들릴 때, 빈번한 가짜 브레이크 신호가 발생할 수 있습니다.
  3. 고정 배수 스톱 로즈 - 고정 배수를 사용하여 스톱 로즈를 설정하여 모든 시장 환경에 적합하지 않을 수 있습니다.
  4. 회수 위험 - 급격한 변동이 있는 시장에서 5%의 정지는 큰 변동에 대응하기에는 충분하지 않을 수 있습니다.

전략 최적화 방향

  1. 변동률 지표 도입 - ATR 지표가 추가되어 스톱 스톱 손실 배수를 동적으로 조정하여 시장의 변동에 더 적합하도록 권장됩니다.
  2. 트렌드 확인이 증가 - RSI, MACD 등의 지표와 결합하여 거래 신호를 필터링하여 승률을 높일 수 있습니다.
  3. 최적화된 포지션 관리 - 시장의 변동에 따라 포지션 크기를 조정할 수 있으며, 보다 세밀한 위험 통제를 가능하게 한다.
  4. 시간 필터 추가 - 거래 시간 창을 늘리는 것을 고려하고, 변동이 큰 시간을 피하십시오.
  5. 정지 메커니즘을 개선 - 모바일 정지를 구현할 수 있으며, 상황이 계속 좋아지면 더 많은 수익을 얻을 수 있습니다.

요약하다

이것은 합리적이고 논리적으로 명확한 트렌드 추적 전략을 설계하고, 트렌드를 쌍평선 교차로 캡처하고, 동적 스톱로스를 사용하여 위험을 관리하는 전략이다. 전략의 장점은 운영 규칙이 명확하고, 위험이 제어 가능하며, 중기 및 장기 거래 시스템의 기본 프레임워크로 적합하다. 더 많은 필터링 조건을 추가하고 스톱로스 메커니즘을 최적화함으로써 전략에는 큰 최적화 공간이 있습니다.

전략 소스 코드
/*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 ——————————————————————————————————————————————————————