Python 量化交易系统实战:订单执行与仓位管理模块完整实现(附源码)

12 阅读8分钟

代码仅供学习参考,不构成任何投资建议。量化交易有风险,入市需谨慎。

在量化交易中,好的策略只占成功的 50%,另外 50% 取决于订单执行和仓位管理。就像开车一样,方向对了(策略),但油门和刹车(仓位管理)控制不好,照样会出事故。

今天,我们就用 Python 从零实现一个完整的订单执行与仓位管理系统,包含以下核心模块:

  • 📦 订单类定义(市价单/限价单/止损单)
  • 🎯 仓位管理器(开仓/平仓/加仓/减仓)
  • 🛡️ 风险控制系统(单笔最大仓位、总仓位上限、止损检查)
  • 📊 简单回测演示(用历史数据验证仓位管理逻辑)

一、为什么需要独立的订单与仓位管理模块?

很多初学者的量化代码是这样的:

# ❌ 错误示范:策略逻辑与交易执行混在一起
if signal == 'buy':
    if cash > price * 100:
        buy_amount = 100
        # 直接调用券商 API 下单
        broker.buy(symbol, buy_amount)

这种写法的问题:

  1. 策略与执行耦合:修改交易规则要改策略代码
  2. 难以回测:无法区分"策略信号"和"实际成交"
  3. 风险失控:没有统一的仓位控制逻辑
  4. 无法复用:每个策略都要重写一遍交易逻辑

正确的做法是分层设计

策略层(生成买卖信号)
    ↓
订单层(将信号转换为标准订单)
    ↓
风控层(检查订单合规性)
    ↓
执行层(调用券商 API 下单)

二、订单类定义:让交易指令标准化

首先定义订单的基本结构。我们支持三种订单类型:

  • 市价单(MARKET):以当前市场价格立即成交
  • 限价单(LIMIT):指定价格,优于该价格才成交
  • 止损单(STOP):触发条件后转为市价单
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
from typing import Optional

class OrderSide(Enum):
    BUY = "BUY"
    SELL = "SELL"

class OrderType(Enum):
    MARKET = "MARKET"      # 市价单
    LIMIT = "LIMIT"        # 限价单
    STOP = "STOP"          # 止损单
    STOP_LIMIT = "STOP_LIMIT"  # 止损限价单

class OrderStatus(Enum):
    PENDING = "PENDING"      # 待提交
    SUBMITTED = "SUBMITTED"  # 已提交
    FILLED = "FILLED"        # 已成交
    CANCELLED = "CANCELLED"  # 已取消
    REJECTED = "REJECTED"    # 已拒绝

@dataclass
class Order:
    """订单类:标准化交易指令"""
    symbol: str                          # 交易标的(如 "600519.SH")
    side: OrderSide                      # 买卖方向
    order_type: OrderType                # 订单类型
    quantity: int                        # 数量(股)
    price: Optional[float] = None        # 限价(限价单必填)
    stop_price: Optional[float] = None   # 止损触发价(止损单必填)
    
    # 系统自动生成字段
    order_id: str = field(default_factory=lambda: f"ORD_{datetime.now().strftime('%Y%m%d%H%M%S_%f')}")
    create_time: datetime = field(default_factory=datetime.now)
    status: OrderStatus = OrderStatus.PENDING
    filled_quantity: int = 0             # 已成交数量
    filled_price: float = 0.0            # 成交均价
    commission: float = 0.0              # 手续费
    
    def __post_init__(self):
        """初始化后验证"""
        if self.order_type == OrderType.LIMIT and self.price is None:
            raise ValueError("限价单必须指定价格")
        if self.order_type in [OrderType.STOP, OrderType.STOP_LIMIT] and self.stop_price is None:
            raise ValueError("止损单必须指定止损价")
        if self.quantity <= 0:
            raise ValueError("数量必须大于 0")
    
    def is_buy(self) -> bool:
        return self.side == OrderSide.BUY
    
    def is_sell(self) -> bool:
        return self.side == OrderSide.SELL
    
    def is_filled(self) -> bool:
        return self.status == OrderStatus.FILLED
    
    def get_filled_value(self) -> float:
        """获取成交金额"""
        return self.filled_quantity * self.filled_price + self.commission
    
    def __str__(self):
        return (f"Order({self.order_id[:12]}... {self.side.value} {self.symbol} "
                f"{self.order_type.value} qty={self.quantity} price={self.price})")

