Skip to content

Learn

Stock Portfolio Research

Find why a stock simulation signal produced no virtual trade

A stock rule can generate an event without producing a virtual trade. The account may already hold the intended position, lack cash, have no usable quote or still await confirmation. Diagnose the event’s path through those gates rather than using a zero-trade total to conclude that the rule failed or never ran.

This guide assigns one explicit outcome to each of nine synthetic events in a fixed A/B USD basket. It does not call a model, observe real market sessions or contact a broker. The status ledger is an external diagnostic method, not proof that CoTrading or a reference shadow module exposes every listed state or continuously processes account events.

Establish whether an event was observed at all

An explicit no_signal result means an evaluated opportunity produced no buy or sell intent. It is different from a missing opportunity row, an interrupted process or unknown feature data. The fixture represents a known no-intent observation with side=None. Do not manufacture that row merely because a source file contains no trade for the relevant date.

Start with a stable event identity, frozen rule version, basket reference and observation boundary in a real handoff. The sample supplies the event fields directly and uses unique E1 through E9 identities. It is a state-classification example rather than a general natural-language rule parser, complete scheduler or market-calendar adapter. Keep unavailable upstream evidence marked unknown before reaching the account gates.

A useful diagnostic question is which last observable transition is confirmed. If rule evaluation is known but a fill is not, preserve a pending or unconfirmed state. If evaluation itself is not known, an execution rejection label would overstate the evidence. Record the relevant input or receipt for the state rather than inventing a reason from an empty chart.

Freeze the order of diagnostic gates

The fixture checks explicit no intent, basket coverage and quote availability before considering inventory and cash. It then checks the existing position, share availability, cash, pending confirmation, market rejection and confirmed virtual fill. This priority produces one terminal outcome for each supplied event. A row may have other hypothetical problems, but the primary result is the first gate reached under the declared policy.

The policy is deliberately narrow. A buy is intended to establish a position only when none exists; it does not add to an existing holding. A sell requires the stated available shares. Missing quote is None, while a supplied nonfinite or nonpositive price is invalid and raises an error. Do not treat those invalid numeric values as a false trading condition.

The Python Decimal documentation supports the sample’s explicit finite checks and decimal arithmetic. The account pays one synthetic fee per committed transaction. Its quote and fee representation does not establish any real market’s board lot, settlement, price-limit, tax or liquidity behavior. Add such fields only after verifying what the actual execution source can observe.

Distinguish coverage, data and account reasons

An outside-basket request is outside_basket, not a rule rejection. A covered request without its required quote is quote_unknown. Neither outcome establishes that a human missed a valid trade. The experiment has not reached the point where it can evaluate a funded execution at the supplied price, and it must not copy a future quote to fill that gap.

already_positioned expresses this rule’s no-addition policy. insufficient_cash means the requested purchase plus fee exceeds available cash. insufficient_shares is the corresponding inventory constraint for a sale. These are different from no_signal: the event did carry an intent, but the virtual account’s current state prevented its proposed transition.

The gate order is part of interpretation. For example, an unaffordable request labeled pending would be classified insufficient_cash here because feasibility precedes confirmation. Another diagnostic design could preserve multiple cause fields, but it must still explain the primary state. This example does not claim to enumerate every simultaneous reason or provide a universal broker rejection taxonomy.

Keep confirmation separate from submission

The pending input maps to fill_unconfirmed, and blocked maps to market_rejected. Neither changes shares or cash. The latter is an injected synthetic execution result, not evidence that a real exchange suspended or rejected this security. Only the filled branch commits a feasible virtual transaction, and even that word refers to this local simulation rather than a broker’s authoritative record.

The SEC fees bulletin recommends reviewing account statements and trade confirmations when checking costs. For an actual account, obtain real execution evidence rather than assuming submission means a fill. This article uses invented confirmations and fees solely to demonstrate how the virtual ledger should react to different supplied outcomes.

Do not deduct a fee merely for an unfilled event under this fixture’s convention. Real order-related charges require their own cash-event contract. Similarly, do not release sale proceeds at submission time and then use them to fund another request before the simulated sale is committed. Execution uncertainty and available buying cash must remain separate fields.

Follow all nine events in the main case

Opening assets are 250 cash and no shares. E1 contains explicit no intent, E2 requests C outside the basket, E3 lacks an A quote, E4 requests five A at 100 plus fee one, and E5 awaits a one-share fill. Their outcomes are no_signal, outside_basket, quote_unknown, insufficient_cash and fill_unconfirmed. Cash remains 250 and holdings remain empty throughout.

E6 receives a feasible one-share A fill at 100 with fee one. Cash becomes 149 and A becomes one. E7 requests another A buy, but the no-addition policy yields already_positioned. E8 tries to sell the one share at 105 but receives blocked, producing market_rejected. Both events leave 149 cash and one A unchanged.

E9 confirms the sale at 105 with fee one. Cash rises by 104 to 253 and A returns to zero. There are nine event outcomes and exactly two committed virtual fills. The three-unit account gain reflects these synthetic prices and two fees; it is not a historical strategy result, a future expectation or evidence that a winner-derived rule is effective.

Verify conservation and nonexecution independently

Every nonfilled outcome is asserted to preserve the cash and share dictionary. On a filled outcome, value at the same execution price before and after must differ only by the fee. This separates bookkeeping from market movement and prevents a pending event from changing inventory just because a later sale would have made the final balance look reasonable.

The counterexamples exercise different mechanisms: E4 is unaffordable before any position exists, E7 is blocked by an existing position despite having enough cash for one share, and E8 is rejected despite possessing the requested inventory. The independent invalid-input checks also reject a repeated identity and a NaN price. They are input errors rather than additional business outcomes in the nine-row summary.

Run and update the diagnostic ledger

Download the complete example, save R644.py and run python R644.py using Python 3.12 or later. Only the standard library and synthetic data are used. Assertions check the ordered nine statuses, unchanged assets for every nonfill, fee conservation for fills, final cash 253, final A zero and a count reconciliation back to nine unique events.

Hand off the status ledger with its gate order, raw supplied confirmations and last trusted account state. Correct a mistaken input through a recorded replay, retaining the prior classification. Do not rewrite an unconfirmed historical event as filled merely because a later process resumed. Idempotent event recovery, partial fills and persistent scheduling require additional mechanisms beyond this local classification loop.

When an external source reports only rejection, preserve that level of evidence. Do not invent suspension, frozen funds or a specific risk-control reason to make the explanation look complete. Retain unknown fields and source receipts so later clarification can improve the classification through an explicit revision.

If a new rule permits adding to positions, replay from a trusted state under that new version. Removing E7’s old reason without recalculating later cash and sale quantities would leave the explanation inconsistent with the asset path.

FAQ

Is fill_unconfirmed a zero-quantity successful trade?

No. It is an unresolved execution outcome and changes neither cash nor shares here.

Does market_rejected identify the real exchange reason?

No. The fixture injects a blocked result. A real rejection reason needs observable evidence from the actual execution source.