99 lines
3.0 KiB
Python
99 lines
3.0 KiB
Python
"""Malformed parquet/input tests for phase boundary contracts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pandas as pd
|
|
import pytest
|
|
|
|
from pipeline.alpha.compute import compute_alpha
|
|
from pipeline.combo.combine import combine_alphas
|
|
from pipeline.derived.compute import validate_derived_frame
|
|
from pipeline.portfolio.construct import construct_positions
|
|
from pipeline.portfolio.simulator import ReferenceSimulator
|
|
from tests.helpers import make_generated_daily_bars
|
|
|
|
|
|
def test_alpha_compute_rejects_daily_data_without_close():
|
|
daily = make_generated_daily_bars().drop(columns=["close"])
|
|
|
|
with pytest.raises(KeyError, match="close"):
|
|
compute_alpha(daily, "bad", "reversal", lookback=3)
|
|
|
|
|
|
def test_alpha_feature_path_rejects_duplicate_symbol_dates(tmp_path):
|
|
daily = make_generated_daily_bars()
|
|
feature = pd.DataFrame({
|
|
"symbol_id": ["sh600000", "sh600000"],
|
|
"date": ["2024-01-02 09:30:00", "2024-01-02 15:00:00"],
|
|
"toy_feature": [1.0, 2.0],
|
|
})
|
|
feature_path = tmp_path / "duplicate_feature_keys.pq"
|
|
feature.to_parquet(feature_path, index=False)
|
|
|
|
with pytest.raises(ValueError, match="duplicate symbol_id,date"):
|
|
compute_alpha(
|
|
daily,
|
|
"bad_features",
|
|
"reversal",
|
|
lookback=3,
|
|
feature_paths=[str(feature_path)],
|
|
)
|
|
|
|
|
|
def test_derived_validation_rejects_bool_value_columns():
|
|
derived = pd.DataFrame({
|
|
"symbol_id": ["sh600000"],
|
|
"date": [pd.Timestamp("2024-01-02")],
|
|
"is_good": [True],
|
|
})
|
|
|
|
with pytest.raises(ValueError, match="numeric"):
|
|
validate_derived_frame(derived)
|
|
|
|
|
|
def test_combo_combine_rejects_missing_weight_column(tmp_path):
|
|
bad_alpha = pd.DataFrame({
|
|
"symbol_id": ["sh600000"],
|
|
"date": [pd.Timestamp("2024-01-02")],
|
|
"alpha_name": ["bad"],
|
|
})
|
|
bad_alpha_path = tmp_path / "bad_alpha.pq"
|
|
bad_alpha.to_parquet(bad_alpha_path, index=False)
|
|
|
|
with pytest.raises(KeyError, match="weight"):
|
|
combine_alphas([str(bad_alpha_path)], "bad_combo")
|
|
|
|
|
|
def test_portfolio_build_rejects_weights_without_symbol_id():
|
|
daily = make_generated_daily_bars()
|
|
bad_weights = pd.DataFrame({
|
|
"date": [pd.Timestamp("2024-01-02")],
|
|
"combo_name": ["bad"],
|
|
"weight": [1.0],
|
|
})
|
|
|
|
with pytest.raises(KeyError, match="symbol_id"):
|
|
construct_positions(
|
|
bad_weights,
|
|
daily,
|
|
booksize=1_000_000.0,
|
|
portfolio_name="bad_portfolio",
|
|
)
|
|
|
|
|
|
def test_portfolio_simulate_rejects_positions_without_position_shares():
|
|
daily = make_generated_daily_bars()
|
|
bad_positions = pd.DataFrame({
|
|
"symbol_id": ["sh600000"],
|
|
"date": [pd.Timestamp("2024-01-02")],
|
|
"portfolio_name": ["bad"],
|
|
"target_weight": [1.0],
|
|
"target_value": [1000.0],
|
|
"target_shares": [100.0],
|
|
"position_value": [1000.0],
|
|
"price": [10.0],
|
|
})
|
|
|
|
with pytest.raises(KeyError, match="position_shares"):
|
|
ReferenceSimulator().run(bad_positions, daily)
|