第三十讲:订单流综合实战项目——构建一个完整的订单流交易系统

终于到了最后一讲。说实话,写到这里我有点感慨。

前面二十九讲,我们从盘口数据讲起,一步步深入到订单流的核心逻辑。现在,是时候把所有东西串起来了。

这一讲,我们要做一个完整的订单流交易系统。从数据获取,到策略执行,全流程用Python实现。你想想看,这其实就是一个迷你版的量化交易平台。

系统架构设计

先画个图,把整体框架理清楚。我个人习惯,做任何系统之前,先画架构图。不然写着写着就乱了。

订单流交易系统架构图 数据层 WebSocket实时行情 | 盘口深度数据 | 逐笔成交 | Level2数据 处理层 订单流重构 | Delta计算 | 累积量分析 | 失衡识别 | 大单检测 策略层 POC追踪策略 | 吸收/派发策略 | 失衡突破策略 | 多因子融合 执行层 信号生成 | 仓位管理 | 风控检查 | 订单执行 | 绩效统计 反馈循环

这个架构分四层:数据层、处理层、策略层、执行层。每层各司其职,数据从下往上流动,信号从上往下执行。

第一步:数据获取模块

数据是订单流系统的命根子。没有高质量的数据,再好的策略也是白搭。

import asyncio
import websockets
import json
from collections import deque

class OrderFlowDataFeed:
    """订单流数据源"""

    def __init__(self, symbol='btcusdt', depth_levels=50):
        self.symbol = symbol
        self.depth_levels = depth_levels
        self.depth_cache = {'bids': deque(maxlen=100), 'asks': deque(maxlen=100)}
        self.trade_buffer = deque(maxlen=1000)  # 逐笔成交缓存

    async def connect_depth(self):
        """连接深度数据WebSocket"""
        url = f'wss://stream.binance.com:9443/ws/{self.symbol}@depth{self.depth_levels}@100ms'
        async with websockets.connect(url) as ws:
            while True:
                data = json.loads(await ws.recv())
                self._update_depth(data)

    async def connect_trades(self):
        """连接逐笔成交WebSocket"""
        url = f'wss://stream.binance.com:9443/ws/{self.symbol}@trade'
        async with websockets.connect(url) as ws:
            while True:
                data = json.loads(await ws.recv())
                self.trade_buffer.append(data)

    def _update_depth(self, data):
        """更新盘口深度"""
        for side in ['bids', 'asks']:
            for price, qty in data.get(side, []):
                qty = float(qty)
                if qty == 0:
                    # 价格为0表示删除该档位
                    self.depth_cache[side] = [
                        d for d in self.depth_cache[side] if d[0] != price
                    ]
                else:
                    self.depth_cache[side].append((float(price), qty))

    def get_order_flow(self):
        """获取当前订单流数据"""
        return {
            'depth': self.depth_cache,
            'recent_trades': list(self.trade_buffer)[-50:]
        }

这里我用了异步WebSocket连接。为什么?因为订单流数据是高频的,同步请求根本跟不上节奏。我之前有个项目,一开始用requests轮询,结果延迟高得离谱,后来改成WebSocket,延迟从秒级降到了毫秒级。

第二步:订单流重构引擎

原始数据拿到手,接下来要重构出订单流的真实面貌。说白了,就是把买卖双方的博弈过程还原出来。

import numpy as np
import pandas as pd

class OrderFlowReconstructor:
    """订单流重构引擎"""

    def __init__(self, tick_size=0.01):
        self.tick_size = tick_size
        self.volume_profile = {}  # 价格 -> 成交量映射

    def reconstruct_from_trades(self, trades):
        """从逐笔成交重构订单流"""
        flow_data = []

        for trade in trades:
            price = float(trade['p'])
            qty = float(trade['q'])
            is_buyer_maker = trade['m']  # True表示卖方主动

            # 判断主动方向
            if is_buyer_maker:
                # 卖方主动卖出,属于被动买入
                side = 'sell'
            else:
                # 买方主动买入,属于被动卖出
                side = 'buy'

            flow_data.append({
                'price': price,
                'volume': qty,
                'side': side,
                'timestamp': trade['T']
            })

            # 更新成交量分布
            price_key = round(price / self.tick_size) * self.tick_size
            if price_key not in self.volume_profile:
                self.volume_profile[price_key] = {'buy': 0, 'sell': 0}
            self.volume_profile[price_key][side] += qty

        return pd.DataFrame(flow_data)

    def calculate_delta(self, df):
        """计算Delta(主动买卖差)"""
        df['delta'] = np.where(df['side'] == 'buy', df['volume'], -df['volume'])
        df['cumulative_delta'] = df['delta'].cumsum()
        return df

    def detect_imbalance(self, df, threshold=2.0):
        """检测失衡信号"""
        df['buy_volume'] = np.where(df['side'] == 'buy', df['volume'], 0)
        df['sell_volume'] = np.where(df['side'] == 'sell', df['volume'], 0)

        # 滚动窗口计算失衡比
        window = 20
        df['buy_sum'] = df['buy_volume'].rolling(window).sum()
        df['sell_sum'] = df['sell_volume'].rolling(window).sum()
        df['imbalance_ratio'] = df['buy_sum'] / (df['sell_sum'] + 1e-8)

        df['imbalance_signal'] = np.where(
            df['imbalance_ratio'] > threshold, 'buy_imbalance',
            np.where(df['imbalance_ratio'] < 1/threshold, 'sell_imbalance', 'neutral')
        )
        return df

