@battlegrid/mcp-server 31.2.4 → 31.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -16
- package/SKILL.md +48 -60
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/EXPORT.json +14 -0
- package/skills/battlegrid-agent-management/SKILL.md +173 -0
- package/skills/battlegrid-arena-play/SKILL.md +132 -0
- package/skills/battlegrid-market-analysis/SKILL.md +76 -0
- package/skills/battlegrid-radar-deployment/SKILL.md +180 -0
- package/skills/battlegrid-strategy-authoring/SKILL.md +283 -0
- package/skills/battlegrid-strategy-doctor/SKILL.md +142 -0
- package/skills/battlegrid-strategy-examples/SKILL.md +401 -0
- package/skills/battlegrid-trade-analysis/SKILL.md +74 -0
- package/skills/battlegrid-strategy-studio/SKILL.md +0 -254
- package/skills/battlegrid-strategy-studio/references/playbooks.md +0 -370
- package/skills/battlegrid-strategy-studio/references/recipes.md +0 -173
- package/skills/battlegrid-strategy-studio/references/tradingview-ports.md +0 -250
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: battlegrid-strategy-examples
|
|
3
|
+
description: Full-surface composition patterns for the strategy studio — validated desk-grade examples of custom report sections, benchmark sections, condition trees with verdicts and enforcement gates, tiered signal weights, routing gates, ATR trade levels, and position management. Activate beside strategy-authoring whenever a strategy is being composed or upgraded beyond a basic template.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Strategy Studio — full-power composition patterns
|
|
7
|
+
|
|
8
|
+
`strategy-authoring` owns the flow (evidence → locked spec → discover → compile → review →
|
|
9
|
+
apply). This skill owns **what to compose**: a default build — a few platform sections, no
|
|
10
|
+
conditions, untouched weights — wastes the studio. The playbooks below are compiled in CI, so their
|
|
11
|
+
shapes are binding in the sense that matters — they are checked, not merely asserted. Loose tokens
|
|
12
|
+
elsewhere in this file are not covered by that gate, and vocabulary moves with deploys, so discovery
|
|
13
|
+
in the conversation stays the authority — prefer what `list_strategy_vocabulary`,
|
|
14
|
+
`get_strategy_column_contract`, and `get_strategy_signal_definition` return over anything
|
|
15
|
+
printed here, and read exact headers from a preview's `conditionColumns` before conditioning on
|
|
16
|
+
them.
|
|
17
|
+
|
|
18
|
+
## The full-power checklist
|
|
19
|
+
|
|
20
|
+
Before compiling a CREATE, every "no" here is a decision to state, not an omission:
|
|
21
|
+
|
|
22
|
+
1. At least one **custom section** whose columns encode the thesis — not only platform modules.
|
|
23
|
+
2. **Conditions** encode the entry logic: building blocks (`verdict: null`) + verdict carriers,
|
|
24
|
+
and at least one `required: true` condition vetoing obvious disqualifiers **before any
|
|
25
|
+
billing or LLM call**.
|
|
26
|
+
3. **Every signal meant to score is named in `rules`** with a deliberate tier — unnamed signals
|
|
27
|
+
keep server defaults (typically Off). Verify in the compiled scorecard, never assume.
|
|
28
|
+
4. **Gates** (`minAggregateScore`, `minRequiredCount`, `minAtrPct`) are computed against the
|
|
29
|
+
chosen weight budget, not guessed.
|
|
30
|
+
5. **Trade levels + position management** match the setup's geometry and holding period.
|
|
31
|
+
6. `marketReadText` states standing orders with `{...}` markers so live values render inline.
|
|
32
|
+
|
|
33
|
+
## Header grammar (system-generated — never named by the author)
|
|
34
|
+
|
|
35
|
+
| Transform | Header | Validated example |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `value` | `<code>` | `bbWidthPct`, `RVOL`, `rate` |
|
|
38
|
+
| `trajectory` w4 | `<code>_t3…_t1`, `_now`, `_trend` (rising/falling/flat) | `RSI14_now`, `RSI14_trend` |
|
|
39
|
+
| `distance` | `dist_<code>` (signed % from price) | `dist_SMA50` |
|
|
40
|
+
| `spread` | `<base>_<operand>_spread` | `mark_oracle_spread` |
|
|
41
|
+
| `aggregate` wN | `<code>_mean<N>` | `rate_mean24` |
|
|
42
|
+
| `rank` | `<code>_rank_<hi\|lo\|far\|near>` — ordinal, `lte N` = top-N | `bbWidthPct_rank_lo` |
|
|
43
|
+
| `efficiency` wN | `<code>_er` (1 straight, ~0 chop) | `close_ltf_er` |
|
|
44
|
+
| `maxShare` wN | `<code>_maxShare` | `volBase_ltf_maxShare` |
|
|
45
|
+
| `classifyZone` / `classifyState` | `<code>_zone` / `<code>_state` | `RSI14_zone`, `ADX_state` |
|
|
46
|
+
|
|
47
|
+
Non-anchor rungs affix `_ltf` (lower) / `_htf` (regime): `MAalign_htf`,
|
|
48
|
+
`zones_htf_support_dist`. Chains are bounded at two: inner `distance`/`spread` → outer
|
|
49
|
+
`trajectory`/`aggregate`/`efficiency`/`maxShare`/`rank` (`EMA5 spread EMA13 × trajectory` →
|
|
50
|
+
`EMA5_EMA13_spread_now` + `_trend`).
|
|
51
|
+
|
|
52
|
+
**Timeframe references are two families.** *Relative* (`anchor`/`lower`/`regime`) re-resolve
|
|
53
|
+
when the strategy timeframe changes — `regime` is the anchor's ladder successor (1d for a 4h
|
|
54
|
+
anchor). *Pinned* (`{abs: "<tf>"}`) is fixed, ignores anchor retunes, suffixes the literal
|
|
55
|
+
(`RSI14_1d`, `dist_SMA200_1d`, `MAalign_1d` — validated), and binds to discovery's
|
|
56
|
+
`rankedTimeframes`, a **superset** of the authorable anchor set — `{abs: "1d"}` is valid while
|
|
57
|
+
`1d` is not an anchor. `offset: 1` on a pinned `value` column reads the last **closed** bar of
|
|
58
|
+
that timeframe (`RSI14[t - 1]`) — the deterministic daily-close read; offset 0 reads the
|
|
59
|
+
forming bar (provisional), and offset does not change the header, so one offset per
|
|
60
|
+
`metric × timeframe` per section. **Daily-strategy pattern:** anchor 4h, pinned-1d thesis
|
|
61
|
+
columns at `offset: 1`, `required: true` daily conditions gating every carrier, anchor-rung
|
|
62
|
+
columns only for entry timing and risk — daily inputs then move once per daily close while
|
|
63
|
+
stops and time decay keep managing intraday. **Benchmark sections** (`benchmarkTicker: "BTC"`,
|
|
64
|
+
required-nullable on every custom section) read the benchmark's values on every row — the
|
|
65
|
+
standard market-leader regime gate. Platform `sectionKey`s are their literal keys
|
|
66
|
+
(`includeMtfConfluence`). Custom `sectionKey`s are the **server's** to issue, and which of the two
|
|
67
|
+
things you do depends on the operation: on a **CREATE, omit `sectionKey` entirely** — supplying one
|
|
68
|
+
is refused, since a new strategy owns no custom sections yet; on an **UPDATE or RESTORE, send back
|
|
69
|
+
the keys `get_strategy` returned** for the sections you are keeping. Either way you never invent
|
|
70
|
+
one. To section-qualify a duplicated header, read the key from a preview's `conditionColumns` or
|
|
71
|
+
from the qualified candidates a `CONDITION_COLUMN_AMBIGUOUS` refusal offers.
|
|
72
|
+
|
|
73
|
+
## Conditions
|
|
74
|
+
|
|
75
|
+
`{ conditionKey, name, definition, verdict, required, exit, clock, closes }` — all eight
|
|
76
|
+
required, no defaults. Clauses: numeric/rank headers take `lt|lte|gte|gt|between`;
|
|
77
|
+
classification/direction headers take `is|in` with the served vocabulary. Groups:
|
|
78
|
+
`ALL | ANY | NOT | N_OF` (with `n`), depth ≤ 2. `conditionRef` composes named conditions (no
|
|
79
|
+
cycles; forward refs legal). `sectionKey: null` is sugar for a report-unique header only.
|
|
80
|
+
Verdicts: first TRUE carrier **in declaration order** decides UP/DOWN/NEITHER — order carriers
|
|
81
|
+
most-specific first; building blocks carry `null`. `required: true` = FALSE blocks compose-trade
|
|
82
|
+
before billing. Evaluation is three-valued: UNRESOLVED never collapses to FALSE; forming-bar
|
|
83
|
+
reads are provisional.
|
|
84
|
+
|
|
85
|
+
**The evidence clock.** `clock: "LIVE"` reads the forming bar; `clock: "CLOSE"` reads settled
|
|
86
|
+
bars, and `closes` is how many consecutive closed bars must read TRUE (1–5) — always `1` under
|
|
87
|
+
LIVE, which has exactly one frame. A CLOSE clock is legal **only** over a header resolved from
|
|
88
|
+
this coin's own candle series at offset 0. Frame-inert operands are refused
|
|
89
|
+
(`CONDITION_CLOCK_OPERAND_ILLEGAL`): perp-payload scalars, published rolling changes, ranks, zone
|
|
90
|
+
entities, MDS regime labels, enrichment metrics, session scalars, and any clause authored at a
|
|
91
|
+
non-zero offset. A closed frame cannot move them, so "held for N closes" would describe reads
|
|
92
|
+
that never happened. The remedy is a split, not a re-clock: move that clause into its own LIVE
|
|
93
|
+
condition and `conditionRef` it. **Worked liquidity floor:** `LIQUID_FLOOR` is LIVE because
|
|
94
|
+
`vol24hUsd` is a bundle scalar; the carrier that refs it may be CLOSE over its own candle-series
|
|
95
|
+
clauses.
|
|
96
|
+
|
|
97
|
+
**The lane a strategy is deployed to.** Report-level scalars split by LANE, and the split is not a
|
|
98
|
+
quality of the header — it is which reader runs. Market breadth and the reference pairs are ordinary
|
|
99
|
+
market-wide reads with no session dimension, so they resolve everywhere. The five **session-field**
|
|
100
|
+
scalars (`fieldPlayers`, `fieldUpBias`, `fieldBiasDir`, `captConc`, `picksSpread`) describe a game
|
|
101
|
+
session the agent is playing in, and **radar runs outside one** — so a radar deployment whose
|
|
102
|
+
strategy reads one is refused outright (`CONDITION_OPERAND_UNSERVED_IN_LANE`), naming the scalars it
|
|
103
|
+
can read instead. The refusal lands at DEPLOY rather than at save, because a strategy carries no lane
|
|
104
|
+
of its own: the same strategy is legal, and reads those scalars correctly, on an arena agent.
|
|
105
|
+
|
|
106
|
+
**The exit role.** `exit: true` makes a settled TRUE reading close open positions its verdict
|
|
107
|
+
opposes — UP exits SHORTs, DOWN exits LONGs, a NEITHER or `null` verdict exits both. Legal only
|
|
108
|
+
under `clock: "CLOSE"`: a LIVE reading is the forming bar, and an exit fired on one is an
|
|
109
|
+
intrabar exit. Orthogonal to `required` — the two act on disjoint lifecycles, pre-entry versus
|
|
110
|
+
open — so a condition may carry both, either, or neither.
|
|
111
|
+
|
|
112
|
+
## Entry
|
|
113
|
+
|
|
114
|
+
`{ trigger, confirmTf, closes, bandAtrMultiple, levelSource, levelOffsetAtrMultiple,
|
|
115
|
+
validForBars }` — all seven required on every CREATE, no defaults. This axis is replaced WHOLE
|
|
116
|
+
on save, so an omitted key would silently revert an author's discipline rather than be refused.
|
|
117
|
+
|
|
118
|
+
**The trigger decides WHEN, and for two of them WHERE, an entry is taken.**
|
|
119
|
+
|
|
120
|
+
- `AT_SIGNAL` — fire the moment the radar observes the qualification flip, at whatever bar is on
|
|
121
|
+
the tape, keeping the platform's flat wall-clock entry window. Today's behaviour.
|
|
122
|
+
- `ON_CANDLE_CLOSE` — the flip ARMS the pair; the entry is taken only after a close on
|
|
123
|
+
`confirmTf` that still reads the conditions true and has not displaced beyond the band.
|
|
124
|
+
- `STOP_THROUGH_LEVEL` — a TRIGGER order rests at the authored level ± offset and the exchange
|
|
125
|
+
book is the watcher; the entry is taken when price trades through, not when the platform
|
|
126
|
+
notices.
|
|
127
|
+
- `ON_RETEST` — a LIMIT order rests at the broken level, waiting for a return to it. Not filling
|
|
128
|
+
is a correct outcome, not a failure.
|
|
129
|
+
|
|
130
|
+
`confirmTf` is the bar whose close confirms. Exactly two values are legal: the strategy's own
|
|
131
|
+
timeframe and the rung below it — one only, when the strategy sits on the ladder floor. It is
|
|
132
|
+
NOT the authorable main-candle set; a rung further down names a bar nothing else in the strategy
|
|
133
|
+
observes and makes the radar sweep on every one of its closes.
|
|
134
|
+
|
|
135
|
+
`closes` (1–5) is how many consecutive confirming closes are required, and `bandAtrMultiple` is
|
|
136
|
+
the veto width: the entry is VOIDED when the confirming close has moved at or beyond that many
|
|
137
|
+
ATR against the armed verdict. Strictly greater than zero — zero is not "no filter" but a filter
|
|
138
|
+
that voids on any adverse move — and at or below the platform's own entry-deviation gate, since
|
|
139
|
+
a wider band cannot refuse anything the platform will not refuse anyway.
|
|
140
|
+
|
|
141
|
+
`levelSource` is one of `SWING_HIGH`, `SWING_LOW`, `BOLLINGER_UPPER`, `BOLLINGER_LOWER`,
|
|
142
|
+
resolved once at decision time. `levelOffsetAtrMultiple` (0–2) is an UNSIGNED magnitude — the
|
|
143
|
+
direction is implied by the trigger and the verdict, so a signed value would invert the
|
|
144
|
+
trigger's meaning. `validForBars` (1–24) denominates validity in the strategy's OWN bars rather
|
|
145
|
+
than minutes, because a 1h setup waiting for a retest has not failed after fifteen minutes.
|
|
146
|
+
|
|
147
|
+
**The legality matrix runs one way.** All seven keys are always present, so the question is
|
|
148
|
+
never "is it set" but "is it set to something that MEANS anything under this trigger".
|
|
149
|
+
`closes` ≠ 1 is refused under any trigger but `ON_CANDLE_CLOSE`; `levelOffsetAtrMultiple` ≠ 0 is
|
|
150
|
+
refused under a non-level trigger. Leave a dial at its inert value rather than setting one the
|
|
151
|
+
platform will ignore.
|
|
152
|
+
|
|
153
|
+
## Report sections
|
|
154
|
+
|
|
155
|
+
`{ kind, sectionKey, title, benchmarkTicker, notes, columns }` — the custom section shape. A
|
|
156
|
+
section carries no `timeframe`: its relative columns resolve against the strategy timeframe, and a
|
|
157
|
+
column reaches any other timeframe by pinning it (`timeframe: { abs: '4h' }`). `benchmarkTicker` and `notes` are **required-nullable**: send an explicit `null` rather
|
|
158
|
+
than omitting them, because the section is rebuilt whole on save and an omitted key clears the
|
|
159
|
+
author's value silently. On a CREATE, omit `sectionKey` — it is derived from the section itself.
|
|
160
|
+
|
|
161
|
+
## Signal rules
|
|
162
|
+
|
|
163
|
+
`{ signalId, allocation, required, params }` — one entry per signal you want scoring.
|
|
164
|
+
`allocation` is the tier (0–3) and `params` replaces canonical defaults only when present.
|
|
165
|
+
|
|
166
|
+
## Signal weights and gate math
|
|
167
|
+
|
|
168
|
+
Tiers: 0 Off · 1 Normal · 2 Important · 3 Critical.
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
aggregateScore = Σ(score × allocation) / Σ(allocation) over triggered signals
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Weights are relative — build a pyramid: 1–2 Critical (thesis, usually `required`), 2–4
|
|
175
|
+
Important (independent confirmation, different modules), 1–3 Normal (context), rest Off so
|
|
176
|
+
noise cannot dilute the average. Gate check: with 3/2/2/1 weights, Critical + one Important at
|
|
177
|
+
score 1.0 → (3+2)/8 = 0.625, so a 0.6 gate means "thesis plus one confirmation".
|
|
178
|
+
`simulate_aggregate_score` does this arithmetic from compiled values at review time.
|
|
179
|
+
`required: true` counts the signal toward `minRequiredCount` when triggered; at
|
|
180
|
+
`allocation: 0` it is rejected (contract 34). `params` replace canonical defaults only when
|
|
181
|
+
present — read `get_strategy_signal_definition({ signalId, timeframe })` before tuning (e.g.
|
|
182
|
+
`rsi_overbought {"threshold": 65}` for a fade book; `volume_surge {"multiplier": 1.5}`).
|
|
183
|
+
`derive_strategy_rule_view` shows which signals a draft report feeds — weighting a signal the
|
|
184
|
+
report never feeds is dead weight.
|
|
185
|
+
|
|
186
|
+
## Routing gates
|
|
187
|
+
|
|
188
|
+
`{ minAggregateScore, minRequiredCount, minAtrPct }` — whether a scored setup may route to a
|
|
189
|
+
trade at all. `minAggregateScore` 0–1 · `minRequiredCount` 0–20 · `minAtrPct` is the dead-market
|
|
190
|
+
floor, with bounds from `get_trading_config_catalog`.
|
|
191
|
+
|
|
192
|
+
## Trade levels
|
|
193
|
+
|
|
194
|
+
`{ minStopLossAtrMultiple, maxStopLossAtrMultiple, minRiskRewardRatio }` — where stops and
|
|
195
|
+
targets may sit. `minStopLossAtrMultiple < maxStopLossAtrMultiple` (≤ the 3×ATR structural cap),
|
|
196
|
+
`minRiskRewardRatio` within the served range. Sizing is risk-budget based — a wider stop means a
|
|
197
|
+
smaller position, never more risk.
|
|
198
|
+
|
|
199
|
+
## Position management
|
|
200
|
+
|
|
201
|
+
`{ breakEvenEnabled, breakEvenTriggerR, trailingEnabled, trailingTriggerR, trailingGivebackPct,
|
|
202
|
+
trailingBufferPct, timeDecayEnabled, timeDecayGracePeriodMinutes, timeDecayIntervalMinutes,
|
|
203
|
+
timeDecayTightenPct, timeDecayMaxTightenPct, timeDecayStaleThresholdTpProgressPct,
|
|
204
|
+
decisionInvalidationExitEnabled }` — how the stop moves after entry, and when a position is
|
|
205
|
+
closed for reasons other than its stop.
|
|
206
|
+
|
|
207
|
+
Validated bounds: break-even trigger 0.5–2R; trailing trigger 0–2R step 0.01 (0 = trail from
|
|
208
|
+
entry), giveback 25–55%, buffer 0.01–1%; timeDecay grace ≥ interval, tighten 0.1–50% to max
|
|
209
|
+
1–100%, stale threshold 0–100% of TP progress. Per-mechanism flags; no umbrella switch.
|
|
210
|
+
|
|
211
|
+
`decisionInvalidationExitEnabled` is the post-fill invalidation exit: a **closed**
|
|
212
|
+
strategy-timeframe candle beyond the decision's invalidation level closes the position
|
|
213
|
+
reduce-only. Bar-close only — the protective stop still owns intrabar moves.
|
|
214
|
+
|
|
215
|
+
Persona presets: scalper (5m/15m) stops 0.5–1.2 ATR, RR 1.5, BE 0.7R, trail 0.9R/giveback 30,
|
|
216
|
+
timeDecay ON (45/15, tighten 15→60, stale 30) · intraday mean-revert (1h) 1.0–2.5 ATR, RR 1.5,
|
|
217
|
+
BE 0.8R, no trail, timeDecay ON (120/60, 10→40, stale 25) · swing breakout (4h) 0.75–1.75 ATR,
|
|
218
|
+
RR 2, BE 1R, trail 1.2R/giveback 35 · swing trend (4h) 1.0–2.5 ATR, RR 2, BE 1R, trail
|
|
219
|
+
1.5R/giveback 45–55, no timeDecay.
|
|
220
|
+
|
|
221
|
+
## Playbooks (validated compositions)
|
|
222
|
+
|
|
223
|
+
*Validated* is a gate, not a claim: every playbook below is compiled against the live catalog by
|
|
224
|
+
`strategy-playbooks.compile.test.ts`, which fails the build if one stops assembling or if a header
|
|
225
|
+
its conditions name stops resolving. Edit a playbook and the gate re-checks it; move the grammar
|
|
226
|
+
underneath one and the gate catches that too.
|
|
227
|
+
|
|
228
|
+
### 1 · Volatility Compression Breakout — 4h swing
|
|
229
|
+
|
|
230
|
+
Custom `Squeeze Scan` (no `sectionKey` — this is a CREATE): `BB_WIDTH_PCT value` + `rank lo`, `ADX value`,
|
|
231
|
+
`RVOL value`, `BB_PCT_B value`, `CLOSE_CHANGE value`, `NOTIONAL_VOLUME_1D value`; plus platform
|
|
232
|
+
`includeStructureZones`. (No `includeBollingerBands`: it renders `bbWidthPct` and
|
|
233
|
+
`bbWidthPct_rank_lo` a second time, which makes both of `SQUEEZE_ON`'s clauses ambiguous, and the
|
|
234
|
+
custom section already carries them.) Conditions: `LIQUID_FLOOR` (required —
|
|
235
|
+
`vol24hUsd gte 25000000`); `SQUEEZE_ON` building block (`bbWidthPct_rank_lo lte 10` AND
|
|
236
|
+
`ADX lt 20`); `BREAK_UP` verdict UP (ref SQUEEZE_ON + `closeChg gt 0` + `RVOL gte 1.5` +
|
|
237
|
+
`pctB gte 0.85`); `BREAK_DOWN` verdict DOWN (mirror with `pctB lte 0.15`). Rules:
|
|
238
|
+
`bollinger_squeeze` 3 required · `volume_surge` 2 required `{"multiplier":1.5}` ·
|
|
239
|
+
`volatility_atr_expanding` 2 · `sr_resistance_break` 2 · `sr_support_break` 2 ·
|
|
240
|
+
`bollinger_upper_touch` 1 · `bollinger_lower_touch` 1 · `trend_adx_ranging` 1. Gates
|
|
241
|
+
0.55 / 2 / 0.8. Levels 0.75–1.75 ATR, RR 2. PM: BE 1R; trail 1.2R giveback 35 buffer 0.3.
|
|
242
|
+
Market Read: "Trade only expansions out of compression: {SQUEEZE_ON} must read TRUE… skip
|
|
243
|
+
anything failing {LIQUID_FLOOR}."
|
|
244
|
+
|
|
245
|
+
### 2 · Crowded-Positioning Fade — 1h intraday
|
|
246
|
+
|
|
247
|
+
Custom `Positioning`: `FUNDING_RATE value`→`rate`, `aggregate w24`→`rate_mean24`,
|
|
248
|
+
`FUNDING_ANN value`→`ann`, `OI_CHG value`→`oiChg`, `OI_PX_REGIME value`→`oiRegime` (vocab:
|
|
249
|
+
new longs / new shorts / short covering / long liquidation), `MARK spread ORACLE`→
|
|
250
|
+
`mark_oracle_spread`, `RSI14 value`, `CHG_24H value`→`chg24h`; plus `includeCvd`. Conditions:
|
|
251
|
+
`NO_LIQUIDATION_TAPE` required NOT-veto (`NOT [oiRegime is "long liquidation"]`);
|
|
252
|
+
`CROWDED_LONGS` building block (`ann gte 25` + `oiChg gte 3` + `oiRegime is "new longs"`);
|
|
253
|
+
`FADE_SHORT` verdict DOWN (ref + `RSI14 gte 65` + `chg24h gte 5`); mirrored `SQUEEZED_SHORTS`
|
|
254
|
+
/ `SQUEEZE_LONG` verdict UP. Rules: `funding_extreme_positive`/`_negative` 3 required
|
|
255
|
+
`{"thresholdPct":0.001}` · `oi_surge` 2 `{"thresholdPct":0.03}` · `rsi_overbought` 2
|
|
256
|
+
`{"threshold":65}` · `rsi_oversold` 2 `{"threshold":35}` · `cvd_bear_divergence` 2 ·
|
|
257
|
+
`cvd_bull_divergence` 2 · `mfi_overbought` 1 · `mfi_oversold` 1. Gates 0.6 / 1 / 0.5. Levels
|
|
258
|
+
1.0–2.5 ATR, RR 1.5. PM: BE 0.8R, no trail, timeDecay ON (120/60, 10→40, stale 25).
|
|
259
|
+
|
|
260
|
+
### 3 · Relative-Strength Rotation with a Benchmark Gate — 4h cross-sectional
|
|
261
|
+
|
|
262
|
+
Custom `Leadership`: `ROC12 rank hi` + `rank lo`, `RVOL rank hi`,
|
|
263
|
+
`EMA5 spread EMA13 × trajectory w4`, `NOTIONAL_VOLUME_1D value`. **Rank `ROC12`, not
|
|
264
|
+
`CLOSE_CHANGE`:** `closeChg` is the one magnitude-only rankable code, so `hi`/`lo` on it are
|
|
265
|
+
refused, and its legal `far` ordering sorts by |change| — which would put the session's biggest
|
|
266
|
+
losers in a "leaders" cohort. Custom `BTC Regime` with
|
|
267
|
+
`"benchmarkTicker": "BTC"`: `MA_ALIGN value`→`MAalign`, `ADX value`, `REGIME_TREND value` —
|
|
268
|
+
every row reads BTC. Conditions: `BTC_RISK_ON` building block (`MAalign is "bullish"` +
|
|
269
|
+
`ADX gte 20` — both read bare, since only this section renders them); `BTC_RISK_OFF`
|
|
270
|
+
(`MAalign is "bearish"`); `LEADER` (`roc12_rank_hi lte 5` + `RVOL_rank_hi lte 10` +
|
|
271
|
+
`vol24hUsd gte 100000000`); `ROTATE_IN` verdict UP (`ALL[ref BTC_RISK_ON, ref LEADER]`);
|
|
272
|
+
`ROTATE_OUT` verdict DOWN (`ALL[ref BTC_RISK_OFF, roc12_rank_lo lte 5]`). Rules:
|
|
273
|
+
`comparison_sector_momentum` 3 · `rel_roc_positive`/`_negative` 2 · `ma_ema_aligned_bull`/
|
|
274
|
+
`_bear` 2 required · `rel_ppo_bull_cross`/`_bear_cross` 1 · `volume_surge` 1. Gates
|
|
275
|
+
0.5 / 1 / 0.6. Levels 1–2 ATR, RR 1.8. PM: BE 1R; trail 1R giveback 45. Ranked cohort ≥ 40 —
|
|
276
|
+
rank conditions need a cohort wider than their thresholds.
|
|
277
|
+
|
|
278
|
+
### 4 · HTF Trend Pullback — 1h, multi-timeframe confluence
|
|
279
|
+
|
|
280
|
+
Platform `includeMtfConfluence` (`MAalign_ltf/…/_htf`, `RSI14_*_zone`, `ADX_*_state` vocab
|
|
281
|
+
weak/developing/trending/extreme), `includeMovingAverages` (`dist_EMA20`, …), `includeRsi`
|
|
282
|
+
(`RSI14_now`, `RSI14_zone`). These three render `MAalign` and `RSI14_zone` twice between them, so
|
|
283
|
+
every condition below reads a suffixed form — never bare `MAalign` or bare `RSI14_zone`, which
|
|
284
|
+
would be ambiguous. Conditions: `HTF_UP` building block (`MAalign_htf is "bullish"` +
|
|
285
|
+
`ADX_htf_state in ["trending","extreme"]`); `HTF_DOWN` mirror; `TREND_PRESENT` **required**
|
|
286
|
+
`ANY[ref HTF_UP, ref HTF_DOWN]` — chop blocks compose-trade entirely, before billing;
|
|
287
|
+
`PULLBACK_LONG` verdict UP (ref HTF_UP + `RSI14_now between 35 55` +
|
|
288
|
+
`dist_EMA20 between -3 0.5`); `PULLBACK_SHORT` verdict DOWN (mirror, 45–65 / −0.5–3). Rules:
|
|
289
|
+
`mtf_pullback_long`/`_short` 3 required · `htf_ma_aligned_bull`/`_bear` 2 required ·
|
|
290
|
+
`htf_trend_adx_trending` 2 · `ma_ema_aligned_bull`/`_bear` 1 · `rsi_oversold` 1
|
|
291
|
+
`{"threshold":40}`. Gates 0.6 / 2 / 0.7 (a pullback signal AND an HTF alignment). Levels
|
|
292
|
+
1–2.5 ATR, RR 2. PM: BE 1R; trail 1.5R giveback 30 buffer 0.3.
|
|
293
|
+
|
|
294
|
+
### 5 · Perp/Spot Flow Divergence at Structure — 15m scalp
|
|
295
|
+
|
|
296
|
+
Platform `includePerpSpotFlow` (`perpSpotFlow` vocab: confirmed_bull / confirmed_bear /
|
|
297
|
+
perp_led_fragile / spot_led_accumulation / neutral), `includeStructureZones`
|
|
298
|
+
(`zones_htf_support_dist` signed %, support below price is negative; `_age_h`), custom `Tape`
|
|
299
|
+
(`BUY_PRESSURE value`→`buyPres` 0–1, `RVOL value`, `CLOSE_CHANGE value`). Conditions:
|
|
300
|
+
`SPOT_ACCUM` (`perpSpotFlow is "spot_led_accumulation"`); `NEAR_SUPPORT`
|
|
301
|
+
(`zones_htf_support_dist between -2 0` + `zones_htf_support_age_h gte 12`); `DIP_BID` verdict
|
|
302
|
+
UP — refs plus an `N_OF(2)` quorum over `buyPres gte 0.55` / `RVOL gte 1.2` / `closeChg gt 0`
|
|
303
|
+
(quorum beats a brittle ALL); `FRAGILE_POP` verdict DOWN (`perp_led_fragile` +
|
|
304
|
+
`zones_htf_resist_dist between 0 2` + `RVOL gte 1.3`). Rules:
|
|
305
|
+
`flow_perp_spot_bull_divergence`/`_bear_divergence` 3 required · `cvd_bull_divergence`/
|
|
306
|
+
`_bear_divergence` 2 · `sr_at_support`/`_at_resistance` 2 · `structure_ob_approach` 1 ·
|
|
307
|
+
`volume_surge` 1. Gates 0.55 / 1 / 0.4. Levels 0.5–1.2 ATR, RR 1.5. PM: BE 0.7R; trail 0.9R
|
|
308
|
+
giveback 30 buffer 0.15; timeDecay ON aggressive (45/15, 15→60, stale 30).
|
|
309
|
+
|
|
310
|
+
## TradingView ports — familiar processes, studio vocabulary
|
|
311
|
+
|
|
312
|
+
Players often ask for strategies by the name of a popular TradingView script. Port the
|
|
313
|
+
**process** (regime filter → setup state → trigger → stop engine), and where the catalog lacks
|
|
314
|
+
the primitive, name the substitution in the spec-lock question — never present a substitute as
|
|
315
|
+
the thing itself. Most TV strategies run on the daily chart: carry that with the
|
|
316
|
+
daily-strategy pattern above (pinned-1d thesis at `offset: 1` on an intraday anchor), which
|
|
317
|
+
binds decisions to daily closes while the studio keeps managing risk intraday. Event columns (`MACD_cross`, `EMA5_13`: Bullish/Bearish) print only on the
|
|
318
|
+
crossing bar and are otherwise null → UNRESOLVED; use them as triggers inside a carrier and
|
|
319
|
+
pair with a persistent state (spread sign, `MAalign`) for regime — as the source scripts do.
|
|
320
|
+
|
|
321
|
+
- **Squeeze Momentum [LazyBear] / TTM Squeeze** → `KC_SQUEEZE is "on"` is the native one-condition
|
|
322
|
+
read: the Bollinger pair sitting inside the Keltner channel, at the script's own multiplier.
|
|
323
|
+
The four boundaries stay addressable, so `BB_UPPER spread KC_UPPER` and
|
|
324
|
+
`BB_LOWER spread KC_LOWER` still express the same reading at a threshold you choose. Release
|
|
325
|
+
direction from the MACD trajectory, `bollinger_squeeze` Critical-required.
|
|
326
|
+
**Name the anchor when you port it:** on crypto the squeeze reads *on* about 57% of 1h bars even
|
|
327
|
+
at canonical parameters — σ/ATR runs low here because Bollinger σ is close-to-close while ATR
|
|
328
|
+
captures intrabar range — against about 19% at 15m. It is a selective filter at 15m and below,
|
|
329
|
+
not at 1h. (`bbWidthPct_rank_lo` + `ADX lt 20` remains
|
|
330
|
+
a serviceable board-relative compression proxy, but it is no longer the only option.)
|
|
331
|
+
- **Supertrend / UT Bot / Chandelier Exit** → `ST_LINE` and `ST_DIR` are native, so the regime
|
|
332
|
+
half is a direct port: `ST_DIR is "bullish"` as the persistent state, `dist_ST_LINE` for
|
|
333
|
+
distance to the plotted stop. The plotted trailing line is still best executed by the studio's
|
|
334
|
+
own stop engine — `trailingTriggerR: 0` (trail from entry), giveback ~30–40 (tight factor) or
|
|
335
|
+
45–55 (loose/chandelier) — because a trailing stop is a position-management mechanism, not a
|
|
336
|
+
column. **`ST_DIR` is a persisting state, not a flip event**: it reads the same on every bar of
|
|
337
|
+
a trend, so the FLIP still needs an event column beside it (`EMA5_13` cross, or a `ST_DIR`
|
|
338
|
+
trajectory whose `_trend` changes). Name that as a substitution.
|
|
339
|
+
- **MACD + 200 MA filter** → `ABOVE_200` building block (`dist_SMA200 gt 0`) referenced by a
|
|
340
|
+
carrier with `MACD_cross is "Bullish"`; rules `macd_bull/bear_cross` 3 required +
|
|
341
|
+
`ma_sma200_above/below` 2 required; swing-trend geometry.
|
|
342
|
+
- **Golden / Death Cross** → `SMA50 spread SMA200 × trajectory` gives state and freshness:
|
|
343
|
+
`SMA50_SMA200_spread_now gt 0` AND `_trend is "rising"`; optional breadth gate on
|
|
344
|
+
`mktBreadth_crypto gte 0` — every published scope resolves, not only `all`, because the leg reads
|
|
345
|
+
the `(timeframe, scope)` pairs a condition names; position-persona geometry. `SMA50 × SMA200` is
|
|
346
|
+
the canonical definition and stays the default port; `EMA50` is available as the crypto variant
|
|
347
|
+
when a player asks for it by name.
|
|
348
|
+
- **RSI-2 (Connors)** → `RSI2` is native, so this ports exactly: `RSI2 lte 10` gated by required
|
|
349
|
+
`ABOVE_200`; the source's fast exit is time — timeDecay ON (180/60, 15→50, stale 20);
|
|
350
|
+
`rsi_oversold` 3 required with a tuned threshold. Keep the literal `lte 10` as the GATE:
|
|
351
|
+
`RSI2 × classifyZone` exists and reads on the same Connors bands, but a zone label is a fixed
|
|
352
|
+
reading while the literal is a threshold the author can see and tune. Use the zone as a report
|
|
353
|
+
column, never as the substitute for the gate.
|
|
354
|
+
- **VWAP reversion** → `dist_VWAP` band + `dist_VWAP_rank_far lte 5` for board-relative
|
|
355
|
+
stretch; required `NOT [ADX_state in ["trending","extreme"]]` veto; scalp geometry +
|
|
356
|
+
aggressive timeDecay (VWAP anchors daily at 00:00 UTC).
|
|
357
|
+
- **Donchian / Turtle breakout** → `zone is "breakout high"` + `dist_swingHi gte 0` +
|
|
358
|
+
`RVOL gte 1.5`; `sr_resistance_break` 3 required; turtle exits = trend preset (trail from
|
|
359
|
+
1R, giveback 50). Mirror with `"breakdown low"`. **Daily-breakout variant on any anchor:**
|
|
360
|
+
pin the structure at 1d — `zone_1d is "breakout high"`, `dist_swingHi_1d gte 0` (validated).
|
|
361
|
+
**Literal previous-day levels are native**: `PDH` and `PDL` are catalogued price levels, so
|
|
362
|
+
`dist_PDH gte 0` composes directly. They are ANCHORED to `1d` — bind `{abs: '1d'}`, which is the
|
|
363
|
+
only reference the save path accepts on them, and read them from any anchor that way. `distance`
|
|
364
|
+
still rejects an `offset` and a clause still compares a column against a literal; neither of
|
|
365
|
+
those shapes is what a previous-day level needed.
|
|
366
|
+
- **ICT / SMC (FVG + order blocks)** → `STRUCT_ZONES` is the native zone engine:
|
|
367
|
+
`zones_htf_support_type` (`bullish FVG`/`bullish order block`), `zones_htf_support_dist
|
|
368
|
+
between -1.5 0`, `_age_h gte 12`, HTF bias required via `MAalign_htf`; rules
|
|
369
|
+
`structure_fvg_approach`/`structure_ob_approach` required (their `proximityPct` is the
|
|
370
|
+
in-zone dial). Liquidity sweeps, displacement, killzones and event *sequencing* are shapes the
|
|
371
|
+
grammar does not have — a clause compares one column against a literal, so an ordered sequence
|
|
372
|
+
of events cannot be stated at all. That is a grammar limit, not a missing metric; name it as
|
|
373
|
+
one.
|
|
374
|
+
- **Now native, formerly substituted** — WaveTrend (`WT1`/`WT2`), QQE (`QQE_RSI_MA`/`QQE_STOP`),
|
|
375
|
+
Hull (`HMA20`), Ichimoku (`ICHI_CONV`/`ICHI_BASE`/`ICHI_SPAN_A`/`ICHI_SPAN_B`/`ICHI_LAG`),
|
|
376
|
+
Parabolic SAR (`PSAR`), Keltner (`KC_UPPER`/`KC_MID`/`KC_LOWER`), daily pivots
|
|
377
|
+
(`PIVOT_P`/`PIVOT_R1`–`R3`/`PIVOT_S1`–`S3`), Williams %R (`WILLR14`), Stochastic RSI
|
|
378
|
+
(`STOCH_RSI14`), the TTM squeeze (`KC_SQUEEZE`), Connors RSI-2 (`RSI2`), the 9/21/50 EMAs
|
|
379
|
+
(`EMA9`/`EMA21`/`EMA50`), and literal previous-day levels (`PDH`/`PDL`). Port these directly —
|
|
380
|
+
do not offer a substitute for a primitive the catalog serves.
|
|
381
|
+
|
|
382
|
+
## Not expressible — the catalog keys this needs
|
|
383
|
+
|
|
384
|
+
The one place a claim that the catalog LACKS something may live, and every row names the key it
|
|
385
|
+
denies so the claim can be checked. A claim about the grammar's shape (a clause compares one
|
|
386
|
+
column against a literal; `distance` rejects an `offset`) belongs in prose above — those are
|
|
387
|
+
permanent. A claim that a metric is absent belongs here, or nowhere.
|
|
388
|
+
|
|
389
|
+
| Script / primitive | Key the catalog would need | Nearest expressible neighbour |
|
|
390
|
+
|---|---|---|
|
|
391
|
+
| 100-period SMA | `SMA100` | the shipped 50- or 200-period simple average, whichever the thesis leans on |
|
|
392
|
+
|
|
393
|
+
## Using a playbook
|
|
394
|
+
|
|
395
|
+
Discover → confirm headers (`get_strategy_column_contract`, or one `preview_strategy_report`
|
|
396
|
+
whose `conditionColumns` lists every addressable header with operators and vocabulary) →
|
|
397
|
+
calibrate literals against the previewed live values → compile once → review the compiled
|
|
398
|
+
scorecard, condition outcomes, verdict tally, and `marketReadMarkers` (fix `unknown` /
|
|
399
|
+
`ambiguous` markers) → apply per the strategy-authoring flow. Coin selection is call context,
|
|
400
|
+
not strategy state: explicit tickers for focused work, `ranked` (with an optional category) for
|
|
401
|
+
scanning books.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: battlegrid-trade-analysis
|
|
3
|
+
description: Read the player's own trading position — where their money actually is, whether each agent is doing the job it was given, what is open right now and how close it sits to its protections, and whether the automation is actually running. Activate whenever the player asks how they are doing, how an agent is performing, what is open, where their funds are, or why something did or did not happen.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Trade Analysis
|
|
7
|
+
|
|
8
|
+
You are answering "how am I actually doing?" — for a player whose money is deployed through
|
|
9
|
+
agents they configured and largely cannot watch.
|
|
10
|
+
|
|
11
|
+
## 1. The money map, with a reconciliation line
|
|
12
|
+
|
|
13
|
+
Start with where the money is, always, even when the question is narrower — a per-agent answer
|
|
14
|
+
means nothing without the whole.
|
|
15
|
+
|
|
16
|
+
- `get_account_state` for the account total.
|
|
17
|
+
- `get_agent_fund_allocation` and `get_agent_budget` for what is committed per agent.
|
|
18
|
+
|
|
19
|
+
Then state a **reconciliation line**: the account total against the sum of its parts. If they
|
|
20
|
+
agree, say they agree. **If they do not, state the gap as a gap** — name the amount and say you
|
|
21
|
+
cannot account for it. Never quietly present a total that does not add up, and never adjust a
|
|
22
|
+
figure to make it add up.
|
|
23
|
+
|
|
24
|
+
## 2. Per agent: "is it doing its job?"
|
|
25
|
+
|
|
26
|
+
Not "what were its returns" — whether it did *the thing it was told to do*.
|
|
27
|
+
|
|
28
|
+
- `get_intelligence_agent` — restate the agent's mandate in one line, in the player's terms. This
|
|
29
|
+
is the yardstick; without it "up 4%" means nothing.
|
|
30
|
+
- `get_agent_performance` and `list_trade_outcomes` — judge against that mandate.
|
|
31
|
+
- `get_trade_outcome_by_decision` / `get_trade_chart` when a specific trade needs explaining.
|
|
32
|
+
- `get_signal_performance` when the question is whether the agent's signals are working, as
|
|
33
|
+
distinct from whether its trades made money.
|
|
34
|
+
|
|
35
|
+
**Name the blemishes.** A verdict with no flaw in it is not a verdict, it is a summary. The trade
|
|
36
|
+
that went against the mandate, the streak, the position held past its thesis — say it. A player
|
|
37
|
+
reading a clean report about a messy account learns nothing.
|
|
38
|
+
|
|
39
|
+
## 3. Open positions, with protections and distance to trigger
|
|
40
|
+
|
|
41
|
+
- `get_agent_open_positions` per agent, or `list_user_active_positions` for everything at once.
|
|
42
|
+
- For each open position, report its protections **and how far price sits from each trigger** —
|
|
43
|
+
a stop is a number the player cannot act on; "3.1% from the stop" is one they can.
|
|
44
|
+
- `get_deployment_policy` / `get_radar_deployment` when the protection state comes from standing
|
|
45
|
+
policy rather than the position itself. `list_pending_approvals` and `list_gate_blocks` when
|
|
46
|
+
something looks like it should have fired and did not.
|
|
47
|
+
|
|
48
|
+
## 4. Automation health — unprompted
|
|
49
|
+
|
|
50
|
+
Call `get_agent_automation_status` and surface anything degraded **even when the player did not
|
|
51
|
+
ask about automation**. A player asking "how's my portfolio?" while an agent has silently stopped
|
|
52
|
+
trading is being answered wrongly if you only answer what they asked.
|
|
53
|
+
|
|
54
|
+
Flag it plainly and **offer to diagnose**. The offer is yours; the diagnosis is
|
|
55
|
+
`strategy-doctor`'s — activate it and let its arc run, rather than reading the gate blocks and
|
|
56
|
+
reason codes from here.
|
|
57
|
+
|
|
58
|
+
## 5. UNDETERMINED, never "no issue"
|
|
59
|
+
|
|
60
|
+
This is the discipline that matters most on this surface.
|
|
61
|
+
|
|
62
|
+
If a tool call fails, returns nothing, or does not cover the thing being asked about, report that
|
|
63
|
+
item as **UNDETERMINED** and say what you could not check. Never convert an absence of data into a
|
|
64
|
+
clean bill of health. "Automation status: UNDETERMINED — the status read failed" is honest and
|
|
65
|
+
actionable. "No issues found" in the same situation is a false statement about the player's money.
|
|
66
|
+
|
|
67
|
+
The same applies to any figure you could not reconcile, any position whose protections did not
|
|
68
|
+
resolve, and any agent whose mandate you could not read.
|
|
69
|
+
|
|
70
|
+
## Reporting discipline
|
|
71
|
+
|
|
72
|
+
- Report numbers exactly as the tools return them. Never recompute, re-derive, or round.
|
|
73
|
+
- Lead with the money map, then agents, then positions, then automation. The player scans top-down.
|
|
74
|
+
- Be concise, and put the worst news first. Do not bury a degraded agent under a good return.
|