# 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 : AND RandomCondition(id, group) short signal : 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-/` in the install.