
적응망 거래 전략은 격자 거래 시스템을 기반으로 한 정량화 전략으로, 격자 라인 위치를 자동으로 조정하여 시장 변화에 적응합니다. 이 전략은 여러 가지 기술 지표를 사용하여 최적의 거래 지점을 계산하고 가격 변화에 따라 격자를 동적으로 업데이트합니다. 핵심 아이디어는 가격의 설정된 범위 내에서 가격이 미리 설정된 격자 라인을 만질 때 구매 또는 판매 작업을 수행하여 시장 변동으로 인한 수익 기회를 포착하는 것입니다. 전략은 탄력적인 메커니즘 ((Elasticity) 과 지연 변수 ((Laziness) 을 특징으로하며, 격자는 다른 시장 환경에 적응하여 더 유연한 거래 실행을 위해 자동으로 조정 할 수 있습니다.
이 전략은 다음과 같은 핵심 구성 요소와 작동 원리에 기반을 두고 있습니다.
부드러운 처리 메커니즘전략은 우선 가격의 평준화를 처리하며, 여러 가지 이동 평균 유형을 지원합니다. (선형 회귀, SMA, EMA, VWMA 및 TEMA), 사용자는 선호에 따라 적절한 평준화 방법을 선택할 수 있습니다.
지연 변수 (Laziness)이 전략의 핵심 혁신은, 지연 함수 lz () 를 도입함으로써, 가격 변화가 특정 비율을 초과할 때만 시스템이 신호를 갱신하고, 시장 소음을 효과적으로 필터링하는 것이다.
격자 구조 메커니즘:
신호 생성 논리:
거래 제어 장치:
동적 격자 업데이트: Lazy Moving Average (LMA) 가 변할 때, 전체 격자 구조가 재조정되어 전략이 새로운 가격 범위에 적응할 수 있게 됩니다.
전략은 각 격자 라인의 가격을 배열로 저장하고, 가격과 격자 라인의 교차점을 계산하여 구체적인 구매 및 판매 지점을 결정하며, 불필요한 거래를 피하기 위해 여러 가지 제약 조건을 고려합니다.
적응력이 전략의 가장 큰 장점은 인적 개입 없이 시장 변화에 따라 그리드 위치를 자동으로 조정할 수 있다는 것입니다. 탄력적인 매개 변수와 포인트 조정 메커니즘을 통해 그리드는 가격 추세 변화에 따라 이동할 수 있으며 항상 관련성을 유지할 수 있습니다.
노이즈 필터: 지연 파라미터 ((Laziness) 의 도입은 가격 변화가 충분히 눈에 띄는 경우에만 격자 조정을 촉발하도록 하는 혁신으로, 시장 소음에 대한 반응을 효과적으로 줄이고 전략의 안정성을 높였다.
유연한 맞춤형: 전략은 격자 수, 격자 간격, 방향 선호, 부드러운 유형 등과 같은 풍부한 파라미터 설정을 제공합니다. 사용자는 다른 시장 특성과 개인 거래 스타일에 따라 조정할 수 있습니다.
거래 영역을 시각화: 전략은 현재 활성 거래 구역을 색으로 채우며 표시하여 거래자가 현재 가격의 격자 위치를 직관적으로 알 수 있도록 하여 의사결정을 용이하게 합니다.
위험 관리: 특정 격자 내에서만 거래가 가능하도록 제한함으로써, 전략은 극단적인 시장 조건에서 불리한 거래를 방지하기 위해 자연스러운 위험 제어 메커니즘을 구축합니다.
통일된 출전 논리: 동일한 그리드 라인을 구매 및 판매 신호로 사용하여 거래 논리의 일관성과 예측성을 유지합니다.
범위를 돌파할 위험이 전략은 본질적으로 간격 거래 전략이며, 강한 트렌드 시장에서 지속적인 손실이 발생할 수 있습니다. 가격이 그리드 상부 경계를 뚫고 계속 한방향으로 이동할 때, 전략은 잘못된 방향으로 계속 가동 할 수 있습니다.
매개변수 민감도: 전략 성능은 파라미터 설정에 크게 의존합니다. 특히 지연 파라미터 (Laziness) 와 탄력 파라미터 (Elasticity) 를 고려하십시오. 부적절한 파라미터는 그리드 조정의 미시 또는 과도한 민감성을 초래할 수 있습니다.
피라미드 포지션 위험: 전략은 같은 방향으로 여러 번 입장을 허용한다 (pyramiding=4), 극단적인 시장 조건에서 과도한 레버리지와 위험 집중으로 이어질 수 있다. 최대 포지션 제한과 동적 포지션 관리를 설정하는 것이 고려되어야 한다.
슬라이드 포인트 및 수수료 영향: 격자 거래 전략은 일반적으로 빈번한 거래를 포함하고 실제 실행에서 슬라이드 포인트와 수수료는 전략의 수익성에 크게 영향을 줄 수 있습니다. 이러한 요소는 재검토에 포함되어야하며 격자 간격은 거래 빈도와 비용을 균형을 맞추기 위해 조정해야 할 수 있습니다.
신호 충돌 처리: 매매 신호가 동시에 나타나면, 현재 전략은 두 신호를 무시하는 것을 선택합니다. 이것은 중요한 거래 기회를 놓치게 할 수 있습니다. 추가적인 시장 지표 또는 가격 패턴을 기반으로 신호 충돌을 해결하는 것을 고려할 수 있습니다.
적응 변수 조정: 전략은 시장의 변동성에 따라 자동으로 격자 간격과 지연 변수를 조정하도록 추가적으로 최적화 할 수 있습니다. 예를 들어, 격자 간격이 높은 변동성 시장에서 증가하고 격자 간격이 낮은 변동성 시장에서 감소하여 전략이 다른 시장 조건에 더 잘 적응 할 수 있습니다.
트렌드 인식 컴포넌트를 통합: 현재 전략은 트렌드 시장에서 좋지 않을 수 있으며, 트렌드 식별 지표 (ADX, 이동 평균 교차 등) 를 도입하여 강력한 트렌드를 식별하면 자동으로 거래 방향을 조정하거나 격자 거래를 중지 할 수 있습니다.
동적 위치 관리: 현재 전략은 고정된 포지션 크기를 사용하지만, 위험 계산에 기반한 동적 포지션 관리로 개선할 수 있습니다. 예를 들어, ATR에 따라 포지션 크기를 조정하거나, 계좌의 순가치 비율에 따라 자금을 배분합니다.
다중 시간 프레임 분석: 멀티 타임 프레임 분석을 도입하고, 더 긴 시간 주기의 트렌드 방향을 사용하여 거래 신호를 필터링하고, 더 큰 시간 프레임 트렌드에 부합하는 방향으로만 그리드 거래를 수행한다.
완벽한 손절매 메커니즘: 현재 전략에는 명확한 스톱 로즈 메커니즘이 없으며, 전체 시장 상황에 따라 전체적인 스톱 로즈를 추가하거나, 단일 거래의 최대 손실을 제한하기 위해 각 격자 수준에 대해 개별적인 스톱 로즈를 설정할 수 있습니다.
출전 시점 최적화전략은 거래량이나 가격 동력 지표를 통합하여, 그리드 신호가 터졌을 때, 추가 필터링 조건을 통해 특정 진출 시기를 최적화하여 성공률을 높일 수 있다.
기계학습 통합: 기계 학습 알고리즘을 사용하여 격자 위치 및 변수 선택을 최적화하고, 역사 데이터 훈련 모델을 통해 최적의 격자 설정을 예측하여 전략의 적응성을 더욱 향상시킬 수 있습니다.
적응형 격자 거래 전략은 혁신적인 지연 함수와 동적 격자 조정 메커니즘을 통해 전통적인 격자 거래 전략의 유연성 부족 문제를 해결합니다. 그것은 시장의 변화에 자동으로 적응하고, 다른 가격 범위 내에서 거래 기회를 포착하며, 여러 가지 매개 변수를 통해 거래 행동을 제어합니다. 이 전략은 불안한 시장에서 적용하기에 적합하며, 합리적인 격자 간격과 방향 선호를 설정하여 자동화 된 거래 실행을 구현 할 수 있습니다.
범위를 돌파하는 위험과 변수 민감성 같은 잠재적인 문제가 있음에도 불구하고, 트렌드 식별과 동적 변수 조정과 같은 최적화 방향을 통합함으로써이 전략은 다양한 시장 환경에서 안정적인 성능을 얻을 수 있습니다. 실제 응용에서는 먼저 전면적인 피트백을 통해 전략의 성능을 확인하는 것이 좋습니다. 특히 다른 시장 조건에서의 성능, 그리고 특정 거래 품종의 특성에 따라 변수를 조정하여 최적의 효과를 얻습니다.
//@version=5
// This source code is subject to the terms of the Mozilla Public License 2.0 https://mozilla.org/MPL/2.0/
// ©mvs1231 || xxattaxx
strategy(title='Grid Bot Auto Strategy', shorttitle='GridBot', initial_capital = 100000, overlay=true, pyramiding=4, default_qty_type = strategy.fixed, default_qty_value = 0, commission_value = 0.04, commission_type = strategy.commission.percent, margin_long = 0, margin_short = 0, process_orders_on_close = true)
//----<User Inputs>------------------------------------------------------------------------------//
iLen = input.int(7, 'Smoothing Length(7)', minval=1)
iMA = input.string('lreg', 'Smoothing Type', options=['lreg', 'sma', 'ema', 'vwma', 'tema'])
iLZ = input.float(4.0, 'Laziness(4%)', step=.25) / 100
iELSTX = input(50.0, 'Elasticity(50)')
iGI = input.float(2.0, 'Grid Interval(2%)', step=.25) / 100
iGrids = input.int(6, 'Number of Grids', options=[2, 4, 6, 8])
iCool = input.int(2, 'Cooldown(2)', minval=0)
iDir = input.string('neutral', 'Direction', options=['neutral', 'up', 'down'])
iGT = input.int(70, 'Grid Line Transparency(100 to hide)', minval=0, maxval=100)
iFT = input.int(90, 'Fill Transparency(100 to hide)', minval=0, maxval=100)
iSS = input.string('small', 'Signal Size', options=['small', 'large'])
iReset = input(true, 'Reset Buy/Sell Index When Grids Change')
iEXTR = input(true, 'Use Highs/Lows for Signals')
iMT = input(true, 'Show Min Tick')
iRFC = input(false, 'Reverse Fill Colors')
qty_ent = iGrids/2
qty_pos = strategy.initial_capital / qty_ent / 2 / open
//----<Colors>-----------------------------------------------------------------------------------//
RedGrid = color.new(color.red, iGT)
GreenGrid = color.new(color.green, iGT)
Crimson = #DC143C
LimeGreen = #32CD32
//----<Variables>--------------------------------------------------------------------------------//
NextUP = 0.0
NextDN = 0.0
LastSignal = 0
LastSignal_Index = 0
AP = 0.0
G = iGrids
Buy = false
Sell = false
UpperLimit = 0.0
LowerLimit = 0.0
SignalLine = 0.0
CurrentGrid = 0.0
BuyLine = 0.0
SellLine = 0.0
DIR = 0
MeaningOfLife = 42
//----<Calculations>-----------------------------------------------------------------------------//
//Lazy Formula
lz(x, lzf) =>
LZ = 0.0
s = math.sign(x)
LZ := x == nz(x[1], x) ? x : x > nz(LZ[1] + lzf * LZ[1] * s, x) ? x : x < nz(LZ[1] - lzf * LZ[1] * s, x) ? x : LZ[1]
LZ
//Smoothing
LR = ta.linreg(close, iLen, 0)
SMA = ta.sma(close, iLen)
EMA = ta.ema(close, iLen)
VWMA = ta.vwma(close, iLen)
TEMA = ta.ema(ta.ema(ta.ema(close, iLen), iLen), iLen)
MA = iMA == 'lreg' ? LR : iMA == 'sma' ? SMA : iMA == 'ema' ? EMA : iMA == 'vwma' ? VWMA : TEMA
//Make Lazy
LMA = lz(MA, iLZ)
//Calculate Elasticity
ELSTX = syminfo.mintick * iELSTX
//Show Mintick
if iMT and barstate.islast
table.cell(table.new(position.top_right, 1, 1), 0, 0, str.tostring(syminfo.mintick))
//Anchor Point
AP := MA > LMA ? AP[1] + ELSTX : MA < LMA ? AP[1] - ELSTX : AP[1]
AP := AP >= NextUP[1] ? NextUP[1] : AP
AP := AP <= NextDN[1] ? NextDN[1] : AP
//Reset if Next Level Reached or AP is crossed
AP := LMA != LMA[1] ? LMA : AP
//Next Gridlines
NextUP := LMA != LMA[1] ? LMA + LMA * iGI : NextUP[1]
NextDN := LMA != LMA[1] ? LMA - LMA * iGI : NextDN[1]
//Grid Interval
GI = AP * iGI
//----<Grid Array>-------------------------------------------------------------------------------//
a_grid = array.new_float(9)
for x = -4 to 4 by 1
array.set(a_grid, x + 4, AP + GI * x)
Get_Array_Values(ArrayName, index) =>
value = array.get(ArrayName, index)
value
//----<Set Static Grids>-------------------------------------------------------------------------//
G0 = Get_Array_Values(a_grid, 0) //Upper4
G1 = Get_Array_Values(a_grid, 1) //Upper3
G2 = Get_Array_Values(a_grid, 2) //Upper2
G3 = Get_Array_Values(a_grid, 3) //Upper1
G4 = Get_Array_Values(a_grid, 4) //Center
G5 = Get_Array_Values(a_grid, 5) //Lower1
G6 = Get_Array_Values(a_grid, 6) //Lower2
G7 = Get_Array_Values(a_grid, 7) //Lower3
G8 = Get_Array_Values(a_grid, 8) //Lower4
//----<Set Upper and Lower Limits>---------------------------------------------------------------//
UpperLimit := G >= 8 ? G8 : G >= 6 ? G7 : G >= 4 ? G6 : G5
LowerLimit := G >= 8 ? G0 : G >= 6 ? G1 : G >= 4 ? G2 : G3
//----<Calculate Signals>------------------------------------------------------------------------//
Get_Signal_Index() =>
Value = 0.0
Buy_Index = 0
Sell_Index = 0
start = 4 - G / 2
end = 4 + G / 2
for x = start to end by 1
Value := Get_Array_Values(a_grid, x)
if iEXTR
Sell_Index := low[1] < Value and high >= Value ? x : Sell_Index
Buy_Index := high[1] > Value and low <= Value ? x : Buy_Index
Buy_Index
else
Sell_Index := close[1] < Value and close >= Value ? x : Sell_Index
Buy_Index := close[1] > Value and close <= Value ? x : Buy_Index
Buy_Index
[Buy_Index, Sell_Index]
[BuyLine_Index, SellLine_Index] = Get_Signal_Index()
//----<Signals>----------------------------------------------------------------------------------//
Buy := BuyLine_Index > 0 ? true : Buy
Sell := SellLine_Index > 0 ? true : Sell
//No repeat trades at current level
Buy := low >= SignalLine[1] - GI ? false : Buy
Sell := high <= SignalLine[1] + GI ? false : Sell
//No trades outside of grid limits
Buy := close > UpperLimit ? false : Buy
Buy := close < LowerLimit ? false : Buy
Sell := close < LowerLimit ? false : Sell
Sell := close > UpperLimit ? false : Sell
//Direction Filter (skip one signal if against market direction)
DIR := iDir == 'up' ? 1 : iDir == 'down' ? -1 : 0
Buy := DIR == -1 and low >= SignalLine[1] - GI * 2 ? false : Buy
Sell := DIR == 1 and high <= SignalLine[1] + GI * 2 ? false : Sell
//Conflicting Signals
if Buy and Sell
Buy := false
Sell := false
LastSignal_Index := LastSignal_Index[1]
LastSignal_Index
//----<Cooldown>---------------------------------------------------------------------------------//
y = 0
for i = 1 to iCool by 1
if Buy[i] or Sell[i]
y := 0
break
y += 1
y
CoolDown = y
Buy := CoolDown < iCool ? false : Buy
Sell := CoolDown < iCool ? false : Sell
//----<Trackers>---------------------------------------------------------------------------------//
LastSignal := Buy ? 1 : Sell ? -1 : LastSignal[1]
LastSignal_Index := Buy ? BuyLine_Index : Sell ? SellLine_Index : LastSignal_Index[1]
SignalLine := Get_Array_Values(a_grid, LastSignal_Index)
//Reset to Center Grid when LMA changes
if iReset
SignalLine := LMA < LMA[1] ? UpperLimit : SignalLine
SignalLine := LMA > LMA[1] ? LowerLimit : SignalLine
SignalLine
BuyLine := Get_Array_Values(a_grid, BuyLine_Index)
SellLine := Get_Array_Values(a_grid, SellLine_Index)
//----<Plot Grids>--------------------------//
color apColor = na
apColor := MA < AP ? color.new(color.red, iGT) : MA > AP ? color.new(color.green, iGT) : apColor[1]
apColor := LMA != LMA[1] ? na : apColor
plot(G >= 8 ? G0 : na, color=GreenGrid)
plot(G >= 6 ? G1 : na, color=GreenGrid)
plot(G >= 4 ? G2 : na, color=GreenGrid)
plot(G >= 2 ? G3 : na, color=GreenGrid)
plot(G4, color=apColor, linewidth=4) // Center
plot(G >= 2 ? G5 : na, color=RedGrid)
plot(G >= 4 ? G6 : na, color=RedGrid)
plot(G >= 6 ? G7 : na, color=RedGrid)
plot(G >= 8 ? G8 : na, color=RedGrid)
//fill
LineAbove = SignalLine == UpperLimit ? SignalLine : SignalLine + GI
LineBelow = SignalLine == LowerLimit ? SignalLine : SignalLine - GI
a = plot(LineAbove, color=color.new(color.red, 100), style=plot.style_circles)
b = plot(LineBelow, color=color.new(color.green, 100), style=plot.style_circles)
boxColor = LastSignal == 1 ? color.new(color.green, iFT) : color.new(color.red, iFT)
if iRFC
boxColor := LastSignal == -1 ? color.new(color.green, iFT) : color.new(color.red, iFT)
boxColor
fill(a, b, color=boxColor)
//----<Plot Signals>-----------------------------------------------------------------------------//
plotchar(Buy and iSS == 'small', 'Buy', color=color.new(LimeGreen, 0), size=size.tiny, location=location.belowbar, char='▲')
plotchar(Sell and iSS == 'small', 'Sell', color=color.new(Crimson, 0), size=size.tiny, location=location.abovebar, char='▼')
plotchar(Buy and iSS == 'large', 'Buy', color=color.new(LimeGreen, 0), size=size.small, location=location.belowbar, char='▲')
plotchar(Sell and iSS == 'large', 'Sell', color=color.new(Crimson, 0), size=size.small, location=location.abovebar, char='▼')
//----<Alerts>-----------------------------------------------------------------------------------//
alertcondition(condition=Buy, title='buy', message='buy')
alertcondition(condition=Sell, title='sell', message='sell')
//-----------------------------------------------------------------------------------------------//
if strategy.position_size >= 0 and Buy
strategy.entry("Long", strategy.long, qty = qty_pos)
if strategy.position_size <= 0 and Sell
strategy.entry("Short", strategy.short, qty = qty_pos)
if strategy.position_size > 0 and Sell
strategy.close("Long", qty = qty_pos)
if strategy.position_size < 0 and Buy
strategy.close("Short", qty = qty_pos)