代码仅供学习参考,不构成任何投资建议。量化交易有风险,入市需谨慎。
在量化交易中,好的策略只占成功的 50%,另外 50% 取决于订单执行和仓位管理。就像开车一样,方向对了(策略),但油门和刹车(仓位管理)控制不好,照样会出事故。
今天,我们就用 Python 从零实现一个完整的订单执行与仓位管理系统,包含以下核心模块:
- 📦 订单类定义(市价单/限价单/止损单)
- 🎯 仓位管理器(开仓/平仓/加仓/减仓)
- 🛡️ 风险控制系统(单笔最大仓位、总仓位上限、止损检查)
- 📊 简单回测演示(用历史数据验证仓位管理逻辑)
一、为什么需要独立的订单与仓位管理模块?
很多初学者的量化代码是这样的:
# ❌ 错误示范:策略逻辑与交易执行混在一起
if signal == 'buy':
if cash > price * 100:
buy_amount = 100
# 直接调用券商 API 下单
broker.buy(symbol, buy_amount)
这种写法的问题:
- 策略与执行耦合:修改交易规则要改策略代码
- 难以回测:无法区分"策略信号"和"实际成交"
- 风险失控:没有统一的仓位控制逻辑
- 无法复用:每个策略都要重写一遍交易逻辑
正确的做法是分层设计:
策略层(生成买卖信号)
↓
订单层(将信号转换为标准订单)
↓
风控层(检查订单合规性)
↓
执行层(调用券商 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)
四、风险控制系统:量化交易的"刹车系统"
没有风控的量化系统就像没有刹车的车——跑得越快,死得越惨。
我们实现以下风控规则:
- 单笔最大仓位:单笔交易不超过总资金的 X%
- 总仓位上限:总持仓不超过总资金的 Y%
- 止损检查:持仓亏损超过 Z% 强制平仓
- 价格异常检查:防止价格明显错误的订单
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%)
============================================================
六、总结与扩展建议
本文核心要点
- 分层设计:策略层、订单层、风控层、执行层分离
- 标准化订单:用数据类统一定义买卖指令
- 仓位管理:独立模块管理持仓,支持盈亏计算
- 风控前置:下单前检查,防止"手滑"和策略失控
- 可回测:用历史数据验证仓位管理逻辑
可扩展方向
- 支持更多订单类型:冰山订单、时间加权订单(TWAP)
- 对接真实券商 API:华泰、东方财富、盈透证券等
- 实时行情接入:Tushare、AKShare、聚宽等
- 数据库持久化:用 SQLite/PostgreSQL 存储订单和持仓
- Web 监控面板:用 Streamlit/FastAPI 搭建可视化界面
重要提醒
本文所有代码仅供学习参考,不构成任何投资建议。
实盘交易前请务必:
- 充分回测(至少 3-5 年数据)
- 模拟盘验证(至少 1 个月)
- 小资金实盘测试
- 建立完整的风控和止损机制
- 了解相关法律法规
互动讨论:
- 你在量化交易中遇到过哪些"仓位管理"的坑?
- 你的交易系统有独立的风控模块吗?
- 欢迎在评论区分享你的仓位管理心得!
下期预告: 《Python 量化实战:用 Tushare 获取 A 股数据并构建选股策略》
标签:#量化交易 #Python #量化投资 #回测 #仓位管理 #风险控制