Hi everyone,
One of the great things about QuantConnect is that it's data-independent, which allows us to integrate any data source. I'm primarily a derivatives trader and have been a long-time user of ORATS. Since I've been building out my QC ML options trading algos, I wanted reliable derived options data for backtesting, without having to construct my own models. Very recently I noticed that ORATS is now selling daily and minute historical data. I purchased the daily version, it's simplified a lot for me when conducting research. The issue still persists for any algos running intraday, I still need to use QC's framework or make my own for anything needing intraday greeks. Hopefully in the future it will be easier to integrate any data source which operates on our brokerage platform.
I'm sharing the code to process the ORATS csv file in the hopes it helps someone else better leverage QuantConnect.
Lauren Roberts
Roberts Trading
def explode_orats_format(df):
print("ORATS raw columns before rename:", df.columns.tolist())
df.rename(columns={"ticker": "underlying", "expirDate": "expiry"}, inplace=True)
df["trade_date"] = pd.to_datetime(df["trade_date"], errors="coerce")
df["expiry"] = pd.to_datetime(df["expiry"], errors="coerce")
# --- Call side ---
call_cols = [
"underlying", "trade_date", "expiry", "strike", "stkPx",
"cVolu", "cOi", "cValue", "extCTheo", "smoothSmvVol", "residualRateData",
"delta", "gamma", "theta", "vega", "rho", "phi", "driftlessTheta", "extVol"
]
calls = df[call_cols].copy()
calls.columns = [
"underlying", "trade_date", "expiry", "strike", "stkPx",
"volume", "openinterest", "close_orats", "orats_theo", "smoothSmvVol", "residualRateData",
"delta", "gamma", "theta", "vega", "rho", "phi", "driftlessTheta", "extVol"
]
calls["right"] = "c"
# --- Put side ---
put_cols = [
"underlying", "trade_date", "expiry", "strike", "stkPx",
"pVolu", "pOi", "pValue", "extPTheo", "smoothSmvVol", "residualRateData",
"delta", "gamma", "theta", "vega", "rho", "phi", "driftlessTheta", "extVol"
]
puts = df[put_cols].copy()
puts.columns = [
"underlying", "trade_date", "expiry", "strike", "stkPx",
"volume", "openinterest", "close_orats", "orats_theo", "smoothSmvVol", "residualRateData",
"delta", "gamma", "theta", "vega", "rho", "phi", "driftlessTheta", "extVol"
]
puts["right"] = "p"
# --- Combine ---
combined = pd.concat([calls, puts], ignore_index=True)
combined.sort_values(["trade_date", "expiry", "strike", "right"], inplace=True)
print("ORATS cleaned shape:", combined.shape)
print("ORATS columns:", combined.columns.tolist())
return combined
Mia Alissi
Here's the complete code to integrate Lauren's cleaned ORATS options data as custom data for QuantConnect. This will allow you to ingest your preprocessed CSV (where each record is a single contract/side, with greeks and meta-data), and access it in your algorithms:
How to use:
explode_orats_format
) asdata/orats_cleaned.csv
in your project.orats_point.delta
,.expiry
,.strike
, etc).Let me know if you want additional logic: filtering by expiry/strike, or stacking the minute version for intraday strategies!
Sources: CSV Format Example - QuantConnect.com, Object Store - QuantConnect.com, docs writing algorithms datasets algoseek us equity options, Requesting Data - QuantConnect.com, docs writing algorithms importing data streaming data key concepts
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Lauren Roberts
import pandas as pd
from io import StringIO
file_path = qb.object_store.get_file_path("SPY.parquet")
# Read the Parquet file content from the Object Store, which is the ORATS csv
# Convert string content to file-like object and load to dataframe
df = pd.read_parquet(file_path)
print(df.columns)
def merge_qc_orats(qc_df: pd.DataFrame, orats_df: pd.DataFrame) -> pd.DataFrame:
qc_df = qc_df.copy()
orats_df = orats_df.copy()
qc_df["expiry"] = pd.to_datetime(qc_df["expiry"])
qc_df["trade_date"] = pd.to_datetime(qc_df["trade_date"])
orats_df["expiry"] = pd.to_datetime(orats_df["expiry"])
orats_df["trade_date"] = pd.to_datetime(orats_df["trade_date"])
merged = pd.merge(
qc_df,
orats_df,
on=["trade_date", "expiry", "strike", "right"],
suffixes=("_qc", "_orats"),
how="inner"
)
return merged
Lauren Roberts
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!