Короткий ответ: биржевые данные из WebSocket в Django лучше сохранять не прямо внутри обычного view, а отдельным worker-процессом. Worker подключается к биржевому WebSocket, принимает события, валидирует формат, складывает данные в базу или очередь, а Django уже показывает сохраненные свечи, сделки или котировки пользователю
Правильная схема:
Exchange WebSocket -> ingest worker -> validation -> database
-> Django API
-> Django Channels для live-обновлений
Почему не view
Обычный Django view рассчитан на запрос-ответ. Биржевой WebSocket может жить часами и присылать тысячи сообщений. Если держать его внутри view, вы получите зависшие запросы, проблемы с перезапуском и плохой контроль ошибок
Лучше вынести чтение биржи в отдельный процесс: management command, Celery worker, отдельный service или async-приложение
Модель данных
Пример для сделок:
from django.db import models
class Trade(models.Model):
symbol = models.CharField(max_length=32)
price = models.DecimalField(max_digits=20, decimal_places=8)
amount = models.DecimalField(max_digits=20, decimal_places=8)
exchange_trade_id = models.CharField(max_length=128, unique=True)
traded_at = models.DateTimeField()
created_at = models.DateTimeField(auto_now_add=True)
exchange_trade_id помогает не сохранить одну сделку дважды, если WebSocket переподключился и биржа прислала часть событий повторно
Worker-логика
Псевдокод:
async def consume_trades():
async with connect_to_exchange() as ws:
async for raw_message in ws:
event = parse_message(raw_message)
if event["type"] != "trade":
continue
await save_trade(event["payload"])
Для реального проекта добавьте reconnect, backoff, логирование и обработку heartbeat
Сохранение пачками
Если поток быстрый, не сохраняйте каждое событие отдельным запросом к базе. Собирайте пачку:
buffer = []
buffer.append(trade)
if len(buffer) >= 500:
Trade.objects.bulk_create(buffer, ignore_conflicts=True)
buffer.clear()
ignore_conflicts=True может помочь с дублями, если есть unique-поле. Но оно не заменяет нормальную стратегию дедупликации
Live-обновления пользователю
Если пользователю нужно видеть свежие данные, не заставляйте frontend подключаться напрямую к бирже. Лучше:
worker -> database
worker -> channel layer -> browser WebSocket
Django Channels может отправлять клиентам только агрегированное или разрешенное событие: например, последнюю цену или обновленную свечу
Как не потерять данные при сбое
Для биржевых данных важна стратегия восстановления. WebSocket может оборваться, worker может перезапуститься, база может временно не принять запись. Поэтому храните checkpoint: последний trade id, timestamp или sequence number, который удалось сохранить
После reconnect worker должен запросить пропущенный диапазон через REST API биржи, если такая возможность есть:
last_saved_trade_id -> REST backfill -> снова WebSocket stream
Так WebSocket остается быстрым каналом доставки, но пропуски закрываются через более надежную синхронизацию
Что сохранять: raw или normalized
На старте полезно сохранять нормализованные поля: symbol, price, amount, traded_at. Для сложных интеграций можно дополнительно хранить сырой JSON в отдельном поле или журнале. Это поможет расследовать ошибки парсинга, если биржа изменила формат события
Частые ошибки
Первая ошибка — сохранять сырой поток без валидации. Биржа может менять формат, присылать heartbeat или служебные сообщения
Вторая ошибка — не учитывать дубли после reconnect
Третья ошибка — писать каждую сделку отдельным insert при высоком потоке
Четвертая ошибка — считать WebSocket источником правды. Для интерфейса источник правды — база или агрегированное состояние, которое можно восстановить после обрыва
Пятая ошибка — не разделять поток сделок и поток свечей. Сделки могут идти часто, а свечи обычно агрегируются по интервалу. Сохранять их стоит разными моделями
Самопроверка
Подключитесь к тестовому WebSocket, сохраните 100 событий, перезапустите worker и убедитесь, что дубли не создаются. Затем отключите сеть на минуту и проверьте, что reconnect не ломает процесс
Что почитать дальше по WebSocket
Если нужен общий маршрут по теме, откройте рубрику WebSocket. Для соседних задач пригодятся эти разборы:
- Django: как подружить Celery с WebSocket
- Spring, Go и Django WebSocket: какой путь выбрать
- Как разобрать данные WebSocket и не потерять формат сообщения
- Как распределять данные из одного источника по WebSocket



