Skip to content

Repository files navigation

Dynamic Grid Trading (DGT) β€” Strategy Research & Backtesting Framework

This repository implements and extends the academic Dynamic Grid Trading (DGT) strategy into a flexible research and backtesting framework.

The strategy is inspired by the paper: "Dynamic Grid Trading Strategy: From Zero Expectation to Market Outperformance"
by Kai-Yuan Chen, Kai-Hsin Chen, and Jyh-Shing Roger Jang (arXiv:2506.11921).

The main objective of this project is to provide a robust environment for testing, comparing, and optimizing multiple Dynamic Grid Trading strategies on historical market data. Users can define custom ranges of the two key grid parameters β€” grid size and number of grid levels β€” and automatically evaluate every parameter combination to identify the most effective configurations.

Building upon the original DGT approach, I introduced a market regime filtering mechanism to improve strategy robustness. Since grid trading strategies are designed to capture price oscillations and generally perform better in range-bound markets than in strong trending environments, I integrated statistical regime detection based on both the Augmented Dickey-Fuller (ADF) test and the Hurst exponent. This allows the strategy to dynamically identify market conditions and avoid initiating grid positions during unfavorable trending periods.

The framework includes a complete backtesting pipeline with portfolio tracking, performance metrics, parameter comparison, and visualization tools, enabling systematic analysis of how different grid configurations behave across various market regimes.

A future extension could integrate the strategy into a live trading environment (e.g., on dYdX), but live execution is not currently implemented in this repository.


🎯 Project Mission

The primary objective of this project is to bridge the gap between academic theory and institutional-grade execution. While the original DGT paper proves that a dynamic reset mechanism can outperform static grid systems and buy-and-hold benchmarks in ideal settings, transitioning this strategy to live cryptocurrency markets requires a rigorous backtester, statistical market regime filters, and low-latency execution logic.

We are transforming this repository into a complete quantitative trading pipeline optimized for dYdX Chain (v4), focusing on capital efficiency, risk-adjusted returns, and safety.


πŸ—ΊοΈ Architectural Roadmap

The transition from academic code to live trading is structured into three main phases:

flowchart TD
    %% Define styles
    classDef phase1 fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,color:#01579b;
    classDef phase2 fill:#e8f5e9,stroke:#388e3c,stroke-width:2px,color:#1b5e20;
    classDef phase3 fill:#fff3e0,stroke:#f57c00,stroke-width:2px,color:#e65100;
    classDef core fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#4a148c;

    subgraph AcademicCore["Academic Foundation"]
        A["DGT Strategy Core Logic"]:::core
    end

    subgraph Phase1["Phase 1: Rigorous Backtesting"]
        B["Historical CSV Data (1m)"]:::phase1
        C["DGT Backtest Engine"]:::phase1
        D["Slippage & Latency Simulator"]:::phase1
        E["dYdX Fee Structure Model"]:::phase1
    end

    subgraph Phase2["Phase 2: Market Filtering"]
        F["Augmented Dickey-Fuller (ADF)"]:::phase2
        G["Hurst Exponent (H)"]:::phase2
        H["Regime Decision Engine"]:::phase2
    end

    subgraph Phase3["Phase 3: Live Execution (dYdX)"]
        I["dYdX v4 API Connector"]:::phase3
        J["WebSocket Orderbook Sync"]:::phase3
        K["Active Order Manager"]:::phase3
        L["Risk Controls & Circuit Breakers"]:::phase3
    end

    A --> C
    B --> C
    C --> D
    C --> E
    F --> H
    G --> H
    H -->|Regime Signal| K
    D & E --> M["Key Metrics (Sharpe, MaxDD, Win Rate)"]:::phase1
    L --> K
    K --> M
Loading

Phase 1: Rigorous Backtesting

To establish a realistic baseline, we are upgrading the simple backtester to simulate live market mechanics:

  • dYdX Fee Modeling: Incorporating the tiered Maker/Taker fee schedules on dYdX.
  • Slippage & Market Impact: Modeling execution slippage using historical bid-ask spreads and order book depth to ensure large orders do not overestimate performance.
  • Execution Delays: Simulating latency (API roundtrips, node execution, and network delay) to test if dynamic grid resets are front-run or suffer from price degradation.

Phase 2: Market Filtering (Regime Detection)

