Skip to content

Repository files navigation

HMM Master Grid — Final Research Version

This document is the standalone presentation for the final VN30 research model. It reports the locked implementation and its existing artifacts; it does not rerun or reinterpret OOS parameters.

Research status: historical simulation, not investment advice. All figures are in Vietnamese đồng (VND). The strategy begins each evaluation with VND 1 billion.

Presentation slide

Grid Trading Strategies for Vietnamese Equities presentation slide

Open or download the presentation PDF.

Executive result

Metric In-sample Out-of-sample
Operational window 5 Jan 2022–31 Dec 2024 7 Feb 2025–17 Jun 2026
Ending equity 1,211,217,423 1,158,740,765
Terminal marked-to-market HPR 21.12% 15.87%
Maximum drawdown 14.91% 12.12%
Realized net P&L 276,511,091 195,536,374
Ending unrealized inventory P&L -65,293,668 -36,795,610
Total execution fills 1,249 531

The result is profitable in both windows, but the economic character changes. In IS, the grid outperformed both benchmarks and materially reduced drawdown. In OOS, it remained profitable with lower drawdown, but captured much less of the strong directional rally than either the VN30 index or the selection-matched equal-weight basket.

1. Research hypothesis

The strategy tests the following hypothesis:

A stock that is trending upward over 60 sessions, remains statistically mean-reverting, and has a high posterior probability of occupying a non-negative, high-variance regime should produce repeated pullbacks and recoveries. A cash-first grid can monetize those oscillations without paying for a permanent core position.

This separates the system into two responsibilities:

  1. The selector searches for upward drift plus oscillation, not merely high volatility.
  2. The execution engine waits below the market, buys stateful tranches, and exits only after T+2.5 settlement through a soft target and ATR-scaled trailing stop.

The hard P_opt >= 0.50 gate is the high-conviction component. The 1.25 incumbency multiplier is intended to reduce needless turnover. The breakeven escape is an inventory-management mechanism, not a loss guarantee.

2. Data collection and experimental split

Local market data

Dataset Coverage used Resolution Validation
Expanded VN30 equity universe 4 Jan 2022–17 Jun 2026 Daily OHLC, floor, ceiling, matched volume 32 symbols, 1,107 trading sessions, unique ticker/date keys
Execution data Same equity window 1-minute OHLCV and best bid/ask fields A ticker-month minute file exists for every daily ticker-month
VN30 benchmark Matching IS/OOS sessions Daily index OHLCV Actual VN30 price-index series, normalized to VND 1 billion

The expanded universe contains ACB, BID, BSR, CTG, FPT, GAS, GVR, HDB, HPG, LPB, MBB, MCH, MSN, MWG, PNJ, SAB, SHB, SSB, SSI, STB, TCB, TCX, VCB, VHM, VIB, VIC, VJC, VND, VNM, VPB, VPL, and VRE.

The external benchmark snapshot was retrieved from the Entrade VN30 daily OHLC endpoint and saved as vn30_index_daily.csv. This is a price index, not a total-return index.

Split and embargo

Stage Nominal specification Effective simulated dates Use
IS 1 Jan 2022–31 Dec 2024 5 Jan 2022–31 Dec 2024 Parameter search and detailed evaluation
Embargo 21 trading sessions 2 Jan–6 Feb 2025 No trading and no overlapping target window
OOS 1 Jan 2025–17 Jun 2026 7 Feb 2025–17 Jun 2026 Blind evaluation with frozen parameters

The first effective IS record is 5 January because the causal signal requires a prior close. The OOS backtest begins on 7 February because the 21-session embargo is applied after 31 December 2024.

Data implementation and reproducibility

The canonical loader is data.py: DailyStore.load() normalizes the daily snapshot, MinuteStore.read_day() loads only the requested ticker/session, and validate_daily_minute_overlap() checks that every daily ticker-month has a minute file. The strategy entry point expects this layout under one data root:

<data-root>/
├── expanded_daily_32_20220101_20260617.csv.gz
└── minute_bars/<TICKER>/minute_bars_<TICKER>_<YYYY_MM>.csv.gz

