Automated Grid Trading in Python: A Beginner’s Guide to Algorithmic Profitability | by Aydar Murt | The Capital | Jan, 2025


Grid trading involves constructing a grid of predefined price levels on a chart. Every time the price touches one of these levels, both long and short positions are executed. Profit targets for these trades are assigned to subsequent grid levels. This strategy thrives in oscillating markets, especially on lower timeframes where frequent price swings are common.

In this article, we’ll implement a Python script to simulate grid trading and backtest its efficacy using historical data. Let’s get started.

Before implementing our strategy, let’s import the necessary Python libraries and retrieve historical EUR/USD data.

import yfinance as yf
import pandas as pd
import numpy as np
import pandas_ta as ta

# Download the EUR/USD data for the last 59 days with a 5-minute interval
dataF = yf.download("EURUSD=X",
start=pd.Timestamp.today() - pd.DateOffset(days=59),
end=pd.Timestamp.today(),
interval='5m')

Libraries Used:

  • yfinance (yf): Downloads financial market data from Yahoo Finance.
  • pandas (pd): Provides robust data manipulation capabilities.
  • numpy (np): Supports efficient numerical calculations.
  • pandas_ta (ta): Offers technical analysis indicators.

By downloading high-frequency data using yfinance, we create a detailed dataset perfect for backtesting our grid trading strategy.

A “grid” is a series of evenly spaced price levels, forming the backbone of the trading strategy. We’ll generate grid values based on parameters that you can adjust for different market conditions.

grid_distance = 0.005  # Distance between grid levels
midprice = 1.065 # Central reference price

def generate_grid(midprice, grid_distance, grid_range):
return np.arange(midprice - grid_range, midprice + grid_range, grid_distance)
grid = generate_grid(midprice=midprice, grid_distance=grid_distance, grid_range=0.1)

  • grid_distance (0.005): The incremental price gap between grid lines.
  • midprice (1.065): Acts as the midpoint of the grid.
  • grid_range (0.1): Determines the total extent of grid levels above and below the midprice.

You can adjust these parameters dynamically, depending on the asset and its market conditions. The generate_grid function automates grid creation, facilitating a structured approach to the trading strategy.

Signals are generated whenever the price crosses a grid level. This triggers both long and short trades.

signal = [0] * len(dataF)
i = 0
for index, row in dataF.iterrows():
for p in grid:
if min(row.Low, row.High) < p and max(row.Low, row.High) > p:
signal[i] = 1
i += 1
dataF["signal"] = signal
dataF[dataF["signal"] == 1]

Signal Logic:

  • If the high and low prices of a row straddle a grid line, a trading signal is generated.
  • A signal column is appended to the dataset for backtesting purposes.

Before running the backtest, we enhance our dataset by calculating the Average True Range (ATR), which helps refine trade parameters.

dfpl = dataF[:].copy()

def SIGNAL():
return dfpl.signal
dfpl['ATR'] = ta.atr(high=dfpl.High, low=dfpl.Low, close=dfpl.Close, length=16)
dfpl.dropna(inplace=True)

The ATR, a measure of volatility, allows us to adapt stop-loss and take-profit levels dynamically.

Here, we define a custom grid trading strategy and evaluate its performance using the backtesting library.

from backtesting import Strategy, Backtest
import backtesting

class MyStrat(Strategy):
mysize = 50
def init(self):
super().init()
self.signal1 = self.I(SIGNAL)
def next(self):
super().next()
slatr = 1.5 * grid_distance # Stop-loss distance
TPSLRatio = 0.5 # Take profit:stop loss ratio
if self.signal1 == 1 and len(self.trades) <= 10000:
# Short Trade
sl1 = self.data.Close[-1] + slatr
tp1 = self.data.Close[-1] - slatr * TPSLRatio
self.sell(sl=sl1, tp=tp1, size=self.mysize)
# Long Trade
sl1 = self.data.Close[-1] - slatr
tp1 = self.data.Close[-1] + slatr * TPSLRatio
self.buy(sl=sl1, tp=tp1, size=self.mysize)
# Execute the backtest
bt = Backtest(dfpl, MyStrat, cash=50, margin=1/100, hedging=True, exclusive_orders=False)
stat = bt.run()

Key Insights:

  • mysize: Determines trade size.
  • slatr and TPSLRatio: Customize stop-loss and take-profit levels.
  • Backtesting library: Streamlines the testing process, ensuring detailed performance analysis.

The backtest results showcase the strategy’s robustness, especially over a 57-day period:

  • Return: 172.04%
  • Annualized Return: 37,364.62%
  • Sharpe Ratio: 0.81
  • Number of Trades: 1,698
  • Win Rate: 73.03%
  • Max Drawdown: -17.03%

Despite occasional drawdowns, the strategy’s performance metrics affirm its viability for short-term trading.

Grid trading, as demonstrated here, is a promising algorithmic strategy. Its systematic nature and adaptability make it a valuable tool in a trader’s arsenal. By leveraging Python’s powerful libraries, even beginners can implement and refine this approach for profitable outcomes.

Stay tuned for more insights and strategies to enhance your algorithmic trading journey!



Source link

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert