VPSРейтинг
ТрейдингФевраль 2026 · 14 мин чтения

VPS для торгового робота: Python, CCXT и systemd

Торговый робот должен работать 24/7 без остановок — пока рынки открыты. Разберём, как выбрать VPS, задеплоить бота на Python с библиотекой CCXT, безопасно хранить API-ключи и получать уведомления о сделках в Telegram.

Что понадобится

  • • VPS с Ubuntu 22.04 — минимум 1 vCPU, 1 ГБ RAM (рекомендуем 2 ГБ)
  • • Root-доступ по SSH
  • • API-ключи биржи (Binance, Bybit, OKX и др.) — только торговые права, без вывода
  • • Базовые знания Python

Нет VPS? Смотрите подборку VPS для ботов — тариф от 200₽/мес.

1. Требования к VPS для торгового робота

Криптовалютные рынки работают 24/7/365. Торговый робот должен быть постоянно подключён к бирже — локальный компьютер или домашний сервер не подходят из-за перебоев в питании, интернете и необходимости перезагрузок.

ПараметрМинимумРекомендуетсяЗачем
RAM1 ГБ2 ГБPython-бот занимает 80–150 МБ
CPU1 vCPU2 vCPUНе узкое место; важна сеть
Диск20 ГБ SSD20 ГБ NVMeТолько код + логи
Сеть100 Мбит/с1 Гбит/сAPI-запросы небольшие
Uptime99.9%99.95%+Пропущенная сделка = убыток
ОСUbuntu 22.04Ubuntu 22.04 LTSsystemd, поддержка до 2027

Расположение сервера — важно для скорости

Для позиционных стратегий (удержание позиции часами) расположение некритично. Для скальпинга и арбитража — задержка решает: снижение пинга с 70 мс до 5 мс может поднять успешность арбитражных сделок вдвое.

БиржаСерверы биржиОптимальный VPS
BinanceAWS ap-northeast-1 (Tokyo)Tokyo / Osaka
BybitAWS ap-southeast-1 (Singapore)Singapore
OKXAWS ap-east-1 (Hong Kong)Hong Kong / Singapore
KrakenAmsterdam (EU)Netherlands / Frankfurt
Позиционный трейдингЛюбаяЛюбой стабильный VPS
Российские биржи (MEXC, XT.com) — ищите VPS поближе к их дата-центрам. Для работы с зарубежными биржами из России может потребоваться VPS вне РФ.

2. CCXT — единый API для 107 бирж

CCXT (CryptoCurrency eXchange Trading Library) — open-source библиотека с единым интерфейсом для 107+ бирж. Один и тот же код работает на Binance, Bybit, OKX, Kraken без изменений. Версия на февраль 2026: 4.5.40.

107+
бирж
Python
JS · PHP
4.5.40
версия 2026
MIT
лицензия
Установка
pip install ccxt python-dotenv

# Опционально: быстрый JSON-парсер
pip install ccxt[orjson]
Основные методы CCXT (работают на любой бирже)
import ccxt

exchange = ccxt.bybit({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_API_SECRET',
    'enableRateLimit': True,  # ОБЯЗАТЕЛЬНО — иначе забанят по IP
})

# Баланс
balance = exchange.fetch_balance()
usdt = balance['USDT']['free']   # доступный баланс

# Свечи OHLCV — [timestamp, open, high, low, close, volume]
candles = exchange.fetch_ohlcv('BTC/USDT', timeframe='1h', limit=100)

# Текущая цена
ticker = exchange.fetch_ticker('BTC/USDT')
price = ticker['last']

# Стакан заявок
orderbook = exchange.fetch_order_book('BTC/USDT')

# Рыночный ордер
order = exchange.create_market_buy_order('BTC/USDT', 0.001)

# Лимитный ордер
order = exchange.create_limit_buy_order('BTC/USDT', 0.001, 60000)

# Открытые ордера
open_orders = exchange.fetch_open_orders('BTC/USDT')

# Отмена ордера
exchange.cancel_order(order['id'], 'BTC/USDT')

Иерархия ошибок CCXT

ccxt.NetworkErrorСетевые проблемы, таймауты, RateLimitExceeded → повторяем запрос
ccxt.ExchangeErrorОшибки биржи (неверный ордер, нет ликвидности) → не повторяем
ccxt.InsufficientFundsНедостаточно средств → ждём пополнения или уведомляем
ccxt.AuthenticationErrorНеверные API-ключи → немедленно останавливаем бота