The minute-tree fingerprint is deterministic: sort the ticker-months present in the daily snapshot, then hash each relative filename, a null byte, and that file's binary SHA-256 digest. The verifier implements this exact algorithm. Extra minute files outside the daily snapshot do not affect the fingerprint.

Run the full input check with:

make reproduce_step_01

For a different local data location, use make reproduce_step_01 DATA_ROOT=/path/to/data.

3. Ticker-selection model

The selector runs every 20 trading sessions using only the trailing 60 sessions ending on the signal date.

3.1 Positive log-price trend

Let $p_t = \ln(C_t)$ and $x_t = 0,\ldots,59$. Fit the ordinary least-squares model:

$$p_t = b + m x_t + \epsilon_t, \qquad m = \frac{\sum_t(x_t-\bar{x})(p_t-\bar{p})}{\sum_t(x_t-\bar{x})^{2}}.$$

The stock survives only if:

$$m > 0.$$

3.2 Strict stationarity screen

The generalized Hurst estimate uses lags $\ell=2,\ldots,20$:

$$\tau(\ell)=\mathrm{Std}(p_{t+\ell}-p_t), \qquad H=\mathrm{Slope}\bigl(\ln \ell,\ln \tau(\ell)\bigr).$$

The discrete OU regression is:

$$\Delta p_t=\alpha+\beta p_{t-1}+\varepsilon_t, \qquad t_{1/2}=-\frac{\ln 2}{\beta},\qquad \beta<0.$$

Both constraints must pass:

$$H\le0.55, \qquad t_{1/2}\le20\ \text{sessions}.$$

3.3 Three-state Gaussian HMM

For every survivor, the HMM observes the standardized vector:

$$\mathbf{X}_t= \begin{bmatrix} R_t \\\ TR_t \end{bmatrix}, \quad R_t=\ln\left(\frac{C_t}{C_{t-1}}\right), \quad TR_t=\max\!\left( H_t-L_t, \left|H_t-C_{t-1}\right|, \left|L_t-C_{t-1}\right| \right).$$

The implementation fits a three-state Gaussian HMM with full covariance, 250 maximum iterations, tolerance $10^{-4}$, minimum covariance $10^{-5}$, and deterministic seed 1729. Parameters are transformed back to return and VND true-range units after fitting.

The grid-optimal state is the highest return-variance state whose return mean is non-negative:

$$s^{\star}=\mathrm{argmax}_{s:\mu_s\ge0}\sigma_s^{2}, \qquad P_{\mathrm{opt}}=P(S_T=s^{\star}\mid X_{1:T}).$$

The hard probability gate is:

$$P_{\mathrm{opt}}\ge0.50.$$

3.4 Ranking and incumbency

$$\mathrm{BaseScore}_i=m_iP_{\mathrm{opt},i}.$$ $$\mathrm{RankScore}_i= \begin{cases} 1.25\,m_iP_{\mathrm{opt},i}, & \text{if ticker }i\text{ was selected in the prior cycle},\\\ m_iP_{\mathrm{opt},i}, & \text{otherwise}. \end{cases}$$

Names are ranked by RankScore and the first five are selected. If fewer than five pass, every missing 20% slot remains cash.

3.5 Selector implementation and reproducibility

Research step Authoritative implementation Reproducibility control
OLS, Hurst, OU and HMM feature stationary_hmm_feature() in signals.py Exactly 60 trailing observations; no forward rows
Non-negative/high-variance state grid_optimal_state() in signals.py Stable state-index tie-break when variances match
Probability gate and incumbency high_conviction_hmm_candidates() in signals.py Seed 1729; deterministic ticker tie-break
Twenty-session schedule periodic_rebalance_actions() in backtest.py Signal is the previous session; action is the next session
Portfolio handoff Backtester.monthly_decision() in backtest.py Maximum five names; unused slots stay cash

