forked from animatedread/Warrior_EA
151 lines
8.5 KiB
Markdown
151 lines
8.5 KiB
Markdown
# Wyckoff strategies and builder templates
| |||
| |||
Two artefacts per setup, generated from one spec so they can never drift apart:
| |||
| |||
| | Where | What it is |
| |||
|---|---|---|
| |||
| **Strategy** | `user/strategies/wyckoff/WYK_*.sqx` | The book setup, and nothing else. Zero random blocks, zero random groups, no `allowRandom`. This is the thing you read, backtest and argue with. |
| |||
| **Template** | `user/settings/StrategyTemplates/Wyckoff/WYK_*.sqx` | The same book setup **plus** one `RandomCondition` slot, its paired `NegatedCondition`, and builder headroom on the entry/exit stack. This is what you point the Builder at. |
| |||
| |||
Both trees are written to the repo **and** to the install
| |||
(`SQX_144_2953_win_20260601`), byte-identical.
| |||
| |||
---
| |||
| |||
## The eight setups
| |||
| |||
Sources: `docs/SQX/SQX_Wyckoff_Workflows.md` (the verified entry/exit tables),
| |||
Villahermosa *La Méthodologie Wyckoff en Profondeur* (**wdepth**) and
| |||
*Wyckoff 2.0* (**w20**).
| |||
| |||
| Strategy | Book | Long | Short | Entry | SL / PT |
| |||
|---|---|---|---|---|---|
| |||
| `WYK_ClimaxReversal` | W4, wdepth Ch.15 | Phase A + selling climax | Phase A + buying climax | market | 1.5 / 3.0 ×ATR |
| |||
| `WYK_SpringShakeout` | W3/W1-1, wdepth Ch.18 | Phase C + Spring + prior event was ST | Phase C + Upthrust + prior event was bearish ST | limit @ signal-bar low / high | 2.0 / 3.0 |
| |||
| `WYK_SOSBreakout` | W1-2, wdepth Ch.19 | Phase D + SOS + (close above creek **or** range floor) | Phase D + SOW + (close below creek **or** range floor) | market | 2.0 / 3.0 |
| |||
| `WYK_SOSBreakoutLevelStop` | W5-3, wdepth Ch.19 | Phase ≥D + SOS | Phase ≥D + SOW | stop @ signal-bar high / low | 2.0 / 3.0 |
| |||
| `WYK_LPSBackup` | W1-3/W5-1, wdepth Ch.20 | Phase D + LPS + close above creek | Phase D + LPSY + close below creek | limit @ signal-bar low / high | 1.5 / 3.0 |
| |||
| `WYK_ReaccumulationContinuation` | W2, wdepth Ch.11 p78 + p16 | Phase ≥D + reaccumulation + SOS | Phase ≥D + redistribution + SOW | market | 2.0 / 3.0 |
| |||
| `WYK_FailedStructureCHoCH` | W7, w20 §1.4–1.5 | Phase ≥D + WFS zero-cross up | Phase ≥D + WFS zero-cross down | market | 2.0 / 3.0 |
| |||
| `WYK_SOTExhaustion` | w20 §1.6 pp.26-27, 41-42 | SOTConfirmation crosses up through 0 | SOTConfirmation crosses down through 0 | market | 2.0 / 3.0 |
| |||
| |||
Every PT is ≥1.5× the SL, which is the minimum R:R the workflow tables call for.
| |||
Break-even at 1×ATR everywhere; trailing stop 1.5–2×ATR activated at 1×ATR on the
| |||
continuation setups, off on `WYK_ClimaxReversal` (Ch.15 wants a tight stop against
| |||
wide-range climax bars, not a trail).
| |||
| |||
### Polarity decisions that were checked against source, not guessed
| |||
| |||
- **`SOTConfirmation` is signed.** `ADShorteningOfThrust.java:475` —
| |||
`pendingConfirmSignal = (sot.sotDir == -1) ? 1.0 : -1.0`. A shortening run to the
| |||
*downside* emits **+1**, so the long takes the **up**-cross through zero.
| |||
- **`ADWyckoffFailedStructure`'s signed `Value` is bullish-positive.**
| |||
`ADWyckoffFailedStructure.java:205,238` — `bullStructuralFailure` is §1.5.2
| |||
"lack of weakness" and *adds* to the signed value; `bearStructuralFailure` is
| |||
§1.5.1 "lack of strength" and subtracts. So the long is the up-cross.
| |||
- **Event codes and phases** come from the install's own combo enumerations
| |||
(`PS=1 … SOS=7`, `PSY=-1 … SOW=-7`; `A=1 … E=5`), not from memory.
| |||
| |||
### Where the book could not be followed exactly
| |||
| |||
The workflow tables anchor stops and targets to `ZoneTop` / `ZoneBottom` /
| |||
`EventPrice`. **This install exposes no Wyckoff price-level block** — the one
| |||
price-typed Wyckoff block, `ADWyckoffEventStream`, returns an *event code*, not a
| |||
price. So SL/PT are ATR multiples, which is what the same tables use for the
| |||
break-even and trailing legs anyway. `docs/SQX/SQX_Wyckoff_Workflows.md` flags this
| |||
limitation itself ("Named level blocks … do NOT exist").
| |||
| |||
`WYK_ReaccumulationContinuation` gates on Phase **≥D** rather than the table's
| |||
Phase ≥E: the SOS *is* the Phase D event that resolves the range (wdepth
| |||
pp.172-174), so requiring E would put the entry after the move it is meant to catch.
| |||
| |||
---
| |||
| |||
## What makes the template a template
| |||
| |||
One random block, not a scattering of them — SQX expands a single
| |||
`RandomCondition` into as many blocks as the Builder is configured to use:
| |||
| |||
```
| |||
long signal : <book setup> AND RandomCondition(id, group)
| |||
short signal : <book setup> AND NegatedCondition(id)
| |||
```
| |||
| |||
The short side carries **explicit bearish book logic** rather than relying on the
| |||
mirror to invert the long side. That matters here: no block in this install
| |||
declares an `oppositeBlockKey`, so nothing guarantees `IsSpring` would mirror to
| |||
`IsUpThrust`. Writing both sides out means the setup is correct regardless of how
| |||
SQX resolves the negation.
| |||
| |||
Each template draws its random slot from the **curated Wyckoff pool** that
| |||
accompanies its setup — `Wyckoff_Context_Bull` for the range setups,
| |||
`Wyckoff_Phase_Filter` for the breakouts, `Wyckoff_Recent_Bull` for continuation,
| |||
`Wyckoff_Structure_Bull` for CHoCH, `Wyckoff_SOT_Bull` for exhaustion. Group ids are
| |||
resolved from the install's `blockGroups.xml`, so importing a template will not
| |||
fork a duplicate group.
| |||
| |||
**Headroom** (`generate="random"` on the long leg, `"same"` on the short):
| |||
| |||
- entry/exit stack — stop loss, profit target, break-even, trailing stop and
| |||
activation, exit-after-bars, and bars-valid on the pending-order setups;
| |||
- the Wyckoff *engine* parameters — lookback, zigzag strength, AR legs, boundary
| |||
tolerance, max range bars, plus SOT lookback/threshold/min-impulses.
| |||
| |||
**Never randomised:** `#Phase#`, `#TargetEventCode#`, `#Slot#`, `#SignalSeries#`,
| |||
`#ContextMode#`, `#SessionType#`. Those Selection params *are* the book setup, and
| |||
giving a Selection param numeric bounds also trips SQX's `parseDouble` NPE.
| |||
| |||
All eight ADWyckoff blocks in a given file share one set of engine parameters —
| |||
otherwise the blocks would be reading different state machines and the "book" logic
| |||
would be comparing unrelated ranges. The check pass enforces this.
| |||
| |||
---
| |||
| |||
## Regenerating and checking
| |||
| |||
```bash
| |||
python -m scripts.wyckoff_builder.build # repo only
| |||
python -m scripts.wyckoff_builder.build --install # repo + SQX install
| |||
python -m scripts.wyckoff_builder.check # the check pass
| |||
```
| |||
| |||
`scripts/wyckoff_builder/` holds the generator. Blocks are materialized straight
| |||
out of the install's `config.xml`, so parameter names, types, ranges and defaults
| |||
cannot be invented; groups are resolved out of `blockGroups.xml`. Rules are
| |||
transplanted into a stripped skeleton (`skeleton/`) that preserves SQX's
| |||
signal-variable protocol — the four boolean variables
| |||
(`33333333-1111-1111-…` long entry, `-2222-1111-` short entry, `-1111-2222-` long
| |||
exit, `-2222-2222-` short exit) and the `If` trees that consume them.
| |||
| |||
`check.py` verifies, for all 16 files: archive shape; name/`StrategyName`/filename
| |||
agreement; `allowRandom` present on templates and absent on strategies; the signal
| |||
variable wiring intact; strategies containing **zero** random blocks or groups;
| |||
templates containing **exactly one** `RandomCondition` and one paired
| |||
`NegatedCondition`, the random slot on the long side and the negated one on the
| |||
short; embedded group ids matching the install; every block key existing in
| |||
`config.xml`; engine parameters agreeing file-wide; typed params holding values of
| |||
their declared type; semantic params never randomised; correct entry direction;
| |||
SL and PT both present with R:R ≥1.5; and pending-order prices pointing the right
| |||
way (buy-stop above / buy-limit below, and the mirror for shorts).
| |||
| |||
The set also passes sqx-lab's own template validator
| |||
(`skills/sqx-strategy-template/engine/generate.py::_validate`): 16/16, no
| |||
unresolved blocks, no dangling group refs, no trigger leaking into an entry rule.
| |||
| |||
---
| |||
| |||
## What was replaced
| |||
| |||
The previous `user/strategies/wyckoff/WYK_*.sqx` were not strategies. Each was a
| |||
template shell filed in the strategies folder whose entire long signal was
| |||
`RandomCondition AND RandomCondition` and whose short was
| |||
`NegatedCondition AND NegatedCondition` — no Wyckoff block appeared anywhere in the
| |||
rules, so they were indistinguishable from plain random generation. They also had
| |||
no stop loss and no profit target (both `SQ.Formulas.SLPT.None`), empty exit
| |||
signals and `ExitAfterBars = 0`, which left a position with no exit at all; and
| |||
`#ExitAfterBars.ExitAfterBars#`, an `int` param, held the string `EnterAtMarket1`.
| |||
| |||
Four whose names no longer map to a setup (`WYK_SOSBreakoutContext`,
| |||
`WYK_SOSBreakoutBookLevelStop`, `WYK_SpringShakeoutVetoStructure`,
| |||
`WYK_SOTExhaustionVetoEvent`) were removed from the repo and moved to
| |||
`user/strategies/wyckoff-stale-<timestamp>/` in the install.
|