3. Установка окружения на VPS

Создаём отдельного пользователя и виртуальное окружение — хорошая практика для любого production-сервиса.

Подключаемся к VPS и готовим сервер
# Обновляем систему
apt update && apt upgrade -y

# Устанавливаем Python 3.11 (есть в Ubuntu 22.04)
apt install -y python3.11 python3.11-venv python3.11-dev git

# Создаём пользователя для бота
useradd -r -m -s /bin/bash botuser
Создаём проект и venv
su - botuser
mkdir -p ~/trading-bot && cd ~/trading-bot

# Виртуальное окружение
python3.11 -m venv venv
source venv/bin/activate

# Устанавливаем зависимости
pip install --upgrade pip
pip install ccxt python-dotenv pandas requests
Структура проекта
trading-bot/
├── venv/              # виртуальное окружение (не в git!)
├── bot.py             # основной файл
├── config.py          # загрузка настроек из .env
├── .env               # API-ключи (не в git!)
├── .env.example       # шаблон без реальных ключей
├── .gitignore
└── requirements.txt
.gitignore
.env
venv/
__pycache__/
*.pyc
*.log
Сохраняем зависимости
pip freeze > requirements.txt
# Позже на новом сервере: pip install -r requirements.txt

4. Безопасность API-ключей

API-ключ с правами торговли — это доступ к вашим деньгам. Три правила, которые нельзя нарушать.

#1
Только в .env
Никогда не вставляйте ключи прямо в код. Только os.getenv() + .env файл.
#2
IP-вайтлист
В настройках биржи ограничьте ключ IP вашего VPS. Украденный ключ — бесполезен без вашего IP.
#3
Без вывода
Только торговые права. Никогда не включайте "Enable Withdrawals" для API торгового бота.
.env — НИКОГДА не коммитьте в git
BYBIT_API_KEY=ваш_ключ_здесь
BYBIT_API_SECRET=ваш_секрет_здесь

# Для Telegram-уведомлений
TELEGRAM_BOT_TOKEN=5123456789:ABCDefgh...
TELEGRAM_CHAT_ID=123456789
Защищаем файл — только владелец может читать
chmod 600 /home/botuser/trading-bot/.env
config.py — загрузка настроек
from dotenv import load_dotenv
import os

load_dotenv()

BYBIT_API_KEY    = os.getenv('BYBIT_API_KEY')
BYBIT_API_SECRET = os.getenv('BYBIT_API_SECRET')
TG_TOKEN         = os.getenv('TELEGRAM_BOT_TOKEN')
TG_CHAT_ID       = os.getenv('TELEGRAM_CHAT_ID')

if not BYBIT_API_KEY or not BYBIT_API_SECRET:
    raise ValueError("API ключи не заданы в .env!")
Как создать API-ключ правильно (Bybit):
  1. Account → API Management → Create New Key
  2. Тип: System-Generated API Key
  3. Права: Read-Write → Spot Trading / Derivatives (только нужное)
  4. Withdrawals — оставьте выключенным
  5. IP Restriction → добавьте статический IP вашего VPS

5. Пример торгового робота (SMA-кроссовер)

Классическая стратегия: покупаем когда быстрая скользящая средняя пересекает медленную снизу вверх (золотой крест), продаём при обратном пересечении (мёртвый крест). Это учебный пример — не финансовый совет.

bot.py — полный код
import ccxt
import pandas as pd
import time
import logging
import requests
from config import BYBIT_API_KEY, BYBIT_API_SECRET, TG_TOKEN, TG_CHAT_ID

# Логирование — идёт в journald через systemd
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s %(message)s',
)
logger = logging.getLogger(__name__)


# --- Telegram-уведомления ---
def notify(message: str) -> None:
    if not TG_TOKEN or not TG_CHAT_ID:
        return
    try:
        requests.post(
            f"https://api.telegram.org/bot{TG_TOKEN}/sendMessage",
            json={'chat_id': TG_CHAT_ID, 'text': message},
            timeout=10,
        )
    except Exception as e:
        logger.error(f"Ошибка Telegram: {e}")


# --- Инициализация биржи ---
exchange = ccxt.bybit({
    'apiKey': BYBIT_API_KEY,
    'secret': BYBIT_API_SECRET,
    'enableRateLimit': True,  # ОБЯЗАТЕЛЬНО
})

