Files
FX-ML-Trading-Engine/QuantTrader/core/execution/base.py
T
2025-11-14 22:56:44 +00:00

183 lines
5.6 KiB
Python

from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Any
from datetime import datetime
import asyncio
from loguru import logger
from ..strategy.base import SignalEvent, Position
class OrderEvent:
"""订单事件"""
def __init__(
self,
instrument: str,
order_type: str, # "MARKET", "LIMIT", "STOP"
direction: str, # "BUY", "SELL"
quantity: float,
timestamp: datetime,
price: Optional[float] = None,
stop_loss: Optional[float] = None,
take_profit: Optional[float] = None,
order_id: Optional[str] = None
):
self.event_type = "ORDER"
self.instrument = instrument
self.order_type = order_type
self.direction = direction
self.quantity = quantity
self.timestamp = timestamp
self.price = price
self.stop_loss = stop_loss
self.take_profit = take_profit
self.order_id = order_id
self.status = "CREATED" # CREATED, SUBMITTED, FILLED, CANCELLED, REJECTED
class FillEvent:
"""成交事件"""
def __init__(
self,
instrument: str,
direction: str,
quantity: float,
price: float,
timestamp: datetime,
commission: float = 0.0,
order_id: Optional[str] = None
):
self.event_type = "FILL"
self.instrument = instrument
self.direction = direction
self.quantity = quantity
self.price = price
self.timestamp = timestamp
self.commission = commission
self.order_id = order_id
class ExecutionHandler(ABC):
"""
执行处理器基类
负责订单执行和管理
"""
def __init__(self):
self.orders: Dict[str, OrderEvent] = {} # order_id -> OrderEvent
self.positions: Dict[str, Position] = {} # instrument -> Position
self.fills: List[FillEvent] = []
self._order_callbacks = []
self._fill_callbacks = []
async def process_signal(self, signal: SignalEvent, price: Optional[float] = None) -> OrderEvent:
"""
处理交易信号并创建订单
Args:
signal: 交易信号
Returns:
创建的订单事件
"""
order = OrderEvent(
instrument=signal.instrument,
order_type="MARKET", # 默认为市价单
direction="BUY" if signal.signal_type == "LONG" else "SELL",
quantity=abs(signal.strength),
timestamp=signal.timestamp,
stop_loss=signal.stop_loss,
take_profit=signal.take_profit,
price=price
)
# 生成订单ID
order.order_id = f"{order.instrument}_{order.timestamp.strftime('%Y%m%d_%H%M%S')}"
self.orders[order.order_id] = order
# 执行订单
try:
await self.execute_order(order)
except Exception as e:
logger.error(f"订单执行失败: {str(e)}")
order.status = "REJECTED"
return order
@abstractmethod
async def execute_order(self, order: OrderEvent) -> None:
"""
执行订单
Args:
order: 要执行的订单
"""
pass
@abstractmethod
async def cancel_order(self, order_id: str) -> bool:
"""
取消订单
Args:
order_id: 要取消的订单ID
Returns:
是否成功取消
"""
pass
def add_order_callback(self, callback):
"""添加订单状态更新回调"""
self._order_callbacks.append(callback)
def add_fill_callback(self, callback):
"""添加成交更新回调"""
self._fill_callbacks.append(callback)
async def _notify_order(self, order: OrderEvent):
"""通知订单状态更新"""
for callback in self._order_callbacks:
await callback(order)
async def _notify_fill(self, fill: FillEvent):
"""通知成交更新"""
for callback in self._fill_callbacks:
await callback(fill)
def get_position(self, instrument: str) -> Optional[Position]:
"""获取某个品种的持仓"""
return self.positions.get(instrument)
def get_all_positions(self) -> List[Position]:
"""获取所有持仓"""
return list(self.positions.values())
def update_position(self, fill: FillEvent) -> None:
"""根据成交更新持仓"""
instrument = fill.instrument
position = self.positions.get(instrument)
if position is None:
# 新建仓位
position = Position(
instrument=instrument,
direction=fill.direction,
size=fill.quantity,
entry_price=fill.price,
entry_time=fill.timestamp
)
self.positions[instrument] = position
else:
# 更新现有仓位
if fill.direction == position.direction:
# 同向加仓
new_size = position.size + fill.quantity
position.entry_price = (position.entry_price * position.size +
fill.price * fill.quantity) / new_size
position.size = new_size
else:
# 反向减仓
position.size -= fill.quantity
if position.size <= 0:
# 清仓
del self.positions[instrument]