이동 평균에 기초한 트렌드 거래 전략

저자:차오장, 날짜: 2023-10-30 15:53:25
태그:

img

전반적인 설명

이 전략은 현재 트렌드 방향을 결정하기 위해 이동 평균 시스템을 사용하여 트렌드에 따라 긴 또는 짧은 포지션을 만듭니다. 이동 평균이 올라갈 때, 긴 신뢰도가 높으므로 길게 이동합니다. 이동 평균이 내려갈 때, 짧은 신뢰도가 높으므로 짧게 이동합니다. 이 전략은 주로 트렌드 다음 전략에 속하는 시장 트렌드 방향을 결정하기 위해 이동 평균 시스템을 사용합니다.

전략 논리

  1. 가중화 이동 평균 vwma를 특정 기간의 이동 평균 지표로 계산합니다 (예정 400 기간).

  2. 이동 평균 vwma가 상승하고 있는지 확인하고, 상승하면 긴 신호 상승 추세를 설정하고, 떨어지면 짧은 신호 하락 추세를 설정합니다.

  3. 상승 추세가 맞을 때, 길게 가세요. 하락 추세가 맞을 때, 길게 닫고 짧게 가세요.

  4. 전략 반환 bar_pnl를 계산하고 매개 & 보유 반환 bar_bh 각 바에 대해.

  5. 분기 및 연간 타임 스탬프에 따라 분기 전략 수익분기_pnl, 연간 수익년_pnl 및 해당 구매 및 보유 수익분기_bh, 년_bh를 계산합니다.

  6. 분기 전략 수익 vs 구매 & 보유 수익을 표로 표시합니다.

이점 분석

이 전략의 주요 장점은 다음과 같습니다.

  1. 조작이 간단하고, 이동평균을 통해 시장 트렌드를 결정합니다. 이해하기 쉽습니다.

  2. 추세를 따라가면 추세가 아닌 시장에서 손실을 줄일 수 있습니다.

  3. 몇 가지 조정 가능한 매개 변수. 주로 이동 평균 기간을 조정합니다. 테스트하고 최적화하기 쉽습니다.

  4. 직관적인 반환 테이블이 결과를 명확하게 보여줍니다.

  5. 비교를 위해 테이블에 구매 & 보유 수익을 추가, 초과 수익을 보여줍니다.

  6. 유연한 테이블 위치, 다른 전략과 쉽게 통합.

위험 분석

또한 몇 가지 위험이 있습니다.

  1. 구매 & 보유에 비해 장기적인 황소 시장에서 낮은 성과. 이동 평균 기간을 최적화 할 수 있습니다.

  2. 범위에 묶인 시장에서 높은 위프사 위험은 거래를 줄이기 위해 이전 최고를 깨는 것과 같은 필터 조건을 추가 할 수 있습니다.

  3. 이동 평균은 곡선 적응 능력이 떨어지고 트렌드 전환점을 놓칠 수 있습니다. 다른 유형의 이동 평균을 테스트 할 수 있습니다.

  4. 스톱 로스 메커니즘이 없고 엄청난 마감 위험이 있습니다. 동적 스톱 로스 또는 포지션 사이즈를 설정할 수 있습니다.

  5. 테이블에 셔프 비율, 최대 유출 등 위험 지표를 추가할 수 있습니다.

최적화 방향

이 전략은 다음과 같은 측면에서 최적화 될 수 있습니다.

  1. 이동평균 매개 변수를 최적화하고, 시장 체제에 따라 기간을 조정합니다.

  2. 윗층을 깨는 필터를 추가해서 윙사브를 줄여줍니다.

  3. 다른 종류의 이동 평균을 시도해보세요. WMA, DEMA 등

  4. 동적 중지 또는 위치 사이징과 같은 스톱 손실 메커니즘을 추가합니다.

  5. 테이블 컨텐츠를 풍부하게 만들고, 프 비율, 최대 드로다운과 같은 메트릭을 추가합니다.

  6. MACD, 볼링거 밴드 같은 다른 지표와 결합하여 트렌드를 결정합니다.

  7. 포지션 크기를 최적화하고 시장 상황에 따라 포지션을 동적으로 조정합니다.

  8. 다른 제품에서 테스트하고 가장 좋은 적용 범위를 찾습니다.

결론

이동 평균 거래 전략은 비교적 간단하고 직설적입니다. 이동 평균을 사용하여 트렌드를 결정하여 트렌드를 따르고 있으며, 좋은 드라우다운 컨트롤을 가지고 있으며, 트렌드를 따르는 거래자에게 적합합니다. 복잡한 시장 환경에 적응 할 수 있도록 이동 평균 시스템, 스톱 로스 메커니즘, 포지션 사이징 등 최적화 할 수있는 많은 공간이 있습니다. 테이블 디자인은 전략 수익을 구매 및 보유에 비교하여 과도한 수익을 직관적으로 보여줍니다. 이 전략의 프레임워크와 테이블 디자인은 양적 거래자에게 좋은 참조를 제공 할 수 있습니다.


