portfolio-engine / tests /test_new_features.py
engineportf's picture
Initial Deployment from Local Engine
208fbf8 verified
Raw
History Blame Contribute Delete
4.91 kB
"""
Tests for P2/P3 features:
- Noise-Filtered Transformer (deep learning sequence model)
- Options Flow Sentiment (alternative data ingestion)
- Exact True Risk Parity (ERC allocation engine)
"""
import pytest
import numpy as np
import pandas as pd
from unittest.mock import patch, MagicMock
# ─────────────────────────────────────────────
# TRANSFORMER (Deep Learning Sequence Model)
# ─────────────────────────────────────────────
import dl_models
def test_transformer_train_and_predict():
"""Train the NoiseFilteredTransformer on synthetic cross-asset data and verify predictions."""
features_dict = {}
for t in ['AAPL', 'MSFT', 'GOOGL']:
df = pd.DataFrame(np.random.randn(100, 10), columns=[f'feat_{i}' for i in range(10)])
df['target'] = df['feat_0'] * 0.5 + df['feat_1'] * 0.2 + np.random.randn(100) * 0.1
df['ret'] = np.random.randn(100) * 0.01
features_dict[t] = df
model, scaler = dl_models.train_cross_asset_transformer(
features_dict,
seq_len=60,
epochs=2,
batch_size=16,
silent=True
)
assert model is not None
assert scaler is not None
preds = dl_models.predict_transformer(model, scaler, features_dict, seq_len=60)
assert len(preds) == 3
assert 'AAPL' in preds
assert 'MSFT' in preds
assert 'GOOGL' in preds
assert isinstance(preds['AAPL'], float)
# ─────────────────────────────────────────────
# OPTIONS FLOW SENTIMENT (Alternative Data)
# ─────────────────────────────────────────────
import alternative_data
@patch('alternative_data.yf.Ticker')
def test_options_sentiment_success(mock_ticker):
"""Verify put/call ratio and IV skew extraction from a mocked options chain."""
mock_tk = MagicMock()
mock_ticker.return_value = mock_tk
mock_tk.options = ('2026-07-01',)
mock_chain = MagicMock()
mock_chain.calls = pd.DataFrame({
'volume': [100, 200, 300],
'impliedVolatility': [0.1, 0.15, 0.2]
})
mock_chain.puts = pd.DataFrame({
'volume': [50, 150],
'impliedVolatility': [0.2, 0.3]
})
mock_tk.option_chain.return_value = mock_chain
results = alternative_data.fetch_options_sentiment(['AAPL'], silent=True)
assert 'AAPL' in results
assert 'put_call_ratio' in results['AAPL']
assert 'iv_skew' in results['AAPL']
# calls volume sum = 600, puts volume sum = 200 β†’ ratio = 0.333
assert pytest.approx(results['AAPL']['put_call_ratio'], 0.01) == 0.333
# calls mean IV = 0.15, puts mean IV = 0.25 β†’ skew = 0.10
assert pytest.approx(results['AAPL']['iv_skew'], 0.01) == 0.10
@patch('alternative_data.yf.Ticker')
def test_options_sentiment_no_options_available(mock_ticker):
"""Verify safe defaults when a ticker has no listed options chains."""
mock_tk = MagicMock()
mock_ticker.return_value = mock_tk
mock_tk.options = ()
results = alternative_data.fetch_options_sentiment(['TSLA'], silent=True)
assert 'TSLA' in results
assert results['TSLA']['put_call_ratio'] == 1.0
assert results['TSLA']['iv_skew'] == 0.0
# ─────────────────────────────────────────────
# EXACT TRUE RISK PARITY (ERC Engine)
# ─────────────────────────────────────────────
from erc_engine import exact_risk_parity_allocation
def test_exact_risk_parity_equal_contributions():
"""Mathematically verify that ERC produces equal marginal risk contributions."""
# 3 assets with widely different volatilities
vols = np.array([0.1, 0.2, 0.4])
corr = np.array([
[1.0, 0.3, 0.2],
[0.3, 1.0, 0.4],
[0.2, 0.4, 1.0]
])
cov = np.outer(vols, vols) * corr
cov_df = pd.DataFrame(cov, columns=['A', 'B', 'C'], index=['A', 'B', 'C'])
weights = exact_risk_parity_allocation(cov_df, silent=True)
assert len(weights) == 3
assert np.isclose(weights.sum(), 1.0)
# Compute marginal risk contributions: w_i * (Ξ£w)_i
w_arr = weights.values
marginal_risk = cov.dot(w_arr)
risk_contributions = w_arr * marginal_risk
# All risk contributions must be equal within tight tolerance
mean_rc = np.mean(risk_contributions)
np.testing.assert_allclose(risk_contributions, mean_rc, rtol=1e-3, atol=1e-5)
# Lower-vol asset A should have the highest weight
assert weights['A'] > weights['C']
assert weights['A'] > weights['B']