
이것은 파인 스크립트 (Pine Script) 를 기반으로 작성된 다공간 자기 적응 동적인 격자 거래 전략이다. 이 전략의 핵심 아이디어는 최근 가격의 고점과 낮은 점 또는 간단한 이동 평균을 기반으로 한 격자의 상하계를 자동으로 계산하고 그 범위를 여러 격자 라인으로 나누는 것이다. 가격이 특정 격자 라인을 만지면, 그 위치에서 포지션을 열거나 공평하게 한다. 이 방법으로, 전략은 충격적인 상황에서 계속 포지션을 공평하게 하고, 가격 차이의 이익을 얻을 수 있다. 동시에 격자 경계를 동적으로 조정하여 다른 시장 추세에도 적응할 수 있다.
그리드 상하계를 계산한다. 사용자 선택에 따라 상하계는 가장 가까운 N 루트 K 선의 최고점과 최저점을 기반으로 하고, 퍼센티지를 확장하거나 축소할 수 있다. 또한 가장 가까운 N 루트 K 선의 종결 가격의 간단한 이동 평균을 기반으로 하고, 상하의 편차 비율을 설정할 수 있다.
그리드 라인 배열을 생성한다. 설정된 그리드 라인 수에 따라 그리드 범위를 평균적으로 나누고, 가격에 해당하는 그리드 라인 배열을 생성한다.
입점/상장. 아래에서 위로 그리드 라인을 가로질러, 현재 폐장 가격이 특정 그리드 라인 가격보다 낮고 그 그리드 라인이 아직 지분을 보유하지 않은 경우, 그 위치에 더 많은 상장을 열습니다. 이렇게 가격이 높은 그리드 라인을 만질 때 계속 상장합니다.
출구/하감 ᄂ. 위아래로 그리드 라인을 가로질러, 현재 폐장 가격이 특정 그리드 라인 가격보다 높고 하위 그리드 라인이 지분을 보유하고 있다면, 하위 그리드 라인의 다중을 평행합니다. 이렇게 가격이 다시 떨어질 때 계속 하락합니다.
동적 조정. 동적 격자 기능을 선택하면, 각 K 선은 격자의 상하계와 격자 선의 배열을 재 계산하여 격자가 상황에 따라 변화하는 것을 계속 적응할 수 있도록합니다.
적응력이 강하다. 격자 거래 전략은 흔들림과 추세 상황에 적응할 수 있다. 격자 전략은 흔들림 상황에서 계속 입장을 열고 가격 차이를 얻을 수 있다. 추세 상황에서 격자가 가격을 따라 움직이기 때문에 특정 입장을 유지하여 추세 수익을 얻을 수 있다.
리스크가 조절된다. 매번 포지션 개설 시 포지션 크기는 설정된 그리드 수에 의해 결정되며, 단일 리스크 포트는 작고 제어된다. 동시에, 가격이 위의 그리드 라인을 만지면 평정 포지션이 수익을 거두기 때문에, 또한 어느 정도 잠재적인 손실을 보호한다.
자동화도 높다. 이 전략은 기본적으로 완전히 자동으로 작동할 수 있으며, 인적 개입이 필요하지 않아 장기적으로 안정적인 수익을 원하는 투자자에게 적합하다.
매개 변수 유연성. 사용자는 시장 특성에 따라 매개 변수 수, 동적 매개 변수 등을 유연하게 설정하여 전략 성능을 최적화할 수 있다.
검은 천둥 위험. 극단적인 시장 폭락에 직면하여 가격이 가장 낮은 그리드 라인 아래로 날아간다면, 이 전략은 포지션이 가득 차 큰 철회에 직면 할 수 있습니다. 이 위험을 줄이기 위해, 손실 조건이 설정 될 수 있으며, 손실이 하락에 도달하면 포지션이 모두 청산됩니다.
격자 매개 변수 설정이 부적절하다. 격자 밀도가 너무 높으면 매번 매개 시점의 차이는 매우 작고, 수수료가 수익의 대부분을 훼손할 수 있다. 격자 폭이 너무 높으면 일회성 매개 비율이 높고, 리스크 이 크다. 표기의 자산 특성을 신중하게 평가하여 적절한 격자 매개 변수를 선택해야 한다.
기저차 위험. 이 전략은 현재 가격에 기반하여 청정 포지션을 설정하는 조건입니다. 선물과 같은 시장에서 계약 가격과 표기된 가격의 차이가 크면 실제 청정 포지션 가격이 예상보다 더 많이 오차 할 수 있습니다.
트렌드 필터를 추가한다. 격자 전략은 일방적인 트렌드 상황에서는 좋지 않은 성능을 발휘한다. 트렌드 지표를 필터로 추가할 수 있다. 예를 들어 ADX가 특정 하위값보다 낮을 때만 격자를 활성화하고, 트렌드가 분명할 때 격자를 닫고, 일방적인 포지션만을 보유한다.
신호 최적화. 그리드 기반에 다른 신호를 중첩할 수 있다. 예를 들어, 그리드+평균선, 즉, 주로 그리드 결정에 의해 매매를 열지만, 가격이 특정 평균선을 통과하면 다시 매매를 열고, 그렇지 않으면 매매를 열지 않는다. 이렇게하면 매매를 빈번하게 여는 비용이 줄어들 수 있다.
포지션 관리. 현재 전략의 매개 포지션은 고정되어 있으며, 가격이 시장 평균 가격에서 멀리 떨어져 있을 때 매개 포지션을 적절히 낮추고, 시장 평균 가격에 가까워질 때 포지션을 증가시켜 자금 활용 효율을 높일 수 있다.
자율적 격자 밀도. 가격 변동률에 따라 격자 밀도를 동적으로 조정하여, 변동률이 높을 때 격자 수를 적절히 증가시킬 수 있으며, 변동률이 낮을 때 격자 수를 줄일 수 있습니다. 이를 통해 격자 폭을 최적화하고 자금 활용도를 향상시킬 수 있습니다.
이 전략은 자기 적응 동적 격자, 불안정한 상황에서 빈번하게 상쇄 상쇄를 할 수 있고, 또한 추세 상황에서 특정 관점 방향을 유지할 수 있습니다. 이는 적응력이 강한 중장기 수량화 전략입니다. 합리적으로 설정 된 격자 트리거 로직과 포지션 관리를 통해 안정적인 수익을 얻을 수 있습니다.
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © jcloyd
//@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)