这里有个细节要注意:is_buyer_maker这个字段。很多人会搞反。我曾经就因为这个bug,回测跑出来收益惊人,实盘一跑就亏。后来发现是方向搞反了。嗯,这种坑踩过一次就记住了。

第三步:策略引擎实现

有了重构好的订单流数据,接下来就是策略逻辑。我们实现一个经典的POC(控制点)追踪策略。

class POCStrategy:
    """POC追踪策略"""

    def __init__(self, lookback_bars=50, threshold_pct=0.3):
        self.lookback_bars = lookback_bars
        self.threshold_pct = threshold_pct
        self.position = 0
        self.trades = []

    def find_poc(self, volume_profile):
        """找到成交量最大的价格(控制点)"""
        if not volume_profile:
            return None
        poc_price = max(volume_profile, key=lambda k: volume_profile[k]['buy'] + volume_profile[k]['sell'])
        return poc_price

    def calculate_value_area(self, volume_profile, poc_price, volume_pct=0.7):
        """计算价值区间(VAH/VAL)"""
        total_volume = sum(v['buy'] + v['sell'] for v in volume_profile.values())
        target_volume = total_volume * volume_pct

        sorted_prices = sorted(volume_profile.keys())
        poc_idx = sorted_prices.index(poc_price)

        # 从POC向两边扩展
        current_volume = volume_profile[poc_price]['buy'] + volume_profile[poc_price]['sell']
        left_idx = right_idx = poc_idx

        while current_volume < target_volume:
            left_vol = volume_profile.get(sorted_prices[left_idx - 1], {}).get('buy', 0) + \
                       volume_profile.get(sorted_prices[left_idx - 1], {}).get('sell', 0) if left_idx > 0 else 0
            right_vol = volume_profile.get(sorted_prices[right_idx + 1], {}).get('buy', 0) + \
                        volume_profile.get(sorted_prices[right_idx + 1], {}).get('sell', 0) if right_idx < len(sorted_prices) - 1 else 0

            if left_vol >= right_vol and left_idx > 0:
                left_idx -= 1
                current_volume += left_vol
            elif right_idx < len(sorted_prices) - 1:
                right_idx += 1
                current_volume += right_vol
            else:
                break

        return {
            'val': sorted_prices[left_idx],
            'vah': sorted_prices[right_idx],
            'poc': poc_price
        }

    def generate_signal(self, current_price, value_area):
        """生成交易信号"""
        if current_price > value_area['vah']:
            # 价格突破价值区间上沿,看多
            return 'buy'
        elif current_price < value_area['val']:
            # 价格跌破价值区间下沿,看空
            return 'sell'
        else:
            return 'hold'

    def execute(self, market_data):
        """策略执行入口"""
        volume_profile = market_data.get('volume_profile', {})
        current_price = market_data.get('price')

        if not volume_profile or not current_price:
            return None

        poc_price = self.find_poc(volume_profile)
        if not poc_price:
            return None

        value_area = self.calculate_value_area(volume_profile, poc_price)
        signal = self.generate_signal(current_price, value_area)

        return {
            'signal': signal,
            'poc': poc_price,
            'val': value_area['val'],
            'vah': value_area['vah'],
            'current_price': current_price
        }
实战小技巧:

POC策略的核心逻辑其实很简单:价格在价值区间内震荡时观望,突破区间时顺势而为。但要注意,这个策略在趋势行情中表现很好,在震荡行情中容易反复打脸。我一般会加一个过滤条件——当Delta也同步确认时再进场。

第四步:风控与执行模块

策略再好,没有风控也是白搭。我见过太多人,策略赚了九次,一次风控没做好就全亏回去了。

class RiskManager:
    """风控管理器"""

    def __init__(self, max_position=100, max_drawdown=0.05, max_daily_loss=0.03):
        self.max_position = max_position
        self.max_drawdown = max_drawdown
        self.max_daily_loss = max_daily_loss
        self.initial_equity = None
        self.peak_equity = None
        self.daily_pnl = 0

    def check_position_limit(self, current_position, order_qty):
        """检查仓位限制"""
        return abs(current_position + order_qty) <= self.max_position

    def check_drawdown(self, current_equity):
        """检查回撤"""
        if self.peak_equity is None:
            self.peak_equity = current_equity
            return True

        self.peak_equity = max(self.peak_equity, current_equity)
        drawdown = (self.peak_equity - current_equity) / self.peak_equity

        return drawdown <= self.max_drawdown

    def check_daily_loss(self, pnl):
        """检查当日亏损"""
        self.daily_pnl += pnl
        return self.daily_pnl >= -self.max_daily_loss * self.initial_equity

    def can_trade(self, signal, current_position, current_equity, pnl):
        """综合风控检查"""
        checks = {
            'position_limit': self.check_position_limit(current_position, signal['qty']),
            'drawdown': self.check_drawdown(current_equity),
            'daily_loss': self.check_daily_loss(pnl)
        }

        if not all(checks.values()):
            failed_checks = [k for k, v in checks.items() if not v]
            print(f'风控未通过: {failed_checks}')
            return False

        return True


