Files
quantdingerdocs/SIGNAL_EXECUTION_STANDARD.md
2026-07-11 20:13:58 +00:00

183 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# QuantDinger Signal & Execution Standard (SSOT)
**Version**: 1.0
**Status**: Current
**Scope**: All `IndicatorStrategy` flows (indicator Python saved as strategies) for backtest and live
**Implementation**: `BacktestService`, `TradingExecutor`, `validate_code_safety` / `verifyCode`
**Guide**: [STRATEGY_DEV_GUIDE.md](./STRATEGY_DEV_GUIDE.md)
---
## 1. Purpose
The platform runs **many different strategies**. Without a single contract, teams see:
- Different meanings of `buy`/`sell` across scripts;
- Backtests filling on **closed bar → next open** while live trades on **forming bars + immediate exits**;
- Indicator exits plus `# @strategy trailingEnabled` → duplicate closes and `invalid amount (0.0)` rejects.
This document is the **single source of truth** for what authors write and how engines interpret it.
New strategies **SHOULD** comply; existing ones **SHOULD** migrate per §9.
---
## 2. Terms
| Term | Meaning |
|------|---------|
| **Signal bar** | Bar where a boolean flag becomes true (timestamp = that bars close) |
| **Fill bar** | Bar where execution is anchored (default: bar after signal bar) |
| **Edge trigger** | true only on false→true transition vs previous bar |
| **Repaint** | Conditions on the forming bar flip as price updates |
| **Exit owner** | One primary close path: indicator signals **or** engine risk, not both narrow rules |
---
## 3. Choose a strategy form first
| Form | Use when | Avoid when |
|------|----------|------------|
| **A. Two-way** `buy` / `sell` | Simple crossovers; symmetric reversal | Separate tp/sl per side, state machines, “close only” semantics |
| **B. Four-way** `open_long` / `close_long` / `open_short` / `close_short` | State machines, touch exits, explicit queue alignment | — (recommended default for new strategies) |
| **C. ScriptStrategy** `on_bar` + `ctx` | Position-aware bots, scaling, cooldowns | Pure vectorized signals on full `df` |
**Platform default for new listings**: **Form B (four-way)**.
---
## 4. Signal output rules (IndicatorStrategy)
### 4.1 Universal MUST
1. **MUST** start mutations with `df = df.copy()`.
2. **MUST** define `output` (`name`, `plots`; optional `signals` for markers only).
3. **MUST** execution columns: length `len(df)`, dtype bool after `fillna(False).astype(bool)`.
4. **MUST** edge-trigger execution columns (§4.3) unless documented otherwise.
5. **MUST NOT** use `shift(-1)` or any look-ahead.
6. **MUST NOT** mix form A and form B execution columns as fill drivers (may keep `buy`/`sell` all-false for legacy UI).
### 4.2 Form A: `buy` / `sell`
| `tradeDirection` | `buy=True` | `sell=True` |
|------------------|------------|-------------|
| `long` | open long | close long |
| `short` | close short | open short |
| `both` | open long; **close short first if short** | open short; **close long first if long** |
**MUST NOT** treat `buy` as “close short only” under `both`. Use form B `close_*` for flat-only exits.
### 4.3 Form B: Four-way (recommended)
| Column | Meaning |
|--------|---------|
| `open_long` | Open / add long |
| `close_long` | Close long |
| `open_short` | Open / add short |
| `close_short` | Close short |
**MUST**: all four columns exist as bool.
**SHOULD**: same-bar priority close before open; avoid simultaneous `open_long` and `open_short` on one bar.
Fills follow **explicit four-way** semantics (not buy/sell both-mode remapping).
### 4.4 `tradeDirection`
`long` / `short` / `both` filters which legs are active; it does not replace four-way columns.
---
## 5. Exit ownership
Each strategy **MUST** declare one owner in comments or docs:
| Mode | Script | `# @strategy` |
|------|--------|---------------|
| **Indicator exits** `exit_owner: indicator` | `close_*` or equivalent explicit signal exits | `trailingEnabled false`; do not rely on SL/TP/trailing |
| **Engine exits** `exit_owner: engine` | entries only, or structural reverse `close_*` signals | SL/TP/trailing as needed |
**MUST NOT** combine tight indicator tp/sl with tight `trailingEnabled` on the same leg.
The current backend supports only `exit_owner: indicator` and `exit_owner: engine`. Do not emit `exit_owner: layered`; a mixed “indicator exits + engine backup” mode needs an explicit product/runtime change first.
---
## 6. Execution contract (backtest ↔ live)
### 6.1 Signal timing
| Setting | Standard |
|---------|----------|
| `signal_mode` | **`confirmed`** |
| `exit_signal_mode` | **`confirmed`** |
Forming-bar evaluation is for display/research only by default.
### 6.2 Fill timing
Default: **`next_bar_open`** (signal on bar *t*, fill on bar *t+1* open ± slippage).
### 6.3 Same-bar ordering
Priority: `close_*` > `reduce_*` > `open_*` > `add_*`.
Document flip mode **R1** (close on bar *t*, open on *t+1*, recommended) or **R2** (same-bar flip).
### 6.4 Close sizing
Sync positions → resolve size from DB and exchange → retry once if zero → fail with log if still zero.
---
## 7. Configuration
Use `# @strategy` for defaults; leverage and credentials stay in product UI.
Optional header block:
```python
# --- QuantDinger execution contract (v1) ---
# signal_form: four_way
# exit_owner: indicator
# flip_mode: R1
# @strategy tradeDirection both
# @strategy trailingEnabled false
```
---
## 8. Release checklist
- Form A/B/C chosen and documented
- Exit owner declared
- `confirmed` modes for live
- Backtest fills reviewed (signal bar vs fill bar)
- Pilot live run without systematic zero-amount closes
---
## 9. Migration tiers
**P0**: `both` + merged tp/sl in `buy`/`sell` + trailing → fix first.
**P1**: Touch logic + large live/backtest drift → four-way + confirmed + edge.
**P2**: Simple two-way → keep A, add contract header.
Optional badge: “Contract v1 certified”.
---
## 10. Implementation map
| Rule | Code |
|------|------|
| Four-way | `TradingExecutor._execute_indicator_with_prices`, `BacktestService` |
| Two-way both | `_indicator_both_mode` only for buy/sell normalization |
| Confirmed bars | `signal_mode`, `exit_signal_mode` |
| Close retry | `PendingOrderWorker`, `resolve_reduce_only_quantity` |
| Sandbox | `safe_exec.py` |
---
## 11. Revision history
| Version | Date | Notes |
|---------|------|-------|
| 1.0 | 2026-05 | Initial standard |