Every HMM is initialized with random_state=1729. Input features are standardized using only their own 60-session window. A selected ticker's entire causal record—including slope, Hurst, half-life, state means and variances, $P_{opt}$, incumbency, and final rank—is exported to selector_state_log.csv.

To reproduce just the final selector evidence after completing the backtest and presentation build:

make show_final_selections

Expected final-stage selections are MCH, PNJ for IS and VPL for OOS. The byte-level verifier additionally compares the full selector-state and ticker-selection logs against the canonical files.

4. Grid construction and minute execution

4.1 Cash-only anchor and stateful tranches

There is no initial base inventory. For each newly selected ticker, the anchor $P_0$ is the last causal daily close available to the deployment engine. Five buy limits are constructed with the locked $d_{\mathrm{buy}}$:

$$L_{b,i}=\mathrm{TickRound}\!\left(P_0\left[1-i\,d_{\mathrm{buy}}\right]\right), \qquad i\in\{1,2,3,4,5\}.$$
Level Slot-capital weight Locked distance from anchor
L1 5% 1%
L2 10% 2%
L3 15% 3%
L4 30% 4%
L5 40% 5%

Each tranche is stateful: a level cannot buy again while its associated inventory remains open. Orders are rounded to valid HOSE tick sizes and 100-share lots. A fill is limited to 10% of the observed minute volume.

4.2 Settlement and soft-target exit

Bought shares enter the T+2.5 queue and cannot sell before the 13:00 settlement release. After settlement, a tranche activates its trailing exit at:

$$P_{\mathrm{trigger}} =P_{\mathrm{fill}}\left(1+0.85\,d_{\mathrm{tp}}\right).$$

Once a minute high crosses the trigger, the stop trails the high by:

$$d_{\mathrm{trail}}=0.15\times \mathrm{ATR}_{14,\%}.$$

expressed as a percentage of price. When the minute path pulls through the stop, the tranche sells subject to volume participation and the sell is followed by a rearmed trap:

$$P_{\text{new buy}} =\mathrm{TickRound}\!\left(P_{\mathrm{sell}}\left[1-d_{\mathrm{buy}}\right]\right).$$

Friction is 0.1% on buys and 0.2% on sells: 0.1% brokerage plus 0.1% sell tax.

4.3 Orphans, anomalies, and breakeven escape

  • A ticker dropped at rebalance becomes orphaned: its unfilled buys are canceled, but its soft-target exits remain active.
  • If an overnight down-gap exceeds 7.5%, the data-free anomaly handler voids the inventory, refunds exact fiat cost, and blacklists the name for 30 sessions.
  • If an orphan is still open after 40 sessions, session 41 replaces its target with $d_{\mathrm{tp}}=0.35%$. Its new soft trigger is $P_{\mathrm{fill}}(1+0.85\times0.0035)$. There is no forced market sale.

The anomaly refund is deliberately capital-neutral and therefore idealized. It prevents unadjusted splits/rights events from appearing as trading losses, but it is not a live-broker cash flow and should be replaced by authoritative corporate-action data before production use.

4.4 Actual execution examples

IS — most profitable completed lot: FPT

IS FPT most profitable completed lot reconstructed from minute data

IS — largest failed ending-inventory episode: MWG

IS MWG largest failed ending-inventory episode reconstructed from minute data

OOS — most profitable completed lot: VND

OOS VND most profitable completed lot reconstructed from minute data

OOS — largest failed ending-inventory episode: VNM

OOS VNM largest failed ending-inventory episode reconstructed from minute data

The success panels use 30-minute candles aggregated from the 1-minute feed. The longer failure panels use daily candles, also rebuilt exclusively from those minute bars, to keep the entire orphan life visible. Triangles are exact timestamps and prices from the fill ledger. Dashed lines are anchors, dotted lines are initial L1–L5 limits, and the failure panels show orphan and escape-repricing dates.

4.5 Execution implementation and reproducibility

The execution path is implemented in engine.py. The key methods are start_stateful_anchor() and _build_stateful_grid() for deployment, process_soft_target_grid() for minute fills and trailing exits, request_breakeven_escape() for session-41 repricing, and refund_anomaly_inventory() for the capital-neutral anomaly rule. calendar.py supplies the observed-session T+2.5 release timestamp.

