@battlegrid/mcp-server 31.2.100 → 31.2.103
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 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/EXPORT.json +9 -8
- package/skills/battlegrid-arena-play/SKILL.md +65 -35
- package/skills/battlegrid-arena-play/references/entry-stage-examples.md +89 -0
- package/skills/battlegrid-market-analysis/SKILL.md +1 -1
- package/skills/battlegrid-radar-deployment/SKILL.md +28 -23
- package/skills/battlegrid-strategy-authoring/SKILL.md +6 -4
- package/skills/battlegrid-strategy-examples/SKILL.md +49 -6
- package/skills/battlegrid-strategy-examples/references/recipes.md +1 -1
- package/skills/battlegrid-strategy-examples/references/tradingview-ports.md +6 -2
package/README.md
CHANGED
|
@@ -24,6 +24,30 @@ Seeing package `31.x` alongside handshake `battlegrid@33.x` — the package **be
|
|
|
24
24
|
|
|
25
25
|
**What this changes for you:** nothing about how you call anything. Upgrading the package no longer waits on a server deploy, and a server deploy no longer strands you on a package that names the wrong contract — reconnect and the announcement follows. **Contract breaking-change notes are no longer keyed to package versions**, since a contract move is no longer a release here; the v11-and-earlier notes below are kept as history, and the live vocabulary is always discovery.
|
|
26
26
|
|
|
27
|
+
## Contract history — v110.6 (the Donchian channel as of the bar before)
|
|
28
|
+
|
|
29
|
+
**Additive at v110.6: two Donchian metric keys, and level-interaction labels judged against the level in
|
|
30
|
+
force when the bar opened.** v110.6 is the contract on top of v110.5. Nothing you send is refused.
|
|
31
|
+
|
|
32
|
+
### Widened enum — something new you can send
|
|
33
|
+
|
|
34
|
+
- **`DONCHIAN_UPPER_PRIOR` and `DONCHIAN_LOWER_PRIOR`** (codes `donchianHiPrior`, `donchianLoPrior`)
|
|
35
|
+
in every tool that takes a column (`stage_strategy_draft`, `preview_strategy_report`,
|
|
36
|
+
`get_strategy_column_contract`, `get_metric_construction_hints`): the 20-bar channel edges as of the
|
|
37
|
+
bar before, Pine's `ta.highest(high, 20)[1]` and `ta.lowest(low, 20)[1]`. The close-based Donchian
|
|
38
|
+
breakout is `dist_donchianHiPrior crossesAbove 0`; the state "close above the prior 20-bar high" is
|
|
39
|
+
`dist_donchianHiPrior gt 0`; a failed breakout is `donchianHiPrior_lvl is reject_from_below`. They take
|
|
40
|
+
`levelInteraction` and not the cross-coin `rank`. Their history begins when the server deployed them.
|
|
41
|
+
|
|
42
|
+
### Behaviour behind unchanged schemas
|
|
43
|
+
|
|
44
|
+
- **`levelInteraction` decides the side and the break against the level in force when the bar opened**:
|
|
45
|
+
the bar's own reading for a level fixed before the bar, the previous bar's reading for a level computed
|
|
46
|
+
from its own bar. Labels move on `DONCHIAN_BROKEN_HI`, `DONCHIAN_BROKEN_LO`, `SWING_FRACTAL_HIGH`,
|
|
47
|
+
`SWING_FRACTAL_LOW`, `ICHI_SPAN_A`, `ICHI_SPAN_B` and `ICHI_LAG`, only on bars where the level stepped
|
|
48
|
+
across the prior close and on the bar a level first appears (null becomes a label). No other level's
|
|
49
|
+
label moves. The transform's `formula` and `nullBehavior` text say so.
|
|
50
|
+
|
|
27
51
|
## Contract history — v110 (a metric names the one line it reads)
|
|
28
52
|
|
|
29
53
|
**Breaking at v110: the metric keys `MACD`, `PPO` and `KC_MID` are refused.** v110 is the contract on
|
package/dist/index.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ import { type Implementation, type Prompt, type Resource } from '@modelcontextpr
|
|
|
49
49
|
* being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
|
|
50
50
|
* correction. Never move it to track the server.
|
|
51
51
|
*/
|
|
52
|
-
export declare const PACKAGE_VERSION = "31.2.
|
|
52
|
+
export declare const PACKAGE_VERSION = "31.2.103";
|
|
53
53
|
export declare const DEFAULT_URL = "https://mcp.battlegrid.trade/mcp";
|
|
54
54
|
export interface EnvConfig {
|
|
55
55
|
apiKeys: string[];
|
package/dist/index.js
CHANGED
|
@@ -52,7 +52,7 @@ import { ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema
|
|
|
52
52
|
* being asked. Move it for a change to THIS package — a proxy fix, a dependency bump, a docs
|
|
53
53
|
* correction. Never move it to track the server.
|
|
54
54
|
*/
|
|
55
|
-
export const PACKAGE_VERSION = '31.2.
|
|
55
|
+
export const PACKAGE_VERSION = '31.2.103';
|
|
56
56
|
export const DEFAULT_URL = 'https://mcp.battlegrid.trade/mcp';
|
|
57
57
|
const MAX_RETRIES = 3;
|
|
58
58
|
const RETRY_DELAYS_MS = [2000, 4000, 8000];
|
package/package.json
CHANGED
package/skills/EXPORT.json
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"generator": "battlegrid-app/server/scripts/export-mcp-skills.mjs",
|
|
3
|
-
"contractVersion": "
|
|
3
|
+
"contractVersion": "110.4.0",
|
|
4
4
|
"files": {
|
|
5
5
|
"battlegrid-agent-management/SKILL.md": "34a868f8068df189ce13af47c23011aabcf6a1f07128da4d4706066628cfaa5f",
|
|
6
6
|
"battlegrid-agent-management/references/agent-stage-examples.md": "d47555906ce8dedf4c17422f8f5d60187f2d6b3c0af5d9545617a10a5bdb59a1",
|
|
7
|
-
"battlegrid-arena-play/SKILL.md": "
|
|
8
|
-
"battlegrid-
|
|
9
|
-
"battlegrid-
|
|
7
|
+
"battlegrid-arena-play/SKILL.md": "88534714cdbaa31344e1798b2b3f18836bf543f5610d118d76095d1a0dbea502",
|
|
8
|
+
"battlegrid-arena-play/references/entry-stage-examples.md": "3bc62f9faca7b5529d51a9794e162333216acb23f0d7f644d5180b9cbc696fca",
|
|
9
|
+
"battlegrid-market-analysis/SKILL.md": "fcbe98e30e1edce39bb170c224cdf20181934f62b5f3a26b293787c70eeb6229",
|
|
10
|
+
"battlegrid-radar-deployment/SKILL.md": "652325c4923d79b9c9b78026a5493bfaaedf01f600641511438a9c4bf497c0b1",
|
|
10
11
|
"battlegrid-radar-deployment/references/arena-stage-examples.md": "f605aaa266a291ef1b6d02a0e8885ad5df2fea88c800be2b6625cd629cd741f2",
|
|
11
12
|
"battlegrid-radar-deployment/references/radar-stage-examples.md": "1ddad4a11f021dd65234ee65cc12d7d1561fe9acfd61cb021f4352080d4cecd5",
|
|
12
|
-
"battlegrid-strategy-authoring/SKILL.md": "
|
|
13
|
+
"battlegrid-strategy-authoring/SKILL.md": "098308e69093796db3bb0a6dab64031128aaffbc108117b72393595564581da1",
|
|
13
14
|
"battlegrid-strategy-authoring/references/strategy-stage-examples.md": "9822cc2bcc8975a3e436c2a960b10e03c95e6e6b4b04bc2206e0ac90688cab66",
|
|
14
15
|
"battlegrid-strategy-doctor/SKILL.md": "e34e055b0cc9b355bc1adeb5d49d464eaa0756ca3f48dc89ca2ccdda94e1311f",
|
|
15
|
-
"battlegrid-strategy-examples/SKILL.md": "
|
|
16
|
+
"battlegrid-strategy-examples/SKILL.md": "375a85a38b21a356291d05af3668a57949f11ba49968a4a53f08dcc590228375",
|
|
16
17
|
"battlegrid-strategy-examples/references/playbooks.md": "2309eb7e8324f563c5b1b51e05da931b37c542484135a2be749eff6ef78aa40f",
|
|
17
|
-
"battlegrid-strategy-examples/references/recipes.md": "
|
|
18
|
-
"battlegrid-strategy-examples/references/tradingview-ports.md": "
|
|
18
|
+
"battlegrid-strategy-examples/references/recipes.md": "635e03d163100f6de37cda1f6cc12928d5d36aa0ea883bf44fc72f17cbf3e98e",
|
|
19
|
+
"battlegrid-strategy-examples/references/tradingview-ports.md": "1b9440bd7180330fb77c8e245e852cbe0b5a9f7df3448233199ecd341565b2b6",
|
|
19
20
|
"battlegrid-trade-analysis/SKILL.md": "3f927b4f9796178526fa1673a2043c5f14358c39aa955de33192ea58641f18fb",
|
|
20
21
|
"battlegrid-trade-proposal/SKILL.md": "e761fc6bddc0d1db79fcb90046d03a18439562c8658de726ec286830edd6369b"
|
|
21
22
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: battlegrid-arena-play
|
|
3
|
-
description: Enter the player into Market Grid sessions — find an open session, read its coin pool and live market context,
|
|
3
|
+
description: Enter the player into Market Grid sessions — find an open session, read its coin pool and live market context, read the player's entry draft and stage picks with real per-coin reasoning into it or have one of their agents generate a grid, commit it against the session's entry fee, then read the results and the player's own entry record after settlement. Activate whenever the player wants to play, enter, join or submit to a session, asks what their grid looks like or to fill it in, wants their agent to enter one, asks what is open to play, or asks how a session they entered turned out.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Arena Play
|
|
7
7
|
|
|
8
|
-
A
|
|
9
|
-
the
|
|
8
|
+
A player's picks for a session live in their **entry draft**, one axis per grid position (`CELL_0` is
|
|
9
|
+
the captain) plus a `RATIONALE`. Their builder on the session page writes the same draft as they pick,
|
|
10
|
+
so the draft is the shared grid: you read it to know what they have picked and stage into it to propose
|
|
11
|
+
picks. Staging is free and enters nothing. **Committing it is the wager**: with no entry the commit
|
|
12
|
+
enters the session and the entry fee moves inside that call; over an entry it replaces the picks for no
|
|
13
|
+
fee. The grid you commit is the one that gets scored, and there is no undo.
|
|
10
14
|
|
|
11
15
|
## The three failures this flow exists to prevent
|
|
12
16
|
|
|
@@ -54,23 +58,31 @@ the enablement path there.
|
|
|
54
58
|
3. `get_market_context` for that session — the indicators, rankings and trends the picks will
|
|
55
59
|
actually be reasoned from.
|
|
56
60
|
4. `check_market_grid_submission` — **before composing anything.** If a submission already exists,
|
|
57
|
-
report it (with its id and time)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
report it (with its id and time); while the session is still PENDING, a commit of the draft
|
|
62
|
+
replaces its picks. Never compose a duplicate.
|
|
63
|
+
5. `get_market_grid_entry_draft({ request: { sessionId } })` — what the draft holds now, the player's
|
|
64
|
+
own picks included, with the `draftVersion` and `committedRevision` your stage and commit name.
|
|
65
|
+
Answer "what does my grid look like" from this read, never from a pick count.
|
|
66
|
+
|
|
67
|
+
### 3. Compose — stage into the draft, and the reasoning is yours to get right
|
|
68
|
+
|
|
69
|
+
`stage_market_grid_entry_draft({ request: { sessionId, draftVersion, axes } })`, naming the
|
|
70
|
+
`draftVersion` the read returned. Each cell axis is `{ cell: { coinId, prediction } }` — `coinId` the
|
|
71
|
+
pool coin's `id` — or `{ cell: null }` to empty it. **Compose on top of what the draft holds**: a cell
|
|
72
|
+
you do not stage keeps the player's pick, and you never discard their picks to start over unless they
|
|
73
|
+
ask. The commit requires a `RATIONALE` axis — `reasoning`, `confidenceScore`, `modelName` and
|
|
74
|
+
`pickReasoning` — covering the whole grid it composes. Complete stage payloads are in
|
|
75
|
+
`references/entry-stage-examples.md`.
|
|
76
|
+
|
|
77
|
+
- **`CELL_0` is the captain.** The session's preset sets what that is worth: a correct captain's
|
|
66
78
|
points are multiplied by its `captainMultiplier`, and a wrong captain's penalty by its
|
|
67
79
|
`captainWrongPenaltyMultiplier` — both published by `list_game_presets`, and different per preset.
|
|
68
80
|
Read them rather than assuming a number, and captain the pick you are most confident in among
|
|
69
81
|
those with a move worth amplifying.
|
|
70
82
|
- **`pickReasoning` carries one entry per grid cell — every cell, no coin twice.** Compose it
|
|
71
83
|
correctly because it is yours to compose, not because something downstream will catch it: the
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
read reports an incomplete one as a diagnostic and the commit refuses it before the fee moves, and
|
|
85
|
+
leaning on that check means committing payloads you have not read.
|
|
74
86
|
- Each entry's reasoning cites **the market context you read in this conversation**, for that
|
|
75
87
|
coin. Boilerplate reasoning attached to a real wager is worse than none — it looks like
|
|
76
88
|
evidence.
|
|
@@ -85,12 +97,16 @@ Present the generation as a card: the agent, its confidence against the threshol
|
|
|
85
97
|
(`confidenceThreshold: null` means no deployment declares a bar here, so the grid is **ungated** —
|
|
86
98
|
say that rather than inventing a bar), whether it meets the threshold, and the per-coin picks.
|
|
87
99
|
|
|
88
|
-
### 4.
|
|
100
|
+
### 4. Read again, confirm, then commit promptly
|
|
89
101
|
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
`get_market_grid_entry_draft` again after staging: show the player the diff, any diagnostic, and the
|
|
103
|
+
`impact` — `ENTER` with the `entryFee` the commit charges, or `REPLACE` for none. One confirmation
|
|
104
|
+
naming **the session, that fee, and the confidence** — then commit on an explicit pick.
|
|
92
105
|
|
|
93
|
-
- Direct → `
|
|
106
|
+
- Direct → `commit_market_grid_entry_draft({ request: { sessionId, draftVersion, expectedRevision } })`,
|
|
107
|
+
naming exactly the `draftVersion` and `committedRevision` the last read returned (`null` with no
|
|
108
|
+
entry). A refusal naming `get_draft` means the draft or the entry moved: read again and confirm
|
|
109
|
+
again — never retry with a bumped number.
|
|
94
110
|
- Agent → `submit_agent_grid`, which consumes the cached generation for that (session, agent).
|
|
95
111
|
|
|
96
112
|
**A regeneration voids any prior confirm.** The submit takes no generation token — it reads
|
|
@@ -98,10 +114,14 @@ whatever is currently cached — so a grid regenerated after the player confirme
|
|
|
98
114
|
under a confirmation given for different picks. Re-present the confirm for the new generation,
|
|
99
115
|
every time, and submit promptly after the confirmed one.
|
|
100
116
|
|
|
117
|
+
**If the submit is refused with `CONFLICT`**, the player's entry changed after the grid was generated —
|
|
118
|
+
replaced, cancelled, re-placed, or placed where there was none. No fee moved. The recovery is
|
|
119
|
+
`generate_agent_grid` again, a fresh confirm of the new grid, then `submit_agent_grid`.
|
|
120
|
+
|
|
101
121
|
**If the submit is refused for a missing pending generation**, the ten-minute window lapsed. The
|
|
102
122
|
recovery is `generate_agent_grid` again and a fresh confirm. **Never** convert the stale picks into
|
|
103
|
-
a hand-
|
|
104
|
-
|
|
123
|
+
a hand-staged draft committed under the player's own name — that enters an agent's reasoning as the
|
|
124
|
+
player's, and the attribution is part of what was scored.
|
|
105
125
|
|
|
106
126
|
### 5. After settlement
|
|
107
127
|
|
|
@@ -113,25 +133,33 @@ reasoning as the player's, and the attribution is part of what was scored.
|
|
|
113
133
|
typed CONFLICT naming the current status: **report it and stop**. Do not poll it in a loop; the
|
|
114
134
|
op budget is finite and a settling session is not a failure.
|
|
115
135
|
- `get_my_market_grid_entry` on request — the player's own entry in that session: its picks, who
|
|
116
|
-
authored
|
|
117
|
-
|
|
118
|
-
reasoning
|
|
119
|
-
the
|
|
120
|
-
|
|
136
|
+
authored the current picks (`source`; `COMMANDER_ASSIST` with `keptPicks` when the player and
|
|
137
|
+
Commander authored it together), whether that differs from who first entered (`edited`), and the
|
|
138
|
+
reasoning that describes the current picks, with one entry per reasoned pick in `reasoning.picks`.
|
|
139
|
+
Compare the outcome against what was actually reasoned, and say where the reasoning was wrong.
|
|
140
|
+
`reasoning` is null when no record describes the current picks — say that rather than
|
|
141
|
+
reconstructing one, and a pick missing from `reasoning.picks` is one the player chose.
|
|
142
|
+
`list_my_market_grid_entries` is the history across sessions. An agent's decisions are a different
|
|
143
|
+
record, `get_agent_journal`.
|
|
121
144
|
|
|
122
145
|
## On the arena's session page
|
|
123
146
|
|
|
124
147
|
When the conversation is embedded in the player's Market Grid session page, the round on screen
|
|
125
148
|
arrives as the attached scope, and the session it names is the one in scope.
|
|
126
149
|
|
|
127
|
-
- **
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
150
|
+
- **Stage, do not enter.** When the player asks you to pick or fill in their grid, read the draft and
|
|
151
|
+
stage the cells into it (step 3). Each staged pick appears in their builder at once, labelled as
|
|
152
|
+
yours; nothing is entered and no fee or deposit is needed. Their own **PLACE ENTRY** places it;
|
|
153
|
+
offer to place it for them only through step 4's confirmation and the draft commit.
|
|
154
|
+
- **Their picks are in the draft.** A pick they make in the builder lands there as they make it, so
|
|
155
|
+
read the draft before answering what they have picked or staging over it. A pick their builder
|
|
156
|
+
rewrote after you staged it is their answer — stage it again only when they ask.
|
|
157
|
+
- **An agent's grid is proposed, not staged.** When they ask for their agent's grid, call
|
|
158
|
+
`generate_agent_grid` for the session in scope (the billed-inference warning in step 3 still
|
|
159
|
+
applies). The result reaches them as a card with **LOAD INTO GRID**, which puts the picks into their
|
|
160
|
+
builder as a starting point. A loaded grid they have not changed is the agent's: if they want it
|
|
161
|
+
entered as it stands, run step 4, then `submit_agent_grid` on their explicit pick, never on free
|
|
162
|
+
text. Once they change a pick, the grid is theirs.
|
|
135
163
|
- **A newer generation for the same agent replaces the older card.** The older one reads SUPERSEDED;
|
|
136
164
|
only the newest is what `submit_agent_grid` would enter.
|
|
137
165
|
|
|
@@ -160,8 +188,10 @@ Each is typed and distinguishable. Read the code, do not paraphrase:
|
|
|
160
188
|
a permission check, do not add a wager gate of your own, and do not treat free text typed while a
|
|
161
189
|
confirmation is open as consent — in chat or in the form's own answer-in-your-own-words box. Only
|
|
162
190
|
an explicit pick from the options you offered confirms.
|
|
163
|
-
- **Never re-
|
|
164
|
-
|
|
191
|
+
- **Never re-commit over an unknown outcome.** An interrupted commit may have moved the fee. A retry
|
|
192
|
+
of the same `draftVersion` returns the first commit's receipt; otherwise run
|
|
193
|
+
`check_market_grid_submission` and `get_market_grid_entry_draft` first and report what actually
|
|
194
|
+
exists.
|
|
165
195
|
|
|
166
196
|
## Reporting discipline
|
|
167
197
|
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Market Grid entry stage examples
|
|
2
|
+
|
|
3
|
+
Complete `stage_market_grid_entry_draft` inputs for the player's entry draft. Each is checked in CI against the live
|
|
4
|
+
stage schema, and the grid it composes is judged by the commit's own grid and reasoning checks, so its shape is
|
|
5
|
+
current.
|
|
6
|
+
|
|
7
|
+
Every `<UPPER_SNAKE>` value is a placeholder. Replace it with the id a read returned:
|
|
8
|
+
|
|
9
|
+
- `<SESSION_ID>` comes from `list_market_grid_sessions`.
|
|
10
|
+
- `<COIN_ID>`, `<SECOND_COIN_ID>` and `<THIRD_COIN_ID>` are three different coins' `id`s from the pool
|
|
11
|
+
`get_market_grid_session` returns.
|
|
12
|
+
|
|
13
|
+
Never send a placeholder as written, and never invent an id. `draftVersion` is the version
|
|
14
|
+
`get_market_grid_entry_draft` returned: 0 when the session has no draft. These examples are a three-cell session; a
|
|
15
|
+
real session's grid has its own `gridSize`, and the commit needs every position from `CELL_0` up to it filled.
|
|
16
|
+
|
|
17
|
+
## Fill the whole grid, with its reasoning
|
|
18
|
+
|
|
19
|
+
`CELL_0` is the captain. The `RATIONALE` carries one `pickReasoning` entry per cell of the grid the commit will
|
|
20
|
+
enter, each citing the market context you read.
|
|
21
|
+
|
|
22
|
+
```json stage_market_grid_entry_draft
|
|
23
|
+
{
|
|
24
|
+
"request": {
|
|
25
|
+
"sessionId": "<SESSION_ID>",
|
|
26
|
+
"draftVersion": 0,
|
|
27
|
+
"axes": {
|
|
28
|
+
"CELL_0": { "cell": { "coinId": "<COIN_ID>", "prediction": "UP" } },
|
|
29
|
+
"CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "DOWN" } },
|
|
30
|
+
"CELL_2": { "cell": { "coinId": "<THIRD_COIN_ID>", "prediction": "UP" } },
|
|
31
|
+
"RATIONALE": {
|
|
32
|
+
"reasoning": "The leader is breaking out on rising volume while the second coin rejects its range high.",
|
|
33
|
+
"confidenceScore": 0.7,
|
|
34
|
+
"modelName": "your-model-name",
|
|
35
|
+
"pickReasoning": [
|
|
36
|
+
{ "coinId": "<COIN_ID>", "reasoning": "Breaking resistance on rising volume.", "confidence": 0.8 },
|
|
37
|
+
{ "coinId": "<SECOND_COIN_ID>", "reasoning": "Bearish divergence at the range high.", "confidence": 0.6 },
|
|
38
|
+
{ "coinId": "<THIRD_COIN_ID>", "reasoning": "Holding its trend above the session open.", "confidence": 0.6 }
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Change one call, keeping every other pick
|
|
47
|
+
|
|
48
|
+
A cell you do not stage keeps the player's own pick. Here the second position's call flips while its coin stays,
|
|
49
|
+
so the reasoning the draft already holds still covers every coin; stage a new `RATIONALE` when your reasoning for
|
|
50
|
+
that coin changed.
|
|
51
|
+
|
|
52
|
+
```json stage_market_grid_entry_draft
|
|
53
|
+
{
|
|
54
|
+
"request": {
|
|
55
|
+
"sessionId": "<SESSION_ID>",
|
|
56
|
+
"draftVersion": 4,
|
|
57
|
+
"axes": {
|
|
58
|
+
"CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "UP" } }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Change a call and its reasoning together
|
|
65
|
+
|
|
66
|
+
```json stage_market_grid_entry_draft
|
|
67
|
+
{
|
|
68
|
+
"request": {
|
|
69
|
+
"sessionId": "<SESSION_ID>",
|
|
70
|
+
"draftVersion": 5,
|
|
71
|
+
"axes": {
|
|
72
|
+
"CELL_1": { "cell": { "coinId": "<SECOND_COIN_ID>", "prediction": "UP" } },
|
|
73
|
+
"RATIONALE": {
|
|
74
|
+
"reasoning": "The second coin reclaimed its range high, so it now runs with the leader.",
|
|
75
|
+
"confidenceScore": 0.65,
|
|
76
|
+
"modelName": "your-model-name",
|
|
77
|
+
"pickReasoning": [
|
|
78
|
+
{ "coinId": "<COIN_ID>", "reasoning": "Breaking resistance on rising volume.", "confidence": 0.8 },
|
|
79
|
+
{ "coinId": "<SECOND_COIN_ID>", "reasoning": "Reclaimed the range high on the last close.", "confidence": 0.6 },
|
|
80
|
+
{ "coinId": "<THIRD_COIN_ID>", "reasoning": "Holding its trend above the session open.", "confidence": 0.6 }
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`{ "cell": null }` empties a position. The draft holds it while the player is still choosing, but the commit
|
|
89
|
+
refuses a grid with an empty position, so stage it only when the player asked to clear that pick.
|
|
@@ -46,7 +46,7 @@ Run these in order. Skip a step only when the player's question makes it irrelev
|
|
|
46
46
|
coin selection and the funding / open-interest / positioning sections chosen — one coin is a
|
|
47
47
|
one-row report, not a different tool. Then `get_coin_candles` for the price action. For momentum
|
|
48
48
|
across timeframes, add the Relative Strength section — it carries the PPO trajectory and its
|
|
49
|
-
zero-crossing — or author `
|
|
49
|
+
zero-crossing — or author `PPO_HIST` columns at the intervals you want pinned; that is the same read
|
|
50
50
|
at the precision the catalog declares, in the call you are already making. Use
|
|
51
51
|
`get_coin_performance_history` when the question is about how it has behaved, not where it is.
|
|
52
52
|
Coin symbols are case-insensitive and exchange symbols are accepted (`btc`, `kPEPE`,
|
|
@@ -316,26 +316,28 @@ Four reads, cheapest first. Stop as soon as the player's question is answered.
|
|
|
316
316
|
and read the verdict's `reading` as step 2 of the deploy flow describes it: `live` is what the
|
|
317
317
|
agent reads now, and `lastClose` is the decision its row names as its last close, with the reading
|
|
318
318
|
that bar was decided on.
|
|
319
|
-
2. **`get_radar_activity_summary`** for everything else about "why is it quiet", in ONE call.
|
|
320
|
-
|
|
319
|
+
2. **`get_radar_activity_summary`** for everything else about "why is it quiet", in ONE call. Pass
|
|
320
|
+
`agentId` when the question is about one agent — "why isn't Hawk firing on SOL?" — and the read is
|
|
321
|
+
that agent's history on the coin. Without it the read is the **coin feed**: the deployment's
|
|
322
|
+
lifecycle, status changes, duty changes and fires, with no agent's gates, an empty `curveDigest`
|
|
323
|
+
and no curve agent. An `agentId` the player cannot access is answered as not found. It carries
|
|
324
|
+
three parts and they answer three different questions, each on its own scope:
|
|
321
325
|
- `groups` — which cause recurs and how often, over the window the response names. Quote the
|
|
322
|
-
counts with that window; never sum them across calls.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
`sampleCount`, and the latest ATR% with how many
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
above.
|
|
329
|
-
- `recentEvents` — the last ten key events, lean. Deliberately NOT bounded by the
|
|
330
|
-
a pair quiet for longer returns no groups beside populated older rows. That is
|
|
331
|
-
contradiction; each row carries its own `occurredAt`.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
`ON_DUTY_JOINED` / `ON_DUTY_LEFT`, one row per agent, and a lost coin as
|
|
338
|
-
`EDGE_PRESERVED_COIN_CLAIMED`.
|
|
326
|
+
counts with that window; never sum them across calls. On the coin feed a blocked status counts
|
|
327
|
+
by its idle reason, never by an agent's gate; an agent's history counts its own gates.
|
|
328
|
+
- `curveDigest` — with `agentId`, how often that agent qualified on this coin, over its own ring
|
|
329
|
+
(named in `curveAgentName`): `qualifiedCount` of `sampleCount`, and the latest ATR% with how many
|
|
330
|
+
samples read one. A pair that qualified on no sample is one whose strategy does not fit this
|
|
331
|
+
coin as it trades now; the `groups` above name the gate that blocked it. Its `ringStartAt` /
|
|
332
|
+
`ringEndAt` describe the ring, NOT the cause window above.
|
|
333
|
+
- `recentEvents` — the last ten key events of the same scope, lean. Deliberately NOT bounded by the
|
|
334
|
+
cause window, so a pair quiet for longer returns no groups beside populated older rows. That is
|
|
335
|
+
correct, not a contradiction; each row carries its own `occurredAt`.
|
|
336
|
+
|
|
337
|
+
With `agentId` the groups, the digest and the rows all describe that one agent. Two agents on duty
|
|
338
|
+
are two reads, one per `agentId`. Joins and departures are journaled as `ON_DUTY_JOINED` /
|
|
339
|
+
`ON_DUTY_LEFT`, one row per agent, in both the coin feed and that agent's history, and a lost coin
|
|
340
|
+
as `EDGE_PRESERVED_COIN_CLAIMED`.
|
|
339
341
|
3. **`get_radar_close_decisions`** when the question is about ONE close — "why didn't the 14:00 bar
|
|
340
342
|
fire?", "why did it fire there?", "what did it see at that close?". Every bar the close step
|
|
341
343
|
decided has one record, whether a policy's agent or a manual request's watch decided it: its
|
|
@@ -350,13 +352,16 @@ Four reads, cheapest first. Stop as soon as the player's question is answered.
|
|
|
350
352
|
refused it and nothing was traded. It is the only history of not-qualifying closes: the journal
|
|
351
353
|
writes no row for one, and `resolvesNow` keeps only each agent's last decision — the one
|
|
352
354
|
`reading.lastClose` (step 1) carries; this read holds every decision before it. Narrow with
|
|
353
|
-
`agentId`; page back by passing the
|
|
355
|
+
`agentId`; page back by passing the response's `nextBefore` as `before`, and stop when
|
|
356
|
+
`nextBefore` is null — that is the end of the history. A bar still
|
|
354
357
|
waiting inside its window has no record yet (`resolvesNow` shows its `closeDecision.state` as
|
|
355
358
|
`DEFERRED`), and records are kept 90 days.
|
|
356
359
|
4. **`get_radar_activity`** only for what steps 2 and 3 cannot do: more rows than its ten, a
|
|
357
|
-
FIRES-only view, paging back through history, or ONE occurrence's full margins.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
+
FIRES-only view, paging back through history, or ONE occurrence's full margins. Its scope is step
|
|
361
|
+
2's: pass `agentId` for one agent's rows, and omit it for the coin feed, which carries no agent's
|
|
362
|
+
gate crossings, verdict flips or regime changes. Rows are lean by default — pass `detail: 'FULL'`
|
|
363
|
+
for the margin surface, and `includeCurve: true` only if something will actually plot the points;
|
|
364
|
+
`includeCurve` requires `agentId`, and is refused without it.
|
|
360
365
|
|
|
361
366
|
**Neither of the first two substitutes for the other, and the reason is structural.** The journal is
|
|
362
367
|
a TRANSITION log, not a state log: a gate that has blocked continuously without crossing again
|
|
@@ -107,10 +107,12 @@ Compose sections, columns and conditions **only** from vocabulary returned in th
|
|
|
107
107
|
field you remember from another strategy is not discovery.
|
|
108
108
|
|
|
109
109
|
**Conditions are the only deterministic entry gate.** A condition gates an entry when it is
|
|
110
|
-
`required` or carries a verdict (UP, DOWN or NEITHER); a building block —
|
|
111
|
-
verdict
|
|
112
|
-
|
|
113
|
-
|
|
110
|
+
`required` or carries a verdict (UP, DOWN or NEITHER); a building block — a condition with no
|
|
111
|
+
verdict — gates nothing unless it is itself marked `required`, and an exit rule never counts.
|
|
112
|
+
Whether a sub-rule should be a building block or inlined is answered by the `strategy-examples`
|
|
113
|
+
skill's **Building block or inline** paragraph. A strategy whose entry conditions include no
|
|
114
|
+
required and no verdict-carrying condition never routes a trade: every coin fails first with
|
|
115
|
+
`NO_ENTRY_CONDITION`, and its draft carries the warning of the same name. It stays a valid
|
|
114
116
|
strategy — Market Grid reads it as context — so a strategy the player means to trade needs at least
|
|
115
117
|
one. Before any condition is read, a coin must clear the ATR floor, `minAtrPct`, the
|
|
116
118
|
TRADE_LEVEL_POLICY dial beside the stop-loss band.
|
|
@@ -77,7 +77,7 @@ add. Either way you never invent one. To section-qualify a duplicated header, re
|
|
|
77
77
|
`detail: "detailed"` preview's `authoring.conditionColumns` or from the qualified candidates a
|
|
78
78
|
`CONDITION_COLUMN_AMBIGUOUS` refusal offers.
|
|
79
79
|
|
|
80
|
-
**Event columns print only on their event.** `
|
|
80
|
+
**Event columns print only on their event.** `MACDhist_cross` and `EMA5_13` (Bullish/Bearish) carry a
|
|
81
81
|
value on the crossing bar and are null on every other one, which reads as UNRESOLVED. Use an event
|
|
82
82
|
column as a TRIGGER inside a carrier, and pair it with a persistent state — a spread sign,
|
|
83
83
|
`MAalign` — for regime. A condition that treats an event column as a standing state is unresolved on
|
|
@@ -163,14 +163,56 @@ setups block and from the `decide_trade` contract, not merely discouraged in the
|
|
|
163
163
|
declares no verdict-carrying condition resolves `null` and constrains no side.
|
|
164
164
|
|
|
165
165
|
**A strategy without an entry condition never routes.** An entry condition gates when it is
|
|
166
|
-
`required: true` or carries a verdict (`UP`, `DOWN` or `NEITHER`); a building block
|
|
167
|
-
and an exit rule never counts. A strategy whose conditions include neither
|
|
168
|
-
fails first with `NO_ENTRY_CONDITION`, before the trade levels, the ATR
|
|
169
|
-
read, and its draft carries the `NO_ENTRY_CONDITION` warning. It stays a valid strategy — Market Grid
|
|
166
|
+
`required: true` or carries a verdict (`UP`, `DOWN` or `NEITHER`); a building block not marked
|
|
167
|
+
`required` gates nothing, and an exit rule never counts. A strategy whose conditions include neither
|
|
168
|
+
never trades: every coin fails first with `NO_ENTRY_CONDITION`, before the trade levels, the ATR
|
|
169
|
+
floor or any condition is read, and its draft carries the `NO_ENTRY_CONDITION` warning. It stays a valid strategy — Market Grid
|
|
170
170
|
reads it as context — so this is a choice to state, never an accident. When the agent decides a
|
|
171
171
|
routed trade, its `decide_trade` call cites 1–8 of the evaluated entry conditions in
|
|
172
172
|
`conditionChecklist`, and only a condition that read TRUE may be cited as `CONFIRM`.
|
|
173
173
|
|
|
174
|
+
**Building block or inline — the same logic, different reach.** A `conditionRef` reads the
|
|
175
|
+
referenced condition's one answer for the bar being decided — TRUE, FALSE or UNRESOLVED, exactly what
|
|
176
|
+
its tree reads in place — so moving a subtree into a building block, or back, never by itself changes
|
|
177
|
+
a coin's result. What differs is what each form can reach and what each costs.
|
|
178
|
+
|
|
179
|
+
Make it a building block when:
|
|
180
|
+
|
|
181
|
+
- **The tree nests past the depth cap.** "Not a breakout", where a breakout is an `ANY` of `ALL`s,
|
|
182
|
+
is a `NOT` over a group over groups; inside another condition's `ALL` that is one level too deep,
|
|
183
|
+
so the breakout becomes its own building block and the carrier reads `NOT [UP_BREAKOUT]`
|
|
184
|
+
(`CONDITION_GROUP_DEPTH_EXCEEDED` names this remedy).
|
|
185
|
+
- **One condition would pass `budgets.conditionClauses`** (served by `list_strategy_vocabulary`). A
|
|
186
|
+
reference spends no clause and no frame read, so a sub-rule referenced from several conditions is
|
|
187
|
+
counted once; every pasted copy is counted again, against `budgets.conditionFrameReads` too.
|
|
188
|
+
- **The gate is "either side".** Every `required` condition must read TRUE, so marking `RANGE_LONG`
|
|
189
|
+
and `RANGE_SHORT` both required demands both at once. The gate is one building block,
|
|
190
|
+
`SETUP_VALID` = `ANY [RANGE_LONG, RANGE_SHORT]`, marked `required: true`. It is not redundant with
|
|
191
|
+
the carriers' verdicts: the verdict that binds direction is held through a contrary reading until
|
|
192
|
+
that reading repeats for the dwell the binding records (`verdictDwellRequired` on a signal log's
|
|
193
|
+
`verdictBinding`), while a required condition reads the decided bar alone — so the required block
|
|
194
|
+
is what insists the setup is present now.
|
|
195
|
+
- **The sub-rule should be read by name.** A building block's outcome renders under its own key in
|
|
196
|
+
the prompt the agent reads, in the signal log's condition evaluation and in the studio's per-coin
|
|
197
|
+
readout; an inlined clause shows only as evidence under the condition holding it.
|
|
198
|
+
`AT_DEMAND TRUE · FLOW_LONG_OK FALSE` tells the agent and the player why; `RANGE_LONG FALSE` alone
|
|
199
|
+
does not.
|
|
200
|
+
- **It must read TRUE without voting.** Verdict resolution skips a building block, so a location or
|
|
201
|
+
flow test never sets a side and never contradicts a carrier into `NEITHER`.
|
|
202
|
+
|
|
203
|
+
Inline it when:
|
|
204
|
+
|
|
205
|
+
- **It is one clause used once.** As a building block it spends a whole condition slot out of
|
|
206
|
+
`budgets.strategyConditions` for nothing but its name.
|
|
207
|
+
- **The composite must be counted across closes.** A group holding more than Once holds no
|
|
208
|
+
`conditionRef`, so "together on 3 closes in a row" over a sub-rule needs its clauses inline.
|
|
209
|
+
|
|
210
|
+
Inlining a `NOT` is not always a flipped operator. A clause whose read ran and found no value reads
|
|
211
|
+
FALSE, so `NOT [dist_donchianHi gt -0.52]` reads TRUE on a coin with no channel value while
|
|
212
|
+
`dist_donchianHi lte -0.52` reads FALSE; `NOT [CVD_state is "bearish"]` and
|
|
213
|
+
`CVD_state in ["bullish", "neutral"]` part the same way. Flip only a header that always carries a
|
|
214
|
+
value, or choose deliberately which answer a missing value gives.
|
|
215
|
+
|
|
174
216
|
A verdict carrier must read no DEVELOPING bar. A verdict is refused over any closure that reads a
|
|
175
217
|
column selecting Developing above the strategy timeframe (`CONDITION_VERDICT_READ_ILLEGAL`). The
|
|
176
218
|
closure is what the condition reads directly plus everything reached through `conditionRef`,
|
|
@@ -344,7 +386,8 @@ within the buffer of the level is `touch_from_below`. From above is the mirror o
|
|
|
344
386
|
crossing 0: `dist_bbUpper crossesAbove 0` from below, `crossesBelow 0` from above. On the strategy's
|
|
345
387
|
own rung a `…_from_below` label never holds on a bar where `crossesAbove 0` holds.
|
|
346
388
|
- **Which levels take it.** A candle-homed level — a band (`BB_UPPER`, `BB_LOWER`, `KC_UPPER`,
|
|
347
|
-
`
|
|
389
|
+
`KC_LOWER`), `VWAP`, a moving average (`SMA20`, `EMA20`, …), `ST_LINE`, `PSAR`, the Donchian break
|
|
390
|
+
memory (`DONCHIAN_BROKEN_HI`, `DONCHIAN_BROKEN_LO`), the
|
|
348
391
|
Ichimoku lines, the swing levels (`SWING_FRACTAL_HIGH`, `SWING_FRACTAL_LOW`) — reads its own value at
|
|
349
392
|
each of the two bars. A prior-session level or pivot (`PDH`,
|
|
350
393
|
`PDL`, `PDO`, `PIVOT_P`, `PRIOR_TPO_POC`, …) has one reading for the session, used as both bars' level;
|
|
@@ -41,7 +41,7 @@ rather than events all live there. This document assumes them.
|
|
|
41
41
|
and is null otherwise:
|
|
42
42
|
|
|
43
43
|
```json
|
|
44
|
-
{ "metric": "
|
|
44
|
+
{ "metric": "MACD_HIST", "transformId": "crossDetect", "timeframe": { "rel": "anchor" } }
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
An event column is a trigger inside a carrier, never a standing state; pair it with a persistent
|
|
@@ -45,7 +45,7 @@ rules about the columns themselves, not about porting — they live in the skill
|
|
|
45
45
|
`ST_DIR enters "bullish"` is TRUE on the one completed bar the direction turned, and
|
|
46
46
|
`ST_DIR exits "bullish"` on the bar it turned back — see `## Conditions` in the skill body.
|
|
47
47
|
- **MACD + 200 MA filter** → `ABOVE_200` building block (`dist_SMA200 gt 0`) referenced by a
|
|
48
|
-
carrier with `
|
|
48
|
+
carrier with `MACDhist_cross is "Bullish"`; swing-trend geometry.
|
|
49
49
|
- **Golden / Death Cross** → `SMA50 spread SMA200 × trajectory` gives state and freshness:
|
|
50
50
|
`SMA50_SMA200_spread_now gt 0` AND `_trend is "rising"`; optional breadth gate on
|
|
51
51
|
`mktBreadth_crypto gte 0` — every published scope resolves, not only `all`, because the leg reads
|
|
@@ -84,7 +84,11 @@ rules about the columns themselves, not about porting — they live in the skill
|
|
|
84
84
|
script ports onto the two-bar swing, and the spec-lock question says so.
|
|
85
85
|
- **Now native, formerly substituted** — WaveTrend (`WT1`/`WT2`), QQE (`QQE_RSI_MA`/`QQE_STOP`),
|
|
86
86
|
Hull (`HMA20`), Ichimoku (`ICHI_CONV`/`ICHI_BASE`/`ICHI_SPAN_A`/`ICHI_SPAN_B`/`ICHI_LAG`),
|
|
87
|
-
Parabolic SAR (`PSAR`), Keltner (`KC_UPPER`/`
|
|
87
|
+
Parabolic SAR (`PSAR`), Keltner (`KC_UPPER`/`KC_LOWER`, its basis is `EMA20`), the MACD and PPO lines
|
|
88
|
+
and signals (`MACD_LINE`/`MACD_SIGNAL`, `PPO_LINE`/`PPO_SIGNAL` — the line's zero cross is
|
|
89
|
+
`MACD_LINE × crossDetect`, and the signal-line cross is `MACD_HIST × crossDetect`, the histogram being
|
|
90
|
+
line minus signal), the 15-bar rate of change (`ROC15`), the Donchian break memory
|
|
91
|
+
(`DONCHIAN_BROKEN_HI`/`DONCHIAN_BROKEN_LO`), daily pivots
|
|
88
92
|
(`PIVOT_P`/`PIVOT_R1`–`R3`/`PIVOT_S1`–`S3`), Williams %R (`WILLR14`), Stochastic RSI
|
|
89
93
|
(`STOCH_RSI14`), the TTM squeeze (`KC_SQUEEZE`), Connors RSI-2 (`RSI2`), the 9/21/50 EMAs
|
|
90
94
|
(`EMA9`/`EMA21`/`EMA50`), literal previous-session levels (`PDH`/`PDL`/`PDO`), and fractal swing
|