विश्लेषण के लिए समायोजित या असमायोजित ETF मूल्य चुनना
सारांश
यह दस्तावेज़ ETF बाज़ार डेटा लोड करने की विधि बताता है, जिसमें वैकल्पिक प्रतीक और तारीख फ़िल्टर तथा लौटाए गए प्रतीकों की नियत सीमा शामिल है। इसका मुख्य विश्लेषणात्मक बिंदु मापी जा रही राशि के अनुसार मूल्य श्रृंखला चुनना है: रिटर्न के लिए समायोजित मूल्य उपयुक्त हैं, जबकि टर्नओवर स्क्रीन या प्रति-शेयर कमीशन जैसी डॉलर और शेयर गणनाओं के लिए असमायोजित मूल्य चाहिए।
यह बताता है कि मूल्य अनुपात में निरस्त हो जाने वाले समायोजन कारक डॉलर में व्यक्त मूल्यों को क्यों बिगाड़ सकते हैं। उदाहरण में शुरुआती ऐतिहासिक तारीख पर समायोजित और वास्तविक कारोबार वाले SPY के क्लोज़िंग मूल्य की तुलना है, जिससे दिखता है कि संचित समायोजनों के साथ अंतर बढ़ता है। लोडर टाइमस्टैम्प को तारीखों में सामान्यीकृत भी करता है और असमायोजित परिणामों को प्रतीक तथा समय के अनुसार क्रमबद्ध करता है। दस्तावेज़ न ट्रेडिंग रणनीति बताता है, न डेटा गुणवत्ता का मूल्यांकन करता है; इसका व्यावहारिक मार्गदर्शन गणना के लिए सही श्रृंखला चुनने और स्थानीय स्टोर से डेटा प्राप्त करने तक सीमित है।
मुख्य विचार
- रिटर्न गणना के लिए समायोजित मूल्य उपयुक्त हैं, क्योंकि सामान्य समायोजन कारक मूल्य अनुपात में निरस्त हो जाते हैं।
- टर्नओवर और प्रति-शेयर लागत गणना सहित डॉलर मूल्य और शेयरों की संख्या के लिए असमायोजित मूल्य चाहिए।
- ऐतिहासिक समायोजित क्लोज़ वास्तव में ट्रेड हुए मूल्यों से काफ़ी अलग हो सकते हैं।
- लोडर प्रतीक और तारीख फ़िल्टर का समर्थन करता है और प्रतीकों की संख्या को नियत रूप से सीमित कर सकता है।
टैग
पूरा पाठ
# loader.py
```py
"""ETF universe loader."""
import polars as pl
from data.exceptions import DataNotFoundError
from utils import ML4T_DATA_PATH
from utils.data_quality import apply_max_symbols
def list_etfs() -> list[str]:
"""List ETF symbols available in the local data store.
Returns:
Sorted list of ETF tickers (e.g., ``["ACWI", "AGG", ..., "XLK"]``).
Raises:
DataNotFoundError: If ``etfs/etf_universe.parquet`` is missing.
Example:
>>> list_etfs()[:3]
['ACWI', 'ACWX', 'AGG']
"""
path = ML4T_DATA_PATH / "etfs" / "market" / "etf_universe.parquet"
if not path.exists():
raise DataNotFoundError(
dataset_name="ETF Universe",
path=path,
download_script="data/etfs/market/download.py",
readme="data/etfs/README.md",
)
return pl.scan_parquet(path).select("symbol").unique().collect().to_series().sort().to_list()
def load_etfs(
symbols: list[str] | None = None,
start_date: str | None = None,
end_date: str | None = None,
max_symbols: int = 0,
) -> pl.DataFrame:
"""Load ETF universe for momentum case study.
Args:
symbols: Optional list of symbols to filter (e.g., ["SPY", "QQQ"])
start_date: Optional start date (YYYY-MM-DD format)
end_date: Optional end date (YYYY-MM-DD format)
max_symbols: Limit to N random symbols (0 = all). Seed-deterministic.
Returns:
DataFrame with columns: timestamp, symbol, open, high, low, close, volume
"""
path = ML4T_DATA_PATH / "etfs" / "market" / "etf_universe.parquet"
if not path.exists():
raise DataNotFoundError(
dataset_name="ETF Universe",
path=path,
download_script="data/etfs/market/download.py",
readme="data/etfs/README.md",
)
lf = pl.scan_parquet(path)
ts_type = lf.collect_schema()["timestamp"]
# Apply filters lazily (parquet pushdown / row-group pruning)
if symbols:
lf = lf.filter(pl.col("symbol").is_in(symbols))
if start_date:
lit = (
pl.lit(start_date).str.to_date()
if ts_type == pl.Date
else pl.lit(start_date).str.to_datetime()
)
lf = lf.filter(pl.col("timestamp") >= lit)
if end_date:
lit = (
pl.lit(end_date).str.to_date()
if ts_type == pl.Date
else pl.lit(end_date).str.to_datetime()
)
lf = lf.filter(pl.col("timestamp") <= lit)
# Normalize daily data to Date type (post-filter so pushdown works on raw type)
if ts_type != pl.Date:
lf = lf.with_columns(pl.col("timestamp").cast(pl.Date))
return apply_max_symbols(lf.collect(), max_symbols)
def load_etfs_unadjusted(
symbols: list[str] | None = None,
start_date: str | None = None,
end_date: str | None = None,
) -> pl.DataFrame:
"""Load the traded close and share count, unadjusted for splits and distributions.
:func:`load_etfs` returns an adjusted panel, which is what a return needs: the
adjustment divides out distributions, and dividing both ends of a ratio by the same
factor leaves the ratio alone. A dollar amount has no such cancellation. An adjusted
close on an early session sits well below what the fund traded at - $87.23 against
$126.70 for SPY on 2006-01-03 - so a turnover screen or a per-share commission read
off it is wrong by the cumulative adjustment, and wrong by more the further back it
looks.
Use this series for anything denominated in dollars or in shares, and
:func:`load_etfs` for anything denominated in returns.
Args:
symbols: Optional list of symbols to filter (e.g., ["SPY", "QQQ"])
start_date: Optional start date (YYYY-MM-DD format)
end_date: Optional end date (YYYY-MM-DD format)
Returns:
DataFrame with columns: timestamp, symbol, close, volume
Raises:
DataNotFoundError: If ``etfs/etf_universe_unadjusted.parquet`` is missing.
"""
path = ML4T_DATA_PATH / "etfs" / "market" / "etf_universe_unadjusted.parquet"
if not path.exists():
raise DataNotFoundError(
dataset_name="ETF Universe (unadjusted)",
path=path,
download_script="data/etfs/market/download.py",
readme="data/etfs/README.md",
)
lf = pl.scan_parquet(path)
ts_type = lf.collect_schema()["timestamp"]
if symbols:
lf = lf.filter(pl.col("symbol").is_in(symbols))
if start_date:
lit = (
pl.lit(start_date).str.to_date()
if ts_type == pl.Date
else pl.lit(start_date).str.to_datetime()
)
lf = lf.filter(pl.col("timestamp") >= lit)
if end_date:
lit = (
pl.lit(end_date).str.to_date()
if ts_type == pl.Date
else pl.lit(end_date).str.to_datetime()
)
lf = lf.filter(pl.col("timestamp") <= lit)
if ts_type != pl.Date:
lf = lf.with_columns(pl.col("timestamp").cast(pl.Date))
return lf.collect().sort(["symbol", "timestamp"])
```स्रोत के लाइसेंस के तहत श्रेय सहित पूरा पाठ दिखाया गया है। लाइसेंस: MIT
यह सारांश मूल स्रोत के आधार पर Stratmill के शोध एजेंट ने लिखा है; यह स्रोत की प्रति नहीं है।