@bitget-ai/getagent-skill 0.2.1
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/.claude-plugin/marketplace.json +28 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +99 -0
- package/VERSION +1 -0
- package/bin/getagent-skill.js +140 -0
- package/package.json +45 -0
- package/skills/getagent/SKILL.md +129 -0
- package/skills/getagent/examples/btc-ema-cross-demo/README.md +61 -0
- package/skills/getagent/examples/btc-ema-cross-demo/backtest.yaml +33 -0
- package/skills/getagent/examples/btc-ema-cross-demo/manifest.yaml +94 -0
- package/skills/getagent/examples/btc-ema-cross-demo/src/main.py +88 -0
- package/skills/getagent/examples/btc-ema-cross-demo/src/strategy.py +118 -0
- package/skills/getagent/references/api/enable.md +95 -0
- package/skills/getagent/references/api/error-responses.md +77 -0
- package/skills/getagent/references/api/index.md +38 -0
- package/skills/getagent/references/api/list.md +80 -0
- package/skills/getagent/references/api/my-playbooks.md +41 -0
- package/skills/getagent/references/api/publish.md +76 -0
- package/skills/getagent/references/api/run.md +149 -0
- package/skills/getagent/references/api/upload.md +76 -0
- package/skills/getagent/references/backtest-engine.md +438 -0
- package/skills/getagent/references/package-schema.md +552 -0
- package/skills/getagent/references/sandbox-runtime.md +201 -0
- package/skills/getagent/references/sdk/backtest/catalog.md +208 -0
- package/skills/getagent/references/sdk/data/arxiv.md +41 -0
- package/skills/getagent/references/sdk/data/catalog.md +56 -0
- package/skills/getagent/references/sdk/data/commodity.md +226 -0
- package/skills/getagent/references/sdk/data/coverage.md +82 -0
- package/skills/getagent/references/sdk/data/crypto.md +2906 -0
- package/skills/getagent/references/sdk/data/currency.md +123 -0
- package/skills/getagent/references/sdk/data/derivatives.md +269 -0
- package/skills/getagent/references/sdk/data/economy.md +1348 -0
- package/skills/getagent/references/sdk/data/equity.md +2120 -0
- package/skills/getagent/references/sdk/data/etf.md +372 -0
- package/skills/getagent/references/sdk/data/famafrench.md +201 -0
- package/skills/getagent/references/sdk/data/fixedincome.md +804 -0
- package/skills/getagent/references/sdk/data/imf_utils.md +225 -0
- package/skills/getagent/references/sdk/data/index.md +216 -0
- package/skills/getagent/references/sdk/data/news.md +149 -0
- package/skills/getagent/references/sdk/data/playbook-supported.md +9871 -0
- package/skills/getagent/references/sdk/data/regulators.md +299 -0
- package/skills/getagent/references/sdk/data/sentiment.md +323 -0
- package/skills/getagent/references/sdk/data/uscongress.md +126 -0
- package/skills/getagent/references/sdk/data/web_search.md +68 -0
- package/skills/getagent/references/sdk/data/wikipedia.md +97 -0
- package/skills/getagent/references/sdk/llm/catalog.md +117 -0
- package/skills/getagent/references/sdk/runtime/catalog.md +195 -0
- package/skills/getagent/references/sdk/trade/account.md +61 -0
- package/skills/getagent/references/sdk/trade/catalog.md +35 -0
- package/skills/getagent/references/sdk/trade/contract.md +331 -0
- package/skills/getagent/references/sdk/trade/helpers.md +466 -0
- package/skills/getagent/references/sdk/trade/market.md +28 -0
- package/skills/getagent/references/sdk/trade/patterns.md +102 -0
- package/skills/getagent/references/sdk/trade/spot.md +165 -0
- package/skills/getagent/references/sdk.md +198 -0
- package/skills/getagent/scripts/validate.py +965 -0
- package/skills/getagent/scripts/version_check.sh +62 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
# Playbook Package Schema
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- [Directory Layout](#directory-layout)
|
|
6
|
+
- [manifest.yaml](#manifestyaml)
|
|
7
|
+
- [backtest.yaml](#backtestyaml)
|
|
8
|
+
- [src/main.py](#srcmainpy)
|
|
9
|
+
|
|
10
|
+
## Directory Layout
|
|
11
|
+
|
|
12
|
+
Implemented upload layout:
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
<package-name>/
|
|
16
|
+
├── README.md
|
|
17
|
+
├── manifest.yaml
|
|
18
|
+
├── src/
|
|
19
|
+
│ ├── main.py
|
|
20
|
+
│ ├── strategy.py
|
|
21
|
+
│ ├── indicators.py
|
|
22
|
+
│ ├── risk.py
|
|
23
|
+
│ ├── execution.py
|
|
24
|
+
│ ├── prompts.py # optional
|
|
25
|
+
│ ├── llm_policy.py # optional
|
|
26
|
+
│ └── agent_tools.py # optional
|
|
27
|
+
└── backtest.yaml # optional; only for backtest_support: full
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Design rules:
|
|
31
|
+
|
|
32
|
+
- **Required:** `README.md`, `manifest.yaml`, `src/main.py`
|
|
33
|
+
- **Optional in upload:** extra modules under `src/`, `backtest.yaml`
|
|
34
|
+
- **Local-only (must not upload):** `tests/`, `notebooks/`, `research/`, `data/`,
|
|
35
|
+
`backtest_results/`, `logs/`, `output/`, virtualenv and cache directories
|
|
36
|
+
- **Do not infer strategy class from file layout.** Public behavior belongs in
|
|
37
|
+
`manifest.yaml`.
|
|
38
|
+
|
|
39
|
+
## README.md
|
|
40
|
+
|
|
41
|
+
Human-readable strategy explanation. This file is required because subscribers
|
|
42
|
+
need to understand the Playbook before trusting its signals.
|
|
43
|
+
|
|
44
|
+
Write in plain language, not implementation notes. Avoid code blocks unless they
|
|
45
|
+
make the explanation easier to understand. Cover at least:
|
|
46
|
+
|
|
47
|
+
- What market behavior this strategy tries to capture
|
|
48
|
+
- When it opens a long or short position
|
|
49
|
+
- When it closes, takes profit, or stops loss
|
|
50
|
+
- What each user-tunable parameter means and what happens when it is raised or
|
|
51
|
+
lowered
|
|
52
|
+
- How to read the backtest metrics, especially strategy return vs account return
|
|
53
|
+
- Main risks and market conditions where the strategy can perform poorly
|
|
54
|
+
|
|
55
|
+
`README.md` must be UTF-8 text, at least 200 characters, and include enough
|
|
56
|
+
plain-language content for the upload validator to detect sections covering
|
|
57
|
+
策略、开仓、平仓、风险.
|
|
58
|
+
|
|
59
|
+
## manifest.yaml
|
|
60
|
+
|
|
61
|
+
Package identity, public behavior, and runtime contract.
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
| Field | Type | Required | Description |
|
|
65
|
+
| ------------------------ | ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
66
|
+
| `name` | string | yes | URL-safe identifier. Lowercase, alphanumeric, hyphens only. 1-63 chars. |
|
|
67
|
+
| `display_name` | string | yes | Human-readable name. |
|
|
68
|
+
| `version` | string | no | Server-assigned on publish. Do not write this for drafts; `upload` returns a `draft_id`, and `publish` returns the formal semver. |
|
|
69
|
+
| `description` | string | yes | One-line description. |
|
|
70
|
+
| `long_description` | string | yes | 300–400 English words. Plain-language strategy summary that subscribers read in the marketplace UI. Must cover what the strategy captures, when it enters/exits, what each tunable parameter does, and where it underperforms — without revealing numeric parameters, indicator periods, thresholds, or formulas. See [`long_description` Writing Rules](#long_description-writing-rules). |
|
|
71
|
+
| `market_type` | string | yes | `"spot"` or `"contract"`. |
|
|
72
|
+
| `trading_symbols` | list[string] | yes | Trading pairs, e.g. `["BTCUSDT"]`. |
|
|
73
|
+
| `decision_mode` | string | yes | `deterministic`, `llm_assisted`, or `agentic`. |
|
|
74
|
+
| `backtest_support` | string | yes | `full` or `none`. |
|
|
75
|
+
| `runtime_profile` | string | yes | `deterministic`, `llm_bounded`, or `agentic`. Historical backtest uses `deterministic`; live-only bounded model execution uses `llm_bounded`. |
|
|
76
|
+
| `execution_mode` | string | yes | `signal_only` or `follow_trade`. |
|
|
77
|
+
| `follow_trade_supported` | bool | yes | Whether the Playbook can follow trades using a subscriber's bound subaccount. |
|
|
78
|
+
| `strategy_config` | mapping | no | User-tunable strategy parameters read by both live and backtest code paths. |
|
|
79
|
+
| `user_config_schema` | mapping | no | Authoritative declaration of which `strategy_config` fields users may override when subscribing. |
|
|
80
|
+
| `tags` | list[string] | no | Searchable tags. |
|
|
81
|
+
| `schedule.cron` | string | no | Suggested publish-time schedule, e.g. `"0 */4 * * *"`. |
|
|
82
|
+
| `schedule.tz` | string | required with `schedule.cron` | Default IANA timezone for subscription instances, e.g. `"Asia/Shanghai"`. Users may override it when creating their own instance. |
|
|
83
|
+
| `official_evidence_kind` | string | no | For live-only strategies, optional declared evidence type: `paper` or `live`. |
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
**Name rules:** must match `^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`.
|
|
87
|
+
|
|
88
|
+
### Contract rules
|
|
89
|
+
|
|
90
|
+
- Use `backtest_support: full` only when the core trading logic is fairly replayable on historical data.
|
|
91
|
+
- Do not manually bump `version` in `manifest.yaml`. Versions belong to published
|
|
92
|
+
artifacts and are assigned by the server from the strategy's latest published
|
|
93
|
+
version.
|
|
94
|
+
- Use `backtest_support: none` when open-ended LLM reasoning or unreplayable external context determines the trade.
|
|
95
|
+
- `decision_mode: agentic` requires `runtime_profile: agentic`.
|
|
96
|
+
- `runtime_profile: llm_bounded` requires `backtest_support: none`.
|
|
97
|
+
- `execution_mode: follow_trade` requires `follow_trade_supported: true`.
|
|
98
|
+
- Live-only playbooks must not declare `official_evidence_kind: backtest`.
|
|
99
|
+
- Backtest-capable playbooks should not predeclare paper/live official evidence.
|
|
100
|
+
- `schedule.cron` must not run more often than every 10 minutes. This limits
|
|
101
|
+
live execution frequency only; Playbooks may still use 5m or other finer-grain
|
|
102
|
+
bars for historical replay and signal features.
|
|
103
|
+
- `schedule.tz` is required whenever `schedule.cron` is present. Use a valid
|
|
104
|
+
IANA timezone such as `Asia/Shanghai`. This is the default for new
|
|
105
|
+
subscription instances, not a strategy parameter, so do not put timezone in
|
|
106
|
+
`strategy_config` or `user_config_schema`.
|
|
107
|
+
- Live contract order prices must align with exchange tick size. Do not pass
|
|
108
|
+
fixed decimal rounding such as `str(round(tp_price, 2))` to
|
|
109
|
+
`tp_trigger_price` / `sl_trigger_price`; use
|
|
110
|
+
`trade.helpers.resolve_contract_tpsl(...)` or quantize with
|
|
111
|
+
`trade.helpers.contract_rules(symbol).price_step`. The helper is
|
|
112
|
+
keyword-only and does not accept percentage override kwargs such as
|
|
113
|
+
`tp_pct_override` or `sl_pct_override`; convert percentage TP/SL tunables to
|
|
114
|
+
concrete trigger prices before calling it.
|
|
115
|
+
- Live code should use `runtime.emit_signal_or_follow(...)` to emit the signal
|
|
116
|
+
and let the runtime decide whether to call the provided trade callback. In
|
|
117
|
+
`signal_only`, it returns successfully without placing orders.
|
|
118
|
+
- Do not add `run_mode`. Historical vs live execution is selected by
|
|
119
|
+
`runtime.evaluation_mode`, injected by the platform at run time.
|
|
120
|
+
- Every user-editable strategy parameter must appear in both `strategy_config`
|
|
121
|
+
(default runtime value) and `user_config_schema` (type/range/options for UI
|
|
122
|
+
and API validation). Do not declare fake editable fields that strategy code
|
|
123
|
+
does not read.
|
|
124
|
+
- Playbook code must read editable values from
|
|
125
|
+
`runtime.manifest["strategy_config"]`; never hardcode user-editable values in
|
|
126
|
+
Python constants.
|
|
127
|
+
- For configurable trading pairs, keep top-level `trading_symbols` and
|
|
128
|
+
`strategy_config.trading_symbols` aligned. The platform syncs the top-level
|
|
129
|
+
field when a user override changes `strategy_config.trading_symbols`.
|
|
130
|
+
- **`strategy_config.margin_budget` is required** when `backtest_support: full`
|
|
131
|
+
or `execution_mode: follow_trade`. It is the per-strategy denominator the
|
|
132
|
+
platform uses to compute user-facing return % (`net_pnl / margin_budget`).
|
|
133
|
+
Validation rejects manifests that omit it or set it to a non-positive value.
|
|
134
|
+
Subscribers may override it via `config_overrides.margin_budget`; otherwise
|
|
135
|
+
the manifest default applies. Pure signal-only / live-only Playbooks that
|
|
136
|
+
never surface a return % may omit the field.
|
|
137
|
+
|
|
138
|
+
Example:
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
name: btc-ema-crossover
|
|
142
|
+
display_name: "BTC EMA Crossover"
|
|
143
|
+
description: "Trend following strategy based on EMA 12/26 crossover on 4h chart"
|
|
144
|
+
long_description: |
|
|
145
|
+
This Playbook is a trend-following strategy on BTC perpetual futures. It is
|
|
146
|
+
built on the assumption that once the broader market enters a sustained
|
|
147
|
+
directional move, price tends to travel along that direction in a relatively
|
|
148
|
+
clean trend rather than chopping back and forth. The goal is to capture the
|
|
149
|
+
middle portion of those trends and stay out of grinding sideways markets where
|
|
150
|
+
most signals are noise.
|
|
151
|
+
|
|
152
|
+
Entry decisions are driven by alignment between a shorter-term and a
|
|
153
|
+
longer-term directional read. When both reads point clearly upward, the
|
|
154
|
+
strategy opens a long; when both point clearly downward, it opens a short. It
|
|
155
|
+
deliberately waits until momentum has formed and is still in motion, rather
|
|
156
|
+
than trying to fade extremes or call tops and bottoms.
|
|
157
|
+
|
|
158
|
+
Exits work by inversion. When the shorter-term direction flips before the
|
|
159
|
+
longer-term direction does, the strategy treats that as a fade in conviction,
|
|
160
|
+
retracts the trade signal, and closes the position. The intent is to lock in
|
|
161
|
+
whatever was captured rather than insist on every trade winning. Many small
|
|
162
|
+
losing trades are accepted as the cost of catching the occasional larger
|
|
163
|
+
trend run.
|
|
164
|
+
|
|
165
|
+
Two parameters are exposed to subscribers: leverage and margin budget. Higher
|
|
166
|
+
leverage amplifies both upside and drawdowns equally; the strategy does not
|
|
167
|
+
become more selective when leverage rises. Margin budget is the per-strategy
|
|
168
|
+
cap that the platform sizes orders against and uses as the denominator for
|
|
169
|
+
return percentage; treat it as the maximum amount of capital you are willing
|
|
170
|
+
to put at risk on this Playbook.
|
|
171
|
+
|
|
172
|
+
The strategy underperforms in choppy, range-bound markets where short-term
|
|
173
|
+
direction flips repeatedly without committing to a real trend. Gap-driven
|
|
174
|
+
moves around major events, illiquid pairs, and persistent funding-rate
|
|
175
|
+
dislocation can also produce a string of stops or trapped positions. Strong
|
|
176
|
+
historical backtest metrics are not a guarantee of live profitability — match
|
|
177
|
+
this Playbook against your own risk tolerance before subscribing.
|
|
178
|
+
market_type: contract
|
|
179
|
+
trading_symbols: ["BTCUSDT"]
|
|
180
|
+
tags: ["trend", "ema", "btc", "contract"]
|
|
181
|
+
schedule:
|
|
182
|
+
cron: "0 */4 * * *"
|
|
183
|
+
tz: "Asia/Shanghai"
|
|
184
|
+
decision_mode: deterministic
|
|
185
|
+
backtest_support: full
|
|
186
|
+
runtime_profile: deterministic
|
|
187
|
+
execution_mode: follow_trade
|
|
188
|
+
follow_trade_supported: true
|
|
189
|
+
|
|
190
|
+
strategy_config:
|
|
191
|
+
trading_symbols: ["BTCUSDT"]
|
|
192
|
+
fast_period: 12
|
|
193
|
+
slow_period: 26
|
|
194
|
+
leverage: 5
|
|
195
|
+
margin_budget: "50"
|
|
196
|
+
|
|
197
|
+
user_config_schema:
|
|
198
|
+
trading_symbols:
|
|
199
|
+
type: array
|
|
200
|
+
item_type: string
|
|
201
|
+
default: ["BTCUSDT"]
|
|
202
|
+
options: ["BTCUSDT", "ETHUSDT", "SOLUSDT", "BNBUSDT", "XRPUSDT"]
|
|
203
|
+
aliases:
|
|
204
|
+
btc: BTCUSDT
|
|
205
|
+
bitcoin: BTCUSDT
|
|
206
|
+
eth: ETHUSDT
|
|
207
|
+
ethereum: ETHUSDT
|
|
208
|
+
min_items: 1
|
|
209
|
+
max_items: 1
|
|
210
|
+
label: "Trading symbol"
|
|
211
|
+
leverage:
|
|
212
|
+
type: integer
|
|
213
|
+
default: 5
|
|
214
|
+
min: 1
|
|
215
|
+
max: 20
|
|
216
|
+
aliases:
|
|
217
|
+
10x: 10
|
|
218
|
+
10倍: 10
|
|
219
|
+
label: "Leverage"
|
|
220
|
+
margin_budget:
|
|
221
|
+
type: string
|
|
222
|
+
default: "50"
|
|
223
|
+
pattern: "^[0-9]+(\\.[0-9]+)?$"
|
|
224
|
+
label: "Margin budget USDT"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Supported `user_config_schema.*.type` values are `string`, `integer`,
|
|
228
|
+
`number`, `boolean`, and `array`. `array` may declare `item_type`, `min_items`,
|
|
229
|
+
and `max_items`. `options` restricts scalar values or each array item.
|
|
230
|
+
`aliases` maps common user phrases to canonical values. The platform also
|
|
231
|
+
normalizes common raw user intent before validation: `eth` -> `ETHUSDT`,
|
|
232
|
+
`10倍` / `10x` -> `10`, and `200U` / `200 USDT` -> `200` for budget fields.
|
|
233
|
+
`key_aliases` or `synonyms` may be used when a field needs custom input names
|
|
234
|
+
beyond built-ins such as `symbol` / `交易对` -> `trading_symbols` and
|
|
235
|
+
`杠杆` / `倍数` -> `leverage`.
|
|
236
|
+
|
|
237
|
+
### long_description Writing Rules
|
|
238
|
+
|
|
239
|
+
`manifest.long_description` is the strategy summary that subscribers see in the
|
|
240
|
+
marketplace UI when deciding whether to subscribe. Unlike `description` (one
|
|
241
|
+
line) or `README.md` (full reference), it is a single short essay. Two goals
|
|
242
|
+
have to coexist:
|
|
243
|
+
|
|
244
|
+
1. **Make a non-technical user understand the strategy** — what market behavior
|
|
245
|
+
it bets on, when it enters and exits, what they can tune, and where it can
|
|
246
|
+
lose them money.
|
|
247
|
+
2. **Protect the strategy** — never reveal the exact recipe a competitor or
|
|
248
|
+
reader could use to clone or front-run it.
|
|
249
|
+
|
|
250
|
+
#### Length
|
|
251
|
+
|
|
252
|
+
- Target **300–400 English words**.
|
|
253
|
+
- Hard floor: **250 words**. Hard ceiling: **500 words**. Outside this range,
|
|
254
|
+
`validate.py` fails the upload.
|
|
255
|
+
- Write in English only. Do not mix Chinese into the same field.
|
|
256
|
+
|
|
257
|
+
#### Required 5-section skeleton
|
|
258
|
+
|
|
259
|
+
The text must read as continuous prose (no bullet headers, no numbered lists),
|
|
260
|
+
but must cover all five logical sections in order. Aim for 60–90 words per
|
|
261
|
+
section.
|
|
262
|
+
|
|
263
|
+
1. **What it does and what behavior it captures.** The strategy thesis. Which
|
|
264
|
+
market(s), which side (long/short/both), which kind of price behavior it
|
|
265
|
+
bets on.
|
|
266
|
+
2. **How it decides to enter.** Direction-of-decision language only ("enters
|
|
267
|
+
long when momentum aligns with trend"). No periods, no thresholds, no
|
|
268
|
+
formulas.
|
|
269
|
+
3. **How it decides to exit, take profit, or stop loss.** Same direction-of-
|
|
270
|
+
decision phrasing.
|
|
271
|
+
4. **What subscribers can tune and what each tunable does.** Describe the
|
|
272
|
+
*effect* of raising or lowering each user-editable parameter declared in
|
|
273
|
+
`user_config_schema`. Do not show default values inside the prose.
|
|
274
|
+
5. **Risks and unsuitable market conditions.** Be honest about where the
|
|
275
|
+
strategy underperforms or actively loses money. Past backtest performance
|
|
276
|
+
disclaimer should appear here.
|
|
277
|
+
|
|
278
|
+
The validator confirms each section is present by detecting required keyword
|
|
279
|
+
clusters (`captures`/`thesis`/`aim` for §1, `enter`/`open`/`long`/`short` for
|
|
280
|
+
§2, `exit`/`close`/`stop`/`take profit` for §3, `parameter`/`tunable`/
|
|
281
|
+
`leverage`/`margin`/`adjust` for §4, `risk`/`drawdown`/`underperform`/
|
|
282
|
+
`unsuitable`/`lose` for §5). Missing any cluster fails validation.
|
|
283
|
+
|
|
284
|
+
#### What you may write (allowed)
|
|
285
|
+
|
|
286
|
+
- The strategy *category* in plain English: `trend-following`, `mean
|
|
287
|
+
reversion`, `momentum`, `breakout`, `range`, `arbitrage`, `grid`,
|
|
288
|
+
`event-driven`, `risk parity`, `pairs`.
|
|
289
|
+
- The general *kind* of feature input, e.g. "price action", "volatility
|
|
290
|
+
regime", "open-interest behavior", "funding-rate behavior", "liquidation
|
|
291
|
+
pressure", "order-book imbalance".
|
|
292
|
+
- The general *direction* of decisions ("waits for momentum to align with the
|
|
293
|
+
trend before entering", "fades extreme moves after volatility contracts").
|
|
294
|
+
- The *effect* of each tunable parameter ("higher leverage amplifies both
|
|
295
|
+
upside and drawdowns equally", "raising the symbol universe spreads risk
|
|
296
|
+
across more pairs but increases data load").
|
|
297
|
+
- The *qualitative* market regimes where it works/fails ("performs well in
|
|
298
|
+
sustained trends; underperforms in choppy ranges or around major news
|
|
299
|
+
gaps").
|
|
300
|
+
|
|
301
|
+
#### What you must not write (forbidden — validator hard-fails)
|
|
302
|
+
|
|
303
|
+
- **Numeric indicator periods.** `EMA 12`, `RSI 14`, `MA 200`, `ATR 1.5`,
|
|
304
|
+
`Bollinger 20`, `MACD 9`, `ADX 14`, `Stochastic 5`, `VWAP 30`, `MFI 14`,
|
|
305
|
+
`CCI 20`, `OBV 50`. Pattern: any indicator name immediately followed by a
|
|
306
|
+
number.
|
|
307
|
+
- **Numeric lookback windows.** `14 bars`, `20 candles`, `5-period`, `30-day`,
|
|
308
|
+
`4-hour`, `15-minute`, `90 days`, `1 week`. Pattern: any number followed by
|
|
309
|
+
a time/candle/period unit.
|
|
310
|
+
- **Explicit numeric thresholds.** `> 30`, `<= 0.7`, `>= 3%`, `drops below 5%`,
|
|
311
|
+
`volatility above 25%`. Any explicit comparison operator with a number, or
|
|
312
|
+
any standalone percentage with a number, is forbidden.
|
|
313
|
+
- **Multipliers and ratios.** `1.5x ATR`, `2x volatility`, `3:1 reward/risk`.
|
|
314
|
+
Any `<number>x` or numeric ratio is forbidden.
|
|
315
|
+
- **Formulas or pseudocode.** No `=`, no arithmetic expressions, no `if/then`
|
|
316
|
+
blocks, no parameter names from the source code.
|
|
317
|
+
- **Default values for tunable parameters.** Do not mention specific defaults
|
|
318
|
+
even though they are public in `manifest.strategy_config`. Describe the
|
|
319
|
+
*effect* of changing the parameter, not its default.
|
|
320
|
+
- **Specific provider/endpoint names.** No `data.crypto.futures.kline`, no
|
|
321
|
+
`Coinglass`, no `Binance funding_weighted`. Stay one level above the SDK.
|
|
322
|
+
|
|
323
|
+
#### Example
|
|
324
|
+
|
|
325
|
+
See the `btc-ema-crossover` manifest example above for a full 300–400 word
|
|
326
|
+
`long_description` block that satisfies all rules.
|
|
327
|
+
|
|
328
|
+
#### Common authoring mistakes
|
|
329
|
+
|
|
330
|
+
- Repeating `description` verbatim or padding it to length. The validator
|
|
331
|
+
catches near-duplicate strings.
|
|
332
|
+
- Writing in numbered list / bullet form ("**1.** Goal: …"). Keep it as
|
|
333
|
+
flowing prose.
|
|
334
|
+
- Naming the indicators by acronym alone with no number (`uses EMA`, `uses
|
|
335
|
+
RSI`). The validator allows this — a clue is fine, an exact period is not —
|
|
336
|
+
but treat naked indicator-name name-dropping as a code smell. Prefer
|
|
337
|
+
category-level language ("uses moving-average crossovers", "uses momentum
|
|
338
|
+
oscillator").
|
|
339
|
+
- Mentioning *backtest* configuration parameters (`max_backtest_symbols`,
|
|
340
|
+
`backtest_batch_size`). These are operational, not strategy semantics, and
|
|
341
|
+
do not belong in this field.
|
|
342
|
+
- Any text that translates to "buy when X drops more than N percent". Rewrite
|
|
343
|
+
as "buys after a sharp washout move" without a number.
|
|
344
|
+
|
|
345
|
+
## backtest.yaml
|
|
346
|
+
|
|
347
|
+
Optional Nautilus replay specification. This file is only valid when
|
|
348
|
+
`manifest.yaml` sets `backtest_support: full`.
|
|
349
|
+
|
|
350
|
+
The runner exposes this file to Playbook code via `runtime.backtest_spec`.
|
|
351
|
+
|
|
352
|
+
Sections:
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
| Field | Type | Description |
|
|
356
|
+
| ----------------------------- | ------------------------ | ------------------------------------------------------------------- |
|
|
357
|
+
| `venue` | mapping | Venue name, account type, OMS type, and starting balances |
|
|
358
|
+
| `instrument` or `instruments` | mapping or list[mapping] | Explicit instrument definitions and `bar_type` declarations |
|
|
359
|
+
| `strategy` | mapping | Author strategy module/class entry plus config payload |
|
|
360
|
+
| `execution` | mapping | Optional replay window such as `start` / `end` |
|
|
361
|
+
| `data_requirements` | mapping | Optional replay data contract such as required enriched bar columns |
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
Optional `data_requirements.required_bar_fields` lets a deterministic strategy
|
|
365
|
+
declare extra normalized bar columns it expects in addition to core OHLCV.
|
|
366
|
+
These names should use lower snake case to match the replay engine's normalized
|
|
367
|
+
DataFrame columns, for example `quote_volume`, `trade_count`, or
|
|
368
|
+
`taker_buy_volume`.
|
|
369
|
+
|
|
370
|
+
Every backtest instrument must declare explicit `maker_fee` and `taker_fee`.
|
|
371
|
+
Do not rely on zero-fee defaults. High-frequency Playbooks can look profitable
|
|
372
|
+
or only slightly negative without fees, while real execution would pay a fee on
|
|
373
|
+
every entry and exit. Use conservative exchange rates for the target venue, for
|
|
374
|
+
example `maker_fee: "0.0002"` and `taker_fee: "0.0005"` for a simple Binance
|
|
375
|
+
contract assumption.
|
|
376
|
+
|
|
377
|
+
Data coverage is part of the package contract. If a strategy requires enriched
|
|
378
|
+
columns such as `quote_volume`, `taker_buy_ratio`, open interest, funding, or
|
|
379
|
+
liquidation data, author code must prove that the selected DataSDK
|
|
380
|
+
endpoint/provider/symbol combination returns enough rows for the claimed replay
|
|
381
|
+
window and the exact fields used by the strategy. Do not silently fill a missing
|
|
382
|
+
decision feature with constants such as `0`, `0.5`, or `False` and still claim a
|
|
383
|
+
valid backtest. If a feature is degraded, expose that in metrics/meta or fail
|
|
384
|
+
the run with a clear error.
|
|
385
|
+
|
|
386
|
+
Large multi-symbol backtests must batch data fetches instead of issuing one
|
|
387
|
+
tight loop over every symbol and endpoint. If a Playbook scans many symbols
|
|
388
|
+
across several historical datasets, expose controls such as
|
|
389
|
+
`max_backtest_symbols`, `backtest_batch_size`, and
|
|
390
|
+
`backtest_batch_sleep_seconds` in both `strategy_config` and
|
|
391
|
+
`user_config_schema`. Default to a modest slice, for example 30 symbols in
|
|
392
|
+
batches of 5 with a short sleep between batches, and report
|
|
393
|
+
`symbols_requested`, `symbols_loaded`, batch settings, and skipped symbols in
|
|
394
|
+
metrics/meta.
|
|
395
|
+
|
|
396
|
+
When `backtest.yaml` declares more instruments than the data fetch actually
|
|
397
|
+
loads, author code must filter the effective runtime spec to the loaded
|
|
398
|
+
instrument ids before calling `backtest.run(...)`. The engine expects OHLCV data
|
|
399
|
+
for every declared instrument and will fail if the spec still includes missing
|
|
400
|
+
symbols. For full-universe evidence, split the symbol universe across multiple
|
|
401
|
+
runs or a controlled workflow rather than making one default run fetch every
|
|
402
|
+
symbol.
|
|
403
|
+
|
|
404
|
+
Sizing is also part of the public contract. Backtest and live signal output
|
|
405
|
+
should expose `notional_usdt`, `min_open_notional_usdt`, and `sizing_ok` when
|
|
406
|
+
orders are sized from margin budgets. If the configured margin and leverage are
|
|
407
|
+
too small for exchange lot size, tell the user to raise margin or leverage.
|
|
408
|
+
|
|
409
|
+
When the strategy class defines `set_feature_frames(...)` or exposes a
|
|
410
|
+
`feature_frames` attribute, the replay engine injects one full DataFrame per
|
|
411
|
+
instrument ID with those extra columns preserved. Nautilus bar construction
|
|
412
|
+
still consumes OHLCV, but the strategy can read richer columns from the
|
|
413
|
+
injected feature frames.
|
|
414
|
+
|
|
415
|
+
Use `getagent.backtest.prepare_frame()` / `getagent.backtest.build_feature_frame()`
|
|
416
|
+
in author code to assemble those extra columns from multiple `getagent.data`
|
|
417
|
+
datasets before calling `backtest.run(...)`.
|
|
418
|
+
|
|
419
|
+
Minimal example:
|
|
420
|
+
|
|
421
|
+
```yaml
|
|
422
|
+
venue:
|
|
423
|
+
name: BINANCE
|
|
424
|
+
account_type: CASH
|
|
425
|
+
oms_type: NETTING
|
|
426
|
+
starting_balances:
|
|
427
|
+
- amount: 100000
|
|
428
|
+
currency: USDT
|
|
429
|
+
|
|
430
|
+
strategy:
|
|
431
|
+
module: strategy
|
|
432
|
+
class: DemoStrategy
|
|
433
|
+
config_class: DemoStrategyConfig
|
|
434
|
+
config:
|
|
435
|
+
order_id_tag: "001"
|
|
436
|
+
trade_size: "0.01"
|
|
437
|
+
|
|
438
|
+
instrument:
|
|
439
|
+
id: BTCUSDT.BINANCE
|
|
440
|
+
kind: spot
|
|
441
|
+
raw_symbol: BTCUSDT
|
|
442
|
+
base_currency: BTC
|
|
443
|
+
quote_currency: USDT
|
|
444
|
+
price_precision: 2
|
|
445
|
+
size_precision: 6
|
|
446
|
+
price_increment: "0.01"
|
|
447
|
+
size_increment: "0.000001"
|
|
448
|
+
lot_size: "0.000001"
|
|
449
|
+
maker_fee: "0.0002"
|
|
450
|
+
taker_fee: "0.0005"
|
|
451
|
+
bar_type: BTCUSDT.BINANCE-1-HOUR-LAST-EXTERNAL
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Feature-aware example:
|
|
455
|
+
|
|
456
|
+
```yaml
|
|
457
|
+
venue:
|
|
458
|
+
name: BINANCE
|
|
459
|
+
account_type: CASH
|
|
460
|
+
oms_type: NETTING
|
|
461
|
+
starting_balances:
|
|
462
|
+
- amount: 100000
|
|
463
|
+
currency: USDT
|
|
464
|
+
|
|
465
|
+
strategy:
|
|
466
|
+
module: strategy
|
|
467
|
+
class: PriceVolStrategy
|
|
468
|
+
config_class: PriceVolStrategyConfig
|
|
469
|
+
|
|
470
|
+
instrument:
|
|
471
|
+
id: BTCUSDT.BINANCE
|
|
472
|
+
kind: spot
|
|
473
|
+
raw_symbol: BTCUSDT
|
|
474
|
+
base_currency: BTC
|
|
475
|
+
quote_currency: USDT
|
|
476
|
+
price_precision: 2
|
|
477
|
+
size_precision: 6
|
|
478
|
+
price_increment: "0.01"
|
|
479
|
+
size_increment: "0.000001"
|
|
480
|
+
lot_size: "0.000001"
|
|
481
|
+
maker_fee: "0.0002"
|
|
482
|
+
taker_fee: "0.0005"
|
|
483
|
+
bar_type: BTCUSDT.BINANCE-1-HOUR-LAST-EXTERNAL
|
|
484
|
+
|
|
485
|
+
data_requirements:
|
|
486
|
+
required_bar_fields:
|
|
487
|
+
- quote_volume
|
|
488
|
+
- trade_count
|
|
489
|
+
- taker_buy_volume
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## src/main.py
|
|
493
|
+
|
|
494
|
+
Sandbox entry point. The runner executes the package as `python -m src.main`.
|
|
495
|
+
`src/main.py` remains the required handoff into the runtime, but additional
|
|
496
|
+
modules under `src/**` are first-class and encouraged.
|
|
497
|
+
|
|
498
|
+
For packages with both live and backtest behavior, keep `manifest.yaml`
|
|
499
|
+
immutable and route in code:
|
|
500
|
+
|
|
501
|
+
```python
|
|
502
|
+
from getagent import runtime
|
|
503
|
+
from . import main_backtest, main_live
|
|
504
|
+
|
|
505
|
+
if runtime.is_historical():
|
|
506
|
+
main_backtest.run()
|
|
507
|
+
elif runtime.is_live():
|
|
508
|
+
main_live.run()
|
|
509
|
+
else:
|
|
510
|
+
raise ValueError(f"unsupported evaluation_mode={runtime.evaluation_mode!r}")
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Put shared data fetch and feature engineering in a neutral module such as
|
|
514
|
+
`features.py`. `main_backtest.py` must not import live trading code, because
|
|
515
|
+
historical runs should not require a configured trading identity.
|
|
516
|
+
|
|
517
|
+
**Allowed imports:** `getagent`, `nautilus_trader`, `pandas`, `numpy`, `json`,
|
|
518
|
+
`math`, `datetime`, `pathlib`, `asyncio`, `typing`, `dataclasses`,
|
|
519
|
+
`collections`, `functools`, `re`, `decimal`, `statistics`, `itertools`, plus
|
|
520
|
+
local modules under `src/`**.
|
|
521
|
+
|
|
522
|
+
**Blocked imports:** `requests`, `httpx`, `trade_sdk`, `ccxt`, `os`, `subprocess`,
|
|
523
|
+
`importlib`, `socket`, and other network/system/database libraries.
|
|
524
|
+
|
|
525
|
+
**Output convention:** signals via `runtime.emit_signal()`, reports/artifacts via
|
|
526
|
+
`/workspace/output/`, and public backtest charts via `backtest.generate_chart()`.
|
|
527
|
+
|
|
528
|
+
## Nautilus strategy lifecycle
|
|
529
|
+
|
|
530
|
+
The Playbook runner uses a NautilusTrader version where strategy lifecycle
|
|
531
|
+
cleanup APIs are instrument-scoped. Do not call these methods without an
|
|
532
|
+
instrument id:
|
|
533
|
+
|
|
534
|
+
```python
|
|
535
|
+
def on_stop(self) -> None:
|
|
536
|
+
if self.config.instrument_id is not None:
|
|
537
|
+
self.cancel_all_orders(self.config.instrument_id)
|
|
538
|
+
self.close_all_positions(self.config.instrument_id)
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
For multi-instrument strategies, iterate `instrument_ids`:
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
def on_stop(self) -> None:
|
|
545
|
+
for instrument_id in self.config.instrument_ids:
|
|
546
|
+
self.cancel_all_orders(instrument_id)
|
|
547
|
+
self.close_all_positions(instrument_id)
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
Invalid patterns such as `self.cancel_all_orders()` or
|
|
551
|
+
`self.close_all_positions()` are rejected by `scripts/validate.py` and
|
|
552
|
+
the server-side upload validator because they fail at replay shutdown.
|