Deterministic execution conventions are part of the model, not presentation assumptions:

  • Minute bars are processed chronologically and the fill cap is 10% of matched minute volume.
  • A soft target first observed in a minute cannot execute until a later minute, avoiding unknown high/low ordering inside one OHLC bar.
  • A gap below an active trailing stop fills at the observed minute open; otherwise it fills at the standing stop.
  • Prices use round_to_tick(), quantities use 100-share round_lot(), and fees are charged directly by _buy() and _sell().
  • Bought inventory uses the observed trading calendar to unlock at 13:00 on T+2.

The authoritative execution outputs are in_sample/fills.csv and out_of_sample/fills.csv. Rebuild the four audited charts from those ledgers and the original minute feed with the presentation command in Section 10. The expected ledger checkpoints are 1,249 total IS fills and 531 total OOS fills; the verifier compares the full ledgers byte-for-byte.

5. In-sample optimization

The optimizer maximized terminal marked-to-market HPR, so trapped inventory was included rather than ignored:

$$E_T=\mathrm{Cash}_T+\sum_j q_{j,T}C_{j,T}, \qquad \mathrm{HPR}_{IS}=\frac{E_T}{1{,}000{,}000{,}000}-1.$$
Parameter Search
d_buy 1.0% to 4.5%, step 0.5%
d_tp 2.5% to 4.5%, step 0.5%
Combinations 40
Selector/HMM Fixed for every combination
Winner d_buy = 1.0%, d_tp = 4.5%
Winner IS HPR 21.1217%

IS HPR sensitivity:

d_buy / d_tp 2.5% 3.0% 3.5% 4.0% 4.5%
1.0% 18.27% 20.58% 19.92% 19.99% 21.12%
1.5% 13.83% 14.77% 16.05% 16.68% 16.70%
2.0% 8.71% 11.07% 11.87% 12.16% 12.08%
2.5% 6.69% 7.72% 8.34% 8.48% 9.25%
3.0% 6.20% 6.15% 7.11% 7.77% 7.75%
3.5% 4.91% 4.82% 5.28% 5.65% 5.93%
4.0% 3.50% 4.65% 5.08% 5.61% 5.71%
4.5% 3.44% 3.78% 4.53% 4.86% 4.90%

The winning d_buy and d_tp lie on opposite boundaries of the tested domain. That is a sensitivity warning: the locked result is valid for this experiment, but the optimum is not an interior plateau.

The full frozen configuration is locked_config.json. Its SHA-256 is 26637593284242b627544785e32cf83f240133eaf3b50d29f576f914f6263db1; the same hash was checked before OOS execution.

5.1 Optimization implementation and reproducibility

high_conviction_hmm_grid.py defines BUY_STEPS, TP_STEPS, _evaluate_pair(), and _optimize(). It evaluates the Cartesian product of eight buy distances and five take-profit distances exclusively over 5 January 2022–31 December 2024. The winning row is selected by descending terminal MTM HPR, then ascending d_buy, then ascending d_tp; this deterministic tie-break is important when scores are equal.

The complete search is written to is_grid_search.csv. Recheck the winner with:

make show_optimization_winner

Expected output is 40 rows and a winner of d_buy=0.01, d_tp=0.045, and IS HPR 0.21121742304930025. Once selected, config_sha256() hashes the sorted canonical JSON representation of BacktestConfig. The runner checks that hash immediately before OOS and stores it again in the OOS metrics.

6. In-sample results and final-stage selection

Accounting item IS
Starting equity 1,000,000,000
Completed-grid gross P&L 305,155,000
Fees and taxes -28,643,909
Realized net P&L 276,511,091
Ending unrealized inventory P&L -65,293,668
Ending equity 1,211,217,423
Maximum drawdown 14.91%
Grid-only fills / all fills 595 / 1,249
Trailing exit fills 654
Breakeven escape activations / sell fills 22 / 105
Capital-neutral anomaly events 7

