이 전략은 미리 설정된 가격 범위 내에서 구매 및 판매 주문을 하기 위해 해양 이론의 그리드 트레이딩 방법을 활용한다. 이 전략은 그리드 가격 범위의 자동 계산과 그리드 라인의 균일 분포를 특징으로 하며, 이는 위험을 효과적으로 관리하는 데 도움이 된다.
이 전략은 먼저 사용자 선택 또는 기본 설정에 따라 가격 그리드의 상부 및 하부 경계를 계산합니다. 계산의 두 가지 방법이 있습니다. 백테스팅 기간 동안 가장 높고 가장 낮은 가격을 얻거나 일정 기간 동안 이동 평균을 계산합니다. 그 다음 그리드 라인은 사용자가 설정 한 그리드 수에 따라 균일하게 분포됩니다.
거래 신호는 가격과 그리드 라인의 관계를 기반으로 생성됩니다. 가격이 그리드 라인의 아래에있을 때, 고정된 양으로 그리드 라인 가격으로 긴 지점이 열립니다. 가격이 그리드 라인을 넘을 때, 지점은 아래의 그리드 라인에서 닫습니다. 그리드 내에서 가격이 변동됨에 따라 지점은 그에 따라 수익을 얻습니다.
구체적으로, 전략은 각 라인에 주문이 배치되는지 여부를 나타내는 그리드 라인 가격 배열과 bool 배열을 유지합니다. 가격이 주문이없는 라인 아래에있을 때 라인에 긴 지위가 열립니다. 가격이 라인 위에있을 때 아래 라인에 주문이있을 때 아래 라인에 지점이 닫습니다. 그리드 거래는 이러한 방식으로 구현됩니다.
그리드 범위는 수동 설정의 어려움을 피하여 자동으로 계산됩니다. 다른 계산 옵션이 있습니다.
그리드 라인은 밀도가 높은 그리드 때문에 과잉 거래를 피하기 위해 균등하게 분포됩니다. 그리드 수는 조정 할 수 있습니다.
그리드 거래 방법은 위험을 효과적으로 제어합니다. 그리드 내에서 가격이 변동하는 한 이익을 얻을 수 있습니다.
가격 방향 가설이 없는데, 범주형 시장에 적합합니다.
각기 다른 거래용품에 대한 사용자 정의 가능한 수수료 및 포지션 크기 설정
그리드 라인의 시각화는 거래 상황을 이해하는 데 도움이됩니다.
가격 폭락 위험. 상위 또는 하위 네트워크 한계를 넘어서면 더 큰 손실이 발생할 수 있습니다.
과도한 네트워크 공간 위험. 너무 느슨한 네트워크는 쉽게 이익을 얻을 수 없으며 너무 좁은 네트워크는 비용을 증가시킵니다. 균형이 필요합니다.
장기 보유 위험. 장기 보유는 수익을 어렵게 하지만 비용을 증가시킵니다.
부적절한 매개 변수 설정 위험. 백테스팅 기간 또는 이동 평균 기간이 부적절하게 설정되면 그리드 범위 계산에 영향을 줄 수 있습니다.
시스템 시장 위험. 장기 트렌드 시장보다는 범위 제한 시장에 더 적합합니다.
그리드 매개 변수를 최적화합니다. 그리드 수, 룩백 기간 등을 최적화하기 위해 시장 조건, 비용 등을 포괄적으로 고려하십시오.
동적 그리드 범위 조정 도입 시장의 중요한 변화가 발생하면 그리드 범위를 조정합니다.
스톱 로스 메커니즘을 포함합니다. 손실을 제한하기 위해 적절한 스톱 로스 라인을 설정합니다. 동적으로 조정 할 수 있습니다.
부적절한 거래를 피하기 위해 볼링거 밴드, 트렌드 지표 등과 같은 다른 지표를 사용하는 필터를 추가하십시오.
자본 사용 효율성을 향상시키고 일정 기간 동안 거래를 줄이기 위해 변동성 분석을 도입하십시오.
이 전략은 그리드 거래 원칙을 활용하여 위험 제어 가능한 범위 거래를 실현합니다. 자동 그리드 계산과 균일 분포는 매개 변수 조정으로 다양한 시장에 적합한 장점을 제공합니다. 위험은 제한적이며 작동하기가 쉽습니다. 그러나 제한이 있으며 진화하는 시장에 적응하기 위해 지속적인 개선이 필요합니다. 전반적으로 전략은 그리드 거래를 구현하는 표준화 된 매개 변수 접근 방식을 제공합니다.
/*backtest start: 2023-09-12 00:00:00 end: 2023-10-12 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 strategy.initial_capital = 50000 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 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)