Dynamic Grid 추세 추종 양적 거래 전략


생성 날짜: 2024-03-22 16:03:09 마지막으로 수정됨: 2024-03-22 16:03:09
복사: 0 클릭수: 1231
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

Dynamic Grid 추세 추종 양적 거래 전략

개요

이것은 고급 동적 격자 트렌드 추적 양적 거래 전략이다. 이 전략의 주요 아이디어는 미리 설정된 가격 범위 내에서 여러 격자 라인을 나누고, 가격이 격자 라인을 만질 때 자동으로 대가 구매 또는 대가 매각을 설정하여 충격적 인 상황에서 이익을 얻습니다. 이 전략은 또한 격자 라인의 위치를 동적으로 조정하는 기능을 가지고 있으며, 최근의 가격 움직임에 따라 격자 배치를 조정할 수 있습니다.

전략 원칙

이 전략의 핵심 원칙은 다음과 같습니다.

  1. 먼저 사용자 설정에 따라 격자의 상하 경계와 격자 라인의 수를 결정한다. 경계 값은 고정 값이거나 최근 높고 낮은 점이나 이동 평균을 기반으로 자동으로 계산할 수 있다.

  2. 정해진 경계 내에서 가격 범위를 여러 개의 격으로 나누십시오. 각 격 줄은 구매 또는 판매 가격에 해당합니다.

  3. 각 가격이 격자선을 만지면, 전략은 그 격자선과 대응하는 포지션을 이미 보유하고 있는지 여부를 확인합니다. 만약 없는 경우 포지션을 세우고 구매하고, 만약 있다면 평점 포지션을 판매합니다.

  4. 상대적으로 높은 가격에 팔고 낮은 가격에 사는 방식으로, 전략은 가격의 변동에 계속 수익을 낼 수 있다.

  5. 또한, 사용자가 자동 경계 조정 기능을 활성화하면, 그리드 라인의 위치는 최근 가격의 높고 낮은 점이나 설정된 이동 평균에 따라 자율적으로 조정되어 그리드 레이아웃을 최적화합니다.

위와 같은 원칙을 통해, 이 전략은 가격 변동 상황 하에서 자동으로 낮은 가격으로 높은 가격으로 판매 할 수 있으며, 추세에 따라 우위를 조정하여 전체 수익을 향상시킬 수 있습니다.

우위 분석

동적 격자 전략은 다음과 같은 장점이 있습니다.

  1. 적응력이 뛰어나다. 다양한 시장과 품종에 대한 변수 설정을 통해 적응할 수 있으며, 흔들림 상황에 대한 적응력이 뛰어나다.

  2. 자동화 수준이 높다. 전략이 엄격한 수학 논리에 기반하고, 지점을 명확하게 설정하기 때문에, 완전히 자동화된 거래가 가능하며, 주관적 감정의 간섭을 줄일 수 있다.

  3. 위험 제어 가능. 격자 수, 격자 경계 등의 파라미터를 설정함으로써, 각 거래의 위험 구멍을 효과적으로 제어하여 전반적인 위험을 허용 범위 내에서 유지할 수 있다.

  4. 트렌드 적응성. 트렌드 전략에는 격자 경계를 동적으로 조정하는 기능이 추가되어, 격자가 가격 추세에 따라 최적화되어, 트렌드 상황에서 수익성을 향상시킵니다.

  5. 승률이 안정적이다. 격자 거래는 가격 변동에 자주 오르락 내리락 하는 특성상, 가격이 변동하는 동안 이 전략은 지속적으로 수익을 낼 수 있으며, 따라서 장기적으로 높은 승률을 보인다.

위험 분석

이 전략의 장점은 분명하지만 위험도 있습니다.

  1. 트렌드 리스크. 가격의 강력한 일방적인 트렌드가 격자 경계를 뚫어지면 이 전략의 수익 공간은 제한될 것이며, 큰 회귀에 직면할 수 있다.

  2. 매개 변수 최적화 난이도가 크다. 이 전략은 매개 변수가 많으며, 격자 수, 초기 경계, 동적 경계 매개 변수 등이 있다. 다른 매개 변수 조합은 전략 성과에 큰 영향을 미치며, 실제 최적화 난이도가 크다.

  3. 자주 거래한다. 격자 전략은 본질적으로 높은 주파수 전략이며, 매우 자주 입점하고, 이는 높은 거래 비용과 잠재적인 슬라이드 포인트 위험을 의미한다.

  4. 시장에 대한 강한 의존성. 이 전략은 충격적인 시장에 대한 강한 의존성을 가지고 있으며, 가격이 빠른 단방향 추세에 들어간다면 이 전략은 큰 회전을 직면할 가능성이 높다.