Traditional grid strategies fail during prolonged, strong trending phases. We are introducing a statistical regime filter to active trading pairs:

  • Augmented Dickey-Fuller (ADF) Test: Evaluates whether a asset's price series is stationary (mean-reverting) or has a unit root (trending).
  • Hurst Exponent ($H$): Measures the long-term memory and persistence of price time series.
    • $H < 0.5$: Mean-reverting regime (Optimal for Grid Trading).
    • $H = 0.5$: Random walk / Brownian motion.
    • $H > 0.5$: Trending regime (Grid trading is halted or parameters are dynamically widened).

N.B.: Customizing Filters: The trading thresholds can be configured in the config.py file. If any threshold is exceeded, the strategy automatically refrains from opening new positions. Lower threshold values make the trading conditions more restrictive, requiring stronger market signals before any trade is executed.

  • Decision Engine: Automatically halts grid generation or dynamically scales grid boundaries based on real-time ADF and Hurst calculations.

Phase 3 (no yet implemented!): Live Execution on dYdX

Developing a secure, low-latency execution wrapper targeting the Cosmos-based dYdX Chain (v4):

  • API & WebSocket Client: Establishing streaming connections to monitor order-books, account balances, and position fills in real-time.
  • Smart Order Router: Handling fast grid resets, dynamic level adjustments, and order placement via asynchronous threads.
  • Risk Management: Multi-layered risk framework featuring automatic margin liquidation warnings, max-drawdown circuit breakers, and asset-specific risk limits.

πŸ› οΈ Technology Stack & Libraries

To support this expansion, we use the following technologies:

Category Component / Library Purpose
Strategy & Logic Python 3.10+ Core development runtime environment
Statistical Analysis statsmodels Performing ADF stationarity checks
numpy & scipy Mathematical modeling, variance ratio tests, and Hurst exponent calculations
Data Processing pandas Large-scale timeseries manipulation and cleaning
Exchange Integration dydx-v4-client Live execution, order creation, and private websocket endpoints
asyncio & aiohttp Async event-loop handling for real-time WebSocket tick streams
Plotting & Analytics matplotlib & seaborn Visualizing equity curves, drawdown profile, and regime transition boundaries

πŸ“Š Key Validation Metrics

A strategy is only as good as its risk metrics. We evaluate all backtest iterations and live performance against the following key metrics:

$$\text{Sharpe Ratio} = \frac{R_p - R_f}{\sigma_p}$$

  • Sharpe Ratio (Annualized): Measures the return per unit of total risk. Target: $> 1.8$ on historical data.
  • Sortino Ratio: Focuses strictly on downside risk rather than total volatility, protecting against asymmetric drawdown risk. Target: $> 2.2$.
  • Maximum Drawdown (Max DD): The maximum peak-to-trough drop in portfolio value. We actively optimize parameters to keep Max DD $< 15%$.
  • Win Rate (Per Grid Segment): The percentage of closed grid segments that yield a positive net return after accounting for all taker/maker fees.
  • Profit Factor: The ratio of gross profits to gross losses.
  • Calmar Ratio: Annualized rate of return divided by the maximum drawdown over the same period; key for tracking structural tail risk.
  • Execution Slippage Leakage: Comparing expected fill prices to actual fill prices to quantify latency costs.

πŸ“‚ Project Structure

Dynamic-Grid-Trading/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ config.py           # Core strategy configuration parameters
β”‚   β”œβ”€β”€ grid_logic.py       # Math formulas, reset bounds, and settlement logic
β”‚   β”œβ”€β”€ dgt_backtest.py     # Main backtest loop & metrics calculator
β”‚   β”‚
β”‚   β”œβ”€β”€ filters/            # Phase 2: Statistical market regime filtering
β”‚   β”‚   β”œβ”€β”€ __init__.py
β”‚   β”‚   β”œβ”€β”€ adf_test.py     # Augmented Dickey-Fuller stationarity implementation
β”‚   β”‚   └── hurst_exp.py    # Hurst exponent calculation (persistence analysis)
β”‚   β”‚
β”‚   └── execution/ (no yet implemented!)          # Phase 3: Live execution engine for dYdX
β”‚       β”œβ”€β”€ __init__.py
β”‚       β”œβ”€β”€ dydx_client.py  # REST and WebSockets wrapper for dYdX v4 Chain
β”‚       └── order_manager.py# Active grid order placement & fail-safe tracker
β”‚
β”œβ”€β”€ requirements.txt        # Updated Python library dependencies
β”œβ”€β”€ README.md               # Project documentation (this file)
└── fetch_candlestick.py    # Historical candlestick download utility