class OrderExecutor:
    """订单执行器"""

    def __init__(self, exchange_api):
        self.api = exchange_api
        self.pending_orders = []
        self.filled_orders = []

    async def execute_market_order(self, symbol, side, qty):
        """执行市价单"""
        order = {
            'symbol': symbol,
            'side': side,
            'qty': qty,
            'type': 'market',
            'status': 'pending'
        }

        try:
            # 模拟下单
            result = await self.api.place_order(**order)
            order['status'] = 'filled'
            order['fill_price'] = result['price']
            self.filled_orders.append(order)
            return order
        except Exception as e:
            order['status'] = 'failed'
            order['error'] = str(e)
            self.pending_orders.append(order)
            return None

    def calculate_position_size(self, signal_strength, account_balance, risk_per_trade=0.02):
        """计算仓位大小"""
        base_qty = account_balance * risk_per_trade
        # 信号强度调整仓位
        adjusted_qty = base_qty * (1 + signal_strength)
        return round(adjusted_qty, 2)

第五步:主循环与系统集成

最后,把所有模块拼起来,形成一个完整的运行循环。

class OrderFlowTradingSystem:
    """订单流交易系统主控"""

    def __init__(self, symbol='btcusdt'):
        self.data_feed = OrderFlowDataFeed(symbol)
        self.reconstructor = OrderFlowReconstructor()
        self.strategy = POCStrategy()
        self.risk_manager = RiskManager()
        self.executor = OrderExecutor(exchange_api=None)  # 实际使用时传入API

        self.position = 0
        self.equity = 100000  # 初始资金
        self.pnl = 0

    async def run(self):
        """系统主循环"""
        print('订单流交易系统启动...')

        # 启动数据采集
        depth_task = asyncio.create_task(self.data_feed.connect_depth())
        trade_task = asyncio.create_task(self.data_feed.connect_trades())

        while True:
            # 1. 获取最新数据
            raw_data = self.data_feed.get_order_flow()

            # 2. 重构订单流
            trades_df = self.reconstructor.reconstruct_from_trades(
                raw_data['recent_trades']
            )
            trades_df = self.reconstructor.calculate_delta(trades_df)
            trades_df = self.reconstructor.detect_imbalance(trades_df)

            # 3. 构建市场数据
            market_data = {
                'volume_profile': self.reconstructor.volume_profile,
                'price': float(raw_data['recent_trades'][-1]['p']) if raw_data['recent_trades'] else None,
                'delta': trades_df['cumulative_delta'].iloc[-1] if len(trades_df) > 0 else 0,
                'imbalance': trades_df['imbalance_signal'].iloc[-1] if len(trades_df) > 0 else 'neutral'
            }

            # 4. 策略决策
            decision = self.strategy.execute(market_data)

            if decision and decision['signal'] != 'hold':
                # 5. 风控检查
                order_qty = self.executor.calculate_position_size(
                    signal_strength=0.5,
                    account_balance=self.equity
                )

                if self.risk_manager.can_trade(
                    signal={'qty': order_qty},
                    current_position=self.position,
                    current_equity=self.equity,
                    pnl=self.pnl
                ):
                    # 6. 执行交易
                    side = 'buy' if decision['signal'] == 'buy' else 'sell'
                    order = await self.executor.execute_market_order(
                        symbol=self.data_feed.symbol,
                        side=side,
                        qty=order_qty
                    )

                    if order:
                        self.position += order_qty if side == 'buy' else -order_qty
                        print(f'执行交易: {side} {order_qty} @ {order["fill_price"]}')

            # 7. 等待下一个周期
            await asyncio.sleep(0.1)  # 100ms一个周期
核心要点总结:
  • 数据层:异步WebSocket连接,保证低延迟
  • 处理层:订单流重构,Delta计算,失衡检测
  • 策略层:POC追踪,价值区间识别,信号生成
  • 执行层:仓位管理,风控检查,订单执行
  • 整个系统是事件驱动的,每个周期100ms
实盘注意事项:

这个系统在模拟环境中跑没问题,但实盘时要注意几点:

  • WebSocket断线重连机制一定要做好,我遇到过交易所凌晨维护,断了半小时没重连
  • 订单流数据量很大,内存管理要小心,建议用环形缓冲区
  • 策略参数不要过度优化,我见过有人把参数调到回测年化500%,实盘一周就爆仓
  • 一定要加熔断机制,当市场出现极端行情时自动暂停交易

好了,整个订单流交易系统就搭建完成了。从数据获取到策略执行,每一步都是我自己在实战中踩过坑、优化过的方案。你拿回去跑一跑,有问题随时交流。

记住一点:系统是死的,市场是活的。再好的系统也需要你根据市场变化不断调整。别指望一劳永逸。


无相订单流研究社 微信Lucian808555