refactor(framework): 框架只保留抽象接口,具体实现移至strategies/shared

- FactorBase/FactorRegistry/FactorCombiner: 因子抽象接口
- SignalGenerator: 信号生成抽象接口
- RiskControl/Position/CallbackHook: 风控抽象接口
- StrategyBase: 策略抽象基类
- Executor/Portfolio: 执行器抽象接口
- ConfigLoader: 配置加载器
- 删除framework/factors/momentum.py(具体实现)
This commit is contained in:
2026-05-11 23:09:01 +08:00
parent 9a8a0d7c72
commit 30ea2970bd
8 changed files with 503 additions and 1516 deletions

View File

@@ -1,55 +1,119 @@
"""
执行层抽象设计
执行层抽象接口(通用)
核心组件:
- Executor: 执行器抽象基类
- BacktestExecutor: 回测执行器
- DryRunExecutor: 模拟盘执行器
只提供抽象基类和Portfolio数据结构具体执行器可扩展
"""
import pandas as pd
from abc import ABC, abstractmethod
from typing import Dict, Any, Optional, List
from dataclasses import dataclass
from typing import Dict, List, Optional
import pandas as pd
from datetime import datetime
from framework.risk import Position
@dataclass
class Portfolio:
"""持仓组合"""
positions: Dict[str, Any] # {code: Position}
cash: float
nav: float
trades: List[Any]
"""
投资组合数据结构(通用)
def get_total_value(self) -> float:
"""获取总价值"""
position_value = sum(
pos.quantity * pos.current_price
for pos in self.positions.values()
用于管理持仓集合
"""
def __init__(self, initial_capital: float = 100000):
"""初始化投资组合"""
self.initial_capital = initial_capital
self.cash = initial_capital
self.positions: Dict[str, Position] = {}
self.trades: List[Dict] = []
self._net_value_history: List[float] = []
def add_position(self, code: str, price: float, quantity: float, time: datetime) -> None:
"""添加持仓"""
position = Position(
code=code,
entry_price=price,
current_price=price,
entry_time=time,
quantity=quantity
)
return self.cash + position_value
self.positions[code] = position
self.cash -= price * quantity
self.trades.append({
'action': 'BUY',
'code': code,
'price': price,
'quantity': quantity,
'time': time
})
def get_position_codes(self) -> List[str]:
"""获取持仓代码列表"""
return list(self.positions.keys())
def remove_position(self, code: str, price: float, time: datetime) -> float:
"""移除持仓"""
if code not in self.positions:
return 0
position = self.positions[code]
profit = (price - position.entry_price) * position.quantity
self.cash += price * position.quantity
del self.positions[code]
self.trades.append({
'action': 'SELL',
'code': code,
'price': price,
'quantity': position.quantity,
'time': time,
'profit': profit
})
return profit
def update_prices(self, prices: Dict[str, float]) -> None:
"""更新持仓价格"""
for code, price in prices.items():
if code in self.positions:
self.positions[code].current_price = price
def get_net_value(self) -> float:
"""计算净值"""
positions_value = sum(
pos.current_price * pos.quantity for pos in self.positions.values()
)
return self.cash + positions_value
def record_net_value(self) -> None:
"""记录当前净值"""
self._net_value_history.append(self.get_net_value())
def get_net_value_series(self) -> pd.Series:
"""获取净值序列"""
return pd.Series(self._net_value_history)
def get_weight(self, code: str) -> float:
"""计算持仓权重"""
if code not in self.positions:
return 0
position_value = self.positions[code].current_price * self.positions[code].quantity
return position_value / self.get_net_value()
def __repr__(self) -> str:
return f"Portfolio(capital={self.cash:.2f}, positions={len(self.positions)})"
class Executor(ABC):
"""
执行器抽象基类
支持不同执行模式:
- backtest: 回测模式
- dry_run: 模拟盘模式
- live: 实盘模式TODO
所有执行器必须实现execute方法
"""
mode: str = "base"
def __init__(self, config: Optional[Dict] = None):
self._config = config or {}
self._portfolio = None
def __init__(self, **params):
"""初始化执行器参数"""
self._params = params
@abstractmethod
def execute(self, signals: pd.DataFrame, data: pd.DataFrame) -> Portfolio:
@@ -58,121 +122,71 @@ class Executor(ABC):
Args:
signals: 信号DataFrame
data: 价格数据
data: OHLCV数据
Returns:
持仓组合
Portfolio对象
"""
pass
@abstractmethod
def get_mode(self) -> str:
"""获取执行模式"""
pass
@property
def portfolio(self) -> Optional[Portfolio]:
"""获取当前持仓"""
return self._portfolio
def __repr__(self) -> str:
params_str = ', '.join([f"{k}={v}" for k, v in self._params.items()])
return f"{self.__class__.__name__}({params_str})"
class BacktestExecutor(Executor):
"""
回测执行器
回测执行器(通用骨架)
执行回测逻辑
- 处理信号
- 计算净值
- 记录交易
具体回测逻辑需要在strategies中定制实现
"""
mode = "backtest"
def __init__(
self,
initial_capital: float = 100000.0,
trade_cost: float = 0.001
):
super().__init__()
def __init__(self, initial_capital: float = 100000, trade_cost: float = 0.001):
super().__init__(initial_capital=initial_capital, trade_cost=trade_cost)
self.initial_capital = initial_capital
self.trade_cost = trade_cost
def execute(self, signals: pd.DataFrame, data: pd.DataFrame) -> Portfolio:
"""执行回测"""
# 初始化持仓
self._portfolio = Portfolio(
positions={},
cash=self.initial_capital,
nav=1.0,
trades=[]
)
"""
执行回测(简化版本)
# 回测逻辑(简化版)
result = pd.DataFrame(index=signals.index)
result['nav'] = 1.0
result['daily_return'] = 0.0
完整回测逻辑需要定制实现
"""
portfolio = Portfolio(self.initial_capital)
# TODO: 完整回测逻辑迁移
# 这里只提供骨架,具体逻辑需要定制实现
# 包括:净值计算、交易成本扣除、基准对比等
return self._portfolio
def get_mode(self) -> str:
return "backtest"
return portfolio
class DryRunExecutor(Executor):
"""
模拟盘执行器
Dry-run执行器通用
执行模拟交易
- 模拟下单
- 模拟成交
- 模拟持仓更新
用于模拟运行,不实际执行交易
"""
mode = "dry_run"
def __init__(
self,
initial_capital: float = 100000.0,
simulated_exchange = None
):
super().__init__()
self.initial_capital = initial_capital
self.simulated_exchange = simulated_exchange
def __init__(self, verbose: bool = True):
super().__init__(verbose=verbose)
self.verbose = verbose
def execute(self, signals: pd.DataFrame, data: pd.DataFrame) -> Portfolio:
"""执行模拟盘"""
# 初始化持仓
self._portfolio = Portfolio(
positions={},
cash=self.initial_capital,
nav=1.0,
trades=[]
)
"""模拟执行"""
portfolio = Portfolio(100000)
# 模拟执行逻辑
# TODO: 模拟订单执行
for date in signals.index:
signal = signals.loc[date, 'signal']
if signal and self.verbose:
print(f"[{date}] Signal: {signal}")
return self._portfolio
def get_mode(self) -> str:
return "dry_run"
def simulate_order(self, code: str, direction: str, quantity: float, price: float):
"""模拟下单"""
# 记录模拟订单
print(f"[DRY_RUN] {direction} {quantity} {code} @ {price}")
# 更新持仓
if direction == 'BUY':
# 模拟买入
cost = quantity * price
if cost <= self._portfolio.cash:
self._portfolio.cash -= cost
# TODO: 创建Position对象
elif direction == 'SELL':
# 模拟卖出
if code in self._portfolio.positions:
# TODO: 平仓逻辑
pass
return portfolio
# 导出抽象接口
__all__ = ['Portfolio', 'Executor', 'BacktestExecutor', 'DryRunExecutor']