/*backtest
start: 2022-10-23 00:00:00
end: 2023-10-29 00:00:00
period: 1d
basePeriod: 1h
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/
// © Dannnnnnny

//@version=4
strategy(title="Quarterly Returns in Strategies vs Buy & Hold", initial_capital= 1000, overlay=true,default_qty_type = strategy.percent_of_equity, default_qty_value = 100, commission_type = strategy.commission.percent, commission_value = 0.1)
maLength= input(400)

wma= vwma(hl2,maLength)
uptrend= rising(wma, 5)
downtrend= falling(wma,5)

plot(wma)

if uptrend
    strategy.entry("Buy", strategy.long)
else
    strategy.close("Buy")//

///////////////////
// QUARTERLY TABLE //
enableQuarterlyTable = input(title="Enable Quarterly Return table", type=input.bool, defval=false)
enableCompareWithMarket = input(title="Compare with Market Benchmark", type=input.bool, defval=false)
table_position = input(title="Table Position", type=input.string, defval='bottom_right', options=['bottom_right','bottom_left','top_right', 'top_left'])
precision = 2
new_quarter = ceil(month(time)/3)  != ceil(month(time[1])/3)
new_year  = year(time)  != year(time[1])

eq = strategy.equity

bar_pnl = eq / eq[1] - 1
bar_bh = (close-close[1])/close[1]

cur_quarter_pnl = 0.0
cur_year_pnl  = 0.0
cur_quarter_bh = 0.0
cur_year_bh  = 0.0

// Current Quarterly P&L
cur_quarter_pnl := new_quarter ? 0.0 : 
                 (1 + cur_quarter_pnl[1]) * (1 + bar_pnl) - 1 
cur_quarter_bh := new_quarter ? 0.0 : 
                 (1 + cur_quarter_bh[1]) * (1 + bar_bh) - 1

// Current Yearly P&L
cur_year_pnl := new_year ? 0.0 : 
                 (1 + cur_year_pnl[1]) * (1 + bar_pnl) - 1
cur_year_bh := new_year ? 0.0 : 
                 (1 + cur_year_bh[1]) * (1 + bar_bh) - 1

// Arrays to store Yearly and Quarterly P&Ls
var quarter_pnl  = array.new_float(0)
var quarter_time = array.new_int(0)
var quarter_bh  = array.new_float(0)

var year_pnl  = array.new_float(0)
var year_time = array.new_int(0)
var year_bh  = array.new_float(0)

end_time = false

end_time:= time_close + (time_close - time_close[1]) > timenow or barstate.islastconfirmedhistory

if (not na(cur_quarter_pnl[1]) and (new_quarter or end_time))
    if (end_time[1])
        array.pop(quarter_pnl)
        array.pop(quarter_time)
        
    array.push(quarter_pnl , cur_quarter_pnl[1])
    array.push(quarter_time, time[1])
    array.push(quarter_bh , cur_quarter_bh[1])

if (not na(cur_year_pnl[1]) and (new_year or end_time))
    if (end_time[1])
        array.pop(year_pnl)
        array.pop(year_time)
        
    array.push(year_pnl , cur_year_pnl[1])
    array.push(year_time, time[1])
    array.push(year_bh , cur_year_bh[1])

// Quarterly P&L Table    
var quarterly_table = table(na)

getCellColor(pnl, bh)  => 
    if pnl > 0
        if bh < 0 or pnl > 2 * bh
            color.new(color.green, transp = 20)
        else if pnl > bh
            color.new(color.green, transp = 50)
        else
            color.new(color.green, transp = 80)
    else
        if bh > 0 or pnl < 2 * bh
            color.new(color.red, transp = 20)
        else if pnl < bh
            color.new(color.red, transp = 50)
        else
            color.new(color.red, transp = 80)

if (end_time and enableQuarterlyTable)
    quarterly_table := table.new(table_position, columns = 14, rows = array.size(year_pnl) + 1, border_width = 1)

    table.cell(quarterly_table, 0,  0, "",     bgcolor = #cccccc)
    table.cell(quarterly_table, 1,  0, "Q1",  bgcolor = #cccccc)
    table.cell(quarterly_table, 2,  0, "Q2",  bgcolor = #cccccc)
    table.cell(quarterly_table, 3,  0, "Q3",  bgcolor = #cccccc)
    table.cell(quarterly_table, 4,  0, "Q4",  bgcolor = #cccccc)
    table.cell(quarterly_table, 5,  0, "Year", bgcolor = #999999)


    for yi = 0 to array.size(year_pnl) - 1
        table.cell(quarterly_table, 0,  yi + 1, tostring(year(array.get(year_time, yi))), bgcolor = #cccccc)
        
        y_color = getCellColor(array.get(year_pnl, yi), array.get(year_bh, yi))
        table.cell(quarterly_table, 5, yi + 1, enableCompareWithMarket ? tostring(round(array.get(year_pnl, yi) * 100, precision)) + " (" + tostring(round(array.get(year_bh, yi) * 100, precision)) + ")" : tostring(round(array.get(year_pnl, yi) * 100, precision)), bgcolor = y_color, text_color=#bfbfbf)
        
    for mi = 0 to array.size(quarter_time) - 1
        m_row   = year(array.get(quarter_time, mi))  - year(array.get(year_time, 0)) + 1
        m_col   = ceil(month(array.get(quarter_time, mi)) / 3)
        m_color = getCellColor(array.get(quarter_pnl, mi), array.get(quarter_bh, mi))
        
        table.cell(quarterly_table, m_col, m_row, enableCompareWithMarket ?  tostring(round(array.get(quarter_pnl, mi) * 100, precision)) + " (" + tostring(round(array.get(quarter_bh, mi) * 100,precision)) +")" : tostring(round(array.get(quarter_pnl, mi) * 100, precision)), bgcolor = m_color, text_color=#bfbfbf)

더 많은