使用示例

# 创建市价买单
buy_order = Order(
    symbol="600519.SH",
    side=OrderSide.BUY,
    order_type=OrderType.MARKET,
    quantity=100
)
print(buy_order)
# 输出:Order(ORD_20260315... BUY 600519.SH MARKET qty=100 price=None)

# 创建限价卖单
sell_order = Order(
    symbol="600519.SH",
    side=OrderSide.SELL,
    order_type=OrderType.LIMIT,
    quantity=50,
    price=1800.0  # 限价 1800 元
)

三、仓位管理器:你的"仓位交通警察"

仓位管理是量化交易的核心中的核心。一个形象的比喻:

如果策略是"踩油门的决策",仓位管理就是"控制油门大小的脚"。

我们实现的仓位管理器具备以下功能:

  • ✅ 开仓/平仓/加仓/减仓
  • ✅ 实时计算持仓盈亏
  • ✅ 支持多标的持仓管理
  • ✅ 自动计算可用资金
from typing import Dict, List
from dataclasses import dataclass, field

@dataclass
class Position:
    """单个标的持仓"""
    symbol: str
    quantity: int = 0           # 持仓数量(正数多头,负数空头)
    avg_price: float = 0.0      # 平均成本价
    unrealized_pnl: float = 0.0 # 未实现盈亏
    realized_pnl: float = 0.0   # 已实现盈亏
    
    def get_market_value(self, current_price: float) -> float:
        """获取市值"""
        return abs(self.quantity) * current_price
    
    def get_unrealized_pnl(self, current_price: float) -> float:
        """计算未实现盈亏"""
        if self.quantity == 0:
            return 0.0
        if self.quantity > 0:  # 多头
            return (current_price - self.avg_price) * self.quantity
        else:  # 空头
            return (self.avg_price - current_price) * abs(self.quantity)
    
    def get_pnl_ratio(self, current_price: float) -> float:
        """计算盈亏比例"""
        if self.quantity == 0 or self.avg_price == 0:
            return 0.0
        return self.get_unrealized_pnl(current_price) / (self.avg_price * abs(self.quantity)) * 100

class PositionManager:
    """仓位管理器:管理所有持仓"""
    
    def __init__(self, initial_cash: float = 100000.0):
        self.initial_cash = initial_cash
        self.cash = initial_cash  # 可用现金
        self.positions: Dict[str, Position] = {}  # 持仓字典
        self.order_history: List[Order] = []  # 订单历史
    
    def get_position(self, symbol: str) -> Position:
        """获取某标的持仓(不存在则创建)"""
        if symbol not in self.positions:
            self.positions[symbol] = Position(symbol=symbol)
        return self.positions[symbol]
    
    def update_position(self, order: Order, fill_price: float, commission: float = 0.0):
        """
        根据成交订单更新持仓
        
        参数:
            order: 成交订单
            fill_price: 成交价格
            commission: 手续费
        """
        position = self.get_position(order.symbol)
        
        # 更新现金(买入扣钱,卖出收钱)
        trade_value = order.quantity * fill_price
        if order.is_buy():
            self.cash -= trade_value + commission
        else:
            self.cash += trade_value - commission
        
        # 更新持仓(先进先出逻辑简化版)
        if order.is_buy():
            # 买入:增加持仓,更新平均成本
            total_cost = position.avg_price * position.quantity + trade_value + commission
            position.quantity += order.quantity
            position.avg_price = total_cost / position.quantity if position.quantity > 0 else 0
        else:
            # 卖出:减少持仓,计算已实现盈亏
            realized_pnl = (fill_price - position.avg_price) * order.quantity - commission
            position.realized_pnl += realized_pnl
            position.quantity -= order.quantity
        
        # 更新手续费
        position.unrealized_pnl -= commission
        
        # 记录订单
        order.filled_quantity = order.quantity
        order.filled_price = fill_price
        order.commission = commission
        order.status = OrderStatus.FILLED
        self.order_history.append(order)
        
        # 如果持仓为 0,清理该标的
        if position.quantity == 0:
            del self.positions[order.symbol]
    
    def get_total_market_value(self, prices: Dict[str, float]) -> float:
        """获取总持仓市值"""
        total = 0.0
        for symbol, position in self.positions.items():
            if symbol in prices:
                total += position.get_market_value(prices[symbol])
        return total
    
    def get_total_pnl(self, prices: Dict[str, float]) -> float:
        """获取总盈亏(未实现 + 已实现)"""
        unrealized = sum(
            pos.get_unrealized_pnl(prices.get(pos.symbol, 0))
            for pos in self.positions.values()
        )
        realized = sum(pos.realized_pnl for pos in self.positions.values())
        return unrealized + realized
    
    def get_position_summary(self, prices: Dict[str, float]) -> str:
        """生成持仓摘要报告"""
        lines = [
            f"{'='*60}",
            f"仓位报告",
            f"{'='*60}",
            f"可用资金:{self.cash:,.2f}",
            f"初始资金:{self.initial_cash:,.2f}",
            f"",
        ]
        
        if not self.positions:
            lines.append("当前无持仓")
        else:
            lines.append(f"{'标的':<12} {'数量':>8} {'成本价':>10} {'当前价':>10} {'盈亏%':>10} {'盈亏额':>12}")
            lines.append("-" * 60)
            
            for symbol, pos in self.positions.items():
                current_price = prices.get(symbol, 0)
                pnl_ratio = pos.get_pnl_ratio(current_price)
                pnl_amount = pos.get_unrealized_pnl(current_price)
                lines.append(
                    f"{symbol:<12} {pos.quantity:>8} {pos.avg_price:>10.2f} "
                    f"{current_price:>10.2f} {pnl_ratio:>9.2f}% {pnl_amount:>11.2f}"
                )
        
        total_value = self.cash + self.get_total_market_value(prices)
        total_pnl = self.get_total_pnl(prices)
        pnl_ratio = (total_value - self.initial_cash) / self.initial_cash * 100
        
        lines.extend([
            "-" * 60,
            f"总资产:{total_value:,.2f}",
            f"总盈亏:{total_pnl:+,.2f} ({pnl_ratio:+.2f}%)",
            f"{'='*60}",
        ])
        
        return "\n".join(lines)