SYMBOL       = 'BTC/USDT'
TIMEFRAME    = '1h'
SHORT_MA     = 20
LONG_MA      = 50
ORDER_AMOUNT = 0.001   # BTC — задайте свой размер позиции


def get_signal() -> str | None:
    """Возвращает 'buy', 'sell' или None."""
    ohlcv = exchange.fetch_ohlcv(SYMBOL, TIMEFRAME, limit=LONG_MA + 10)
    df = pd.DataFrame(ohlcv, columns=['ts', 'o', 'h', 'l', 'close', 'v'])
    df['sma_short'] = df['close'].rolling(SHORT_MA).mean()
    df['sma_long']  = df['close'].rolling(LONG_MA).mean()
    df = df.dropna()

    prev = df.iloc[-2]
    curr = df.iloc[-1]

    # Золотой крест — покупаем
    if prev['sma_short'] <= prev['sma_long'] and curr['sma_short'] > curr['sma_long']:
        return 'buy'
    # Мёртвый крест — продаём
    if prev['sma_short'] >= prev['sma_long'] and curr['sma_short'] < curr['sma_long']:
        return 'sell'
    return None


def main() -> None:
    logger.info("Торговый робот запущен")
    notify("Торговый робот запущен ✅")

    while True:
        try:
            signal = get_signal()
            price  = exchange.fetch_ticker(SYMBOL)['last']

            if signal == 'buy':
                order = exchange.create_market_buy_order(SYMBOL, ORDER_AMOUNT)
                msg = f"BUY {ORDER_AMOUNT} BTC @ {price:.2f}$ \nID: {order['id']}"
                logger.info(msg)
                notify(f"📈 {msg}")

            elif signal == 'sell':
                order = exchange.create_market_sell_order(SYMBOL, ORDER_AMOUNT)
                msg = f"SELL {ORDER_AMOUNT} BTC @ {price:.2f}$ \nID: {order['id']}"
                logger.info(msg)
                notify(f"📉 {msg}")

            else:
                logger.info(f"Сигналов нет. {SYMBOL}: {price:.2f}$")

            time.sleep(3600)  # ждём следующую часовую свечу

        except ccxt.InsufficientFunds as e:
            msg = f"Недостаточно средств: {e}"
            logger.error(msg)
            notify(f"⚠️ {msg}")
            time.sleep(300)

        except ccxt.NetworkError as e:
            # Сетевые ошибки — повторяем
            logger.warning(f"Сетевая ошибка (повтор через 60 сек): {e}")
            time.sleep(60)

        except ccxt.AuthenticationError as e:
            # Неверные ключи — останавливаем бота
            msg = f"ОШИБКА АУТЕНТИФИКАЦИИ: {e}"
            logger.error(msg)
            notify(f"🚨 {msg} — бот остановлен!")
            raise SystemExit(1)

        except ccxt.ExchangeError as e:
            logger.error(f"Ошибка биржи: {e}")
            notify(f"❌ Ошибка биржи: {e}")
            time.sleep(300)

        except Exception as e:
            logger.error(f"Неизвестная ошибка: {e}", exc_info=True)
            notify(f"🚨 Критическая ошибка: {e}")
            time.sleep(60)


if __name__ == '__main__':
    main()
Тестовый запуск — убедитесь что код работает
cd ~/trading-bot
source venv/bin/activate
python bot.py
# INFO: Торговый робот запущен
# INFO: Сигналов нет. BTC/USDT: 85234.50$
Совет: Перед запуском на реальные деньги тестируйте в sandbox/testnet: Binance Testnet, Bybit Testnet. В CCXT:'options': {'defaultType': 'spot'} + exchange.set_sandbox_mode(True)

6. Автозапуск через systemd

Systemd перезапустит бота при сбое и включит его автоматически после перезагрузки сервера. RestartSec=30 — даём бирже время восстановиться перед повторным подключением.

/etc/systemd/system/trading-bot.service
[Unit]
Description=Python Trading Bot (CCXT)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=botuser
WorkingDirectory=/home/botuser/trading-bot

# Загружаем .env — ключи не нужно прописывать в unit-файле
EnvironmentFile=/home/botuser/trading-bot/.env

# Запуск через venv
ExecStart=/home/botuser/trading-bot/venv/bin/python bot.py

# Перезапуск при любом падении
Restart=always
RestartSec=30

# Graceful shutdown
KillMode=mixed
TimeoutStopSec=30

# Логи → journald
StandardOutput=journal
StandardError=journal
SyslogIdentifier=trading-bot

