Skip to content

Commit 8f9d77c

Browse files
authored
Merge pull request #47 from QuantStrategyLab/codex/qmt-offline-dry-run-20260903
fix(qmt): fail closed for non-dry-run orders
2 parents 67a98f6 + fabbe93 commit 8f9d77c

3 files changed

Lines changed: 11 additions & 9 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
A-share quant platform layer for **miniQMT / QMT**, built on `QuantPlatformKit` and `CnEquityStrategies`.
1313

14-
Current scope is **dry-run first**: evaluate strategy targets and preview orders without submitting to the broker.
14+
Current scope is **offline dry-run only**: evaluate strategy targets and preview orders without submitting to the broker. This repository is not a shadow/live runtime; any non-dry-run order request is rejected as `blocked` and is never reported as `submitted`.
1515

1616
## Supported dry-run profiles
1717

@@ -64,7 +64,7 @@ python3 scripts/smoke_cn_industry_etf_rotation_aggressive_dry_run_e2e.py
6464

6565
| Variable | Default | Description |
6666
|---|---|---|
67-
| `QMT_DRY_RUN_ONLY` | `true` | When true, never submit live orders |
67+
| `QMT_DRY_RUN_ONLY` | `true` | Offline-only guard; non-dry-run requests remain blocked |
6868
| `STRATEGY_PROFILE` | required | QMT-enabled strategy profile id |
6969
| `QMT_MARKET_HISTORY_PATH` || CSV with `date,symbol,close` for direct strategies |
7070
| `RUNTIME_TARGET_JSON` || Optional runtime target override from QuantRuntimeSettings |

application/qmt_client.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,20 @@ def load_market_history(self) -> pd.DataFrame:
4141
return frame
4242

4343
def submit_order(self, order: OrderIntent, *, dry_run: bool = True) -> ExecutionReport:
44-
status = "previewed" if dry_run else "submitted"
44+
status = "previewed" if dry_run else "blocked"
4545
return ExecutionReport(
4646
symbol=order.symbol,
4747
side=order.side,
4848
quantity=float(order.quantity),
4949
status=status,
50-
# This adapter has no broker fill query. A submitted order must
51-
# stay unfilled until a future reconciliation adapter proves it.
50+
# This offline adapter never submits to QMT. Non-dry-run requests
51+
# must remain explicitly blocked rather than looking executable.
5252
filled_quantity=0.0,
5353
raw_payload={
5454
"dry_run": dry_run,
5555
"broker": "qmt",
56-
"execution_status": "dry_run_preview" if dry_run else "pending_reconciliation",
56+
"execution_status": "dry_run_preview" if dry_run else "dry_run_only_blocked",
57+
"executable": False,
5758
},
5859
)
5960

tests/test_qmt_client.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44
from quant_platform_kit.common.models import OrderIntent
55

66

7-
def test_live_qmt_submission_is_not_reported_as_filled() -> None:
7+
def test_non_dry_run_qmt_submission_is_blocked() -> None:
88
report = QmtBrokerClient().submit_order(
99
OrderIntent(symbol="510300.SH", side="buy", quantity=100.0),
1010
dry_run=False,
1111
)
1212

13-
assert report.status == "submitted"
13+
assert report.status == "blocked"
1414
assert report.filled_quantity == 0.0
15-
assert report.raw_payload["execution_status"] == "pending_reconciliation"
15+
assert report.raw_payload["execution_status"] == "dry_run_only_blocked"
16+
assert report.raw_payload["executable"] is False
1617

1718

1819
def test_qmt_dry_run_remains_an_unfilled_preview() -> None:

0 commit comments

Comments
 (0)