advanced
15 minMulti-Factor Portfolio Backtest
Combine ROE, FCF yield, and Piotroski F-score into a simple long-short factor portfolio.
factorbacktestPITDuckDB
## Multi-Factor Portfolio
This example combines 3 factors from the factor_scores table into a simple composite and tests whether the top quintile outperformed the bottom quintile historically.
python
import pandas as pd
from valuein_sdk import ValueinClient, ValueinError
try:
with ValueinClient() as client:
# Get factor scores for S&P 500
factor_df = client.query("""
SELECT
r.symbol, r.name, r.sector,
fs.roe_rank,
fs.fcf_to_assets_rank,
fs.piotroski_f_score_rank,
fs.composite_rank,
-- Custom 3-factor composite
(fs.roe_rank + fs.fcf_to_assets_rank + fs.piotroski_f_score_rank) / 3 AS custom_composite
FROM factor_scores fs
JOIN references r USING (entity_id)
WHERE r.is_sp500 = TRUE
AND r.symbol IS NOT NULL
ORDER BY custom_composite DESC
""")
# Quintile breakdown
factor_df['quintile'] = pd.qcut(factor_df['custom_composite'], 5, labels=['Q1','Q2','Q3','Q4','Q5'])
print(factor_df.groupby('quintile')[['roe_rank','fcf_to_assets_rank','piotroski_f_score_rank']].mean())
# Top 20 (long basket)
print("\nTop 20 — long basket:")
print(factor_df.head(20)[['symbol','name','sector','custom_composite']].to_string())
except ValueinError as e:
print(f"Error: {e}")Try it yourself
Get your API token and run this notebook against 105M+ real SEC EDGAR facts.