# Минимальные привилегии
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
Активируем и запускаем
systemctl daemon-reload
systemctl enable trading-bot   # автозапуск при загрузке сервера
systemctl start trading-bot    # запустить сейчас

# Статус
systemctl status trading-bot
Работа с логами
# Логи в реальном времени
journalctl -u trading-bot -f

# Логи за сегодня
journalctl -u trading-bot --since today

# Последние 100 строк
journalctl -u trading-bot -n 100

# Только ошибки
journalctl -u trading-bot -p err

# За конкретный период
journalctl -u trading-bot --since "2026-02-28 00:00" --until "2026-02-28 23:59"
After=network-online.target — бот не запустится пока не поднимется сеть. Это важно: при перезагрузке сервера без этого бот может стартовать раньше сети и упасть с NetworkError.

7. Мониторинг и Telegram-уведомления

Бот уже отправляет уведомления о сделках через notify(). Добавим уведомление при неожиданной остановке через systemd.

Уведомление при остановке сервиса

/etc/systemd/system/trading-bot.service — добавить в [Service]
# Запускаем при падении сервиса
OnFailure=trading-bot-notify@%n.service
/etc/systemd/system/trading-bot-notify@.service
[Unit]
Description=Notify on trading-bot failure

[Service]
Type=oneshot
User=botuser
EnvironmentFile=/home/botuser/trading-bot/.env
ExecStart=/bin/bash -c 'curl -s -X POST   "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage"   -d "chat_id=${TELEGRAM_CHAT_ID}&text=🚨 Торговый робот упал! Сервис: %i"'

Что логировать обязательно

  • Запуск и остановка бота
  • 📈Каждая открытая и закрытая позиция (символ, цена, объём, ID ордера)
  • ⚠️Недостаточно средств, превышен лимит запросов
  • Ошибки биржи и аутентификации
  • 🔄Статус каждые N часов — бот жив, баланс X USDT

Heartbeat — бот жив?

Добавьте в main() — статус каждые 6 часов
# Счётчик итераций
iteration = 0

while True:
    iteration += 1
    # Heartbeat каждые 6 часов (при sleep=3600 → каждые 6 итераций)
    if iteration % 6 == 0:
        balance = exchange.fetch_balance()
        usdt = balance.get('USDT', {}).get('free', 0)
        notify(f"💚 Робот работает. Баланс: {usdt:.2f} USDT")

    # ... остальная логика

8. Обновление кода без долгих остановок

Деплой нового кода: копируем файлы и перезапускаем сервис. Systemd отправит SIGTERM, бот корректно завершит текущий цикл, затем запустит новую версию.

Через rsync с локальной машины

deploy.sh на вашем компьютере
#!/bin/bash
VPS_IP="YOUR_VPS_IP"

# Копируем код (исключаем venv, .env и кэш)
rsync -avz \
  --exclude='venv/' \
  --exclude='.env' \
  --exclude='__pycache__/' \
  --exclude='*.pyc' \
  --exclude='*.log' \
  ./trading-bot/ \
  botuser@${VPS_IP}:/home/botuser/trading-bot/

# Устанавливаем новые зависимости и перезапускаем
ssh botuser@${VPS_IP} "
  cd ~/trading-bot
  source venv/bin/activate
  pip install -r requirements.txt -q
  sudo systemctl restart trading-bot
  echo 'Деплой завершён!'
"
Запускаем деплой
chmod +x deploy.sh
./deploy.sh

Через git

На сервере — после обновления кода
cd ~/trading-bot
git pull origin main
source venv/bin/activate
pip install -r requirements.txt -q
sudo systemctl restart trading-bot
journalctl -u trading-bot -n 20  # проверяем что запустился
Важно: При наличии открытых позиций — перезапуск в неподходящий момент может пропустить закрытие позиции. Реализуйте проверку открытых позиций при старте бота:exchange.fetch_open_orders()

Чеклист перед запуском

  • VPS с минимум 1 ГБ RAM, Ubuntu 22.04, статический IP
  • API-ключ создан: торговые права, без вывода средств, IP-вайтлист
  • Ключи в .env, файл chmod 600, .env в .gitignore
  • python bot.py запускается без ошибок в тестовом режиме
  • systemd сервис создан, включён (systemctl enable), запущен
  • Telegram-уведомление о запуске пришло
  • journalctl -u trading-bot не показывает ошибок
  • Сервер перезагружен — бот поднялся автоматически

Частые вопросы

Смотрите также