이러한 위험에 대해, 다음과 같은 측면에서 개선 할 수 있습니다: 전략의 시작 필터 조건으로 추세를 판단하는 지표를 추가하고, 변수 검색 공간과 방법을 최적화하고, 자금 관리 및 포지션 제어 논리를 도입하고, 평평한 포지션을 돌파하는 추세를 증가시킵니다. 이러한 최적화를 통해 전략의 안정성과 수익성을 더욱 향상시킬 수 있습니다.

최적화 방향

위와 같은 분석을 바탕으로, 이 전략의 최적화 방향은 다음과 같습니다.

  1. 트렌드 필터 조건을 도입한다. 전략이 시작되기 전에 이동 평균, ADX 등과 같은 트렌드 판단 지표를 추가한다. 동요 상황에서만 전략을 시작하며, 트렌드 상황에서는 관측을 유지한다. 이렇게하면 트렌드 상황에서의 회수 위험을 효과적으로 피할 수 있다.

  2. 최적화 변수 검색. 지능형 알고리즘을 사용하여 그리드 변수를 최적화합니다. 예를 들어, 유전 알고리즘, 입자 그룹 알고리즘 등으로 최적의 변수 조합을 자동으로 찾아 최적화 효율성과 품질을 향상시킵니다.

  3. 강화된 위드 컨트롤 논리. 전략에 더 많은 위드 컨트롤 논리를 추가하여, 가격 변동률에 따라 동적으로 격 너비를 조정하고, 최대 회수 마이너스를 설정하여 평준을 유발하는 등, 위험을 더 잘 제어합니다.

  4. 트렌드 스톱을 도입한다. 트렌드 스톱 라인을 깨는 트렌드를 설정한다. 격자 경계와 같은 일정 비율로, 가격이 스톱 라인을 깨면 완전히 평평한 위치를 차지한다. 트렌드 상황의 큰 회전을 피한다.

  5. 거래 실행을 최적화한다. 거래 실행을 최적화한다. 예를 들어, 더 고급 조건 목록과 주문 알고리즘을 사용하여 거래 빈도와 비용을 최대한 줄이고 실행 효율성을 높인다.

이러한 최적화를 통해 전략의 적응성, 안정성 및 수익성을 전면적으로 향상시킬 수 있으며, 실제 요구에 더 가깝게 만들 수 있습니다.

요약하다

일반적으로, 이 동적 격자 트렌드 추적 전략은 격자 거래 원리에 기반한 동시에 동적 조정 및 트렌드 적응 메커니즘을 통합한 중고 주파수 거래 전략이다. 그것의 장점은 적응력이 강하고, 자동화 수준이 높고, 위험 제어 가능하며, 트렌드 적응력이 좋으며, 승률이 안정적이다. 그러나 동시에 트렌드 위험, 파라미터 최적화가 어려운, 빈번한 거래, 행동 상황에 대한 의존성 등이 있습니다. 이러한 문제에 대해, 트렌드 필터, 파라미터 최적화, 위험 제어 강화, 트렌드 손실 중지, 거래 최적화 등에서 전략의 전반적인 성능을 향상시키고 향상시킬 수 있습니다.

격자 거래 아이디어는 그 자체로 비교적 성숙하고 실용적인 계량화 방법이며, 전략의 동적 최적화 및 추세 적응 메커니즘의 추가로 클래식 격자 거래의 장점을 확장하고 발전시킵니다. 투자자에게 새로운 계량화 거래 아이디어와 가능성을 제공합니다. 추가적인 최적화 및 개선으로, 이 전략은 우수한 중·고 주파수 계량화 거래 도구가 될 전망입니다.

