Risk control and order lifecycle
This chapter helps you understand two things: why orders sometimes “don’t go through”; and why, even after going through, sometimes they remain “partially completed.” The key difference is between risk control order rejection and counter order rejection—these are the most common pitfalls in Live troubleshooting.
Dear user, “no trade” in simulated trading doesn’t always mean the strategy isn’t sending a signal. It could be that local risk control blocked it, or it could be that the simulated brokerage isn’t accepting the order. We’ll explain these two paths separately so you won’t mistakenly think that risk control rejection means “the brokerage is malfunctioning.”
0. 适用场景
You can now run live, but you need to determine exactly what happened in the “unsold/rejected/cancelled” cases.
You want to link interface prompts, logs, and order status into a same explainable chain.
1. 核心概念:两条「拒单」路径
Many users, when encountering order rejections for the first time, assume “they’re all rejected by brokerage firms.” In qteasy, please first clarify:
┌─ 风控拒单:复核台打回,委托单未入库、未递柜台
策略信号 → 订单意图 ─┤
└─ 柜台受理拒单:已入库,券商同步回复「不收」,status=rejected
↓(若受理成功)
异步成交回报 → partial-filled → filled
In the live subsystem, an order goes through several stages from strategy signal to final execution: RiskManager (optional) → Local order creation → Broker processing → Execution report. The table below summarizes three possible outcomes—when troubleshooting, first match the category to the “Type” column, then click “First check which part” to open the corresponding log.
Column Meanings: Type is the path name; What You Will See is the interface/return value characteristic; Is There a Record in the Orders Table? indicates whether a new row has been added to the local sys_op_trade_orders; Where to Check First is the first piece of evidence for the suggestion.
How to use: When the CLI displays “Order rejected by risk rule”, select the “Risk Rejection” line and check the “risk_log”. If the order list contains “rejected” and no broker number, select the “Counter Rejection” line.
Type |
What will you see? |
Is there a record in the order form? |
Where to search first |
|---|---|---|---|
Order rejection due to risk control |
CLI rejection reason (English); Submission result is empty |
No new lines |
|
Counter service for rejected orders |
There is an order line with |
have |
Order form, trace |
Application Successful |
|
Yes, and it usually has a |
Order table, trade_log |
For the complete comparison table, see:doc:6-trader-snapshot-gate.
The RiskManager acts like a review panel before placing an order: it checks the OrderIntent and AccountSnapshot sequentially according to the rule chain you assembled (whitelist, single transaction limit, transaction period, etc.); if any rule fails, it generates a RiskDecision—a rejection, accompanied by the English reason and rule_id.
If approved, qteasy will then proceed with creating and verifying the order, and submit it to the Broker’s submit_with_ack function to see if the counter will accept it.
2. 风控如何工作(用户视角)
Before placing an order during live trading, if you have configured RiskManager for Trader:
Qteasy assembles account snapshots based on the current ledger
Submit the “order to be placed” to the rule chain for evaluation.
Rejection: Orders are not written to the order table, and the order is not entered into the brokerage queue; English rejections are due to being written to the system log and
risk_log.Approval: Continue submitting as before, without risk control.
If you do not pass in RiskManager, the local rule chain will be skipped, and the process of creating and submitting the order will proceed directly—the behavior is closer to the old version.
2.1 Rule Example (for easier understanding of thresholds)
RiskManager evaluates the rule chain before a Trader submits an order—like checking off items on a checklist at a review desk. The table below lists common rule types and user-visible results to help you understand rule_id and rejection reasons; not a complete list of built-in rules (rules are assembled by you in Python).
The meaning of each column: Scenario refers to the business context; The rules you set refer to the rule semantics; What will happen refers to the performance in the live session.
How to use: Compare the risk_log or the rule_id (e.g., MAX_ORDER_QTY) in the CLI’s English rejection reason to find similar scenarios, and then adjust the threshold or whitelist.
Example: Rejection due to MAX_ORDER_QTY → corresponding “Single Transaction Quantity” row → reduce the number of delegates or increase the rule limit.
Scene |
The rules you set |
what happens |
|---|---|---|
White list |
Only |
Order placed for |
Number of transactions per transaction |
Maximum 500 shares |
Request to buy 501 shares → Rejected; 500 shares and other requests approved → Proceeded |
Trading Hours |
Only from 9:30–11:30 and 13:00–15:00 |
Orders placed during lunch break → Rejected |
Daily transaction volume |
Daily cumulative total + This transaction exceeding the limit |
Rejected; Not exceeded → Released |
Assembly method: Before creating the Trader, construct RiskManager([Rule 1, Rule 2, ...]) in Python and pass it in; otherwise, close the local rule chain. See :doc:2-configuration-and-run and tutorial for details.
2.2 User-visible English rejection reason example
CLI/TUI will display something like:
Order rejected by risk rule [MAX_ORDER_QTY]: order quantity exceeds limit
Meaning: Risk control rule MAX_ORDER_QTY indicates the quantity has exceeded the limit. Please search in risk_log.
3. 订单状态生命周期
After successful processing, the order will go through typical statuses in Live (which you can see in the CLI orders or logs):
submitted → partial-filled → filled
It is also possible that:
submitted → canceled
After successful processing, the order will go through several status in the live session (visible via CLI orders or logs). These statuses describe “where the order is progressing on the brokerage’s side,” which is different from risk control rejection (where the order was never submitted). The table below covers the most common statuses; a complete enumeration is subject to the actual output during runtime.
The meaning of each column: Status is the English status name; Meaning is the investment semantics; What you should pay attention to are the checkpoints for investigation or confirmation.
How to use: If stuck in a certain state for a long time → check the line “What should you pay attention to” → if necessary, go to the script D/E:doc:5-artifacts-and-troubleshooting.
Status |
Meaning |
What should you pay attention to? |
|---|---|---|
submitted |
The counter has received the orders, but not all transactions have been completed. |
Does it have a |
partial-filled |
Partial transactions completed, cumulative volume < order volume. |
Is the cumulative trading volume increasing? |
filled |
The cumulative transaction volume reached the order volume |
Have your holdings and cash balances been updated? |
canceled |
Order cancelled |
Final state after market close or manual order cancellation |
Often |
Refusal during counter service stage |
The broker number is usually empty; this is not a risk control order rejection. |
Investigation Approach:
“No submissions were submitted” → First check the risk control and pre-submission verification (§1 Table)
“Always partially filled” → Check if the transaction returns are continuously arriving (§4)
4. 分批成交与全部成交
When a large order is split into multiple transactions, the status will initially remain at partial-filled, like “Only part of the order has been filled.” Once the cumulative transaction volume reaches the target order quantity, Qteasy will update the status to filled. If you see a prolonged period of partial-filled status, please compare the transaction data with the target quantity—sometimes it simply means that market conditions or demo matching haven’t yet filled the entire order.
5. 收盘后未成交订单
After the market closes, qteasy will use the post_close task to close all pending orders for the day.
**
submitted/partial-filled: This indicates that the order was submitted to the counter, and the remaining amount was withdrawn at the close. The final state is **canceled(there may be cancellation transaction records).created: This is considered a local draft of an unsuccessful order (e.g., an interrupted order placement process or a legacy issue). It is set torejectedat the close of trading. It should not be confused with intraday order rejections, nor should it be written into the cancellation transaction results.
For you: After the market closes, please check the post_close logs and reconcile reconciliation outputs to confirm whether orders in transit have been closed according to the rules, without having to remember the internal API names.
6. 遇到异常时建议顺序
CLI/TUI Instant English Prompts (Note down
rule_idor your order number first)risk_log: Does it exist?
(Risk control path) Order and Transaction Records: Status sequence, whether
broker_order_idis written back.
For a more systematic decision tree, see §3 of :doc:5-artifacts-and-troubleshooting.
7. 快速判定清单
Has this order entered the submission process (can it be found in the order table or logs)?
If not submitted: Can you find
rule_id/reasoninrisk_logor the interface?If submitted: Are there corresponding transaction results? Is the status consistent with the cumulative amount?
Are order rejection types clearly distinguished: Risk Control (line with no order) vs. Counter (rejected line)
8. 相关跳转
Configuration and Run: :doc:
2-configuration-and-runTroubleshooting Manual: :doc:
5-artifacts-and-troubleshootingOrder Rejection and Access Control Details: :doc:
6-trader-snapshot-gateCLI command: :doc:
8-cli-trader-capability-matrixDual path tutorial: tutorials/8-live-trade-risk-and-broker-walkthrough.md