Custom MA/EMA Trading Bot with ADX Filter – Development & Optimization

Typical EMA Strategy Problem — False Signals in Sideways Markets The ADX filter solves this but requires proper parametrization. We build bots where the moving average crossover strategy is reinforced by the ADX indicator and risk management. Our team has 5+ years of experience and has implemente

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1308
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1003
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1269
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1009

Typical EMA Strategy Problem — False Signals in Sideways Markets

The ADX filter solves this but requires proper parametrization. We build bots where the moving average crossover strategy is reinforced by the ADX indicator and risk management. Our team has 5+ years of experience and has implemented 50+ trading bots for the crypto market, including complex multi-timeframe configurations and backtesting.

Moving averages (MA) are a basic technical analysis tool. An MA/EMA bot generates signals based on crossovers and price position relative to the average. However, without additional filters, such strategies produce many false entries in flat markets. We implement ADX (Average Directional Index) — a trend strength indicator that filters out trades when ADX < 25.

What's the difference between MA and EMA?

SMA (Simple MA) — simple average over N periods, equal weight for all candles. EMA (Exponential MA) — weighted average giving more weight to recent candles, allowing faster reaction to price changes.

import pandas as pd def sma(close: pd.Series, period: int) -> pd.Series: return close.rolling(period).mean() def ema(close: pd.Series, period: int) -> pd.Series: return close.ewm(span=period, adjust=False).mean() 

For trading, EMA is preferable: it signals trend reversals faster.

How to optimize EMA parameters for your asset?

Optimal EMA periods depend on the timeframe and asset volatility. We use grid search with out-of-sample testing to prevent overfitting.

Timeframe Fast EMA Slow EMA When to use
1h 9 21 Intraday
4h 21 55 Swing
Daily 50 200 Golden/Death Cross
Weekly 20 50 Long-term

Classic Golden Cross / Death Cross Strategy

Crossing EMA50 and EMA200:

class GoldenCrossStrategy: def generate_signal(self, df: pd.DataFrame) -> str: ema_fast = ema(df['close'], 50).shift(1) ema_slow = ema(df['close'], 200).shift(1) prev_fast = ema_fast.iloc[-2] prev_slow = ema_slow.iloc[-2] curr_fast = ema_fast.iloc[-1] curr_slow = ema_slow.iloc[-1] if prev_fast <= prev_slow and curr_fast > curr_slow: return 'BUY' # Golden Cross if prev_fast >= prev_slow and curr_fast < curr_slow: return 'SELL' # Death Cross return 'HOLD' 

Without a trend filter, this strategy produces many false signals. Adding ADX significantly improves results — win rate rises from 45% to 62% (38% better).

Strategy Comparison by Metrics

Strategy Win rate Sharpe ratio Max drawdown
Golden Cross (no ADX) 45% 0.8 18%
Golden Cross + ADX 62% 1.2 12%
Triple EMA 50% 0.9 15%

Triple EMA Strategy (9/21/55)

Three averages provide more confirmation:

class TripleEMAStrategy: def generate_signal(self, df: pd.DataFrame) -> str: e9 = ema(df['close'], 9).shift(1) e21 = ema(df['close'], 21).shift(1) e55 = ema(df['close'], 55).shift(1) last_9 = e9.iloc[-1] last_21 = e21.iloc[-1] last_55 = e55.iloc[-1] price = df['close'].iloc[-1] if last_9 > last_21 > last_55 and price > last_9: return 'BUY' if last_9 < last_21 < last_55 and price < last_9: return 'SELL' return 'HOLD' 

Improving EMA Strategy with ADX Filter

EMA strategies perform poorly in sideways markets — many false signals. The ADX (Average Directional Index) filter solves this: trade only when ADX > 25 (market is trending). This reduces the number of trades but increases their quality — the Sharpe ratio improves by 50% (from 0.8 to 1.2).

Bot Implementation

class MABot: def __init__(self, strategy, exchange_client, config): self.strategy = strategy self.exchange = exchange_client self.config = config self.position = None self.candles = [] async def on_candle(self, candle: dict): self.candles.append(candle) if len(self.candles) > 300: self.candles = self.candles[-300:] if len(self.candles) < 210: # нужен прогрев для EMA 200 return df = pd.DataFrame(self.candles) signal = self.strategy.generate_signal(df) if signal == 'BUY' and not self.position: order = await self.exchange.place_market_order( self.config.symbol, 'buy', self.config.position_size ) self.position = {'entry': order.fill_price, 'side': 'long'} elif signal == 'SELL' and self.position and self.position['side'] == 'long': await self.exchange.place_market_order( self.config.symbol, 'sell', self.config.position_size ) pnl = (order.fill_price - self.position['entry']) / self.position['entry'] * 100 logger.info(f"Closed long, PnL: {pnl:.2f}%") self.position = None 

Parametrization and Optimization

We perform grid search over EMA periods, ADX thresholds, stop-loss, and take-profit. Optimization is done on historical data (1–3 years) with out-of-sample testing. Average trade profit is 2%, and annual returns can reach 30% with proper tuning.

EMA Formula EMA = (Close - EMA_prev) * k + EMA_prev, where k = 2 / (N + 1)

What's Included

  • Market analysis and timeframe selection
  • Bot architecture design (modules: data, strategy, execution, risk management)
  • Strategy implementation in Python using CCXT and Pandas
  • Backtesting on historical data (minimum 1 year) with metrics: Sharpe, max drawdown, win rate
  • Parameter optimization (grid search) with out-of-sample testing
  • Deployment on VPS (AWS, DigitalOcean) with monitoring
  • Documentation and training (2 hours)
  • 2-week stability guarantee after launch

Our Process

  1. Analytics — discuss strategy, asset, time frame.
  2. Design — architecture, exchange and API selection.
  3. Implementation — write code, integrate with exchange.
  4. Testing — backtesting, real-time simulation.
  5. Deployment — to your server or our VPS.
  6. Monitoring — first 2 weeks, adjust parameters if needed.

Common Mistakes When Building MA/EMA Bots

  • No trend filter (ADX) — false signals in flat markets.
  • Overfitting parameters to historical data — future losses.
  • Ignoring fees and slippage — profitable on paper, unprofitable in reality.
  • No risk management (stop-loss, position sizing).
  • Incorrect EMA calculation on incomplete candles.

Timeline and Cost

Timeline: 7 to 14 days for a basic version. Cost ranges from $2,000 to $5,000 depending on complexity, number of exchanges, and additional modules. Order your bot with already tuned optimization. Get an expert consultation to evaluate your project.

Smooth Moving Averages — a basic concept. We use CCXT for exchange integration. Contact us — we'll help you implement a reliable moving average trading bot.