# JoinQuant Comparison Plugin This plugin exports frozen targets from the internal A-share research pipeline, drives a standalone JoinQuant wrapper strategy, ingests JoinQuant output files, and reconciles them against the internal reference simulator. The plugin validates system mechanics, not alpha quality: - date alignment - symbol mapping - target position generation - open execution timing - lot rounding and filled shares - position carry - trading cost and PnL accounting - blocked trades from suspension and price limits ## Commands ```bash uv run python cli.py joinquant prepare-smoke \ --out-dir /tmp/chinese-equity-quant-realdata uv sync --extra joinquant-browser uv run playwright install chromium uv run python cli.py joinquant browser-login \ --storage-state ~/.config/chinese-equity-quant/joinquant_storage_state.json uv run python cli.py joinquant write-browser-config \ --out-path /tmp/chinese-equity-quant-realdata/joinquant_browser_config.json \ --strategy-url "https://www.joinquant.com/..." uv run python cli.py joinquant run-browser-backtest \ --manifest-path /tmp/chinese-equity-quant-realdata/joinquant_smoke_manifest.json \ --config-path /tmp/chinese-equity-quant-realdata/joinquant_browser_config.json \ --storage-state ~/.config/chinese-equity-quant/joinquant_storage_state.json uv run python cli.py joinquant export-targets \ --positions-path portfolio/run1.pq \ --portfolio-name run1 \ --mode target_shares \ --execution-calendar-path data/daily_bars/csi500 \ --start-date 2026-07-01 \ --end-date 2026-07-31 \ --out-dir plugins_output/joinquant/targets uv run python cli.py joinquant write-wrapper \ --portfolio-name run1 \ --mode target_shares \ --out-path plugins_output/joinquant/wrapper_strategy_run1.py uv run python cli.py joinquant ingest \ --portfolio-name run1 \ --fills-csv path/to/jq_fills.csv \ --positions-csv path/to/jq_positions.csv \ --pnl-csv path/to/jq_pnl.csv \ --out-dir plugins_output/joinquant/ingested uv run python cli.py joinquant reconcile \ --portfolio-name run1 \ --targets-dir plugins_output/joinquant/targets/run1 \ --our-fills-path fills/run1.pq \ --our-positions-path portfolio/run1.pq \ --our-pnl-path pnl/run1.pq \ --jq-fills-path plugins_output/joinquant/ingested/run1/fills.pq \ --jq-positions-path plugins_output/joinquant/ingested/run1/positions.pq \ --jq-pnl-path plugins_output/joinquant/ingested/run1/pnl.pq \ --out-dir plugins_output/joinquant/reconcile ``` `target_shares` is the default and uses the built integer `position_shares` from `portfolio build`, matching what the internal simulator executes. For strict simulator-vs-JoinQuant comparison, pass `--execution-calendar-path` so position dates are shifted to the next session open, matching the internal simulator's next-open convention. `prepare-smoke` automates the local side of the first sanity check: tiny real data download, one-stock long-only position file, internal simulation, aligned target export, wrapper generation, and a manifest with expected JoinQuant CSV export paths. `run-browser-backtest` automates the remote JoinQuant web run through Playwright. It reuses a saved browser login state, executes the configured UI actions, downloads JoinQuant CSVs when configured, and runs ingest/reconcile automatically once all three CSVs are present.