Разработка бота на базе скользящих средних (MA/EMA)

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка бота на базе скользящих средних (MA/EMA)
Простая
~3-5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1060
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка бота на базе скользящих средних (MA/EMA)

Скользящие средние (Moving Average) — базовый и один из наиболее надёжных инструментов технического анализа. Бот на MA/EMA генерирует сигналы на основе пересечений и положения цены относительно средней. Прост в реализации, понятен в логике, и при правильной параметризации даёт стабильные результаты на трендовых рынках.

MA vs EMA: в чём разница

SMA (Simple MA) — простое среднее за N периодов. Все свечи имеют одинаковый вес.

EMA (Exponential MA) — взвешенное среднее, последние свечи имеют больший вес. Быстрее реагирует на изменения цены.

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()

Для трейдинга EMA предпочтительнее: быстрее сигнализирует о разворотах тренда.

Классические стратегии

Golden Cross / Death Cross

Пересечение EMA 50 и EMA 200:

  • Golden Cross: EMA50 пересекает EMA200 снизу вверх → бычий сигнал
  • Death Cross: EMA50 пересекает 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'

Triple EMA strategy (9/21/55)

Три средних дают больше подтверждений:

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]

        # Бычий сигнал: все EMA выстроены по порядку
        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'

Реализация бота

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

Параметризация и оптимизация

Оптимальные периоды EMA зависят от таймфрейма:

Таймфрейм Fast EMA Slow EMA Применение
1h 9 21 Интрадей
4h 21 55 Свинг
Daily 50 200 Golden/Death Cross
Weekly 20 50 Долгосрок

EMA-стратегии работают плохо на боковом рынке — дают много ложных сигналов. Добавьте фильтр ADX (Average Directional Index): торговать только когда ADX > 25 (рынок в тренде). Это снижает количество сделок, но улучшает качество.