@battlegrid/mcp-server 31.2.51 → 31.2.59
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 +471 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/EXPORT.json +7 -7
- package/skills/battlegrid-agent-management/SKILL.md +39 -20
- package/skills/battlegrid-radar-deployment/SKILL.md +99 -17
- package/skills/battlegrid-strategy-doctor/SKILL.md +20 -11
- package/skills/battlegrid-strategy-examples/SKILL.md +37 -8
- package/skills/battlegrid-strategy-examples/references/playbooks.md +1 -1
- package/skills/battlegrid-trade-proposal/SKILL.md +23 -5
package/README.md
CHANGED
|
@@ -24,6 +24,477 @@ 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 — v77 (agent risk rules: each loss stop on its own rail)
|
|
28
|
+
|
|
29
|
+
**Breaking at v77: an agent's `tradingConfig` accepts less.** `create_intelligence_agent` and
|
|
30
|
+
`update_intelligence_agent` refuse values v76 stored, and one loss stop moves to a different bound.
|
|
31
|
+
|
|
32
|
+
### Rejected input — `tradingConfig`
|
|
33
|
+
|
|
34
|
+
- **`maxLeverage` must be a whole number.** `1.5` was stored and executed at `1`; it is now refused.
|
|
35
|
+
- **`maxSlippageBps` is at most `300`**, the entry slippage ceiling no fill could exceed anyway.
|
|
36
|
+
- **USD fields and the three size presets take at most 2 decimals.**
|
|
37
|
+
- **`maxDailyLossUsd` must be at or below `maxCumulativeDrawdownUsd`.**
|
|
38
|
+
- **A body accepted at v76 can be refused at v77 without one byte of it changing.** Each refusal
|
|
39
|
+
names its field in a plain sentence, such as `Whole numbers only.` or
|
|
40
|
+
`Can’t exceed the drawdown stop ($20.00).`
|
|
41
|
+
|
|
42
|
+
### Wider input — the drawdown stop
|
|
43
|
+
|
|
44
|
+
- **`maxCumulativeDrawdownUsd` is bounded by the platform's drawdown maximum, not by
|
|
45
|
+
`maxConcurrentExposureUsd`.** Max exposure caps margin open at once; the drawdown stop caps loss
|
|
46
|
+
over time. A `$150` drawdown stop on a `$100` max exposure is accepted.
|
|
47
|
+
|
|
48
|
+
### Wider output
|
|
49
|
+
|
|
50
|
+
- **`get_trading_config_catalog` gains `maximumMaxCumulativeDrawdownUsd`**, the drawdown stop's
|
|
51
|
+
upper bound.
|
|
52
|
+
- **The execution-failure reason gains `BELOW_AGENT_MIN_ORDER`** (owner-private) on `get_signal_log`
|
|
53
|
+
and `get_public_agent_signal_log_detail`: an order sized under the agent's own `minAllocationUsd`,
|
|
54
|
+
which was reported as `BELOW_EXCHANGE_MINIMUM`.
|
|
55
|
+
|
|
56
|
+
### Served values
|
|
57
|
+
|
|
58
|
+
- **`get_agent_budget`'s `tradesToday` counts entries filled since 00:00 UTC plus entries still
|
|
59
|
+
waiting to fill.** Refused and expired entries no longer count, and the cap is enforced where an
|
|
60
|
+
entry is created. `DAILY_LIMIT_RESERVED` is no longer emitted.
|
|
61
|
+
- **A daily-loss halt whose drawdown stop is also breached becomes a drawdown halt** when the day
|
|
62
|
+
rolls over, rather than lifting.
|
|
63
|
+
- **A capital-feasibility refusal names what clears it**: the `maxConcurrentExposureUsd` that would,
|
|
64
|
+
and, when one at or above the platform minimum would, a lower `minAllocationUsd`.
|
|
65
|
+
|
|
66
|
+
## Contract history — v76 (the extreme funding signals in percent a year)
|
|
67
|
+
|
|
68
|
+
**Breaking at v76: `funding_extreme_positive` and `funding_extreme_negative` take their threshold in
|
|
69
|
+
percent a year.** Their parameter is `thresholdAnnualizedPct`, the unit of the strategy grammar's
|
|
70
|
+
`ann` column, where it was `thresholdPct`, a fraction of one hourly funding settlement.
|
|
71
|
+
|
|
72
|
+
### Rejected input — the retired `thresholdPct`
|
|
73
|
+
|
|
74
|
+
- **Both signals take `thresholdAnnualizedPct`**, bounded 1–43,800 and defaulting to 100 — the
|
|
75
|
+
funding label's crypto `extreme` band, so `100` means 100% a year, and the negative signal fires
|
|
76
|
+
below -100%.
|
|
77
|
+
- **`thresholdPct` on either signal is refused as `VALIDATION_ERROR`** wherever a rule's parameters
|
|
78
|
+
are authored: `compile_strategy_plan`, `update_strategy_signal_rule`, `derive_strategy_rule_view`
|
|
79
|
+
and a strategy draft's `SIGNAL_RULES` axis. `oi_surge` keeps its own `thresholdPct`.
|
|
80
|
+
- **A body accepted at v75 can be refused at v76 without one byte of it changing.** A rate per hourly
|
|
81
|
+
settlement converts to percent a year by × 8,760 × 100: `0.0002` is `175.2`.
|
|
82
|
+
|
|
83
|
+
### Stale plans
|
|
84
|
+
|
|
85
|
+
- **A plan token compiled before the deploy fails as a stale plan** at `stage_strategy_plan` and
|
|
86
|
+
`apply_strategy_plan`, because the authoring catalog digest covers each signal's parameters,
|
|
87
|
+
defaults and explanation: compile again. The strategy preview's `vocabularyDigest` moves too.
|
|
88
|
+
|
|
89
|
+
### Served values
|
|
90
|
+
|
|
91
|
+
- **`get_strategy_signal_definition` and `list_strategy_signals` serve the new parameter**, its
|
|
92
|
+
default and its explanation.
|
|
93
|
+
- **Each signal's indicator values gain `funding_annualized_pct`**, the annualized rate the signal
|
|
94
|
+
compared, beside `funding_rate`.
|
|
95
|
+
- **Stored rules move to the new key after the deploy**: a rule at the retired default takes `100`,
|
|
96
|
+
and any other converts exactly. `get_coin_signal_preview` and every stored rule then score at the
|
|
97
|
+
new threshold.
|
|
98
|
+
- **No schema hash moves.** Signal parameters are published as a JSON object on every input and
|
|
99
|
+
output, so the change is in the values accepted and served, and `toolCount` is unchanged.
|
|
100
|
+
|
|
101
|
+
## Contract history — v75 (readability from each coin's data profile)
|
|
102
|
+
|
|
103
|
+
**Breaking at v75: the seven tools v73 narrowed refuse by the coin's market-data profile, and one
|
|
104
|
+
output vocabulary gains a member.** Which data a coin carries is now the profile the market-data
|
|
105
|
+
service publishes for that coin, no longer the coin's asset class.
|
|
106
|
+
|
|
107
|
+
### Rejected input — the seven tools v73 narrowed
|
|
108
|
+
|
|
109
|
+
- **A condition reading a kind of data the coin's profile does not serve is refused as
|
|
110
|
+
`INSTRUMENT`**, on the coin or on a benchmark section's own instrument: a spot read on a crypto
|
|
111
|
+
coin no spot venue lists is refused as one on a TradFi coin always was.
|
|
112
|
+
- **A coin the market-data service publishes no profile for refuses every condition that reads
|
|
113
|
+
market data**: a coin enabled since the service's last boot, a roster coin whose candle stream it
|
|
114
|
+
did not subscribe, a ticker with no catalog row.
|
|
115
|
+
- **The tools, codes and `details.context` are v73's**: `preview_radar_resolution` (every kind,
|
|
116
|
+
issuing no `previewToken`); `commit_radar_deployment_draft`, `rebind_intelligence_agent`,
|
|
117
|
+
`compile_strategy_plan` and `restore_strategy` (`VALIDATION_ERROR` with
|
|
118
|
+
`CONDITION_UNREADABLE_BY_RADAR_SCAN`); `apply_strategy_plan`, which applies only what its compile
|
|
119
|
+
checked; and `propose_entry_decision` (`CONDITION_UNREADABLE_ON_COIN`).
|
|
120
|
+
- **A body accepted at v74.1.1 can be refused at v75 without one byte of it changing.** A write whose
|
|
121
|
+
read of the published profiles fails is refused, never admitted unchecked.
|
|
122
|
+
|
|
123
|
+
### Reclassified reason — `FEED` becomes `INSTRUMENT`
|
|
124
|
+
|
|
125
|
+
- **A spot read for a ticker with no catalog row is `INSTRUMENT`, where it was `FEED`**, and an
|
|
126
|
+
uncatalogued benchmark refuses every market-data read, where only its spot reads refused before.
|
|
127
|
+
- **The `INSTRUMENT` message names what the profile lacks**: "`<instrument>`'s market-data profile
|
|
128
|
+
carries no `<kind>` data", or "the market-data service publishes no data profile for
|
|
129
|
+
`<instrument>`, so it carries no market data", where it read "`<instrument>` has no spot tape".
|
|
130
|
+
- **The readings v74 added report it as the sweep does**: `preview_radar_resolution`'s `readings`
|
|
131
|
+
and `get_agent_coin_qualification`'s `reading` mark a condition on a kind the coin's profile lacks
|
|
132
|
+
`INSTRUMENT`.
|
|
133
|
+
|
|
134
|
+
### Wider output — `BarFamily` gains `MARKET_STATS`
|
|
135
|
+
|
|
136
|
+
- **The market-stats snapshot is a per-bar value**: a decision reads the snapshot fetched inside the
|
|
137
|
+
`1m` bar ending at its close. A snapshot missing there is a per-bar shortfall, a `families` entry or
|
|
138
|
+
a MISSED close's `INPUTS_OFF_BAR` `lacking` entry naming `MARKET_STATS` at `1m` with its
|
|
139
|
+
`dueBarStart`, `ABSENT` or `GONE`, and the decision waits or misses as for any per-bar family.
|
|
140
|
+
- **A decided close records no `MARKET_STATS` stale sample.** A reading at the latest values still
|
|
141
|
+
does, and its `boundMs` is the coin's market-stats freshness target, never below 300,000 ms.
|
|
142
|
+
- **Five outputs publish the member**: `get_agent_coin_qualification`, `get_radar_close_decisions`,
|
|
143
|
+
`get_signal_log`, `list_gate_blocks` and `preview_radar_resolution`. No input takes the vocabulary.
|
|
144
|
+
A client that validates results against a cached output schema should list the tools again after
|
|
145
|
+
the server deploys.
|
|
146
|
+
|
|
147
|
+
## Contract history — v74.1.1 (a same-agent request answered from what stopped the fire)
|
|
148
|
+
|
|
149
|
+
**Not breaking: one answer corrected behind unchanged schemas.**
|
|
150
|
+
|
|
151
|
+
- **A request on a pair your own radar policy decides with the same agent** is answered from that
|
|
152
|
+
policy's decision. When the policy's fire enqueued no trade decision and no admission gate refused
|
|
153
|
+
it — a coin cooldown, the hourly fire cap, post-close suppression, a decision already running on the
|
|
154
|
+
coin, a deduplicated fire, or a fire aborted at its re-read — the conversation gains the card the
|
|
155
|
+
request's own unfired fire gets: `close_claimed_by_radar` when another agent's fire holds the coin,
|
|
156
|
+
otherwise `close_refused` with the reading's score against its minimum. It gained
|
|
157
|
+
`close_fired_by_radar` before, though no trade was taken.
|
|
158
|
+
- **Both cards are already in `get_trade_conversation`'s vocabulary**, so no served shape moves.
|
|
159
|
+
|
|
160
|
+
## Contract history — v74.1 (missed-bar alerts and the entry pause)
|
|
161
|
+
|
|
162
|
+
**Not breaking: four output vocabularies gain a member, and `propose_entry_decision` refuses while an
|
|
163
|
+
entry pause is open.** While bars missed for lack of market data span many coins, the platform pauses
|
|
164
|
+
every new entry the radar decides, a radar fire and a manual request alike, and the pause lifts by
|
|
165
|
+
itself after a quiet period.
|
|
166
|
+
|
|
167
|
+
### Refused while a pause is open — `propose_entry_decision`
|
|
168
|
+
|
|
169
|
+
- **A request is refused after its own checks and before a watch is registered**, whatever the agent
|
|
170
|
+
or coin: `type: "error"` with `{ origin: "ENGINE", reasonCode: "ENTRIES_PAUSED" }`. The same
|
|
171
|
+
`idempotencyKey` replays the refusal for five minutes; ask again under a fresh key once the pause
|
|
172
|
+
lifts.
|
|
173
|
+
- **A request queued before the pause** whose close qualifies while it is open gets the same ENGINE
|
|
174
|
+
error card in its conversation, and no decision is proposed. `accept_entry_decision` on a decision
|
|
175
|
+
already proposed, and every exit, run as without a pause.
|
|
176
|
+
|
|
177
|
+
### Wider output — four vocabularies
|
|
178
|
+
|
|
179
|
+
- **`TradeEvaluationAttemptReasonCode` gains `ENTRIES_PAUSED`**: the refusal's `reasonCode`,
|
|
180
|
+
`list_gate_blocks`' `reasonCode`, and the `scanBlockReason` of a refused fire's close record and
|
|
181
|
+
journal row.
|
|
182
|
+
- **`TradingPipelineGateStage` gains `PLATFORM`**: a `list_gate_blocks` entry for each fire the pause
|
|
183
|
+
refused, with no coin, no detail and no decision record.
|
|
184
|
+
- **`RadarFireDisposition` gains `EDGE_PRESERVED_ENTRIES_PAUSED`**: the refused fire keeps its edge,
|
|
185
|
+
so the pair fires at a later close only if that close qualifies on its own data. It is served on
|
|
186
|
+
`get_radar_activity` and `get_radar_activity_summary`, and as a close record's
|
|
187
|
+
`outcome.fireDisposition` beside `outcome.scanBlockReason: "ENTRIES_PAUSED"`, with
|
|
188
|
+
`outcome.outcome` staying `FIRED`.
|
|
189
|
+
- **`RadarIdleReason` gains `ENTRIES_PAUSED`**: the `resolvesNow.reason` of every `SCANNING` card on
|
|
190
|
+
`get_radar_deployment` and `list_radar_deployments` while a pause is open. The section stays
|
|
191
|
+
`SCANNING`, because closes are still decided and recorded.
|
|
192
|
+
|
|
193
|
+
### Answer corrected — a same-agent request
|
|
194
|
+
|
|
195
|
+
- **When an admission gate refused your own policy's fire** — an entry pause, an account block, a
|
|
196
|
+
position already held on the coin — the request's conversation gains that block's ENGINE error card
|
|
197
|
+
instead of `close_fired_by_radar`.
|
|
198
|
+
|
|
199
|
+
## Contract history — v74 (preview `conditionReach` replaced by `readings`)
|
|
200
|
+
|
|
201
|
+
**Breaking at v74: one required output field replaced on one tool, and an opt-in reading added to
|
|
202
|
+
another.** Both now serve what an agent reads on a coin, in the decision-record format v73.3
|
|
203
|
+
introduced.
|
|
204
|
+
|
|
205
|
+
### Reshaped output — `preview_radar_resolution`
|
|
206
|
+
|
|
207
|
+
- **`conditionReach` is gone, replaced by `readings`**: one entry per on-duty agent, in on-duty order,
|
|
208
|
+
each naming `agentId` and `agentDisplayName`. A `kind: "READ"` entry carries the agent's `reading`,
|
|
209
|
+
the one `get_agent_coin_qualification` serves (below). A `kind: "UNSCORABLE"` entry, an agent whose
|
|
210
|
+
evaluation was rejected, carries `coinDataStopped` instead: the coin's stopped-data reading, or
|
|
211
|
+
null. One agent's rejection is its own entry, never a failed preview. The tool always asks for
|
|
212
|
+
readings, so `readings` is null only under a `simulatedRegime`.
|
|
213
|
+
- **`blocksScanGate` has no successor.** Since v73 the preview refuses a slot agent with a condition
|
|
214
|
+
the radar scan cannot read on the coin, so no previewed pair holds a permanently blocking
|
|
215
|
+
condition. Whether the conditions hold the coin is the reading's own gate,
|
|
216
|
+
`reading.live.reading.qualification.gates.requiredConditions`.
|
|
217
|
+
- **Read `reachReason` from the reading.** Each `READ` entry's
|
|
218
|
+
`reading.live.reading.conditions.entries[]` lists the conditions: a `kind: "UNEVALUATED"` entry
|
|
219
|
+
carries the condition's `conditionKey`, `name` and `reachReason`, and a `kind: "EVALUATED"` entry,
|
|
220
|
+
the counterpart of a null `reachReason`, carries its outcome with its clause values.
|
|
221
|
+
`declaration.required` marks the required ones, the set `conditionReach` covered.
|
|
222
|
+
- **A client that validates results against a cached output schema** fails the call until it lists
|
|
223
|
+
the tools again, because the old schema required `conditionReach`. Reconnect, or re-list, after the
|
|
224
|
+
server deploys.
|
|
225
|
+
|
|
226
|
+
### Wider input and output — `get_agent_coin_qualification`
|
|
227
|
+
|
|
228
|
+
- **`reading` (boolean, default false) asks for the pair's reading**, and each verdict gains the
|
|
229
|
+
required-nullable `reading`, null unless asked. A call without the flag is answered as before, with
|
|
230
|
+
`reading: null`.
|
|
231
|
+
- **`reading.live`** is the reading the verdict was built from, with `anchorBarStatus` (`live` while
|
|
232
|
+
the anchor bar still forms), `scoredBarStart` (the bar the signals and gates were scored on) and
|
|
233
|
+
`observedAt`. It is what the agent reads now, not a decision: the radar decides at the close.
|
|
234
|
+
- **`reading.lastClose`** is the deciding reading of the bar the agent's on-duty row names as its
|
|
235
|
+
last close decision: `state: "RECORDED"` with that bar's close-decision `record`,
|
|
236
|
+
`state: "PENDING"` with its `barStart` while that record is being written, or `state: "NONE"`.
|
|
237
|
+
`get_radar_close_decisions` holds the decisions before it.
|
|
238
|
+
|
|
239
|
+
## Contract history — v73.3 (decision records)
|
|
240
|
+
|
|
241
|
+
Purely additive: **one read tool, one evaluation-attempt reason and four output fields added.** What
|
|
242
|
+
a decision read is now served: the radar's close decisions on a coin, the report behind a trade, and
|
|
243
|
+
the compose decision behind a gate block.
|
|
244
|
+
|
|
245
|
+
### Wider surface — one tool added
|
|
246
|
+
|
|
247
|
+
- **`get_radar_close_decisions`** (`coinId`; optional `agentId`, `before`, `limit`; `mcp:read`) — one
|
|
248
|
+
coin's radar close-decision records, newest decided bar first: every bar an agent decided —
|
|
249
|
+
`FIRED`, `CLAIMED`, `NOT_QUALIFIED` or `MISSED` — with the reading it was decided on (a miss's
|
|
250
|
+
answer instead), its fire disposition and its versions. Your own records only: a SYSTEM agent's
|
|
251
|
+
records on a coin belong to every user who deployed it. A page never splits a bar, so it can run
|
|
252
|
+
past `limit`; to page back, pass the oldest record's `bar.barStart` as `before`. `toolCount` goes
|
|
253
|
+
141 → 142.
|
|
254
|
+
|
|
255
|
+
### Wider output — the risk budget, Radar reads, the trade conversation, gate blocks and signal logs
|
|
256
|
+
|
|
257
|
+
- **`TradeEvaluationAttemptReasonCode` may read `SCREENED_OUT`** on `get_agent_budget`,
|
|
258
|
+
`reset_agent_drawdown_baseline`, `get_radar_activity`, `get_radar_deployment`,
|
|
259
|
+
`list_radar_deployments`, `preview_radar_resolution`, `get_trade_conversation`,
|
|
260
|
+
`propose_entry_decision`, `list_gate_blocks`, `get_signal_log` and
|
|
261
|
+
`get_public_agent_signal_log_detail`: compose's deterministic pre-model screen found no routable
|
|
262
|
+
direction. That refusal now writes a gate block. It is public: the public profile carries it as is.
|
|
263
|
+
A client holding its own closed copy of the enum rejects the new member; one that renders unknown
|
|
264
|
+
reasons generically is unaffected.
|
|
265
|
+
- **`get_signal_log`'s `log` gains `reportSections`** (the report the model read, section by section,
|
|
266
|
+
in the shape of `preview_strategy_report`'s `renderedSections`), **`promptDataSerialization`** (the
|
|
267
|
+
serialization it was rendered under) and **`missingData`** (the data compose lacked), each null for
|
|
268
|
+
a trade recorded before capture. `get_public_agent_signal_log_detail` carries none of them.
|
|
269
|
+
- **Each `list_gate_blocks` entry gains `decisionRecord`**: the compose decision record written with
|
|
270
|
+
the block — its outcome, its evidence (the reading compose computed, the per-bar values a refused
|
|
271
|
+
decided bar lacked, or none), its missing data and its versions. It is null for a block written
|
|
272
|
+
before capture and for a block raised before compose.
|
|
273
|
+
|
|
274
|
+
## Contract history — v73.2 (decided-bar refusal)
|
|
275
|
+
|
|
276
|
+
**One member added to the evaluation-attempt reason**, published as output only, and two detail
|
|
277
|
+
fields added to gate blocks. A confirming-close fire now names the bar it decided, and compose reads
|
|
278
|
+
that bar or refuses with the new reason, instead of reading the newest completed bar at its own
|
|
279
|
+
instant.
|
|
280
|
+
|
|
281
|
+
### Wider output — the risk budget, Radar reads, the trade conversation, gate blocks and signal logs
|
|
282
|
+
|
|
283
|
+
- **`TradeEvaluationAttemptReasonCode` may read `DECIDED_BAR_UNAVAILABLE`** on `get_agent_budget`,
|
|
284
|
+
`reset_agent_drawdown_baseline`, `get_radar_activity`, `get_radar_deployment`,
|
|
285
|
+
`list_radar_deployments`, `preview_radar_resolution`, `get_trade_conversation`,
|
|
286
|
+
`propose_entry_decision`, `list_gate_blocks`, `get_signal_log` and
|
|
287
|
+
`get_public_agent_signal_log_detail`: compose refused a radar fire at the conditions stage, before
|
|
288
|
+
any LLM call, because a per-bar value its conditions gate reads was not on its due bar for the bar
|
|
289
|
+
the radar decided — its entry had not landed, or had gone. It is public: the public profile carries
|
|
290
|
+
it as is. A client holding its own closed copy of the enum rejects the new member; one that renders
|
|
291
|
+
unknown reasons generically is unaffected.
|
|
292
|
+
- **`list_gate_blocks`' `reasonDetail` gains `decidedBarStart`** (ISO 8601, the decided bar's open)
|
|
293
|
+
**and `decidedBarTimeframe`** (the strategy timeframe), present on that reason alone.
|
|
294
|
+
|
|
295
|
+
## Contract history — v73.1 (strategy card fields)
|
|
296
|
+
|
|
297
|
+
Purely additive: **thirteen read-only fields added to every `list_strategies` row.** The input is
|
|
298
|
+
unchanged, and a client that ignores the fields is unaffected.
|
|
299
|
+
|
|
300
|
+
### Wider output — `list_strategies`
|
|
301
|
+
|
|
302
|
+
- **The strategy card:** `regimeTimeframe` and `lowerTimeframe` (the derived ladder rungs
|
|
303
|
+
`get_strategy` already serves); `conditionTally`, `signalRuleTally` and `exitTally` (`armed` out of
|
|
304
|
+
`total`, the four exit mechanisms); and `minRequiredCount`, `entryTrigger`, `minRiskRewardRatio` and
|
|
305
|
+
`maxStopLossAtrMultiple`.
|
|
306
|
+
- **`forkedFromStrategyName`**, null when the strategy is not a fork or its source is neither yours
|
|
307
|
+
nor a SYSTEM strategy.
|
|
308
|
+
- **`viewerBoundAgentCount` and `viewerOpenPositionCount`**, your own agents on the strategy and their
|
|
309
|
+
open positions. `boundAgentCount` still counts every user's agents; read the viewer fields for
|
|
310
|
+
yours.
|
|
311
|
+
- **`viewerPerformance`**, your own all-time results on the strategy, null when you never traded it.
|
|
312
|
+
A trade counts toward the strategy recorded on the signal log that opened it, so rebinding an agent
|
|
313
|
+
never moves it.
|
|
314
|
+
|
|
315
|
+
## Contract history — v73 (unreadable radar conditions refused)
|
|
316
|
+
|
|
317
|
+
**Breaking at v73: seven tools refuse bodies they used to accept, behind unchanged input schemas.**
|
|
318
|
+
A condition the radar acts on — a required one, a direction-setting one (a verdict carrier), an exit
|
|
319
|
+
one, and every condition they reference — must be readable by the radar scan on every coin the radar
|
|
320
|
+
acts on for its agent: each coin a Radar policy slots it on, enabled or paused; each coin it holds an
|
|
321
|
+
open position on, for its exit conditions; and each coin it has a pending manual request on.
|
|
322
|
+
|
|
323
|
+
### Rejected input — refused behind unchanged schemas
|
|
324
|
+
|
|
325
|
+
- **`VALIDATION_ERROR` with the authoring code `CONDITION_UNREADABLE_BY_RADAR_SCAN`** from
|
|
326
|
+
`preview_radar_resolution` (every kind, for every slot agent whether on duty now or not, issuing no
|
|
327
|
+
`previewToken`), `commit_radar_deployment_draft`, `rebind_intelligence_agent`, and
|
|
328
|
+
`compile_strategy_plan` and `restore_strategy` on behalf of the bound agents the radar acts on (a
|
|
329
|
+
strategy none of whose agents holds a slot, an open position or a pending request is never
|
|
330
|
+
checked). `details.context.reachReason` says why: `INSTRUMENT` (the coin, or a benchmark section's
|
|
331
|
+
own instrument, has no such data), `AGENT_TIMEFRAME` (the agent has no such rung) or `FEED` (the
|
|
332
|
+
radar scan never reads that data: crowd reads, a spot read for an uncatalogued ticker, a timeframe
|
|
333
|
+
the agent's plan does not load).
|
|
334
|
+
- **The message names the first conflicting agent, the condition, the column, the coin and the
|
|
335
|
+
fixes**: stop the radar acting on the condition, make it read a column the scan has on that coin,
|
|
336
|
+
or free the coin — take the agent off that coin's policy, close the position, or cancel the pending
|
|
337
|
+
request. It is a fact about the pair, which no later sweep changes.
|
|
338
|
+
- **A refused compile issues no plan token**, so `stage_strategy_plan` cannot stage that content, and
|
|
339
|
+
**`apply_strategy_plan` applies only a plan whose bound agents still hold the radar slot coins its
|
|
340
|
+
compile checked**: a plan compiled before a deploy moved them fails verification. Compile again.
|
|
341
|
+
- **A condition reading a Session Field scalar** keeps `CONDITION_OPERAND_UNSERVED_IN_LANE`, now
|
|
342
|
+
refused at the rebind and every strategy revision too, not only at the deploy.
|
|
343
|
+
- `stage_radar_deployment_draft` is unchanged: a draft holds no slot, and the preview its commit
|
|
344
|
+
needs refuses. A body accepted under v72 is refused under v73 without one byte of it changing.
|
|
345
|
+
|
|
346
|
+
### Wider output — `propose_entry_decision`, `get_trade_conversation`
|
|
347
|
+
|
|
348
|
+
- **`propose_entry_decision` refuses a request whose agent the radar scan cannot read on the
|
|
349
|
+
requested coin**, before its watch is registered, and releases its idempotency claim. It returns
|
|
350
|
+
`type: "error"` with `error: { reasonCode: "CONDITION_UNREADABLE_ON_COIN", unreadable: {
|
|
351
|
+
conditionKey, conditionName, column, coinTicker, reachReason } }`: facts only, no prose. Choose
|
|
352
|
+
another coin, another agent, or a condition reading a column the radar reads on that coin, and
|
|
353
|
+
send it again. `get_trade_conversation`'s error card carries the same `reasonCode` and
|
|
354
|
+
`unreadable`.
|
|
355
|
+
- **A client that validates results against a cached output schema** fails a call that returns the
|
|
356
|
+
new error until it lists the tools again, because the old schema has no such member. Reconnect, or
|
|
357
|
+
re-list, after the server deploys.
|
|
358
|
+
|
|
359
|
+
### Refusals worth knowing before you apply, restore or rebind
|
|
360
|
+
|
|
361
|
+
- **`CONFLICT` with `details.reason: "RADAR_DEPLOYMENT_MOVED"`** from `apply_strategy_plan`,
|
|
362
|
+
`restore_strategy` and `rebind_intelligence_agent`: the agents' radar slot coins moved after the
|
|
363
|
+
write's check. Re-read and retry, so the retry's check covers the moved deployment; for a plan,
|
|
364
|
+
compile again.
|
|
365
|
+
- **`commit_radar_deployment_draft` is a `CONFLICT`** when a slot agent's strategy or timeframes
|
|
366
|
+
changed after its check. Preview again.
|
|
367
|
+
|
|
368
|
+
## Contract history — v72.0.1 (account read faults withheld on the public profile)
|
|
369
|
+
|
|
370
|
+
**No schema change: one value reclassified on one public read.**
|
|
371
|
+
|
|
372
|
+
### Reclassified output — `get_public_agent_signal_log_detail`
|
|
373
|
+
|
|
374
|
+
- **`pipeline.attempt.reasonCodes` carries `OWNER_PRIVATE`, with its detail omitted, where it would
|
|
375
|
+
have carried `EQUITY_CHECK_UNAVAILABLE`, `ALLOCATION_CHECK_UNAVAILABLE`,
|
|
376
|
+
`DAILY_COUNT_CHECK_UNAVAILABLE` or `APPROVAL_CHECK_UNAVAILABLE`.** Each says the account has an open
|
|
377
|
+
block, which the public profile withholds. This supersedes the v71.1 note below that the public
|
|
378
|
+
detail carries the two faults v71.1 added. `OWNER_PRIVATE` has been in that field's schema since
|
|
379
|
+
v71, so a client validating against a cached output schema accepts it. `get_signal_log` still
|
|
380
|
+
carries every precise code on your own agents.
|
|
381
|
+
|
|
382
|
+
## Contract history — v72 (public decision `userId` removed)
|
|
383
|
+
|
|
384
|
+
**Breaking at v72: one output field removed from one public read.**
|
|
385
|
+
|
|
386
|
+
### Removed output — `get_public_agent_signal_log_detail`
|
|
387
|
+
|
|
388
|
+
- **`log.linkedEntryDecision.userId` is gone.** It was the user the agent acted for. On a SYSTEM
|
|
389
|
+
agent, which has no author and which any user may deploy, that named whoever deployed it, and the
|
|
390
|
+
public profile deliberately shows no owner for a SYSTEM agent. There is **no replacement path** on
|
|
391
|
+
the public read. A PRIVATE agent's author is `ownerUserId` on the agent's public profile, and the
|
|
392
|
+
owner tool `get_signal_log` still carries `linkedEntryDecision.userId` on your own agents.
|
|
393
|
+
- **A client that validates results against a cached output schema** fails the call until it lists
|
|
394
|
+
the tools again, because the old schema required the field. Reconnect, or re-list, after the server
|
|
395
|
+
deploys.
|
|
396
|
+
|
|
397
|
+
## Contract history — v71.1 (two read-fault refusals)
|
|
398
|
+
|
|
399
|
+
**Two members added to the evaluation-attempt reason**, published as output only. When the server
|
|
400
|
+
cannot read an agent's daily trade count or its trading account's approval, the admission is blocked
|
|
401
|
+
with its own reason instead of borrowing the verdict it could not reach.
|
|
402
|
+
|
|
403
|
+
### Wider output — the risk budget, Radar reads, the trade conversation, gate blocks and signal logs
|
|
404
|
+
|
|
405
|
+
- **`TradeEvaluationAttemptReasonCode` may read `DAILY_COUNT_CHECK_UNAVAILABLE` or
|
|
406
|
+
`APPROVAL_CHECK_UNAVAILABLE`** on `get_agent_budget`, `reset_agent_drawdown_baseline`,
|
|
407
|
+
`get_radar_activity`, `get_radar_deployment`, `list_radar_deployments`, `preview_radar_resolution`,
|
|
408
|
+
`get_trade_conversation`, `propose_entry_decision`, `list_gate_blocks`, `get_signal_log` and
|
|
409
|
+
`get_public_agent_signal_log_detail`. `DAILY_TRADE_LIMIT_REACHED` and `AGENT_APPROVAL_EXPIRED` still
|
|
410
|
+
mean what they say. A client holding its own closed copy of the enum rejects the new members; one
|
|
411
|
+
that renders unknown reasons generically is unaffected.
|
|
412
|
+
|
|
413
|
+
## Contract history — v71 (owner-private reasons on the public profile)
|
|
414
|
+
|
|
415
|
+
**Breaking at v71: two public inputs narrow, and one public output widens.**
|
|
416
|
+
|
|
417
|
+
### Rejected input — `get_public_agent_signal_logs`, `get_public_agent_realized_trades`
|
|
418
|
+
|
|
419
|
+
- **`filter.rejectionReason` refuses the six owner-private failure reasons** —
|
|
420
|
+
`BELOW_EXCHANGE_MINIMUM`, `INSUFFICIENT_BALANCE`, `INSUFFICIENT_MARGIN`,
|
|
421
|
+
`AGENT_APPROVAL_EXPIRED`, `SIGNING_KEY_UNAVAILABLE`, `AGENT_HALTED` — with a validation error,
|
|
422
|
+
where they used to filter. These tools read another user's agent, and a private reason answered a
|
|
423
|
+
question about that user's budget, margin, approval, key or halt. No alias exists; filter by a
|
|
424
|
+
public reason. `filter.expiryReason` still accepts every member.
|
|
425
|
+
|
|
426
|
+
### Wider output — `get_public_agent_signal_log_detail`
|
|
427
|
+
|
|
428
|
+
- **`pipeline.attempt.reasonCodes`, `pipeline.execution.failureReason` and `.expiryReason` may read
|
|
429
|
+
`OWNER_PRIVATE`** in place of an owner-private reason, whose detail is then omitted. A client
|
|
430
|
+
holding its own closed copy of these enums rejects the new member; one that renders unknown
|
|
431
|
+
reasons generically is unaffected. A failed execution's `executionMessage` is now always null.
|
|
432
|
+
- **`get_signal_log` is unchanged**: on your own agents it still carries every precise code, its
|
|
433
|
+
detail and the narrative.
|
|
434
|
+
|
|
435
|
+
## Contract history — v70.2 (allocation-check refusal)
|
|
436
|
+
|
|
437
|
+
**One member added to the evaluation-attempt reason**, published as output only. An admission the
|
|
438
|
+
server blocked because it could not read the account's allocation now carries
|
|
439
|
+
`ALLOCATION_CHECK_UNAVAILABLE`; `NO_AGENT_ALLOCATION` survives only on historical rows.
|
|
440
|
+
|
|
441
|
+
### Wider output — the risk budget, Radar reads, the trade conversation and gate blocks
|
|
442
|
+
|
|
443
|
+
- **`TradeEvaluationAttemptReasonCode` may read `ALLOCATION_CHECK_UNAVAILABLE`** on
|
|
444
|
+
`get_agent_budget`, `reset_agent_drawdown_baseline`, `get_radar_activity`, `get_radar_deployment`,
|
|
445
|
+
`list_radar_deployments`, `preview_radar_resolution`, `get_trade_conversation`,
|
|
446
|
+
`propose_entry_decision` and `list_gate_blocks`. A client holding its own closed copy of the enum
|
|
447
|
+
rejects the new member; one that renders unknown reasons generically is unaffected.
|
|
448
|
+
- **The reason detail no longer declares `availableUsd` or `requiredUsd`** (`get_signal_log`,
|
|
449
|
+
`get_public_agent_signal_log_detail`). No response ever carried them.
|
|
450
|
+
|
|
451
|
+
## Contract history — v70 (risk-gauge `configured` removed)
|
|
452
|
+
|
|
453
|
+
**Breaking at v70: one output field removed from every risk-budget gauge.**
|
|
454
|
+
|
|
455
|
+
### Reshaped output — `get_agent_budget`, `reset_agent_drawdown_baseline`
|
|
456
|
+
|
|
457
|
+
- **`budget.gauges.<gauge>.configured` is gone** from all four gauges (`dailyTrades`, `exposure`,
|
|
458
|
+
`drawdown`, `dailyLoss`). It could only read `true`: the daily-trades cap is at least 1, and an
|
|
459
|
+
agent's exposure ceiling, drawdown stop and daily-loss stop are all required and strictly positive.
|
|
460
|
+
Every gauge has a limit, so read `fill`, `remaining` and `breached` and render every meter enabled.
|
|
461
|
+
- **A client that validates results against a cached output schema** fails the call until it lists
|
|
462
|
+
the tools again, because the old schema required the field. Reconnect, or re-list, after the server
|
|
463
|
+
deploys.
|
|
464
|
+
|
|
465
|
+
## Contract history — v69.7 (insufficient-margin refusal)
|
|
466
|
+
|
|
467
|
+
Purely additive: **one member added to the trade-failure reason**, in both directions. An agent entry
|
|
468
|
+
the shared trading account cannot post the isolated margin for is now refused before any order is
|
|
469
|
+
sent, with its own reason. The same reason replaces `EXCHANGE_ERROR` when the exchange refuses an
|
|
470
|
+
order for margin first.
|
|
471
|
+
|
|
472
|
+
### Wider input — `get_public_agent_signal_logs`, `get_public_agent_realized_trades`
|
|
473
|
+
|
|
474
|
+
- **`filter.rejectionReason` accepts `INSUFFICIENT_MARGIN`**, where it used to refuse it.
|
|
475
|
+
|
|
476
|
+
### Wider output — `get_signal_log`, `get_public_agent_signal_log_detail`
|
|
477
|
+
|
|
478
|
+
- **`failureReason` may read `INSUFFICIENT_MARGIN`.** A client that switches exhaustively on the
|
|
479
|
+
reason needs one more arm; one that renders unknown reasons generically is unaffected.
|
|
480
|
+
|
|
481
|
+
## Contract history — v69.5 (liquidation-buffer refusal)
|
|
482
|
+
|
|
483
|
+
Purely additive: **one member added to the trade-failure reason**, in both directions. An agent entry
|
|
484
|
+
whose hard stop no whole leverage can keep clear of liquidation is now refused before any order is
|
|
485
|
+
sent, with its own reason. Below that, an agent order's reported effective leverage may sit under the
|
|
486
|
+
agent's bound: it is lowered until the isolated liquidation is at least twice as far from the fill as
|
|
487
|
+
the hard stop.
|
|
488
|
+
|
|
489
|
+
### Wider input — `get_public_agent_signal_logs`, `get_public_agent_realized_trades`
|
|
490
|
+
|
|
491
|
+
- **`filter.rejectionReason` accepts `LIQUIDATION_BUFFER_UNREACHABLE`**, where it used to refuse it.
|
|
492
|
+
|
|
493
|
+
### Wider output — `get_signal_log`, `get_public_agent_signal_log_detail`
|
|
494
|
+
|
|
495
|
+
- **`failureReason` may read `LIQUIDATION_BUFFER_UNREACHABLE`.** A client that switches exhaustively on
|
|
496
|
+
the reason needs one more arm; one that renders unknown reasons generically is unaffected.
|
|
497
|
+
|
|
27
498
|
## Contract history — v69 (Radar multi-agent duty)
|
|
28
499
|
|
|
29
500
|
**Breaking: one input removed from two tools, three outputs reshaped.** A Radar policy carries no
|
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.59";
|
|
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.59';
|
|
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,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"generator": "battlegrid-app/server/scripts/export-mcp-skills.mjs",
|
|
3
|
-
"contractVersion": "
|
|
3
|
+
"contractVersion": "76.0.0",
|
|
4
4
|
"files": {
|
|
5
|
-
"battlegrid-agent-management/SKILL.md": "
|
|
5
|
+
"battlegrid-agent-management/SKILL.md": "5ea8384ff76ccb9fdf00e4ec8b584f88fdba6d1c9d5679ce0b7380c23bfbaab1",
|
|
6
6
|
"battlegrid-arena-play/SKILL.md": "4cfaa92a8d0dcaf477b227abd774e7aa8642c185d72108dfd401be0cf8aecd7f",
|
|
7
7
|
"battlegrid-market-analysis/SKILL.md": "22fde9c4eac0261c89a8056ab8b20b66fcbe1fd58447fa0ac84fd410b4d134d7",
|
|
8
|
-
"battlegrid-radar-deployment/SKILL.md": "
|
|
8
|
+
"battlegrid-radar-deployment/SKILL.md": "17301fa66f4b128154435462ffa967efcb3d016df671b03c485d0f8b840fc891",
|
|
9
9
|
"battlegrid-strategy-authoring/SKILL.md": "95e91dd1ff36922b7ed0f5eb92c98def98fa39cce37c3d7447269aea1b5a017f",
|
|
10
|
-
"battlegrid-strategy-doctor/SKILL.md": "
|
|
11
|
-
"battlegrid-strategy-examples/SKILL.md": "
|
|
12
|
-
"battlegrid-strategy-examples/references/playbooks.md": "
|
|
10
|
+
"battlegrid-strategy-doctor/SKILL.md": "a3446f24059be72ae797ba4e9669848d851ac3dc38675923fe3d307f557eb82f",
|
|
11
|
+
"battlegrid-strategy-examples/SKILL.md": "a60b766de81f859f2fa9b352d65937b6a6f3eb24c4e88a064123a4985906bce5",
|
|
12
|
+
"battlegrid-strategy-examples/references/playbooks.md": "02168e3af35268a30fd156f3337d25fe15e6df67da1592f4cb4d31090be3f94f",
|
|
13
13
|
"battlegrid-strategy-examples/references/recipes.md": "53887daece17995543e7d3fe1bf2577fc41a6254c291acacde48d7de63853641",
|
|
14
14
|
"battlegrid-strategy-examples/references/tradingview-ports.md": "2b13adbc137178955edcca31b6ab40c01c745a932a0750b91db8820c736700bb",
|
|
15
15
|
"battlegrid-trade-analysis/SKILL.md": "f49482702f17d7fc44db00c31a19fc6e9350668fe76e8948d22faaa9c7e9d6bf",
|
|
16
|
-
"battlegrid-trade-proposal/SKILL.md": "
|
|
16
|
+
"battlegrid-trade-proposal/SKILL.md": "9bf7b7648fb009db118a3a428b15abf38df5ba56a2ef4c8a4eae3d979bdc8bcb"
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -25,8 +25,8 @@ step named beside it before doing anything else.
|
|
|
25
25
|
configuration change to an agent the player is mid-edit on is staged, not committed. → steps 3
|
|
26
26
|
and 4.
|
|
27
27
|
3. **Mis-lever'd halt recovery.** *Cue: "why is it stopped", "start it again", any halted agent.*
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
The halt reason says why the agent stopped, not what clears it. Offering an exit the server's
|
|
29
|
+
resume verdict does not offer is offering something that cannot work. → step 5.
|
|
30
30
|
4. **Driving strategy writes from this arc.** *Cue: the answer to an agent problem turns out to be
|
|
31
31
|
"change the strategy".* You can SEE strategies here because you must name what you bind. That is
|
|
32
32
|
not permission to author them. → the cross-skill rule below.
|
|
@@ -118,7 +118,16 @@ mid-edit in their form.** Then:
|
|
|
118
118
|
- `discard_agent_draft` only on the player's word: call it with `confirm:false` first, tell them
|
|
119
119
|
when the draft was last written and from which surface, ask, then confirm.
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
**In a conversation the agent console hosts** — your context names the agent console and an agent
|
|
122
|
+
id — the player's form is open on that agent whether or not a draft exists yet. Stage every change
|
|
123
|
+
into that agent's draft, naming that id as `agentId`, create or edit alike: the create recipe's
|
|
124
|
+
omitted id does not apply there, because the screen already holds the id the agent will be created
|
|
125
|
+
at. Create, update, rebind and discard are refused there — the player's own Create, Save or Discard
|
|
126
|
+
is the act. On an existing agent a strategy change is a recommendation the player picks in the
|
|
127
|
+
Strategy step. An axis their form rewrote after your proposal — typed over or undone — is their
|
|
128
|
+
answer: propose it again only on their word.
|
|
129
|
+
|
|
130
|
+
With **no draft open**, the update verb below stands, confirm and all — outside the agent console.
|
|
122
131
|
|
|
123
132
|
### 4. Lifecycle verbs: read first, state the radius, then confirm
|
|
124
133
|
|
|
@@ -152,23 +161,33 @@ the reason, and name what would clear it (un-deploy via the radar/deployment too
|
|
|
152
161
|
the positions resolve, wait for the session to settle). Never paraphrase the refusal into "it
|
|
153
162
|
didn't work", and never retry it unchanged.
|
|
154
163
|
|
|
155
|
-
### 5. Halt recovery:
|
|
156
|
-
|
|
157
|
-
`get_agent_budget` serves `haltReason
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
- **
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
-
|
|
165
|
-
`
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
164
|
+
### 5. Halt recovery: offer exactly the served verdict's exits
|
|
165
|
+
|
|
166
|
+
`get_agent_budget` serves `haltReason` — why the agent stopped — and `haltResumeEligibility`, the
|
|
167
|
+
server's resume verdict. **The verdict decides the recovery**; the reason only explains the stop.
|
|
168
|
+
|
|
169
|
+
- **`haltResumeEligibility` is null** — the agent is not halted. Every halt carries a verdict, one
|
|
170
|
+
the player set by hand included, and is recovered through it.
|
|
171
|
+
- **`eligible: true`** — nothing is still breached, and a resume will succeed. Offer
|
|
172
|
+
`resume_intelligence_agent`.
|
|
173
|
+
- **`eligible: false`** — `breachedStop` names the stop still breached, with `breachingFigureUsd`
|
|
174
|
+
against `limitUsd`. Present that stop and exactly the exits the verdict marks open:
|
|
175
|
+
- `canRaiseTriggeringStop` — raise that stop above the figure through the update verb
|
|
176
|
+
(`maxCumulativeDrawdownUsd` for the drawdown stop, `maxDailyLossUsd` for the daily loss limit);
|
|
177
|
+
- `canResetBaseline` — `reset_agent_drawdown_baseline`, which acknowledges the loss and re-arms
|
|
178
|
+
the drawdown stop from today (it erases no history and journals the acknowledgement);
|
|
179
|
+
- a `breachedStop` of `DAILY_LOSS` also clears at the UTC-day rollover.
|
|
180
|
+
|
|
181
|
+
Then resume. An exit the verdict does not mark open is never offered.
|
|
182
|
+
|
|
183
|
+
After any resume, read the response's `haltedAt`. The server re-checks every stop once the halt is
|
|
184
|
+
cleared, so a set `haltedAt` means the agent was halted again at once: a loss settled, or a stop was
|
|
185
|
+
lowered, while the resume ran. Read `get_agent_budget` again and present its `haltReason` and
|
|
186
|
+
verdict; never report that agent as trading.
|
|
187
|
+
|
|
188
|
+
**A resume attempted while a stop is still breached is refused by the server**, naming the same
|
|
189
|
+
stop, figure and exits. Surface them as served. Do not retry the resume; after a raise or a reset,
|
|
190
|
+
read the verdict again rather than assuming it cleared.
|
|
172
191
|
|
|
173
192
|
### 6. Risk limits are a whole object
|
|
174
193
|
|
|
@@ -51,7 +51,10 @@ Then read what exists:
|
|
|
51
51
|
|
|
52
52
|
- `get_radar_deployment` (one coin) or `list_radar_deployments` (the fleet, plus the platform
|
|
53
53
|
`radarPaused` kill-switch — if that is set, say so up front: nothing will fire whatever you
|
|
54
|
-
write).
|
|
54
|
+
write). A `SCANNING` card whose reason is `ENTRIES_PAUSED` is the platform's **entry pause**: new
|
|
55
|
+
entries are paused platform-wide while market data is missing across many coins. Say that up front
|
|
56
|
+
too — the radar takes no new entry on any coin until it lifts, which it does by itself once the
|
|
57
|
+
data is back, and nothing the player changes on a deployment clears it.
|
|
55
58
|
- **For Radar, also read the player's draft of the coin** with `get_radar_deployment_draft` — or
|
|
56
59
|
`list_radar_deployment_drafts` when no coin is named yet. The player may be part-way through a
|
|
57
60
|
change in their radar builder. **If a draft exists, say so** — what it holds, and when and from
|
|
@@ -104,17 +107,62 @@ repeatedly while iterating is free and correct.
|
|
|
104
107
|
Render the preview as a card and read it out. For **Radar**: the coin's `section` and any typed idle
|
|
105
108
|
or blocked reason, then every row of `resolvesNow.onDuty` in the order served — each agent, the slot
|
|
106
109
|
and priority that put it on duty, its regime reading at its own `regimeTimeframe` with conviction, its
|
|
107
|
-
qualification verdict and its close clock — and
|
|
108
|
-
|
|
109
|
-
what priority, the regime and conviction used, and the qualification
|
|
110
|
-
the server sends it — never re-derive it, and never pick, rank or drop
|
|
111
|
-
reason does not mean idle (`ON_DUTY_BUT_POSITION_BLOCKED` carries a reason
|
|
112
|
-
deciding the headline yourself gets it wrong. `enabledAfterCommit` says whether
|
|
113
|
-
once committed — a paused policy stays paused, and a first Arena deployment
|
|
110
|
+
qualification verdict and its close clock — and `readings`, one entry per on-duty agent in the same
|
|
111
|
+
order: what that agent reads on the coin right now (below). For **Arena**: which agent goes on duty,
|
|
112
|
+
which slot matched and at what priority, the regime and conviction used, and the qualification
|
|
113
|
+
verdict. **Render `section` as the server sends it — never re-derive it, and never pick, rank or drop
|
|
114
|
+
rows yourself.** A non-null reason does not mean idle (`ON_DUTY_BUT_POSITION_BLOCKED` carries a reason
|
|
115
|
+
and is not idle), so deciding the headline yourself gets it wrong. `enabledAfterCommit` says whether
|
|
116
|
+
the policy will play once committed — a paused policy stays paused, and a first Arena deployment
|
|
117
|
+
always plays. A Radar preview simulates a running platform, so it never reports the kill switch or an
|
|
118
|
+
entry pause: those come from step 1's read.
|
|
114
119
|
|
|
115
120
|
**If anything changes after a preview, re-preview.** A preview never vouches for what it did not
|
|
116
121
|
resolve.
|
|
117
122
|
|
|
123
|
+
**A Radar preview refuses an agent the scan cannot read on the coin.** Every slot agent, on duty now
|
|
124
|
+
or not, must have every condition the radar acts on — its required conditions, the ones carrying a
|
|
125
|
+
verdict, its exit conditions, and every condition they reference — readable by the radar scan on this
|
|
126
|
+
coin. When one is not, the preview itself is refused, issues no certificate, and nothing can be
|
|
127
|
+
committed: `CONDITION_UNREADABLE_BY_RADAR_SCAN`, whose `details.context.reachReason` says why
|
|
128
|
+
(`INSTRUMENT` — the market-data profile of the coin, or of a benchmark section's own instrument, carries
|
|
129
|
+
no such data, or the market-data service publishes no profile for it at all: the refusal names the kind
|
|
130
|
+
of data the profile lacks, or says there is none; `AGENT_TIMEFRAME` — the agent has no such rung;
|
|
131
|
+
`FEED` — the radar scan never reads that data for this agent), or
|
|
132
|
+
`CONDITION_OPERAND_UNSERVED_IN_LANE` for a session-field scalar. Read the player the refusal as served:
|
|
133
|
+
it names the agent, the condition, the column and the fixes — stop the radar acting on the condition,
|
|
134
|
+
make it read a column the radar scan has on that coin, or take the agent off the coin. A commit
|
|
135
|
+
re-checks the same rule, so a strategy edit landing after the preview can still refuse it.
|
|
136
|
+
|
|
137
|
+
**`readings` is each on-duty agent's requirements, read now.** A `READ` entry carries the agent's
|
|
138
|
+
`reading` — the same one `get_agent_coin_qualification` returns with `reading: true`, through the same
|
|
139
|
+
resolver:
|
|
140
|
+
|
|
141
|
+
- `reading.live` is the reading its qualification verdict was built from: the gates with their margins
|
|
142
|
+
(`qualification`); every entry-lane condition — required, direction-setting, and the ones they
|
|
143
|
+
reference — with its outcome and its clause values against their thresholds
|
|
144
|
+
(`conditions.entries[]`); the allocated signals with their attribution; and the data it lacked
|
|
145
|
+
(`missingData`). An `UNEVALUATED` entry is a condition this tick could not read, with its
|
|
146
|
+
`reachReason`. A pair the scan can never read was refused above, so every such cause is one the next
|
|
147
|
+
sweep can change — report it as the current reading, never as a reason the deployment will not
|
|
148
|
+
work. `anchorBarStatus` says which bar the conditions read (`live` while it is still forming), and
|
|
149
|
+
`scoredBarStart` names the bar the signals and gates were scored on. **A live reading decides
|
|
150
|
+
nothing**: the radar decides at the close, on the closed bar, so say what it reads right now, never
|
|
151
|
+
that it will fire.
|
|
152
|
+
- `reading.lastClose` is the one decision the agent's on-duty row names as its last close: `RECORDED`
|
|
153
|
+
with that bar's close-decision record — the reading it was decided on, or why it was missed —
|
|
154
|
+
`PENDING` while that record is still being written, or `NONE` when the pair remembers no decision.
|
|
155
|
+
For the decisions before it, call `get_radar_close_decisions` (step 5).
|
|
156
|
+
|
|
157
|
+
An `UNSCORABLE` entry is an on-duty agent the preview could not read on the coin, with
|
|
158
|
+
`coinDataStopped` when the coin's data explains why; it never fails the preview. `readings` is null
|
|
159
|
+
under a simulated regime: duty is simulated there, and every reading would judge the real one.
|
|
160
|
+
|
|
161
|
+
There is no `conditionReach` list and no `blocksScanGate` flag (contract 74.0.0). A condition's reach
|
|
162
|
+
reason is its `UNEVALUATED` entry's `reachReason` in
|
|
163
|
+
`readings[].reading.live.reading.conditions.entries[]`, and whether the conditions hold the coin is the
|
|
164
|
+
reading's own conditions gate, `qualification.gates.requiredConditions` — never a verdict of your own.
|
|
165
|
+
|
|
118
166
|
### 3. Confirm against the preview, then commit
|
|
119
167
|
|
|
120
168
|
One confirmation whose question **references what the preview showed** — the agents it put on duty and
|
|
@@ -176,16 +224,28 @@ eligible, what the policy was firing on, and that the slots are not recoverable.
|
|
|
176
224
|
`pause_radar_deployment` for Radar and `pause_deployment_policy` for Arena. Offer that
|
|
177
225
|
whenever the ask sounds like "pause", "stop for now", or "take it off duty for a while".
|
|
178
226
|
|
|
179
|
-
### 5. "Why isn't it firing?" — state, then pattern, then rows
|
|
227
|
+
### 5. "Why isn't it firing?" — state, then pattern, then the bar, then rows
|
|
180
228
|
|
|
181
|
-
|
|
229
|
+
Four reads, cheapest first. Stop as soon as the player's question is answered.
|
|
182
230
|
|
|
183
231
|
1. **`get_radar_deployment` → `resolvesNow`** for what is true **right now**: the coin's section and
|
|
184
232
|
reason, and one `onDuty` row per agent — its blocked reason and since when, its qualification
|
|
185
233
|
block, its cooldown, whether its edge is spent, its last fire and its close clock. A row whose last
|
|
186
234
|
close reads `CLAIMED` qualified but lost the coin's one fire that pass to a higher-priority agent;
|
|
187
|
-
its edge is preserved and it fires at a later close only if it still qualifies there.
|
|
188
|
-
|
|
235
|
+
its edge is preserved and it fires at a later close only if it still qualifies there. A `SCANNING`
|
|
236
|
+
coin whose reason is `ENTRIES_PAUSED` is under the entry pause (step 1): its agents still decide and
|
|
237
|
+
record every close, and a close that qualifies is held — its fire refused, its edge preserved,
|
|
238
|
+
journaled and recorded as `EDGE_PRESERVED_ENTRIES_PAUSED` with `scanBlockReason` `ENTRIES_PAUSED` —
|
|
239
|
+
so it fires at a later close only if that close qualifies on its own data after the pause lifts. A
|
|
240
|
+
lower-priority agent behind that fire reads `CLAIMED` on the same bar: the coin's one fire went to
|
|
241
|
+
the agent the pause refused, not to a trade. That is the whole answer while the pause lasts; never
|
|
242
|
+
send the player to change an agent or a policy for it. Most "is it working?" questions end here.
|
|
243
|
+
When the question is what ONE on-duty agent of a scanning coin needs to fire — which condition
|
|
244
|
+
reads false, how far a gate sits from its threshold — drill into its row
|
|
245
|
+
with `get_agent_coin_qualification({ agentId, coinTickers: [<the coin's ticker>], reading: true })`
|
|
246
|
+
and read the verdict's `reading` as step 2 of the deploy flow describes it: `live` is what the
|
|
247
|
+
agent reads now, and `lastClose` is the decision its row names as its last close, with the reading
|
|
248
|
+
that bar was decided on.
|
|
189
249
|
2. **`get_radar_activity_summary`** for everything else about "why is it quiet", in ONE call. It
|
|
190
250
|
carries three parts and they answer three different questions, each on its own scope:
|
|
191
251
|
- `groups` — which cause recurs and how often, over the window the response names. Quote the
|
|
@@ -205,10 +265,27 @@ Three reads, cheapest first. Stop as soon as the player's question is answered.
|
|
|
205
265
|
"duty just changed" rather than reporting a contradiction. Joins and departures are journaled as
|
|
206
266
|
`ON_DUTY_JOINED` / `ON_DUTY_LEFT`, one row per agent, and a lost coin as
|
|
207
267
|
`EDGE_PRESERVED_COIN_CLAIMED`.
|
|
208
|
-
3. **`
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
268
|
+
3. **`get_radar_close_decisions`** when the question is about ONE close — "why didn't the 14:00 bar
|
|
269
|
+
fire?", "why did it fire there?", "what did it see at that close?". Every bar the close step
|
|
270
|
+
decided has one record, whether a policy's agent or a manual request's watch decided it: its
|
|
271
|
+
`outcome` (`FIRED`, `NOT_QUALIFIED`, `CLAIMED` or `MISSED`), the fire's `fireDisposition` as
|
|
272
|
+
arbitration settled it, and the `evidence` the bar was decided on — the closed-bar reading's gates
|
|
273
|
+
with their margins, every condition's outcome with its clause evidence, each condition the scan
|
|
274
|
+
could not evaluate with its reach reason, the allocated signals and `missingData` — or, for a
|
|
275
|
+
`MISSED` bar, the close step's own answer: the bar never settled, an input was not on its due bar,
|
|
276
|
+
or the window passed. An `outcome` of `FIRED` says the bar qualified and its agent was offered the
|
|
277
|
+
coin's fire; `fireDisposition` says what the fire came to — `FIRED` when a decision was enqueued,
|
|
278
|
+
`EDGE_PRESERVED_ENTRIES_PAUSED` beside `scanBlockReason` `ENTRIES_PAUSED` when the entry pause
|
|
279
|
+
refused it and nothing was traded. It is the only history of not-qualifying closes: the journal
|
|
280
|
+
writes no row for one, and `resolvesNow` keeps only each agent's last decision — the one
|
|
281
|
+
`reading.lastClose` (step 1) carries; this read holds every decision before it. Narrow with
|
|
282
|
+
`agentId`; page back by passing the oldest returned `bar.barStart` as `before`. A bar still
|
|
283
|
+
waiting inside its window has no record yet (`resolvesNow` shows its `closeDecision.state` as
|
|
284
|
+
`DEFERRED`), and records are kept 90 days.
|
|
285
|
+
4. **`get_radar_activity`** only for what steps 2 and 3 cannot do: more rows than its ten, a
|
|
286
|
+
FIRES-only view, paging back through history, or ONE occurrence's full margins. Rows are lean by
|
|
287
|
+
default — pass `detail: 'FULL'` for the margin surface, and `includeCurve: true` only if something
|
|
288
|
+
will actually plot the points.
|
|
212
289
|
|
|
213
290
|
**Neither of the first two substitutes for the other, and the reason is structural.** The journal is
|
|
214
291
|
a TRANSITION log, not a state log: a gate that has blocked continuously without crossing again
|
|
@@ -216,13 +293,18 @@ inside the window produces no group in the rollup at all. It shows up in `resolv
|
|
|
216
293
|
else. So an empty or quiet rollup NEVER means "nothing is blocking it" — check step 1 before saying
|
|
217
294
|
anything of the sort.
|
|
218
295
|
|
|
219
|
-
|
|
296
|
+
Three negatives, all checkable:
|
|
220
297
|
|
|
221
298
|
- **Never page journal rows in order to count causes yourself.** The counts are served. Re-deriving
|
|
222
299
|
them spends the player's op budget on work the server already did and floods the transcript.
|
|
223
300
|
- **Never sum counts across pages, and never report a windowed count as a lifetime one.** The
|
|
224
301
|
rollup's counts span every matching row inside `windowStartAt`–`windowEndAt` — quote them with
|
|
225
302
|
that window ("41 times in the last 7 days"), never as a total.
|
|
303
|
+
- **Never explain one close from the live verdict or the journal.** A not-qualifying close writes no
|
|
304
|
+
journal row, and the live reading is not the reading the close was decided on — at the same moment
|
|
305
|
+
the two can sit on opposite sides of a gate. Read the bar's record — `reading.lastClose` for the
|
|
306
|
+
last decision a row names, `get_radar_close_decisions` for any other — and quote it as stored;
|
|
307
|
+
never recompute it.
|
|
226
308
|
|
|
227
309
|
## Preview-before-commit: enforced for both
|
|
228
310
|
|
|
@@ -31,7 +31,10 @@ problem: the fix runs through the flow that owns it, with that flow's own confir
|
|
|
31
31
|
|
|
32
32
|
Three reads, and they are not interchangeable:
|
|
33
33
|
|
|
34
|
-
- **`get_agent_budget`** — the health read. `
|
|
34
|
+
- **`get_agent_budget`** — the health read. `runStatus` (`blocked` / `paused` / `active` — the run-state
|
|
35
|
+
already ranked, so read it rather than re-deriving it from the fields below; a halt reads `paused` even
|
|
36
|
+
while its own `AGENT_HALTED` block stands), `haltReason` (why it stopped, if it did),
|
|
37
|
+
`haltResumeEligibility` (whether a resume would now succeed, and what still blocks it),
|
|
35
38
|
`blockedReason` + `blockedSince` (the typed pipeline block currently standing, and since when),
|
|
36
39
|
and `gauges` — four guardrail meters (dailyTrades, exposure, drawdown, dailyLoss), each with a
|
|
37
40
|
server-computed `breached` flag. **Read `breached`; never compare fill against limit yourself.**
|
|
@@ -85,16 +88,22 @@ a diagnosis; "OPEN_POSITION_CONFLICT, 14 times, most recently 2h ago" is.
|
|
|
85
88
|
|
|
86
89
|
### 3. Halted agents, and healthy ones
|
|
87
90
|
|
|
88
|
-
**If `haltReason`
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- **
|
|
92
|
-
|
|
93
|
-
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
**If the agent is halted, `haltReason` says why and `haltResumeEligibility` says what clears it.**
|
|
92
|
+
Name the recovery from the verdict alone:
|
|
93
|
+
|
|
94
|
+
- **null** — the agent is not halted. A halt the player set by hand carries a verdict like any
|
|
95
|
+
other, and is recovered through it.
|
|
96
|
+
- **`eligible: true`** — nothing is still breached; resuming will succeed.
|
|
97
|
+
- **`eligible: false`** — name `breachedStop`, the stop still breached, with `breachingFigureUsd`
|
|
98
|
+
against `limitUsd`, and exactly the exits the verdict marks open: raising that stop above the
|
|
99
|
+
figure (`canRaiseTriggeringStop`), the drawdown baseline reset (`canResetBaseline`), and, when
|
|
100
|
+
`breachedStop` is `DAILY_LOSS`, the UTC-day rollover. Then resuming. An exit it does not mark
|
|
101
|
+
open is never offered.
|
|
102
|
+
|
|
103
|
+
Say that a resume attempted while a stop is still breached is **refused by the server**, naming the
|
|
104
|
+
same stop, figure and exits. A resume the server accepts is followed by a re-check of every stop, so
|
|
105
|
+
read the resume response's `haltedAt`: set means a loss settled, or a stop was lowered, while the
|
|
106
|
+
resume ran and the agent was halted again at once; `get_agent_budget`'s `haltReason` names the stop.
|
|
98
107
|
|
|
99
108
|
**If the reads are clean, say so.** An agent whose gauges are unbreached, whose blocks are ordinary
|
|
100
109
|
no-trade verdicts, and whose deployment covers what the player expected, is working — report the
|
|
@@ -143,7 +143,10 @@ strategy timeframe, and at or below it the series as the frame carries it. At or
|
|
|
143
143
|
timeframe the choice therefore sets only what the live lane shows — no bar is in progress at the
|
|
144
144
|
anchor's own close — so Developing there is legal and changes no decision. A condition reading a
|
|
145
145
|
developing bar is single-frame: it holds one close, carries no verdict and cannot take the `exit`
|
|
146
|
-
role.
|
|
146
|
+
role. One exception overrides both the stored value and the default: a column reading a metric with
|
|
147
|
+
no live value (itself, or a `spread` operand) reads completed bars at every rung, because the forming
|
|
148
|
+
bar publishes nothing for it. The resolved answer for a column is served on
|
|
149
|
+
`effectiveParameters.bars`, and it states that exception.
|
|
147
150
|
|
|
148
151
|
**A higher-timeframe level is measured from the current strategy-bar price.** The distance to a `4h`
|
|
149
152
|
Donchian band, and every candle label classifier (`MA_ALIGN`, `PRICE_ZONE`, `BB_TOUCH`), compares
|
|
@@ -158,8 +161,31 @@ market-wide reads with no session dimension, so they resolve everywhere. The fiv
|
|
|
158
161
|
scalars (`fieldPlayers`, `fieldUpBias`, `fieldBiasDir`, `captConc`, `picksSpread`) describe a game
|
|
159
162
|
session the agent is playing in, and **radar runs outside one** — so a radar deployment whose
|
|
160
163
|
strategy reads one is refused outright (`CONDITION_OPERAND_UNSERVED_IN_LANE`), naming the scalars it
|
|
161
|
-
can read instead.
|
|
162
|
-
|
|
164
|
+
can read instead.
|
|
165
|
+
|
|
166
|
+
**What the radar scan can read on a coin.** Beyond the lane, a condition the radar acts on — a
|
|
167
|
+
required one, one carrying a verdict, an exit one, and every condition they reference — must be
|
|
168
|
+
readable by the radar scan on each coin the radar acts on for the agent, or it would be decided unread.
|
|
169
|
+
What a coin can be read for is its market-data profile: the kinds of data the market-data service
|
|
170
|
+
publishes that it serves for that coin, never the coin's asset class. A refusal carries
|
|
171
|
+
`CONDITION_UNREADABLE_BY_RADAR_SCAN` with its `reachReason`: `INSTRUMENT` when the profile of the coin —
|
|
172
|
+
or of a benchmark section's own instrument — carries no such data, or the service publishes no profile
|
|
173
|
+
for it at all (spot-tape columns on a coin no spot venue lists, TradFi or crypto alike; any market-data
|
|
174
|
+
column on a ticker with no catalog row), `AGENT_TIMEFRAME` when the agent has no such rung on the
|
|
175
|
+
enabled ladder, and `FEED` when the radar scan never reads that data for the agent (crowd reads:
|
|
176
|
+
compose reads them, but only for a coin the scan has already admitted). An `INSTRUMENT` refusal names
|
|
177
|
+
the kind of data the profile lacks, or says the coin has no profile. The fixes it names: take the
|
|
178
|
+
condition's radar role away (neither required nor a verdict, or no exit role), read a column the radar
|
|
179
|
+
scan has on that coin, or free the coin.
|
|
180
|
+
|
|
181
|
+
**The refusal lands where an agent meets a coin**: at the radar deploy (its preview, the builder's
|
|
182
|
+
Save and the draft commit); at a manual entry request, as `CONDITION_UNREADABLE_ON_COIN`;
|
|
183
|
+
and, for an agent already deployed or holding an open position or a pending manual request, at a
|
|
184
|
+
strategy save (`compile_strategy_plan`, `apply_strategy_plan`, `restore_strategy`) or a rebind. A save
|
|
185
|
+
is checked only on behalf of those agents: a strategy carries no lane of its own, so one with no agent
|
|
186
|
+
the radar acts on is never checked, and the same strategy is legal, and reads session-field scalars
|
|
187
|
+
correctly, on an arena agent. A refused compile issues no plan token, so nothing can stage that
|
|
188
|
+
content.
|
|
163
189
|
|
|
164
190
|
**The exit role.** `exit: true` makes a settled TRUE reading close open positions its verdict
|
|
165
191
|
opposes — UP exits SHORTs, DOWN exits LONGs, a NEITHER or `null` verdict exits both. Legal only over
|
|
@@ -277,11 +303,14 @@ smaller position, never more risk.
|
|
|
277
303
|
trailingBufferPct, timeDecayEnabled, timeDecayGracePeriodMinutes, timeDecayIntervalMinutes,
|
|
278
304
|
timeDecayTightenPct, timeDecayMaxTightenPct, timeDecayStaleThresholdTpProgressPct,
|
|
279
305
|
decisionInvalidationExitEnabled }` — how the stop moves after entry, and when a position is
|
|
280
|
-
closed for reasons other than its stop.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
306
|
+
closed for reasons other than its stop. The policy is stamped on each position when it opens: an
|
|
307
|
+
edit applies to positions opened after it, and an open position keeps the policy it opened with.
|
|
308
|
+
|
|
309
|
+
Validated bounds: break-even trigger 0.5–2R step 0.01; trailing trigger 0–2R step 0.01 (0 = trail
|
|
310
|
+
from entry), giveback 25–55% step 1, buffer 0.01–1% step 0.01; timeDecay grace 5–1440 min step 5,
|
|
311
|
+
interval 5–480 min step 5, grace ≥ interval while time decay is armed, tighten 0.5–50% step 0.5,
|
|
312
|
+
max tighten 1–100% step 1, stale threshold 0–100% of TP progress step 1. Per-mechanism flags; no
|
|
313
|
+
umbrella switch.
|
|
285
314
|
|
|
286
315
|
`decisionInvalidationExitEnabled` is the post-fill invalidation exit: a **closed**
|
|
287
316
|
strategy-timeframe candle beyond the decision's invalidation level closes the position
|
|
@@ -44,7 +44,7 @@ new longs / new shorts / short covering / long liquidation), `MARK spread ORACLE
|
|
|
44
44
|
`CROWDED_LONGS` building block (`ann gte 25` + `oiChg gte 3` + `oiRegime is "new longs"`);
|
|
45
45
|
`FADE_SHORT` verdict DOWN (ref + `RSI14 gte 65` + `chg24h gte 5`); mirrored `SQUEEZED_SHORTS`
|
|
46
46
|
/ `SQUEEZE_LONG` verdict UP. Rules: `funding_extreme_positive`/`_negative` 3 required
|
|
47
|
-
`{"
|
|
47
|
+
`{"thresholdAnnualizedPct":100}` · `oi_surge` 2 `{"thresholdPct":0.03}` · `rsi_overbought` 2
|
|
48
48
|
`{"threshold":65}` · `rsi_oversold` 2 `{"threshold":35}` · `cvd_bear_divergence` 2 ·
|
|
49
49
|
`cvd_bull_divergence` 2 · `mfi_overbought` 1 · `mfi_oversold` 1. Gates 0.6 / 1 / 0.5. Levels
|
|
50
50
|
1.0–2.5 ATR, RR 1.5. PM: BE 0.8R, no trail, timeDecay ON (120/60, 10→40, stale 25).
|
|
@@ -70,12 +70,18 @@ re-sorts a list, re-derives a verdict, or approves on the player's behalf.
|
|
|
70
70
|
`get_trade_conversation({ conversationId })`, using the id the `queued` result carried. It serves
|
|
71
71
|
the whole transcript in stored order — the queued card, the agent's reasoning, its thesis and
|
|
72
72
|
setups, the recommendation, a no-trade with its reason and next coins, or a close answer.
|
|
73
|
-
- `get_entry_request` re-reads a request
|
|
74
|
-
|
|
73
|
+
- `get_entry_request` re-reads a request until it is answered — including while its close has fired
|
|
74
|
+
and the decision is being composed. `cancel_entry_request` withdraws it only while it still awaits
|
|
75
|
+
its close; once the close has fired it is `NOT_FOUND`, and the answer arrives in the conversation.
|
|
76
|
+
Both are `NOT_FOUND` once it has been answered, cancelled or expired, and that is the honest record:
|
|
75
77
|
the answer is in the conversation.
|
|
76
78
|
- `type: "error"` — the block, with its remedy: `OPEN_POSITION_CONFLICT` means a position already
|
|
77
79
|
holds the slot (see step 0) and nothing was queued; `LLM_CREDITS_EXHAUSTED` means top up when
|
|
78
|
-
`topupAvailable` is true
|
|
80
|
+
`topupAvailable` is true; `ENTRIES_PAUSED` means the platform has paused new entries while market
|
|
81
|
+
data is missing across many coins, and nothing was queued. The pause is platform-wide, not the
|
|
82
|
+
agent's or the coin's, so never retry it through another agent or on another coin. It lifts by
|
|
83
|
+
itself once the data is back: ask again then, under a fresh `idempotencyKey` — the same key only
|
|
84
|
+
replays this refusal. A refused request (`RATE_LIMITED`) is a refusal with its retry-after.
|
|
79
85
|
Never "nothing to do".
|
|
80
86
|
- `type: "recommendation"` and `type: "no_trade"` arrive only as the **replay** of a request made
|
|
81
87
|
before the queued contract shipped. Report them as step 5 describes and do not expect them from a
|
|
@@ -90,8 +96,20 @@ the player's explicit typed word — never inferred from interest, agreement, or
|
|
|
90
96
|
trade.
|
|
91
97
|
|
|
92
98
|
- A decided close produces one of: a PROPOSED decision awaiting approval; a no-trade with the
|
|
93
|
-
reason and the next coins worth asking about; a
|
|
94
|
-
|
|
99
|
+
reason and the next coins worth asking about; a refusal, `close_refused`, which names the gate that
|
|
100
|
+
failed when the close did not qualify and none when it qualified and the radar's own gates stopped
|
|
101
|
+
its fire; a window that passed with no sweep; a bar the agent's own radar deployment decided first;
|
|
102
|
+
or an error carrying the engine's block, with nothing proposed, when admission refused the
|
|
103
|
+
qualifying close's fire — `ENTRIES_PAUSED` while new entries are paused, an account block, a
|
|
104
|
+
position already held.
|
|
105
|
+
- A bar the agent's own radar deployment decided first is reported from that deployment's decision,
|
|
106
|
+
never decided again. It arrives as `close_fired_by_radar` — a trade taken in full — only when the
|
|
107
|
+
deployment's fire enqueued a trade decision. Otherwise it arrives as what stopped that fire, and
|
|
108
|
+
none of these is a trade: a fire admission refused arrives as the engine's block, exactly as when
|
|
109
|
+
the refused fire was the request's own; a fire the radar's own gates stopped — its coin cooldown,
|
|
110
|
+
its hourly cap, post-close suppression, a decision already running on the coin — arrives as
|
|
111
|
+
`close_refused` with no gate, because the close qualified and nothing was entered; and a close
|
|
112
|
+
whose coin another agent's fire took arrives as `close_claimed_by_radar`.
|
|
95
113
|
- On a proposal, state the direction, the entry, stop and take-profit levels, the position size,
|
|
96
114
|
the **`convictionPercent`**, and the expiry (`expiresAt`). No conviction floor is applied on this
|
|
97
115
|
surface: the conviction is the agent's own reading, and the player judges it.
|