test: 更新测试以验证框架重构正确性
- 测试文件改用strategies.shared的具体实现 - 新增framework_comparison_test.py对比新旧实现结果 - 因子计算相关系数达到1.0000,差异为0.000000 - 79个单元测试全部通过
This commit is contained in:
@@ -1,101 +1,173 @@
|
||||
"""
|
||||
执行层测试
|
||||
|
||||
测试Portfolio、Executor抽象接口
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from framework.execution import Executor, BacktestExecutor, DryRunExecutor, Portfolio
|
||||
from framework.execution import Portfolio, Executor, BacktestExecutor, DryRunExecutor
|
||||
from framework.risk import Position
|
||||
|
||||
|
||||
class TestExecutor:
|
||||
"""测试执行器基类"""
|
||||
class TestPortfolio:
|
||||
"""测试Portfolio"""
|
||||
|
||||
def test_executor_mode(self):
|
||||
"""测试执行器模式"""
|
||||
backtest = BacktestExecutor()
|
||||
assert backtest.get_mode() == "backtest"
|
||||
def test_portfolio_init(self):
|
||||
"""测试初始化"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
|
||||
dry_run = DryRunExecutor()
|
||||
assert dry_run.get_mode() == "dry_run"
|
||||
assert portfolio.initial_capital == 100000
|
||||
assert portfolio.cash == 100000
|
||||
assert len(portfolio.positions) == 0
|
||||
|
||||
def test_add_position(self):
|
||||
"""测试添加持仓"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
|
||||
portfolio.add_position(
|
||||
code='AAPL',
|
||||
price=100.0,
|
||||
quantity=10,
|
||||
time=datetime.now()
|
||||
)
|
||||
|
||||
assert len(portfolio.positions) == 1
|
||||
assert 'AAPL' in portfolio.positions
|
||||
assert portfolio.cash == 99000 # 100000 - 100*10
|
||||
|
||||
def test_remove_position(self):
|
||||
"""测试移除持仓"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
|
||||
portfolio.add_position('AAPL', 100.0, 10, datetime.now())
|
||||
profit = portfolio.remove_position('AAPL', 110.0, datetime.now())
|
||||
|
||||
assert len(portfolio.positions) == 0
|
||||
assert profit == 100.0 # (110-100)*10
|
||||
assert portfolio.cash == 100100 # 99000 + 110*10
|
||||
|
||||
def test_update_prices(self):
|
||||
"""测试更新价格"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
|
||||
portfolio.add_position('AAPL', 100.0, 10, datetime.now())
|
||||
portfolio.add_position('MSFT', 200.0, 5, datetime.now())
|
||||
|
||||
portfolio.update_prices({'AAPL': 110.0, 'MSFT': 220.0})
|
||||
|
||||
assert portfolio.positions['AAPL'].current_price == 110.0
|
||||
assert portfolio.positions['MSFT'].current_price == 220.0
|
||||
|
||||
def test_get_net_value(self):
|
||||
"""测试净值计算"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
|
||||
portfolio.add_position('AAPL', 100.0, 10, datetime.now())
|
||||
portfolio.update_prices({'AAPL': 110.0})
|
||||
|
||||
net_value = portfolio.get_net_value()
|
||||
expected = 99000 + 110 * 10 # cash + position_value
|
||||
assert net_value == expected
|
||||
|
||||
def test_get_weight(self):
|
||||
"""测试权重计算"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
|
||||
portfolio.add_position('AAPL', 100.0, 100, datetime.now())
|
||||
portfolio.update_prices({'AAPL': 110.0})
|
||||
|
||||
weight = portfolio.get_weight('AAPL')
|
||||
# 持仓价值=110*100=11000,净值=90000+11000=101000
|
||||
expected_weight = 11000 / 101000
|
||||
assert abs(weight - expected_weight) < 0.01
|
||||
|
||||
def test_record_net_value(self):
|
||||
"""测试净值记录"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
|
||||
portfolio.record_net_value()
|
||||
portfolio.add_position('AAPL', 100.0, 10, datetime.now())
|
||||
portfolio.record_net_value()
|
||||
|
||||
series = portfolio.get_net_value_series()
|
||||
assert len(series) == 2
|
||||
|
||||
def test_portfolio_repr(self):
|
||||
"""测试字符串表示"""
|
||||
portfolio = Portfolio(initial_capital=100000)
|
||||
portfolio.add_position('AAPL', 100.0, 10, datetime.now())
|
||||
|
||||
repr_str = repr(portfolio)
|
||||
assert 'Portfolio' in repr_str
|
||||
assert 'positions=1' in repr_str
|
||||
|
||||
|
||||
class TestBacktestExecutor:
|
||||
"""测试回测执行器"""
|
||||
|
||||
def test_backtest_init(self):
|
||||
"""测试回测初始化"""
|
||||
executor = BacktestExecutor(
|
||||
initial_capital=100000.0,
|
||||
trade_cost=0.001
|
||||
)
|
||||
def test_backtest_executor_init(self):
|
||||
"""测试初始化"""
|
||||
executor = BacktestExecutor(initial_capital=100000, trade_cost=0.001)
|
||||
|
||||
assert executor.initial_capital == 100000.0
|
||||
assert executor.initial_capital == 100000
|
||||
assert executor.trade_cost == 0.001
|
||||
assert executor.mode == "backtest"
|
||||
|
||||
def test_backtest_execute(self):
|
||||
"""测试回测执行"""
|
||||
executor = BacktestExecutor(initial_capital=100000.0)
|
||||
executor = BacktestExecutor(initial_capital=100000)
|
||||
|
||||
# 创建测试数据
|
||||
dates = pd.date_range('2020-01-01', periods=10)
|
||||
dates = pd.date_range('2020-01-01', periods=50)
|
||||
signals = pd.DataFrame({
|
||||
'signal': ['code1,code2'] * 10
|
||||
'signal': ['AAPL'] * 50
|
||||
}, index=dates)
|
||||
|
||||
data = pd.DataFrame({
|
||||
'code1': [100.0] * 10,
|
||||
'code2': [50.0] * 10,
|
||||
'close': np.random.randn(50).cumsum() + 100
|
||||
}, index=dates)
|
||||
|
||||
portfolio = executor.execute(signals, data)
|
||||
|
||||
assert portfolio is not None
|
||||
assert portfolio.cash == 100000.0
|
||||
assert isinstance(portfolio, Portfolio)
|
||||
|
||||
def test_backtest_executor_repr(self):
|
||||
"""测试字符串表示"""
|
||||
executor = BacktestExecutor(initial_capital=100000, trade_cost=0.001)
|
||||
repr_str = repr(executor)
|
||||
|
||||
assert 'BacktestExecutor' in repr_str
|
||||
|
||||
|
||||
class TestDryRunExecutor:
|
||||
"""测试模拟盘执行器"""
|
||||
"""测试DryRun执行器"""
|
||||
|
||||
def test_dry_run_init(self):
|
||||
"""测试模拟盘初始化"""
|
||||
executor = DryRunExecutor(initial_capital=50000.0)
|
||||
def test_dry_run_executor_init(self):
|
||||
"""测试初始化"""
|
||||
executor = DryRunExecutor(verbose=True)
|
||||
|
||||
assert executor.initial_capital == 50000.0
|
||||
assert executor.verbose == True
|
||||
assert executor.mode == "dry_run"
|
||||
|
||||
def test_simulate_order(self):
|
||||
"""测试模拟下单"""
|
||||
executor = DryRunExecutor(initial_capital=100000.0)
|
||||
def test_dry_run_execute(self):
|
||||
"""测试模拟执行"""
|
||||
executor = DryRunExecutor(verbose=False)
|
||||
|
||||
# 初始化持仓
|
||||
executor._portfolio = Portfolio(
|
||||
positions={},
|
||||
cash=100000.0,
|
||||
nav=1.0,
|
||||
trades=[]
|
||||
)
|
||||
dates = pd.date_range('2020-01-01', periods=50)
|
||||
signals = pd.DataFrame({
|
||||
'signal': ['AAPL,MSFT'] * 50
|
||||
}, index=dates)
|
||||
|
||||
# 模拟买入
|
||||
executor.simulate_order('code1', 'BUY', 100, 50.0)
|
||||
data = pd.DataFrame({
|
||||
'close': np.random.randn(50).cumsum() + 100
|
||||
}, index=dates)
|
||||
|
||||
# 检查现金减少
|
||||
assert executor._portfolio.cash == 100000.0 - 100 * 50.0
|
||||
|
||||
|
||||
class TestPortfolio:
|
||||
"""测试持仓组合"""
|
||||
|
||||
def test_portfolio_value(self):
|
||||
"""测试持仓价值计算"""
|
||||
portfolio = Portfolio(
|
||||
positions={},
|
||||
cash=50000.0,
|
||||
nav=1.0,
|
||||
trades=[]
|
||||
)
|
||||
portfolio = executor.execute(signals, data)
|
||||
|
||||
assert portfolio.get_total_value() == 50000.0
|
||||
assert isinstance(portfolio, Portfolio)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user