feat: Add P09x acceptance gate script and enhance pair generation tools with argument aliases and explicit security master path for determinism verification.

pull/12760/head
vijay sharma 3 months ago
parent 78dac5a998
commit 75879aebaf

@ -0,0 +1,81 @@
#!/bin/bash
set -e
# P09 Acceptance Gate Script
# Objective: Verify determinism of Universe Scan and Whitelist Generation
STRATEGY_YAML="user_data/india_strategy.yaml"
BASE_CONFIG="user_data/config_icicibreeze.json"
OUT_DIR="user_data/generated"
mkdir -p "$OUT_DIR"
UNIVERSE_SCAN_PY="scripts/universe_scan_and_generate_pairs.py"
GEN_WHITELIST_PY="scripts/make_config_with_pairs.py"
SECURITY_MASTER_TXT="user_data/data/icicibreeze/FONSEScripMaster.txt"
V1_PAIRS="$OUT_DIR/p09x_pairs_v1.json"
V1_REPORT="$OUT_DIR/p09x_report_v1.json"
V1_CONFIG="$OUT_DIR/config_p09x_v1.json"
V2_PAIRS="$OUT_DIR/p09x_pairs_v2.json"
V2_REPORT="$OUT_DIR/p09x_report_v2.json"
V2_CONFIG="$OUT_DIR/config_p09x_v2.json"
PYTHON=".venv/bin/python3"
echo "=== STEP 1: Run Universe Scan (Pass 1) ==="
$PYTHON "$UNIVERSE_SCAN_PY" \
--config "$STRATEGY_YAML" \
--security-master "$SECURITY_MASTER_TXT" \
--out-pairs "$V1_PAIRS" \
--out-report "$V1_REPORT"
echo "=== STEP 2: Generate Config (Pass 1) ==="
$PYTHON "$GEN_WHITELIST_PY" \
--base-config "$BASE_CONFIG" \
--pairs "$V1_PAIRS" \
--out-config "$V1_CONFIG"
echo "=== STEP 3: Run Universe Scan (Pass 2) ==="
$PYTHON "$UNIVERSE_SCAN_PY" \
--config "$STRATEGY_YAML" \
--security-master "$SECURITY_MASTER_TXT" \
--out-pairs "$V2_PAIRS" \
--out-report "$V2_REPORT"
echo "=== STEP 4: Generate Config (Pass 2) ==="
$PYTHON "$GEN_WHITELIST_PY" \
--base-config "$BASE_CONFIG" \
--pairs "$V2_PAIRS" \
--out-config "$V2_CONFIG"
echo "=== STEP 5: Verify Determinism ==="
sha256sum "$V1_PAIRS" "$V2_PAIRS"
sha256sum "$V1_REPORT" "$V2_REPORT"
sha256sum "$V1_CONFIG" "$V2_CONFIG"
# Compare hashes and fail if they differ
DIFF=$(sha256sum "$V1_PAIRS" "$V2_PAIRS" | awk '{print $1}' | sort | uniq | wc -l)
if [ "$DIFF" -ne 1 ]; then
echo "ERROR: Determinism check failed for pairs!"
exit 1
fi
echo "=== STEP 6: Verify Content Integrity ==="
# Check if RELIANCE (from stocks) and NIFTY (from indices) are present if they were in yaml
grep -q "RELIANCE" "$V1_PAIRS" || echo "Note: RELIANCE not in pairs (expected if filter excluded it)"
grep -q "NIFTY" "$V1_PAIRS" || echo "Note: NIFTY not in pairs (expected if filter excluded it)"
echo "=== STEP 7: Check Empty Cases ==="
if [ ! -s "$V1_PAIRS" ]; then
echo "ERROR: Generated pairs file is empty!"
exit 1
fi
echo "=== STEP 8: Archive Results ==="
tar -czf "$OUT_DIR/p09x_acceptance_artifacts.tar.gz" \
"$V1_PAIRS" "$V1_REPORT" "$V1_CONFIG" \
"$V2_PAIRS" "$V2_REPORT" "$V2_CONFIG"
echo "=== P09 ACCEPTANCE GATE PASSED ==="
echo "Artifacts: $OUT_DIR/p09x_acceptance_artifacts.tar.gz"

@ -32,9 +32,9 @@ def _write_json(path: Path, payload: dict) -> None:
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Create config with generated pairs whitelist.")
parser.add_argument("--base", required=True, help="Base config JSON path")
parser.add_argument("--base", "--base-config", required=True, help="Base config JSON path")
parser.add_argument("--pairs", required=True, help="Pairs JSON path")
parser.add_argument("--out", required=True, help="Output config path")
parser.add_argument("--out", "--out-config", required=True, help="Output config path")
return parser.parse_args()

@ -128,11 +128,15 @@ def _parse_option_policy(payload: dict[str, Any]) -> OptionPolicy:
)
def _load_contracts() -> SecurityMaster:
master_file = find_latest_master_file("FONSEScripMaster.txt")
if not master_file:
logger.error("SecurityMaster file not found.")
raise FileNotFoundError("FONSEScripMaster.txt not found")
def _load_contracts(master_path: Path | None = None) -> SecurityMaster:
if master_path:
master_file = master_path
else:
master_file = find_latest_master_file("FONSEScripMaster.txt")
if not master_file or not master_file.exists():
logger.error("SecurityMaster file not found: %s", master_file)
raise FileNotFoundError(f"Security master file not found: {master_file}")
master = load_nfo_options_master(master_file)
return SecurityMaster(master.get("by_contract", {}))
@ -175,15 +179,27 @@ def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Scan universe and generate pairs.")
parser.add_argument(
"--strategy-config",
"--config",
required=True,
help="Strategy YAML config path",
)
parser.add_argument("--out", required=True, help="Output pairs JSON path")
parser.add_argument(
"--out",
"--out-pairs",
required=True,
help="Output pairs JSON path",
)
parser.add_argument(
"--report",
"--out-report",
default=None,
help="Output report JSON path (default: derived from --out)",
)
parser.add_argument(
"--security-master",
default=None,
help="Path to FONSEScripMaster.txt",
)
parser.add_argument(
"--mode",
choices=["mock", "real"],
@ -331,7 +347,7 @@ def main() -> None:
universe = _parse_universe_config(payload)
option_policy = _parse_option_policy(payload)
security_master = _load_contracts()
security_master = _load_contracts(Path(args.security_master) if args.security_master else None)
today = _kolkata_today()
pairs, report = _build_pairs_report(universe, option_policy, security_master, today)

Loading…
Cancel
Save