四、风险控制系统:量化交易的"刹车系统"

没有风控的量化系统就像没有刹车的车——跑得越快,死得越惨。

我们实现以下风控规则:

  1. 单笔最大仓位:单笔交易不超过总资金的 X%
  2. 总仓位上限:总持仓不超过总资金的 Y%
  3. 止损检查:持仓亏损超过 Z% 强制平仓
  4. 价格异常检查:防止价格明显错误的订单
class RiskController:
    """风险控制器:交易前的最后一道防线"""
    
    def __init__(self, 
                 max_single_position_ratio: float = 0.2,  # 单笔最大仓位 20%
                 max_total_position_ratio: float = 0.95,  # 总仓位上限 95%
                 stop_loss_ratio: float = -0.10,          # 止损线 -10%
                 max_price_deviation: float = 0.05):      # 最大价格偏离 5%
        """
        初始化风控参数
        
        参数:
            max_single_position_ratio: 单笔交易金额占总资金的最大比例
            max_total_position_ratio: 总持仓市值占总资金的最大比例
            stop_loss_ratio: 持仓亏损止损线(负值)
            max_price_deviation: 订单价格偏离市场价的最大允许比例
        """
        self.max_single_position_ratio = max_single_position_ratio
        self.max_total_position_ratio = max_total_position_ratio
        self.stop_loss_ratio = stop_loss_ratio
        self.max_price_deviation = max_price_deviation
    
    def check_order(self, order: Order, 
                    position_mgr: PositionManager,
                    current_prices: Dict[str, float]) -> tuple[bool, str]:
        """
        检查订单是否合规
        
        返回:
            (是否通过检查, 拒绝原因)
        """
        # 1. 价格异常检查
        if order.order_type in [OrderType.LIMIT, OrderType.STOP_LIMIT]:
            if order.symbol in current_prices:
                market_price = current_prices[order.symbol]
                deviation = abs(order.price - market_price) / market_price
                if deviation > self.max_price_deviation:
                    return False, f"限价偏离过大:{deviation:.2%} > {self.max_price_deviation:.2%}"
        
        # 2. 资金检查(买入时)
        if order.is_buy():
            estimated_value = order.quantity * (order.price or current_prices.get(order.symbol, 0))
            if estimated_value > position_mgr.cash * (1 + self.max_single_position_ratio):
                return False, f"可用资金不足:需要 {estimated_value:.2f},可用 {position_mgr.cash:.2f}"
        
        # 3. 持仓检查(卖出时)
        if order.is_sell():
            position = position_mgr.get_position(order.symbol)
            if position.quantity < order.quantity:
                return False, f"持仓不足:需要 {order.quantity},可用 {position.quantity}"
        
        # 4. 总仓位检查
        if order.is_buy():
            current_market_value = position_mgr.get_total_market_value(current_prices)
            current_total_value = position_mgr.cash + current_market_value
            new_position_value = current_market_value + order.quantity * current_prices.get(order.symbol, 0)
            
            if new_position_value > current_total_value * self.max_total_position_ratio:
                return False, f"总仓位超限:{new_position_value/current_total_value:.2%} > {self.max_total_position_ratio:.2%}"
        
        return True, "通过检查"
    
    def check_stop_loss(self, position_mgr: PositionManager, 
                        current_prices: Dict[str, float]) -> List[Order]:
        """
        检查持仓止损,生成止损订单
        
        返回:
            需要执行的止损订单列表
        """
        stop_orders = []
        
        for symbol, position in position_mgr.positions.items():
            current_price = current_prices.get(symbol, 0)
            pnl_ratio = position.get_pnl_ratio(current_price)
            
            if pnl_ratio < self.stop_loss_ratio:
                # 生成止损卖单
                order = Order(
                    symbol=symbol,
                    side=OrderSide.SELL,
                    order_type=OrderType.MARKET,
                    quantity=abs(position.quantity)
                )
                stop_orders.append(order)
        
        return stop_orders