The last IS selection was formed from the 20 December 2024 signal and acted on 23 December:

Rank Ticker Log-price slope (m) Hurst OU half-life (P_{opt}) Incumbent Rank score
1 MCH 0.002609 0.111966 10.78 1.000000 No 0.002609
2 PNJ 0.000035 0.411844 5.04 0.999118 No 0.000035

Only two of five slots qualified; the other three remained cash.

6.1 IS implementation checkpoint

Backtester.run(IS_EFFECTIVE_START, IS_END) executes the locked winner over the complete IS window after optimization. compute_metrics() produces the daily-equity metrics, while _tear_sheet() in high_conviction_hmm_grid.py reconciles execution P&L and ending marked-to-market inventory.

For an exact result, the following identities must hold within floating-point tolerance:

$$\text{Realized Net P\&L}=\text{Completed-Grid Gross P\&L}-\text{Fees and Taxes},$$ $$E_T-E_0=\text{Realized Net P\&L}+\text{Ending Unrealized Inventory P\&L}.$$

The canonical machine-readable checkpoints are tear_sheet.json, daily_equity.csv, and monthly_decisions.csv. The verifier checks these identities, terminal equity 1,211,217,423.0493002, HPR 0.21121742304930025, and the complete files.

7. Blind out-of-sample results and final-stage selection

Accounting item OOS
Starting equity 1,000,000,000
Completed-grid gross P&L 211,375,000
Fees and taxes -15,838,626
Realized net P&L 195,536,374
Ending unrealized inventory P&L -36,795,610
Ending equity 1,158,740,765
Maximum drawdown 12.12%
Grid-only fills / all fills 271 / 531
Trailing exit fills 260
Breakeven escape activations / sell fills 8 / 46
Capital-neutral anomaly events 2

The last OOS selection was formed from the 22 May 2026 signal and acted on 25 May:

Rank Ticker Log-price slope (m) Hurst OU half-life (P_{opt}) Incumbent Rank score
1 VPL 0.003054 0.084722 11.34 0.501864 No 0.001532

Only one of five slots qualified; 80% of deployable capital remained unassigned at that final rebalance.

7.1 OOS implementation checkpoint

OOS is not a second call to the optimizer. The runner first verifies that the in-memory configuration still hashes to 26637593284242b627544785e32cf83f240133eaf3b50d29f576f914f6263db1, then calls Backtester.run(OOS_START, OOS_END) once. The 21 observed sessions between IS and OOS are counted from the daily snapshot and asserted before any search begins.

The canonical OOS checkpoints are tear_sheet.json, daily_equity.csv, and monthly_decisions.csv. Exact terminal equity is 1,158,740,764.6341465, HPR is 0.15874076463414655, and total fills are 531. The same accounting checks used for IS are applied to OOS.

8. Benchmark comparison

8.1 IS equity

IS equity: grid, VN30 index, and equal-weight selection-matched benchmark

8.2 IS drawdown

IS drawdown: grid, VN30 index, and equal-weight selection-matched benchmark

8.3 OOS equity

OOS equity: grid, VN30 index, and equal-weight selection-matched benchmark

8.4 OOS drawdown

OOS drawdown: grid, VN30 index, and equal-weight selection-matched benchmark

Window Portfolio Ending equity Return Maximum drawdown
IS High-Conviction HMM Grid 1,211,217,423 21.12% 14.91%
IS Selection-matched equal-weight hold 990,422,999 -0.96% 26.16%
IS VN30 price index 869,819,729 -13.02% 41.89%
OOS High-Conviction HMM Grid 1,158,740,765 15.87% 12.12%
OOS Selection-matched equal-weight hold 1,635,284,143 63.53% 13.04%
OOS VN30 price index 1,459,703,162 45.97% 16.96%

The equal-weight comparator buys the strategy-selected names equally across five fixed 20% slots at the action-session open, holds them until the next selection cycle, and leaves missing slots in cash. It applies the same 0.1% buy fee, 0.1% sell fee, 0.1% sell tax, valid lots, and causal rebalance dates. It deliberately contains no grid timing, soft exits, orphan retention, or HMM execution overlay; therefore it isolates whether the grid adds value beyond simply holding the selected basket.