πŸ—„οΈ Persistent Data Storage & Incremental Caching

To optimize backtesting speed and avoid hitting API rate limits or downloading redundant historical files, the system implements a persistent, serverless local database.

Database Choice: SQLite

We chose SQLite as the local database solution for several key architectural reasons:

  • Zero Configuration: A serverless database that stores everything in a single local file (data/market_data.db) without requiring any daemon process or Docker containers.
  • Persistence: Stored permanently on the host system, surviving kernel restarts, Python environment resets, and machine restarts.
  • Index-backed Speeds: A compound primary key on (symbol, interval, open_time_ms) facilitates sub-millisecond query filtering.
  • Pandas Native: Seamless reading and writing of query results directly to and from pandas DataFrames.

Incremental Fetch & Caching Architecture

The download utility in fetch_candlestick.py integrates this local database to provide an intelligent cache-aside logic:

  1. Cache Inspection: The requested time frame is partitioned into discrete 1000-candle chunks. The script queries the database for existing records within each chunk.
  2. Gap Filtering: The scheduler filters out chunks that are already fully cached, targeting only the missing time gaps for API downloading.
  3. Deduplicated Upsert: Newly fetched candles are merged using INSERT OR REPLACE statements to avoid duplicates while retaining historical consistency.
  4. Legacy CSV Export: Once cached, the entire continuous dataset is queried from SQLite and written to the configured CSV (e.g., BTCUSDT_spot_1m.csv) to keep the backtest engine backward-compatible.

πŸš€ Setup & Execution

1. Installation

Clone the repository and install the project in a Python virtual environment:

git clone https://github.com/mathiasmoka/Dynamic-Grid-Trading.git
cd Dynamic-Grid-Trading
python3 -m venv venv

source venv/bin/activate
pip install -r requirements.txt

Note

If you have an error message with the command python3 -m venv venv, remove the virtual environement with the following command: rm -rf venv and then try python3 -m venv venv

2. Configure Parameters

Set up your parameters inside src/config.py, specifying the currency pair, time frame, grid settings, and dYdX API keys.

3. Run Backtest

Run the updated DGT backtester:

python -m src.dgt_backtest

Comparing the strategies using the backtest results

1. The summary in the terminal

At the end of the backtest, a brief summary of some metrics is provided in the terminal.

alt text

2. The CSV

After running the backtest, a CSV file named BTCUSDT_spot_grid_strategy_backtest_results containing the backtest results, is generated in the local directory.

N.B.: If you run a new backtest, it will overwrite this file. If you want to save it, rename it to avoid overwriting, or download it.

3. The Dashboard

To compare visually the different strategies of the backtest, you can open the HTML dashboard. It is a static HTML file, which uses the content of the BTCUSDT_spot_grid_strategy_backtest_results.

After running a new backtest, make sure to refresh the dashboard page to view the updated results.

N.B.: the x-axis is the Grid size.

alt text

What do we change between the different strategies of a same backtest?

In a backtest, each strategy corresponds to a different combination of parameters tested on the same historical data. For the Dynamic Grid Trading (DGT) strategy, we mainly vary the grid size (the percentage distance between grid levels) and the number of grid levels (controlled by grid_numbers_half). These parameters determine how frequently trades are triggered and how the strategy reacts to price movements. A smaller grid size creates more frequent trades with smaller gains per trade, while a larger grid size reduces trading frequency but captures larger price movements. The number of grid levels controls the width and granularity of the grid, influencing risk exposure and the ability to handle larger market fluctuations. Each parameter combination is evaluated independently to compare profitability, return, and risk-adjusted performance.

alt text

N.B: the grid sizes and the numbers of grid levels included in the backtest are 100% customizable in the config.py file.


🧾 Citation & Academic Credit

If you use this codebase or build upon these concepts, please credit the original authors of the strategy:

@article{chen2025dynamic,
  title={Dynamic Grid Trading Strategy: From Zero Expectation to Market Outperformance},
  author={Chen, Kai-Yuan and Chen, Kai-Hsin and Jang, Jyh-Shing Roger},
  journal={arXiv preprint arXiv:2506.11921},
  year={2025},
  url={https://arxiv.org/abs/2506.11921}
}

About

A research and backtesting framework for Dynamic Grid Trading (DGT), enabling systematic comparison and optimization of grid strategies across different parameter configurations.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages