Grid Trading Strategy for Crypto Sideways Markets: Analysis and Parameter Tuning
Grid Trading Strategy for Crypto Sideways Markets: Analysis and Parameter Tuning
Grid trading thrives in choppy, range-bound markets — exactly the conditions that frustrate trend-followers. Here's how to build, tune, and evaluate a grid strategy.
How Grid Trading Works
A grid strategy places buy and sell limit orders at fixed intervals above and below the current price:
Sell $68,000 ─────────── Grid Level 5
Sell $67,500 ─────────── Grid Level 4
Sell $67,000 ─────────── Grid Level 3
$66,500 ←── Current price
Buy $66,000 ─────────── Grid Level 2
Buy $65,500 ─────────── Grid Level 1
Buy $65,000 ─────────── Grid Level 0
Every time the price drops to a buy level, you accumulate. Every time it rises to a sell level, you take profit. In a range-bound market, this prints money.
Implementation
import numpy as np
import pandas as pd
from dataclasses import dataclass, field
from typing import List, Optional
@dataclass
class GridConfig:
lower_price: float # Bottom of the grid
upper_price: float # Top of the grid
num_grids: int # Number of grid levels
total_investment: float # Total capital to deploy
symbol: str = "BTC/USDT"
@property
def grid_spacing(self) -> float:
return (self.upper_price - self.lower_price) / self.num_grids
@property
def order_size(self) -> float:
return self.total_investment / self.num_grids
@property
def grid_levels(self) -> List[float]:
return [
self.lower_price + i * self.grid_spacing
for i in range(self.num_grids + 1)
]
@dataclass
class GridBacktestResult:
total_return_pct: float
num_trades: int
profit_per_trade: float
max_drawdown_pct: float
sharpe_ratio: float
grid_captures: int # How many grid cycles completed
def backtest_grid(
prices: pd.Series,
config: GridConfig,
) -> GridBacktestResult:
"""Backtest a grid strategy on historical price data."""
levels = config.grid_levels
position = 0.0 # Amount of base asset held
cash = config.total_investment
initial_value = cash
trades = 0
grid_captures = 0
portfolio_values = []
buy_fills = set() # Track which levels have been bought
for price in prices:
# Check buy levels
for i, level in enumerate(levels[:-1]):
if price <= level and i not in buy_fills:
# Buy at this grid level
qty = config.order_size / price
position += qty
cash -= config.order_size
buy_fills.add(i)
trades += 1
# Check sell levels
for i, level in enumerate(levels[1:], 1):
if price >= level and (i - 1) in buy_fills:
# Sell matching position
qty = config.order_size / levels[i - 1] # original buy qty
sell_value = qty * price
position -= qty
cash += sell_value
buy_fills.discard(i - 1)
trades += 1
grid_captures += 1
# Track portfolio value
portfolio_value = cash + position * price
portfolio_values.append(portfolio_value)
# Calculate metrics
pv = pd.Series(portfolio_values)
total_return = (pv.iloc[-1] / initial_value - 1) * 100
daily_returns = pv.pct_change().dropna()
sharpe = (
daily_returns.mean() / daily_returns.std()
* np.sqrt(365)
) if daily_returns.std() > 0 else 0
max_dd = (
(pv.cummax() - pv) / pv.cummax()
).max() * 100
return GridBacktestResult(
total_return_pct=round(total_return, 2),
num_trades=trades,
profit_per_trade=round(
(pv.iloc[-1] - initial_value) / max(trades, 1), 2
),
max_drawdown_pct=round(max_dd, 2),
sharpe_ratio=round(sharpe, 2),
grid_captures=grid_captures,
)
Parameter Tuning
def optimize_grid_params(
prices: pd.Series,
capital: float = 10000,
) -> dict:
"""Find optimal grid parameters via grid search."""
best_result = None
best_config = None
price_range = prices.max() - prices.min()
mid_price = prices.median()
for num_grids in [5, 10, 15, 20, 30]:
for range_pct in [0.05, 0.10, 0.15, 0.20]:
lower = mid_price * (1 - range_pct)
upper = mid_price * (1 + range_pct)
config = GridConfig(
lower_price=lower,
upper_price=upper,
num_grids=num_grids,
total_investment=capital,
)
result = backtest_grid(prices, config)
if (best_result is None or
result.sharpe_ratio > best_result.sharpe_ratio):
best_result = result
best_config = config
return {
'config': best_config,
'result': best_result,
}
Optimal Parameters by Market Regime
| Market Condition | Grid Count | Range Width | Expected Sharpe |
|---|---|---|---|
| Low volatility sideways | 20-30 | 5-10% | 1.5-3.0 |
| Medium volatility | 10-15 | 10-15% | 0.8-1.5 |
| High volatility | 5-10 | 15-25% | 0.3-0.8 |
| Strong trend | Don't use grid | — | Negative |
Grid strategies are one of the most popular strategy types traded on ClawDUX, where the AI verification engine independently calculates grid capture rates and validates performance claims before listing.
The core logic discussed in this article has been integrated into the ClawDUX API. Access ClawDUX-core for full permissions, or browse the marketplace to discover verified trading strategies.