diff --git a/.codex/skills/analyst/SKILL.md b/.codex/skills/analyst/SKILL.md index 82e52cf..cc200c9 100644 --- a/.codex/skills/analyst/SKILL.md +++ b/.codex/skills/analyst/SKILL.md @@ -7,7 +7,7 @@ description: Use for Hong Kong IPO subscription analysis in this project: T0/T1/ ## Purpose -Assess Hong Kong IPO subscription candidates using the project's archived facts, scoring rules, prediction cards, and review history. This skill owns judgment: whether to subscribe, wait, avoid, hold after allocation, or revise a rule after outcomes arrive. +Assess Hong Kong IPO subscription candidates using the project's archived facts, scoring rules, prediction cards, and review history. This skill owns judgment: whether to subscribe, wait, avoid, sell in grey market or on D1, or revise a rule after outcomes arrive. Use `archivist` first when source documents, listing facts, allotment results, prices, or database snapshots need to be updated. @@ -22,6 +22,16 @@ Separate the decision stage from later facts: Do not let later facts leak into earlier prediction cards. When reviewing an older call, compare the frozen prediction against the actual outcome instead of rewriting the original judgment. +## Trading Horizon + +The analyst model is a short-exit IPO subscription model, not a long-term holding model. + +- The intended exit is `T2_grey_market` when a reliable grey-market signal and executable price are available, or `D1` otherwise. +- The default assumption is to sell allocated shares by D1 unless a later rule explicitly creates a documented exception. +- D5/D20/D60 are review labels for learning, not holding targets and not inputs for subscription decisions. +- Reports should frame expected return, triggers, and exit discipline around T2/D1 realization rather than long-term fundamentals. +- Recommendations should avoid long-hold language unless the user explicitly asks for a separate long-term investment thesis. + ## Project Storage Contract Use repo-relative paths everywhere: @@ -77,7 +87,7 @@ Generated prediction reports must remain stage-safe: - T0 reports use only prospectus-stage fields and T0 calibration. - T1 reports may add allotment demand fields and T1 calibration. -- D1/D5/D20/D60 returns are never shown as prediction inputs; they are reserved for later review cards. +- T2/D1 is the intended sell window; D5/D20/D60 returns are never shown as prediction inputs and are reserved for later review cards. ## Output Standards @@ -96,6 +106,7 @@ Every prediction card should include: - key risks - triggers for upgrade/downgrade - exit plan +- explicit T2/D1 sell discipline - source paths Every review card should include: diff --git a/README.md b/README.md index 3f057e3..9c8f0d7 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ The project is designed around a feedback loop: 3. Compare predictions with post-listing outcomes. 4. Improve the scoring rules only from reviewed evidence. +The investment horizon is deliberately short. The subscription model is built for selling allocated shares in `T2_grey_market` when a reliable executable grey-market signal exists, or on `D1` otherwise. It is not a long-term holding model. + ## Goals - Maintain a local, Git-tracked history of Hong Kong IPO data. @@ -28,6 +30,8 @@ Each IPO is evaluated by stage: The key discipline is to avoid hindsight leakage. A T0 prediction should only use T0 information, even after the IPO has listed. +The default exit discipline is T2/D1. D5/D20/D60 outcomes are kept to review whether the model missed later information, not to justify holding IPO allocations beyond the intended sell window. + ## Project Skills This repository includes project-local Codex skills under `.codex/skills/`. @@ -153,7 +157,7 @@ Use the analyst model builder to digest archived data into a stage-safe scoring The v0 model is documented in `rules/ipo_score_v0.yaml`. It writes `data/snapshots/analysis_model_v0_dataset.csv` and `reports/2026-06-15_analysis_model_v0.md`. -The model separates T0 prospectus inputs from T1 allotment inputs. D1/D5/D20/D60 returns are labels for calibration and review, not prediction inputs. +The model separates T0 prospectus inputs from T1 allotment inputs. Its live trading target is a T2 or D1 sale. D5/D20/D60 returns are labels for calibration and review, not prediction inputs or planned holding targets. ## Single IPO Markdown Report @@ -166,7 +170,7 @@ Use the analyst report generator after the archive and model dataset are current The generator writes `reports/{date}_{ticker}_{stage}_analysis.md` by default. It auto-selects `T1_allotment` when structured allotment-demand facts exist; otherwise it generates a `T0_prospectus` report. Use `--stdout` for a dry run or `--output` to choose a specific Markdown path. -Prediction reports are stage-safe: T0 reports use only prospectus-stage facts and T0 calibration, while T1 reports add allotment demand and T1 calibration. Post-listing D1/D5/D20/D60 performance stays out of prediction reports and is reserved for review cards. +Prediction reports are stage-safe: T0 reports use only prospectus-stage facts and T0 calibration, while T1 reports add allotment demand and T1 calibration. Reports should frame the trade as a T2/D1 exit. Post-listing D5/D20/D60 performance stays out of prediction reports and is reserved for review cards. ## Incremental Archive Sync diff --git a/reports/2026-06-15_06106_T0_prospectus_analysis.md b/reports/2026-06-15_06106_T0_prospectus_analysis.md index 8d9617f..9341e89 100644 --- a/reports/2026-06-15_06106_T0_prospectus_analysis.md +++ b/reports/2026-06-15_06106_T0_prospectus_analysis.md @@ -9,8 +9,9 @@ - Model dataset as of: `2026-06-15T14:04:34Z` - Rule version: `ipo_score_v0` - Rule path: `rules/ipo_score_v0.yaml` +- Strategy horizon: short IPO subscription trade; intended exit is T2 grey market if reliable, otherwise D1. - Decision: `strong_watch` -- PM action: Strong watch at T0, still pending T1 demand confirmation. +- PM action: Strong watch at T0, still pending T1 demand confirmation for a T2/D1 exit. - T0 score: `11` - Score bucket: `t0_gte_8` - Calibrated D1 positive probability: 76.4% from 72 historical D1 labels @@ -35,12 +36,14 @@ | Initial public offer percentage | 5.0% | | Over-allotment shares | 1,574,550 | -## Model Inference +## Short-Exit Model Inference - D1 positive probability: 76.4% - D1 >= 10% probability: 47.2% - Historical average D1 return for bucket: 28.6% - Historical median D1 return for bucket: 9.6% +- T2 sell return is not modeled until an approved grey-market data source exists. +- D5/D20/D60 outcomes are review labels only, not holding targets. ## Score Breakdown @@ -64,8 +67,8 @@ - No material negative scoring component. - No required report field is blank for this stage. -- T2 grey-market signal is not used because the project has no approved reproducible source. -- Post-listing D1/D5/D20/D60 outcomes are labels for model calibration only and are not shown as prediction inputs. +- T2 grey-market signal is not used yet because the project has no approved reproducible source. +- Post-listing D5/D20/D60 outcomes are labels for later review only and are not holding-period targets. ## Triggers @@ -74,9 +77,10 @@ ## Exit Plan -- If subscribed and allocated, reassess after allotment and before first trading session using only information available at that stage. -- For T1 reports without approved T2 data, treat first-day liquidity and position sizing conservatively. -- Record actual D1/D5/D20/D60 outcomes later as review labels, not as retroactive prediction inputs. +- If subscribed and allocated, plan to sell in T2 grey market when reliable executable data is available. +- If T2 is unavailable or unreliable, use D1 as the default exit window. +- Do not treat D5/D20/D60 as planned holding periods for this model. +- Record D1/D5/D20/D60 outcomes later as review labels, not as retroactive prediction inputs. ## Source Paths diff --git a/reports/2026-06-15_analysis_model_v0.md b/reports/2026-06-15_analysis_model_v0.md index eaa2e79..380eb0f 100644 --- a/reports/2026-06-15_analysis_model_v0.md +++ b/reports/2026-06-15_analysis_model_v0.md @@ -7,9 +7,9 @@ ## What This Model Does -This is the first analyst model built from the downloaded archive. It creates a repeatable feature table, scores each IPO using stage-safe rules, and calibrates the score buckets against archived D1 outcomes. It is intentionally transparent: the output includes every score component and the archived source paths used for each ticker. +This is the first analyst model built from the downloaded archive. It creates a repeatable feature table, scores each IPO using stage-safe rules, and calibrates the score buckets against archived D1 sell outcomes. It is intentionally transparent: the output includes every score component and the archived source paths used for each ticker. -The model does not use grey-market data in v0 because T2 currently has no approved reproducible source. It also does not use post-listing returns as inputs; returns are labels only. +The model is built for a short IPO allocation trade: sell in T2 grey market when reliable executable data exists, or sell on D1 otherwise. It does not use grey-market data in v0 because T2 currently has no approved reproducible source. It also does not use post-listing returns as inputs; D1 is the primary sell label, while D5/D20/D60 are review labels only. ## Data Inventory @@ -58,7 +58,8 @@ The high-conviction bucket remains clearly differentiated, but the middle and lo 1. Run `scripts/build_analysis_dataset.py` after archivist updates the database. 2. Use `t0_score` for prospectus-stage watchlisting. 3. Use `total_score`, `decision_band`, and `calibrated_d1_positive_rate` for T1-stage subscription cards. -4. Treat D1/D5/D20/D60 columns as review labels only, never as prediction inputs. +4. Frame live decisions around a T2 or D1 sell, not long-term holding. +5. Treat D5/D20/D60 columns as review labels only, never as prediction inputs or holding targets. ## Known Gaps diff --git a/rules/ipo_score_v0.yaml b/rules/ipo_score_v0.yaml index 737ecb5..ddca486 100644 --- a/rules/ipo_score_v0.yaml +++ b/rules/ipo_score_v0.yaml @@ -7,14 +7,27 @@ purpose: > Build the first transparent Hong Kong IPO subscription scoring model from archived project data. The model is a rules-plus-calibration baseline, not a black-box predictor. It separates T0 prospectus information from T1 allotment - information so later facts do not leak into earlier decisions. + information so later facts do not leak into earlier decisions. It is designed + for short IPO subscription exits, not long-term holding. targets: - primary: D1 return versus IPO offer price + primary: D1 sell return versus IPO offer price secondary: - - D5 return versus IPO offer price - - D20 return versus IPO offer price - - D60 return versus IPO offer price + - T2 grey-market sell return versus IPO offer price, disabled until a reliable source exists + - D1 strong-return probability + +holding_policy: + intended_exit_window: + - T2_grey_market when a reliable grey-market price is available + - D1 otherwise + default_assumption: sell allocated shares by D1 + non_targets: + - D5 return + - D20 return + - D60 return + note: > + D5/D20/D60 outcomes are retained for review and error attribution only. + They do not define the subscription model's target holding period. stage_policy: T0_prospectus: @@ -147,4 +160,4 @@ known_limitations: - T1 is structurally complete for listed rows, but some individual demand fields remain null when the archived source does not explicitly state them. - Industry labels and issuer fundamentals are not yet sufficiently structured for v0. - T2 grey-market signal is intentionally disabled until a reliable source exists. - - Current D1 outcomes are from archived market data and should be reviewed for extreme corporate-action or data-vendor anomalies. + - Current D1 sell-return outcomes are from archived market data and should be reviewed for extreme corporate-action or data-vendor anomalies. diff --git a/rules/rule_change_log.md b/rules/rule_change_log.md index 149aa75..14f3908 100644 --- a/rules/rule_change_log.md +++ b/rules/rule_change_log.md @@ -1,5 +1,29 @@ # Rule Change Log +## 2026-06-15 - Clarify short-exit IPO strategy horizon + +Request: + +- Emphasize that the analyst model is focused on selling allocated IPO shares in T2 grey market or on D1, not long-term holding. + +Change: + +- Added an explicit T2/D1 sell horizon to the analyst skill. +- Updated `ipo_score_v0` targets and holding policy to make D1 sell return the primary modeled label and T2 the intended extension when reliable grey-market data exists. +- Clarified that D5/D20/D60 are review labels only, not holding-period targets. +- Updated single-ticker reports and the report generator to show T2/D1 exit discipline. + +Rationale: + +- The subscription decision should optimize for immediate IPO exit execution, not a long-term equity thesis. +- This preserves stage safety while aligning report language, model targets, and review labels with the actual trading process. + +Verification: + +- Generated dry-run single-ticker reports after the template update. +- Rebuilt the analysis model report with the same dataset timestamp to refresh language without changing model rows. +- Ran py_compile for the modified scripts and checked Markdown/report text for the new T2/D1 discipline. + ## 2026-06-15 - Refresh `ipo_score_v0` after T1 demand backfill Request: diff --git a/scripts/build_analysis_dataset.py b/scripts/build_analysis_dataset.py index 8081b7c..b26c331 100644 --- a/scripts/build_analysis_dataset.py +++ b/scripts/build_analysis_dataset.py @@ -611,9 +611,9 @@ def write_report( "", "## What This Model Does", "", - "This is the first analyst model built from the downloaded archive. It creates a repeatable feature table, scores each IPO using stage-safe rules, and calibrates the score buckets against archived D1 outcomes. It is intentionally transparent: the output includes every score component and the archived source paths used for each ticker.", + "This is the first analyst model built from the downloaded archive. It creates a repeatable feature table, scores each IPO using stage-safe rules, and calibrates the score buckets against archived D1 sell outcomes. It is intentionally transparent: the output includes every score component and the archived source paths used for each ticker.", "", - "The model does not use grey-market data in v0 because T2 currently has no approved reproducible source. It also does not use post-listing returns as inputs; returns are labels only.", + "The model is built for a short IPO allocation trade: sell in T2 grey market when reliable executable data exists, or sell on D1 otherwise. It does not use grey-market data in v0 because T2 currently has no approved reproducible source. It also does not use post-listing returns as inputs; D1 is the primary sell label, while D5/D20/D60 are review labels only.", "", "## Data Inventory", "", @@ -652,7 +652,8 @@ def write_report( "1. Run `scripts/build_analysis_dataset.py` after archivist updates the database.", "2. Use `t0_score` for prospectus-stage watchlisting.", "3. Use `total_score`, `decision_band`, and `calibrated_d1_positive_rate` for T1-stage subscription cards.", - "4. Treat D1/D5/D20/D60 columns as review labels only, never as prediction inputs.", + "4. Frame live decisions around a T2 or D1 sell, not long-term holding.", + "5. Treat D5/D20/D60 columns as review labels only, never as prediction inputs or holding targets.", "", "## Known Gaps", "", diff --git a/scripts/generate_ipo_report.py b/scripts/generate_ipo_report.py index 85a65bf..02ec9d4 100644 --- a/scripts/generate_ipo_report.py +++ b/scripts/generate_ipo_report.py @@ -216,13 +216,13 @@ def action_for_decision(decision: str) -> str: actions = { "weak_or_avoid": "Avoid at T0 unless later T1 demand changes the setup.", "neutral": "Wait for T1 allotment demand before subscribing.", - "positive_watch": "Watch positively, but wait for T1 confirmation before sizing.", - "strong_watch": "Strong watch at T0, still pending T1 demand confirmation.", + "positive_watch": "Watch positively, but wait for T1 confirmation before sizing for a T2/D1 exit.", + "strong_watch": "Strong watch at T0, still pending T1 demand confirmation for a T2/D1 exit.", "avoid": "Avoid subscription.", "avoid_or_wait": "Avoid or wait; do not size without a stronger catalyst.", - "watch_or_small": "Small subscription only if execution constraints are favorable.", - "selective_subscribe": "Selective subscription with disciplined sizing.", - "high_conviction_subscribe": "Subscribe, subject to allocation and liquidity discipline.", + "watch_or_small": "Small subscription only if execution constraints support a T2/D1 exit.", + "selective_subscribe": "Selective subscription with disciplined T2/D1 sell sizing.", + "high_conviction_subscribe": "Subscribe, subject to allocation, liquidity, and T2/D1 sell discipline.", } return actions[decision] @@ -360,6 +360,7 @@ def build_report(record: dict[str, str], rows: list[dict[str, str]], stage: str, f"- Model dataset as of: `{dataset_as_of}`", f"- Rule version: `{model_version}`", f"- Rule path: `{MODEL_RULE_PATH.as_posix()}`", + "- Strategy horizon: short IPO subscription trade; intended exit is T2 grey market if reliable, otherwise D1.", f"- Decision: `{decision}`", f"- PM action: {action_for_decision(decision)}", f"- {score_label}: `{score}`", @@ -370,12 +371,14 @@ def build_report(record: dict[str, str], rows: list[dict[str, str]], stage: str, "", facts_table(record, stage), "", - "## Model Inference", + "## Short-Exit Model Inference", "", f"- D1 positive probability: {fmt_pct_rate(metric.d1_positive_rate)}", f"- D1 >= 10% probability: {fmt_pct_rate(metric.d1_strong_rate)}", f"- Historical average D1 return for bucket: {fmt_num(metric.average_d1_return_pct, '%')}", f"- Historical median D1 return for bucket: {fmt_num(metric.median_d1_return_pct, '%')}", + "- T2 sell return is not modeled until an approved grey-market data source exists.", + "- D5/D20/D60 outcomes are review labels only, not holding targets.", "", "## Score Breakdown", "", @@ -389,8 +392,8 @@ def build_report(record: dict[str, str], rows: list[dict[str, str]], stage: str, "", *reason_lines(components, positive=False), *missing_field_lines(record, stage), - "- T2 grey-market signal is not used because the project has no approved reproducible source.", - "- Post-listing D1/D5/D20/D60 outcomes are labels for model calibration only and are not shown as prediction inputs.", + "- T2 grey-market signal is not used yet because the project has no approved reproducible source.", + "- Post-listing D5/D20/D60 outcomes are labels for later review only and are not holding-period targets.", "", "## Triggers", "", @@ -399,9 +402,10 @@ def build_report(record: dict[str, str], rows: list[dict[str, str]], stage: str, "", "## Exit Plan", "", - "- If subscribed and allocated, reassess after allotment and before first trading session using only information available at that stage.", - "- For T1 reports without approved T2 data, treat first-day liquidity and position sizing conservatively.", - "- Record actual D1/D5/D20/D60 outcomes later as review labels, not as retroactive prediction inputs.", + "- If subscribed and allocated, plan to sell in T2 grey market when reliable executable data is available.", + "- If T2 is unavailable or unreliable, use D1 as the default exit window.", + "- Do not treat D5/D20/D60 as planned holding periods for this model.", + "- Record D1/D5/D20/D60 outcomes later as review labels, not as retroactive prediction inputs.", "", "## Source Paths", "",