The OOS conclusion is nuanced: the grid preserved capital well, but cash waiting below market and early trailing exits imposed a large opportunity cost during the 2025–2026 momentum advance. It should be presented as a defensive, path-dependent trading system—not as a strategy that consistently outperforms a rising index.

8.5 Benchmark and figure reproducibility

The comparator itself is implemented by selection_matched_buy_hold() in benchmark.py. build_high_conviction_presentation.py joins it to the strategy's daily equity and the frozen VN30 index by trading date, writes the underlying CSVs, and renders both combined and standalone PNG/SVG charts.

Use the checked-in index snapshot to avoid a changing network response:

make reproduce_step_04

Numeric benchmark results are authoritative in benchmark_metrics.csv and the joined equity series is in benchmark_equity_daily.csv. PNG bytes may vary with fonts or rendering backend; compare the CSVs for numerical reproducibility and use the pinned Matplotlib version for the closest visual reproduction.

9. Tickers selected in every cycle

“Cash” means no ticker passed every selector gate. These are action dates; every selection was calculated from the preceding signal date.

In-sample selections (38 cycles)
Action date Selected tickers
2022-01-05 Cash
2022-02-09 Cash
2022-03-09 Cash
2022-04-06 BSR, GAS
2022-05-09 FPT
2022-06-06 Cash
2022-07-04 Cash
2022-08-01 BID
2022-08-29 BID
2022-09-28 MSN, MCH
2022-10-26 VNM, SAB
2022-11-23 VNM
2022-12-21 CTG, VNM
2023-01-19 SSI, VPB, VCB, MBB, HDB
2023-02-23 HDB, ACB, FPT, MBB, TCB
2023-03-23 VCB, STB, CTG
2023-04-20 SSI
2023-05-23 SSI, TCB
2023-06-20 SHB
2023-07-18 VPB, VNM
2023-08-15 SSI, VND, BID, STB
2023-09-14 MWG, VPB, GAS
2023-10-12 SSI, VND, BSR, STB
2023-11-09 HDB, VJC
2023-12-07 LPB
2024-01-05 LPB, SSI, FPT, VIB, SHB
2024-02-02 MWG, HPG
2024-03-08 VND, BSR
2024-04-05 VND, CTG, VCB
2024-05-09 MCH, TCB, GVR, VCB, VIB
2024-06-06 Cash
2024-07-04 FPT, MSN, SHB
2024-08-01 BSR, HDB, VPB, VNM
2024-08-29 MWG, PNJ, BSR, VHM
2024-09-30 ACB, FPT, VJC
2024-10-28 VHM, TCB, VJC
2024-11-25 HPG, TCB
2024-12-23 MCH, PNJ
Out-of-sample selections (17 cycles)
Action date Selected tickers
2025-02-07 PNJ
2025-03-07 ACB
2025-04-04 Cash
2025-05-08 SHB
2025-06-05 Cash
2025-07-03 GVR, VND, MBB, SSI
2025-07-31 MBB, GAS, MWG, BID, LPB
2025-08-28 STB, MWG
2025-09-29 VJC, STB, VND, HDB, CTG
2025-10-27 LPB
2025-11-24 Cash
2025-12-22 VPL, GAS, VNM, FPT
2026-01-21 VPL, TCX, SAB, BSR, SSB
2026-02-25 VNM, MSN, VHM, HPG
2026-03-25 PNJ, GAS, MBB
2026-04-22 LPB, STB
2026-05-25 VPL

The machine-readable history is selection_by_cycle.csv, and the last-cycle quantitative evidence is final_stage_selector_evidence.csv.

9.1 Selection-history reproducibility

The backtest writes the causal signal date, next-session action date, selected tuple, and ranked survivor count to ticker_selection_log.csv. The presentation script formats that ledger but does not recalculate selections. Therefore ticker_selection_log.csv, not the Markdown table, is the source of truth.

