8.5 KiB
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
SOTConfirmationis 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 signedValueis bullish-positive.ADWyckoffFailedStructure.java:205,238—bullStructuralFailureis §1.5.2 "lack of weakness" and adds to the signed value;bearStructuralFailureis §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
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.