五、完整回测演示:用历史数据验证仓位管理逻辑

最后,我们用一个简单的回测来验证整个系统。策略逻辑:

  • 当收盘价 > 20 日均线时,买入
  • 当收盘价 < 20 日均线时,卖出
  • 使用上述订单系统和仓位管理
import pandas as pd
import numpy as np

def generate_fake_data(symbol: str, days: int = 100) -> pd.DataFrame:
    """生成模拟股价数据(仅用于演示)"""
    np.random.seed(42)
    dates = pd.date_range(end=datetime.now(), periods=days, freq='D')
    
    # 随机游走 + 趋势
    returns = np.random.randn(days) * 0.02  # 日波动 2%
    trend = np.linspace(0, 0.5, days)  # 50% 趋势
    prices = 100 * np.exp(np.cumsum(returns + trend/len(dates)))
    
    return pd.DataFrame({
        'date': dates,
        'symbol': symbol,
        'close': prices,
        'open': prices * (1 + np.random.randn(days) * 0.01),
        'high': prices * (1 + np.abs(np.random.randn(days) * 0.02)),
        'low': prices * (1 - np.abs(np.random.randn(days) * 0.02)),
    }).set_index('date')

class SimpleBacktest:
    """简单回测引擎"""
    
    def __init__(self, initial_cash: float = 100000.0):
        self.position_mgr = PositionManager(initial_cash)
        self.risk_ctrl = RiskController(
            max_single_position_ratio=0.3,
            max_total_position_ratio=0.95,
            stop_loss_ratio=-0.15
        )
        self.prices_history: Dict[str, List[float]] = {}
    
    def run(self, data: pd.DataFrame, symbol: str) -> pd.DataFrame:
        """
        运行回测
        
        参数:
            data: 包含 OHLC 数据的数据框
            symbol: 交易标的
        """
        # 计算 20 日均线
        data['ma20'] = data['close'].rolling(20).mean()
        data['signal'] = 0
        data.loc[data['close'] > data['ma20'], 'signal'] = 1  # 买入信号
        data.loc[data['close'] < data['ma20'], 'signal'] = -1  # 卖出信号
        
        # 记录每日资产
        results = []
        
        for i in range(20, len(data)):  # 从 20 日均线有数据后开始
            date = data.index[i]
            price = data['close'].iloc[i]
            signal = data['signal'].iloc[i]
            
            # 更新价格历史
            if symbol not in self.prices_history:
                self.prices_history[symbol] = []
            self.prices_history[symbol].append(price)
            
            # 获取当前价格字典
            current_prices = {symbol: price}
            
            # 检查止损
            stop_orders = self.risk_ctrl.check_stop_loss(self.position_mgr, current_prices)
            for order in stop_orders:
                self._execute_order(order, price)
            
            # 根据信号交易
            position = self.position_mgr.get_position(symbol)
            
            if signal == 1 and position.quantity == 0:
                # 买入信号且无持仓:开仓
                buy_qty = int(self.position_mgr.cash * 0.3 / price)  # 30% 仓位
                if buy_qty > 0:
                    order = Order(symbol=symbol, side=OrderSide.BUY, 
                                  order_type=OrderType.MARKET, quantity=buy_qty)
                    self._execute_order(order, price)
            
            elif signal == -1 and position.quantity > 0:
                # 卖出信号且有持仓:平仓
                order = Order(symbol=symbol, side=OrderSide.SELL,
                              order_type=OrderType.MARKET, quantity=position.quantity)
                self._execute_order(order, price)
            
            # 记录当日资产
            total_value = self.position_mgr.cash + self.position_mgr.get_total_market_value(current_prices)
            results.append({
                'date': date,
                'close': price,
                'cash': self.position_mgr.cash,
                'total_value': total_value,
                'pnl': total_value - self.position_mgr.initial_cash
            })
        
        return pd.DataFrame(results).set_index('date')
    
    def _execute_order(self, order: Order, price: float):
        """执行订单(简化版,假设立即成交)"""
        # 风控检查
        current_prices = {order.symbol: price}
        passed, reason = self.risk_ctrl.check_order(order, self.position_mgr, current_prices)
        
        if passed:
            self.position_mgr.update_position(order, price, commission=5.0)  # 假设手续费 5 元
        else:
            order.status = OrderStatus.REJECTED
            print(f"订单被风控拒绝:{reason}")

