{T}

Django 量化交易监控平台

监控系统是量化交易的最后一道防线——它让你在策略异常、仓位偏离、系统故障时第一时间获知并响应。本文使用 Django 框架,从零搭建一个交易监控 Web 平台。

阅读提示

  • 如果你只关心"怎么做",可以直接跳到搭建监控平台
  • 如果你想理解 Django 的 MVC 架构思想,建议从MVC 架构开始
  • 本文代码基于 Django 5.2 LTS(当前长期支持版),Python 3.12+;旧版 Django 2.2/Python 3.7 代码在文末版本差异小节有对照说明

监控系统概述

监控什么?

一个量化交易监控系统需要追踪的关键指标:

图表渲染中…

为什么需要监控?

没有监控有监控
策略跑飞了数小时才发现异常触发告警,数分钟内响应
手动登录交易所查看持仓监控面板一键查看所有信息
月底才知道盈亏实时 PnL,随时掌握
故障后被动排查主动发现,防患于未然

Django 简介

Django 是 Python 最流行的 Web 框架之一,采用 MVC(Model-View-Controller) 架构:

图表渲染中…
组件文件职责
Modelmodels.py定义数据结构,映射数据库表
Viewviews.py处理 HTTP 请求,实现业务逻辑
Templatetemplates/*.html渲染 HTML 页面,展示数据
URLConfurls.pyURL 路由映射

搭建监控平台

步骤 1:创建项目

bash
# 安装 Django
pip install Django
django-admin --version
# 输出: 2.2.3

# 创建项目
django-admin startproject TradingMonitor
cd TradingMonitor/

# 初始化数据库
python manage.py migrate

# 创建管理员账户
python manage.py createsuperuser
# Username: admin
# Password: ******

# 启动开发服务器
python manage.py runserver
# 访问 http://127.0.0.1:8000 验证

项目结构

code
TradingMonitor/
├── manage.py                      # 项目管理命令行工具
├── db.sqlite3                     # 默认数据库(开发环境)
└── TradingMonitor/                # 项目 Python 包
    ├── __init__.py                # 声明为 Python 包
    ├── settings.py                # 全局配置
    ├── urls.py                    # URL 路由入口
    ├── wsgi.py                    # WSGI 部署配置
    ├── models.py                  # 数据模型(待创建)
    ├── views.py                   # 视图逻辑(待创建)
    ├── migrations/                # 数据库迁移记录
    │   └── __init__.py
    └── templates/                 # HTML 模板(待创建)
        └── positions.html

步骤 2:定义 Model

python
# TradingMonitor/models.py
from django.db import models


class Position(models.Model):
    """交易仓位模型"""
    asset = models.CharField(max_length=10)
    timestamp = models.DateTimeField()
    amount = models.DecimalField(max_digits=10, decimal_places=3)

    class Meta:
        ordering = ['-timestamp']  # 默认按时间倒序

    def __str__(self):
        return f'{self.asset}: {self.amount} @ {self.timestamp}'


class TradingOrder(models.Model):
    """交易订单模型"""
    SIDE_CHOICES = [
        ('buy', '买入'),
        ('sell', '卖出'),
    ]
    STATUS_CHOICES = [
        ('pending', '待成交'),
        ('filled', '已成交'),
        ('cancelled', '已取消'),
        ('rejected', '已拒绝'),
    ]

    symbol = models.CharField(max_length=10)
    side = models.CharField(max_length=4, choices=SIDE_CHOICES)
    price = models.DecimalField(max_digits=15, decimal_places=2)
    amount = models.DecimalField(max_digits=15, decimal_places=8)
    status = models.CharField(
        max_length=10, choices=STATUS_CHOICES, default='pending'
    )
    created_at = models.DateTimeField(auto_now_add=True)
    executed_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['symbol', 'status']),
            models.Index(fields=['created_at']),
        ]

    def __str__(self):
        return f'{self.side} {self.symbol} @ {self.price} [{self.status}]'

ORM 的核心优势:用 Python class 描述数据库表,无需手动编写 SQL。

操作原始 SQLDjango ORM
查询SELECT * FROM position WHERE asset='btc'Position.objects.filter(asset='btc')
插入INSERT INTO position VALUES (...)Position(asset='btc', ...).save()
筛选排序SELECT ... ORDER BY timestamp DESCPosition.objects.filter(...).order_by('-timestamp')

步骤 3:设计 View

python
# TradingMonitor/views.py
from django.shortcuts import render
from django.db.models import Sum, Count, Q
from .models import Position, TradingOrder


def dashboard(request):
    """监控仪表板主页面"""
    # 最新持仓
    positions = Position.objects.all()[:20]

    # 订单统计
    order_stats = TradingOrder.objects.aggregate(
        total_orders=Count('id'),
        filled_orders=Count('id', filter=Q(status='filled')),
        total_buy=Sum('amount', filter=Q(side='buy', status='filled')),
        total_sell=Sum('amount', filter=Q(side='sell', status='filled')),
    )

    # 最近订单
    recent_orders = TradingOrder.objects.all()[:20]

    context = {
        'positions': positions,
        'stats': order_stats,
        'recent_orders': recent_orders,
    }
    return render(request, 'dashboard.html', context)


def render_positions(request, asset):
    """按资产查看持仓历史"""
    positions = Position.objects.filter(asset=asset)
    context = {'asset': asset, 'positions': positions}
    return render(request, 'positions.html', context)

步骤 4:设计 Template

html
<!-- TradingMonitor/templates/positions.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Positions for {{ asset }}</title>
    <style>
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #4CAF50; color: white; }
        tr:nth-child(even) { background-color: #f2f2f2; }
    </style>
</head>
<body>
    <h1>{{ asset|upper }} 持仓历史</h1>

    <table>
        <thead>
            <tr>
                <th>时间</th>
                <th>持仓量</th>
            </tr>
        </thead>
        <tbody>
            {% for position in positions %}
            <tr>
                <td>{{ position.timestamp|date:"Y-m-d H:i:s" }}</td>
                <td>{{ position.amount }}</td>
            </tr>
            {% empty %}
            <tr>
                <td colspan="2">暂无数据</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

    <p>共 {{ positions|length }} 条记录</p>
</body>
</html>

Django 模板的关键语法

语法含义示例
{{ variable }}输出变量的值{{ asset }}btc
{% for ... in ... %}循环迭代{% for position in positions %}
{% if condition %}条件判断{% if positions %}
{{ value|filter }}过滤器(格式化){{ timestamp|date:"Y-m-d" }}
{% empty %}循环为空时{% for ... %}{% empty %}无数据{% endfor %}

步骤 5:配置 URL 路由

python
# TradingMonitor/urls.py
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.dashboard, name='dashboard'),
    path('positions/<str:asset>', views.render_positions, name='positions'),
]

步骤 6:修改 Settings

python
# TradingMonitor/settings.py

# 注册应用
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'TradingMonitor',  # 添加我们的 app
]

# 配置模板目录
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'TradingMonitor/templates')],
        'APP_DIRS': True,
        # ... 其他配置
    },
]

步骤 7:数据库迁移

bash
# 根据 Model 生成迁移文件
python manage.py makemigrations
# 输出: Migrations for 'TradingMonitor':
#   TradingMonitor/migrations/0001_initial.py
#     - Create model Position

# 应用到数据库
python manage.py migrate
# 输出: Applying TradingMonitor.0001_initial... OK

步骤 8:运行

bash
python manage.py runserver

访问 http://127.0.0.1:8000/positions/btc 查看持仓页面。

Django Admin 管理界面

Django 自带强大的后台管理系统,无需额外编码:

python
# TradingMonitor/admin.py
from django.contrib import admin
from .models import Position, TradingOrder


@admin.register(Position)
class PositionAdmin(admin.ModelAdmin):
    list_display = ['asset', 'amount', 'timestamp']
    list_filter = ['asset']
    search_fields = ['asset']
    date_hierarchy = 'timestamp'


@admin.register(TradingOrder)
class TradingOrderAdmin(admin.ModelAdmin):
    list_display = ['symbol', 'side', 'price', 'amount', 'status', 'created_at']
    list_filter = ['symbol', 'side', 'status']
    search_fields = ['symbol']
    date_hierarchy = 'created_at'

访问 http://127.0.0.1:8000/admin/ 即可使用。

MVC 架构全景

图表渲染中…
概念Django 实现数据流
Modelmodels.py 中的 Python class定义数据 → 迁移到数据库
Viewviews.py 中的函数接收请求 → 查询 Model → 渲染 Template
Templatetemplates/*.html接收 context 数据 → 生成 HTML
Controllerurls.py + Django 框架本身URL 路由分发

开源监控插件

插件用途特点
Graphite存储时间序列数据,通过 Django Web 应用图形化展示专为时序数据设计
Grafana通用仪表板支持多种数据源,界面美观
Vimeo基于 Graphite 的仪表板平滑的设计,额外功能
Scout监控 Django/Flask 应用性能自动检测视图、SQL 查询、模板
Sentry错误监控实时错误追踪和告警

从开发到部署

图表渲染中…

常见问题

Q: Django vs Flask 怎么选?

A: Django 是"全包含"框架(ORM、Admin、认证、模板一应俱全),适合快速搭建功能完整的 Web 应用。Flask 是"微框架",只提供核心功能,其他靠插件,更灵活但需要更多决策。量化监控平台推荐 Django——Admin 后台可以直接当管理界面用。

Q: 为什么需要 makemigrations 和 migrate?

A: makemigrations 是根据 Model 的 Python 代码生成迁移脚本(纯文本的数据库变更指令)。migrate 是将迁移脚本实际应用到数据库。这个两步流程让你可以在版本控制中追踪数据库 schema 的演进历史。

Q: 生产环境怎么部署 Django?

A: 不要用 python manage.py runserver(这是开发服务器,单线程、无安全保障)。生产环境使用 Gunicorn/uWSGI + Nginx 反向代理,数据库使用 PostgreSQL/MySQL。

术语表

术语英文定义
MVCModel-View-Controller将应用分为数据层、展示层和控制层的架构模式
ORMObject-Relational Mapping用 Python 对象操作数据库,无需写 SQL
迁移Migration数据库 schema 的版本控制机制
上下文Context从 View 传递给 Template 的变量字典
SRESite Reliability Engineering用软件工程方法解决运维问题的理念

延伸阅读

版本差异(Django → 5.2 LTS)

特性本文编写时当前(Django 5.2 LTS)
版本基线Django 2.x/3.x5.2 为当前 LTS(长期支持到 2028);要求 Python 3.10+(5.x)
异步支持部分5.x 全面支持异步 ORM(aget/afirst 等)与 ASGI
时区需配置默认启用 USE_TZ=Truezoneinfo 取代 pytz
表单/认证5.x 强化密码哈希(PBKDF2→scrypt 默认,5.1 起)
生产部署Heroku推荐 ASGI(Daphne/Uvicorn)+ 白名单;Heroku 已停止免费计划
数据库SQLite/MySQL5.x 支持 PostgreSQL 全特性;4.2 起支持 STORAGES 配置

本文讲解的 MVT 架构、Model/View/Template 核心模式在 Django 5.2 中完全成立;升级注意 Python 3.10+、异步 ORM、USE_TZ 与部署方式变化。