
The Adaptive Grid Trading Strategy is a quantitative approach based on grid trading systems that automatically adjusts grid line positions to adapt to market changes. This strategy utilizes multiple technical indicators to calculate optimal trading points and dynamically updates the grid based on price movements. The core concept involves executing buy or sell operations when the price touches preset grid lines within a defined price range, thereby capturing profit opportunities from market fluctuations. The strategy’s distinctive features are its elasticity mechanism and laziness parameter, which allow the grid to automatically adjust to different market environments, enabling more flexible trade execution.
This strategy is based on the following core components and operating principles:
Smoothing Mechanism: The strategy first smooths price data, supporting multiple moving average types (linear regression, SMA, EMA, VWMA, and TEMA), allowing users to choose the appropriate smoothing method according to their preferences.
Laziness Parameter: This is a key innovation of the strategy. Through the lz() function, the system only updates signals when price movements exceed a certain percentage, effectively filtering market noise.
Grid Construction Mechanism:
Signal Generation Logic:
Trade Control Mechanism:
Dynamic Grid Updates: When the Lazy Moving Average (LMA) changes, the entire grid structure readjusts, allowing the strategy to adapt to new price ranges.
The strategy stores grid line prices in an array and determines specific buy and sell points by calculating price crossovers with grid lines, while considering various constraints to avoid unnecessary trades.
Strong Adaptability: The strategy’s greatest advantage is its ability to automatically adjust grid positions according to market changes without manual intervention. Through the elasticity parameter and anchor point adjustment mechanism, the grid can move with price trend changes, maintaining relevance.
Noise Filtering: The introduction of the laziness parameter is an innovation that ensures grid adjustments are triggered only when price changes are significant enough, effectively reducing reactions to market noise and improving strategy stability.
Flexible Customization: The strategy provides rich parameter settings, including grid quantity, grid interval, directional preference, smoothing type, etc., allowing users to adjust according to different market characteristics and personal trading styles.
Visualization of Trading Zones: The strategy displays the currently active trading range through color filling, allowing traders to intuitively understand the current price position within the grid, facilitating decision-making.
Risk Control: By restricting trades to occur only within a specific grid range, the strategy establishes a natural risk control mechanism, preventing unfavorable trades under extreme market conditions.
Unified Entry and Exit Logic: Using the same grid lines as buy and sell signals maintains consistency and predictability in trading logic.
Range Breakout Risk: This strategy is essentially a range trading strategy and may face continuous losses in strong trending markets. When prices break through the grid’s upper or lower limits and continue to move in one direction, the strategy may continue to add positions in the wrong direction. The solution is to add trend identification components or pause grid trading when a trend is confirmed.
Parameter Sensitivity: Strategy performance is highly dependent on parameter settings, especially the laziness parameter and elasticity parameter. Inappropriate parameters may lead to untimely or overly sensitive grid adjustments. It is recommended to optimize these parameters through backtesting in different market environments.
Pyramiding Position Risk: The strategy allows multiple entries in the same direction (pyramiding=4), which may lead to excessive leverage and risk concentration under extreme market conditions. Consider setting maximum position limits and implementing dynamic position management.
Slippage and Fee Impact: Grid trading strategies typically involve frequent trading. In actual execution, slippage and fees may significantly affect strategy profitability. These factors need to be incorporated into backtesting, and grid intervals may need adjustment to balance trading frequency and costs.
Signal Conflict Handling: When buy and sell signals appear simultaneously, the current strategy chooses to ignore both signals, which may lead to missing important trading opportunities. Consider resolving signal conflicts based on additional market indicators or price patterns.
Adaptive Parameter Adjustment: The strategy can be further optimized to automatically adjust grid intervals and laziness parameters based on market volatility. For example, increasing grid intervals in high-volatility markets and decreasing them in low-volatility markets, allowing the strategy to better adapt to different market conditions.
Integration of Trend Identification Components: The current strategy may not perform well in trending markets. Trend identification indicators (such as ADX, moving average crossovers, etc.) can be introduced to automatically adjust trading direction or pause grid trading when strong trends are identified.
Dynamic Position Management: The strategy currently uses fixed position sizes. It can be improved to implement risk-based dynamic position management, such as adjusting position size based on ATR (Average True Range) or allocating funds according to account equity percentage.
Multi-Timeframe Analysis: Introduce multi-timeframe analysis, using longer timeframe trend directions to filter trading signals, executing grid trades only in the direction that aligns with larger timeframe trends.
Stop-Loss Mechanism Improvement: The current strategy lacks a clear stop-loss mechanism. Global stop-losses based on overall market conditions can be added, or separate stop-loss points can be set for each grid level to limit maximum losses per trade.
Entry and Exit Timing Optimization: The strategy can integrate volume or price momentum indicators to optimize specific entry and exit timing through additional filtering conditions when grid signals are triggered, improving success rates.
Machine Learning Integration: Consider using machine learning algorithms to optimize grid positions and parameter selection, training models to predict optimal grid settings using historical data, further enhancing strategy adaptability.
The Adaptive Grid Trading Strategy addresses the lack of flexibility in traditional grid trading strategies through innovative laziness functions and dynamic grid adjustment mechanisms. It can automatically adapt to market changes, capture trading opportunities within different price ranges, and control trading behavior through various parameters. This strategy is suitable for application in oscillating markets and can achieve automated trade execution by setting reasonable grid intervals and directional preferences.
Despite potential issues such as range breakout risk and parameter sensitivity, the strategy has the potential to achieve stable performance in various market environments through optimization directions such as trend identification integration and dynamic parameter adjustments. In practical application, it is recommended to first validate strategy performance through comprehensive backtesting, especially performance under different market conditions, and adjust parameters according to specific trading instrument characteristics to achieve optimal results.
//@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)