"""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)