전략 소스 코드
/*backtest
start: 2024-03-01 00:00:00
end: 2024-03-21 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=4
strategy("(IK) Grid Script", overlay=true, pyramiding=14, close_entries_rule="ANY", default_qty_type=strategy.cash, initial_capital=100.0, currency="USD", commission_type=strategy.commission.percent, commission_value=0.1)
i_autoBounds    = input(group="Grid Bounds", title="Use Auto Bounds?", defval=true, type=input.bool)                             // calculate upper and lower bound of the grid automatically? This will theorhetically be less profitable, but will certainly require less attention
i_boundSrc      = input(group="Grid Bounds", title="(Auto) Bound Source", defval="Hi & Low", options=["Hi & Low", "Average"])     // should bounds of the auto grid be calculated from recent High & Low, or from a Simple Moving Average
i_boundLookback = input(group="Grid Bounds", title="(Auto) Bound Lookback", defval=250, type=input.integer, maxval=500, minval=0) // when calculating auto grid bounds, how far back should we look for a High & Low, or what should the length be of our sma
i_boundDev      = input(group="Grid Bounds", title="(Auto) Bound Deviation", defval=0.10, type=input.float, maxval=1, minval=-1)  // if sourcing auto bounds from High & Low, this percentage will (positive) widen or (negative) narrow the bound limits. If sourcing from Average, this is the deviation (up and down) from the sma, and CANNOT be negative.
i_upperBound    = input(group="Grid Bounds", title="(Manual) Upper Boundry", defval=0.285, type=input.float)                      // for manual grid bounds only. The upperbound price of your grid
i_lowerBound    = input(group="Grid Bounds", title="(Manual) Lower Boundry", defval=0.225, type=input.float)                      // for manual grid bounds only. The lowerbound price of your grid.
i_gridQty       = input(group="Grid Lines",  title="Grid Line Quantity", defval=8, maxval=15, minval=3, type=input.integer)       // how many grid lines are in your grid

f_getGridBounds(_bs, _bl, _bd, _up) =>
    if _bs == "Hi & Low"
        _up ? highest(close, _bl) * (1 + _bd) : lowest(close, _bl)  * (1 - _bd)
    else
        avg = sma(close, _bl)
        _up ? avg * (1 + _bd) : avg * (1 - _bd)

f_buildGrid(_lb, _gw, _gq) =>
    gridArr = array.new_float(0)
    for i=0 to _gq-1
        array.push(gridArr, _lb+(_gw*i))
    gridArr

f_getNearGridLines(_gridArr, _price) =>
    arr = array.new_int(3)
    for i = 0 to array.size(_gridArr)-1
        if array.get(_gridArr, i) > _price
            array.set(arr, 0, i == array.size(_gridArr)-1 ? i : i+1)
            array.set(arr, 1, i == 0 ? i : i-1)
            break
    arr

var upperBound      = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true) : i_upperBound  // upperbound of our grid
var lowerBound      = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false) : i_lowerBound // lowerbound of our grid
var gridWidth       = (upperBound - lowerBound)/(i_gridQty-1)                                                       // space between lines in our grid
var gridLineArr     = f_buildGrid(lowerBound, gridWidth, i_gridQty)                                                 // an array of prices that correspond to our grid lines
var orderArr        = array.new_bool(i_gridQty, false)                                                              // a boolean array that indicates if there is an open order corresponding to each grid line

var closeLineArr    = f_getNearGridLines(gridLineArr, close)                                                        // for plotting purposes - an array of 2 indices that correspond to grid lines near price
var nearTopGridLine = array.get(closeLineArr, 0)                                                                    // for plotting purposes - the index (in our grid line array) of the closest grid line above current price
var nearBotGridLine = array.get(closeLineArr, 1)                                                                    // for plotting purposes - the index (in our grid line array) of the closest grid line below current price
strategy.initial_capital = 50000
for i = 0 to (array.size(gridLineArr) - 1)
    if close < array.get(gridLineArr, i) and not array.get(orderArr, i) and i < (array.size(gridLineArr) - 1)
        buyId = i
        array.set(orderArr, buyId, true)
        strategy.entry(id=tostring(buyId), long=true, qty=(strategy.initial_capital/(i_gridQty-1))/close, comment="#"+tostring(buyId))
    if close > array.get(gridLineArr, i) and i != 0
        if array.get(orderArr, i-1)
            sellId = i-1
            array.set(orderArr, sellId, false)
            strategy.close(id=tostring(sellId), comment="#"+tostring(sellId))

if i_autoBounds
    upperBound  := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true)
    lowerBound  := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false)
    gridWidth   := (upperBound - lowerBound)/(i_gridQty-1)
    gridLineArr := f_buildGrid(lowerBound, gridWidth, i_gridQty)

closeLineArr    := f_getNearGridLines(gridLineArr, close)
nearTopGridLine := array.get(closeLineArr, 0)
nearBotGridLine := array.get(closeLineArr, 1)