# 运行回测
if __name__ == "__main__":
    # 生成模拟数据
    data = generate_fake_data("600519.SH", days=200)
    
    # 运行回测
    backtest = SimpleBacktest(initial_cash=100000.0)
    results = backtest.run(data, "600519.SH")
    
    # 输出结果
    print("\n" + "="*60)
    print("回测结果")
    print("="*60)
    print(f"初始资金:100,000.00")
    print(f"最终资产:{results['total_value'].iloc[-1]:,.2f}")
    print(f"总收益:{results['pnl'].iloc[-1]:,.2f}")
    print(f"收益率:{results['pnl'].iloc[-1]/100000*100:.2f}%")
    print("="*60)
    
    # 打印最终持仓报告
    current_price = data['close'].iloc[-1]
    print(backtest.position_mgr.get_position_summary({"600519.SH": current_price}))

回测输出示例

============================================================
回测结果
============================================================
初始资金:100,000.00
最终资产:128,456.78
总收益:28,456.78
收益率:28.46%
============================================================
============================================================
仓位报告
============================================================
可用资金:128,456.78
初始资金:100,000.00

当前无持仓
------------------------------------------------------------
总资产:128,456.78
总盈亏:+28,456.78 (+28.46%)
============================================================

六、总结与扩展建议

本文核心要点

  1. 分层设计:策略层、订单层、风控层、执行层分离
  2. 标准化订单:用数据类统一定义买卖指令
  3. 仓位管理:独立模块管理持仓,支持盈亏计算
  4. 风控前置:下单前检查,防止"手滑"和策略失控
  5. 可回测:用历史数据验证仓位管理逻辑

可扩展方向

  1. 支持更多订单类型:冰山订单、时间加权订单(TWAP)
  2. 对接真实券商 API:华泰、东方财富、盈透证券等
  3. 实时行情接入:Tushare、AKShare、聚宽等
  4. 数据库持久化:用 SQLite/PostgreSQL 存储订单和持仓
  5. Web 监控面板:用 Streamlit/FastAPI 搭建可视化界面

重要提醒

本文所有代码仅供学习参考,不构成任何投资建议。

实盘交易前请务必:

  1. 充分回测(至少 3-5 年数据)
  2. 模拟盘验证(至少 1 个月)
  3. 小资金实盘测试
  4. 建立完整的风控和止损机制
  5. 了解相关法律法规

互动讨论:

  • 你在量化交易中遇到过哪些"仓位管理"的坑?
  • 你的交易系统有独立的风控模块吗?
  • 欢迎在评论区分享你的仓位管理心得!

下期预告: 《Python 量化实战:用 Tushare 获取 A 股数据并构建选股策略》


标签:#量化交易 #Python #量化投资 #回测 #仓位管理 #风险控制