Expected invariants are 38 IS cycles, 17 OOS cycles, final IS action date 23 December 2024, and final OOS action date 25 May 2026. Byte comparison of both the selection and selector-state logs is included in the verifier.

10. Reproduction and artifact map

10.1 Create the exact numerical environment

The project uses a Makefile as its task runner. It keeps installation flags, environment variables, paths, and Python entry points out of the README. Display every available task with:

make reproduce_help

The canonical run used Python 3.12.13. requirements-repro.txt pins the numerical libraries. Step 01 creates .venv-repro, installs those packages, runs all tests, and verifies the daily and minute-data fingerprints:

make reproduce_step_01

10.2 Run the complete IS-search/IS/OOS pipeline

The authoritative entry point is high_conviction_hmm_grid.py. It deliberately refuses to overwrite an existing output directory. Use a new path and one worker for the most portable deterministic reproduction:

make reproduce_step_02

The pipeline order is fixed:

  1. Validate the 21-session embargo.
  2. Evaluate all 40 parameter pairs on IS only.
  3. Select and hash the winning configuration.
  4. Rerun the full IS evaluation with the winner.
  5. Verify the configuration hash and run OOS once.
  6. Export metrics, daily equity, fills, decisions, selections, and selector evidence.

10.3 Verify the reproduced result

The verifier checks package versions, daily and minute input fingerprints, the optimizer winner, configuration hash, accounting identities, exact IS/OOS endpoints, and byte identity of the key output ledgers:

make reproduce_step_03

A successful run ends with "status": "PASS". Use --semantic-only only when platform-specific serialization prevents byte equality; it still enforces the exact input hashes, configuration, optimizer winner, accounting, terminal equity, HPR, and fill counts. --skip-minute-hash is a faster diagnostic mode, not an exact reproducibility check.

10.4 Rebuild the presentation layer

After the verifier passes, build the benchmark tables and all eight standalone presentation images from the reproduced ledgers:

make reproduce_step_04

Run the complete sequence with one command:

make reproduce_all

Paths remain configurable without exposing the underlying commands. For example:

make reproduce_all \
  DATA_ROOT=/path/to/vn30-data \
  REPRO_OUTPUT=artifacts/my_high_conviction_reproduction

REPRO_OUTPUT must not already exist; the task runner never deletes or overwrites a prior research run.

10.5 Artifact map

Stage Authoritative artifact What to verify
Input/config lock locked_config.json Search space, winner, embargo count, configuration hash
IS optimization is_grid_search.csv All 40 parameter combinations and terminal MTM objective
Selector selector_state_log.csv Every causal feature, gate, probability, and rank
Selection handoff ticker_selection_log.csv Signal/action dates and selected names
IS evaluation in_sample/tear_sheet.json Accounting and reported IS headline metrics
OOS evaluation out_of_sample/tear_sheet.json Accounting and reported OOS headline metrics
Minute execution fills.csv — IS, fills.csv — OOS Exact timestamp, ticker, side, quantity, price, purpose, fee
Benchmarks benchmark_metrics.csv Strategy, equal-weight, and VN30 returns/drawdowns
Grid reconstruction grid_levels_and_initial_fills.csv Anchor, L1–L5 prices, weights, and filled quantities
Example audit execution_examples_summary.csv Focused profitable and failed inventory episodes
Presentation slide GRID_TRADING_STRATEGY.pdf and PNG preview Original slide and README-renderable 2400×1350 preview

11. Limitations

  • The 32-name expanded universe is not a point-in-time VN30 constituent database; composition and survivorship effects may remain.
  • The VN30 comparison is a price-index comparison and excludes dividends.
  • Minute OHLCV does not reveal the within-minute event path. The simulator uses volume caps and next-observable conditions, but cannot reproduce queue priority.
  • The 7.5% anomaly refund is an OHLC-derived proxy for corporate actions and is economically neutral by construction.
  • The winning grid parameters are on search boundaries, increasing selection-risk concerns.
  • OOS is one market regime, not proof of future robustness.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages