مستقبل کی معلومات کے تعصب کے بغیر لاگت کے قابل ایکویٹی کائنات بنانا
خلاصہ
یہ دستاویز تخمینی راؤنڈ ٹرپ ٹریڈنگ لاگت استعمال کرتے ہوئے توثیق اور ہولڈ آؤٹ بیک ٹیسٹس کے لیے ایکویٹیز کا منجمد مجموعہ منتخب کرنے کا طریقہ بیان کرتی ہے۔ تخمینہ فی حصص لاگت کو اوسط حصص کی قیمت کے مقابلے میں اور اوسط نصف اسپریڈ کو دو گنا کرکے یکجا کرتا ہے؛ دونوں بیسس پوائنٹس میں ظاہر کیے جاتے ہیں۔ سمبلز اس تخمینے کی بنیاد پر درجہ بند کیے جاتے ہیں اور ہر تقسیم کے لیے کم ترین لاگت والے نام منتخب ہوتے ہیں۔
مستقبل کی معلومات کے تعصب کو کم کرنے کے لیے توثیقی فہرست میں وہ کوٹ بارز استعمال ہوتی ہیں جو توثیقی ونڈو سے پہلے ختم ہوں، جبکہ ہولڈ آؤٹ فہرست لیکویڈیٹی پروفائل صرف ہولڈ آؤٹ شروع ہونے سے پہلے کی تاریخوں تک محدود رکھتی ہے۔ فہرست بنانے والا یہ بھی بتاتا ہے کہ دونوں فہرستوں میں کتنے نام مشترک ہیں، جو کائنات کے استحکام کا سادہ پیمانہ ہے۔ فہرستیں رولنگ انتخاب کے بجائے مخصوص وقت کے اسنیپ شاٹس ہیں، اس لیے بعد کی لیکویڈیٹی تبدیلیوں کے مطابق نہیں ڈھلتیں۔ دستاویز فہرستیں بنانے کا طریقہ بیان کرتی ہے مگر ناپی گئی لاگت، اوورلیپ کا نتیجہ یا اس بات کا ثبوت فراہم نہیں کرتی کہ یہ تخمینہ حقیقی عمل درآمدی لاگت کی پیش گوئی کرتا ہے۔
اہم خیالات
- فی حصص لاگت اور کوٹ کیے گئے اسپریڈز کو ملانے والے راؤنڈ ٹرپ لاگت کے تخمینے سے ایکویٹیز کی درجہ بندی کریں۔
- ہر تقسیم کی کائنات صرف اس تقسیم کے آغاز سے پہلے دستیاب لیکویڈیٹی معلومات سے بنائیں۔
- ہر ری بیلنس پر دوبارہ حساب کرنے کے بجائے ہر تقسیم کے لیے منتخب کائنات منجمد رکھیں۔
- رکنیت کے استحکام کی وضاحت کے لیے توثیق اور ہولڈ آؤٹ کی فہرستوں کا موازنہ کریں۔
- لاگت کا تخمینہ اندازہ ہے اور حقیقی ٹریڈنگ لاگت ثابت نہیں کرتا۔
ٹیگز
مکمل متن
# _build_cost_feasible_universe.py
```py
"""Provenance: builder for the frozen, per-split cost-feasible universe.
Run from the repo root (``uv run python
case_studies/nasdaq100_microstructure/_build_cost_feasible_universe.py``).
The canonical lists live in ``config/setup.yaml::universe.cost_feasible.
{validation,holdout}`` and are consumed by the backtest pipeline via
``strategy.signal.universe_filter='cost_feasible'`` (see
``case_studies/utils/backtest_runner.py::_apply_cost_feasible_filter``). This
script documents HOW those lists were produced so they can be regenerated.
The universe is a frozen snapshot per split (profiled with no look-ahead),
NOT full-sample and NOT per-rebalance rolling:
- validation universe := top-50 by round-trip-cost proxy, computed on quote
bars STRICTLY BEFORE the validation window start (2020-01-01 -> 2020-06-30,
the first expanding-window training block). No validation-period liquidity
leaks into the universe pick.
- holdout universe := top-50 from the pre-holdout liquidity_profile.parquet,
which 01_feasibility_analysis.py restricts to < HOLDOUT_START (2021-07-01).
Causal at the holdout boundary.
Round-trip cost proxy: 2*(per_share/mean_price)*1e4 + 2*median_half_spread_bps.
Prints the val/holdout overlap so stability can be documented.
"""
from __future__ import annotations
import json
from pathlib import Path
import polars as pl
import yaml
from data import load_nasdaq100_bars
from utils.paths import get_case_study_dir
CS = "nasdaq100_microstructure"
CASE_DIR = get_case_study_dir(CS)
SETUP = yaml.safe_load((CASE_DIR / "config/setup.yaml").open())
PER_SHARE_USD = float(SETUP["costs"]["per_share"])
UNIVERSE = sorted(SETUP["universe"]["symbols"])
START_DATE = "2020-01-01"
VALIDATION_START = "2020-06-30"
HOLDOUT_START = str(SETUP["evaluation"]["holdout_start"]) # 2021-07-01
TOP_N = 50
OUT = Path(__file__).parent
def build_profile(start: str, end: str) -> pl.DataFrame:
qb = load_nasdaq100_bars(start_date=start, end_date=end, include_quotes=True, symbols=UNIVERSE)
qb = (
qb.with_columns(
mid=(pl.col("bid_close") + pl.col("ask_close")) / 2,
raw_spread=pl.col("ask_close") - pl.col("bid_close"),
)
.filter(
pl.col("bid_close").is_not_null()
& pl.col("ask_close").is_not_null()
& (pl.col("bid_close") > 0)
& (pl.col("ask_close") >= pl.col("bid_close"))
)
.with_columns(half_spread_bps=(pl.col("raw_spread") / 2 / pl.col("mid") * 1e4))
)
return (
qb.group_by("symbol")
.agg(
n_bars=pl.len(),
median_half_spread_bps=pl.col("half_spread_bps").median(),
mean_price=pl.col("close").mean(),
)
.with_columns(
rt_cost_bps=2 * (PER_SHARE_USD / pl.col("mean_price")) * 1e4
+ 2 * pl.col("median_half_spread_bps"),
)
.sort("rt_cost_bps")
)
def top50_from_existing() -> list[str]:
lp = pl.read_parquet(CASE_DIR / "liquidity_profile.parquet").select(
["symbol", "median_half_spread_bps", "mean_price"]
)
lp = lp.with_columns(
rt_cost_bps=2 * (PER_SHARE_USD / pl.col("mean_price")) * 1e4
+ 2 * pl.col("median_half_spread_bps")
)
return lp.sort("rt_cost_bps").head(TOP_N)["symbol"].to_list()
def main() -> None:
print(f"per_share=${PER_SHARE_USD} top_n={TOP_N}", flush=True)
val_prof = build_profile(START_DATE, VALIDATION_START)
val_univ = val_prof.head(TOP_N)["symbol"].to_list()
ho_univ = top50_from_existing()
val_set, ho_set = set(val_univ), set(ho_univ)
print(f"OVERLAP: {len(val_set & ho_set)}/{TOP_N} symbols common", flush=True)
(OUT / "universe_validation.json").write_text(json.dumps(val_univ, indent=2))
(OUT / "universe_holdout.json").write_text(json.dumps(ho_univ, indent=2))
print(
"Wrote universe_{validation,holdout}.json — copy into "
"config/setup.yaml::universe.cost_feasible",
flush=True,
)
if __name__ == "__main__":
main()
```ماخذ کا حوالہ دیتے ہوئے مکمل متن دکھایا گیا ہے، ماخذ کے لائسنس کے تحت۔ لائسنس: MIT
یہ خلاصہ اصل ماخذ سے Stratmill کے تحقیقی ایجنٹ نے لکھا ہے؛ یہ ماخذ کی نقل نہیں۔