alphaspec 0.1.0__py3-none-any.whl
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.
- alphaspec/__init__.py +8 -0
- alphaspec/_data/catalog/i18n/en.json +1016 -0
- alphaspec/_data/catalog/indicators.json +9790 -0
- alphaspec/_data/docs/MARKETS.md +29 -0
- alphaspec/_data/docs/RULES.md +133 -0
- alphaspec/_data/docs/RUNTIME_API.md +80 -0
- alphaspec/_data/docs/SPEC.md +99 -0
- alphaspec/_data/examples/artifacts/01-ema-cross-us-equity.json +20 -0
- alphaspec/_data/examples/artifacts/02-rsi-reversion-params.json +25 -0
- alphaspec/_data/examples/artifacts/03-mtf-trend-pullback.json +25 -0
- alphaspec/_data/examples/artifacts/04-breakout-retest-sequence.json +58 -0
- alphaspec/_data/examples/artifacts/05-cn-limit-up-pullback.json +33 -0
- alphaspec/_data/examples/scores/01-model-scores-cn-stock.json +17 -0
- alphaspec/_data/examples/scores/02-target-weights-us-equity.json +13 -0
- alphaspec/_data/schema/0.1/artifact.schema.json +259 -0
- alphaspec/_data/schema/0.1/common.schema.json +96 -0
- alphaspec/_data/schema/0.1/evidence.schema.json +152 -0
- alphaspec/_data/schema/0.1/gate-result.schema.json +55 -0
- alphaspec/_data/schema/0.1/score.schema.json +79 -0
- alphaspec/_data/skills/alphaspec/SKILL.md +93 -0
- alphaspec/_resources.py +77 -0
- alphaspec/cli.py +360 -0
- alphaspec/client.py +146 -0
- alphaspec/lints.py +266 -0
- alphaspec/mcp_server.py +231 -0
- alphaspec/validate.py +108 -0
- alphaspec-0.1.0.dist-info/METADATA +322 -0
- alphaspec-0.1.0.dist-info/RECORD +31 -0
- alphaspec-0.1.0.dist-info/WHEEL +4 -0
- alphaspec-0.1.0.dist-info/entry_points.txt +3 -0
- alphaspec-0.1.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Market registry
|
|
2
|
+
|
|
3
|
+
Market ids are lower snake case. A runtime declares which ids it supports and rejects the
|
|
4
|
+
rest. New ids are added here by pull request.
|
|
5
|
+
|
|
6
|
+
| id | Instruments | Calendar / time zone | Symbol form | Notes |
|
|
7
|
+
|---|---|---|---|---|
|
|
8
|
+
| `cn_stock` | China A-shares | SSE/SZSE, Asia/Shanghai | `600000.SH`, `000001.SZ`, `830799.BJ` | T+1, daily price limits, 100-share lots |
|
|
9
|
+
| `cn_etf` | China ETFs | SSE/SZSE, Asia/Shanghai | `510300.SH` | |
|
|
10
|
+
| `cn_convbond` | China convertible bonds | SSE/SZSE, Asia/Shanghai | `113039.SH` | quantity in units of 10 bonds |
|
|
11
|
+
| `cn_future` | China futures | CFFEX/SHFE/DCE/CZCE/INE/GFEX, Asia/Shanghai | `RB2505.SHF` | night sessions belong to the next trading day |
|
|
12
|
+
| `cn_option` | China options | SSE/SZSE/CFFEX, Asia/Shanghai | `10008001.SH` | contract multiplier |
|
|
13
|
+
| `hk_stock` | Hong Kong equities | HKEX, Asia/Hong_Kong | `00700.HK` | board lots vary per stock; half-day sessions |
|
|
14
|
+
| `us_equity` | US equities and ETFs | NYSE/Nasdaq, America/New_York | `AAPL` | |
|
|
15
|
+
| `crypto_spot` | crypto spot pairs | 24/7, UTC | `BTCUSDT` | |
|
|
16
|
+
|
|
17
|
+
## Indicator profiles
|
|
18
|
+
|
|
19
|
+
Every catalog entry has a profile:
|
|
20
|
+
|
|
21
|
+
| profile | Meaning | Allowed on |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `core` | computable from OHLCV bars | any market |
|
|
24
|
+
| `ext.cn` | encodes China exchange rules: price-limit streaks, sealed boards, call auction, main-force money flow | `cn_*` |
|
|
25
|
+
| `ext.l2` | needs order-book or trade-by-trade data | markets where the runtime's data source provides it |
|
|
26
|
+
| `ext.data` | needs a runtime dataset beyond bars (fundamentals, index series) | where the runtime provides it |
|
|
27
|
+
|
|
28
|
+
Market rules are scoped, not deleted. A new market brings its own rules the same way:
|
|
29
|
+
as a profile, with lint rules stating where it applies.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Lint rules
|
|
2
|
+
|
|
3
|
+
Schema validation tells you a document is well-formed. These rules tell you it will do
|
|
4
|
+
what you think. Every rule here exists because a runtime accepted the mistake, ran it,
|
|
5
|
+
and produced wrong results without raising an error.
|
|
6
|
+
|
|
7
|
+
Severity: **error** = a compliant runtime must reject the document.
|
|
8
|
+
**warning** = accepted, but almost certainly not what the author meant.
|
|
9
|
+
|
|
10
|
+
Each rule has at least one case in `conformance/cases/` named after it.
|
|
11
|
+
|
|
12
|
+
## Artifact rules
|
|
13
|
+
|
|
14
|
+
### AS001
|
|
15
|
+
**Indicator reference does not resolve** · error
|
|
16
|
+
|
|
17
|
+
A rule refers to `{"ind": "alias"}` but `dsl.indicators` has no such alias (`close` is
|
|
18
|
+
built in). The reference runtime compiles the node to nothing; the strategy runs, never
|
|
19
|
+
enters, and reports nothing wrong.
|
|
20
|
+
|
|
21
|
+
### AS002
|
|
22
|
+
**Parameter reference does not resolve** · error
|
|
23
|
+
|
|
24
|
+
`{"ref": "name"}` where `dsl.params` has no `name`.
|
|
25
|
+
|
|
26
|
+
### AS003
|
|
27
|
+
**Higher-timeframe indicator uses LIVE bars (look-ahead)** · error
|
|
28
|
+
|
|
29
|
+
An indicator on a timeframe above the primary one with `barPolicy: "LIVE"`. Live, that
|
|
30
|
+
reads the still-forming bar, which is legitimate. In a backtest, that bar has already
|
|
31
|
+
finished: a daily bar read at 10:00 contains the 15:00 close. Backtest results look
|
|
32
|
+
excellent and cannot be reproduced. Use `CLOSED` (the default): only completed
|
|
33
|
+
higher-timeframe bars are visible.
|
|
34
|
+
|
|
35
|
+
### AS004
|
|
36
|
+
**Indicator references form a cycle** · error
|
|
37
|
+
|
|
38
|
+
`a` uses `b` and `b` uses `a`.
|
|
39
|
+
|
|
40
|
+
### AS005
|
|
41
|
+
**Unknown indicator type** · error
|
|
42
|
+
|
|
43
|
+
The type is not in `catalog/indicators.json`.
|
|
44
|
+
|
|
45
|
+
### AS006
|
|
46
|
+
**Unknown indicator parameter** · warning
|
|
47
|
+
|
|
48
|
+
A key the indicator type does not take, e.g. `length` on `EMA` (which takes `period`).
|
|
49
|
+
The runtime ignores it and uses the default, so the strategy runs with a different
|
|
50
|
+
parameter than the one written.
|
|
51
|
+
|
|
52
|
+
### AS007
|
|
53
|
+
**Indicator not available on this market** · error
|
|
54
|
+
|
|
55
|
+
An indicator from the `ext.cn` profile (price-limit streaks, sealed limit-up boards,
|
|
56
|
+
call auction, main-force money flow) on a market outside `cn_*`. These encode China
|
|
57
|
+
exchange rules and have no meaning elsewhere.
|
|
58
|
+
|
|
59
|
+
### AS008
|
|
60
|
+
**timeframe/barPolicy ignored for primary-series-only indicator** · warning
|
|
61
|
+
|
|
62
|
+
Some indicators (listed in the catalog under `primarySeriesOnly`) always compute on the
|
|
63
|
+
primary series with their own daily aggregation. A `timeframe` or `barPolicy` on them
|
|
64
|
+
has no effect.
|
|
65
|
+
|
|
66
|
+
### AS009
|
|
67
|
+
**Indicator timeframe finer than primary timeframe** · error
|
|
68
|
+
|
|
69
|
+
A 5m indicator on a 1d strategy. A finer series cannot be derived from coarser bars.
|
|
70
|
+
|
|
71
|
+
### AS010
|
|
72
|
+
**tick timeframe cannot be bar-backtested** · warning
|
|
73
|
+
|
|
74
|
+
`tick` means "evaluate on every market-data frame". That timing dimension does not
|
|
75
|
+
exist in bar history, so a bar backtest of a tick strategy would be a different strategy.
|
|
76
|
+
|
|
77
|
+
### AS011
|
|
78
|
+
**Symbol missing venue suffix** · error
|
|
79
|
+
|
|
80
|
+
On `cn_*` and `hk_*` markets the code is only unique together with its venue:
|
|
81
|
+
`600000.SH`, `000001.SZ`, `00700.HK`. A bare code is stored and looked up as a different
|
|
82
|
+
series, so data silently splits in two.
|
|
83
|
+
|
|
84
|
+
### AS012
|
|
85
|
+
**searchTrials required for generated output** · error
|
|
86
|
+
|
|
87
|
+
`producer.kind` is `AI_AGENT` or `FACTOR_MINER` and `searchTrials` is missing. Anyone who
|
|
88
|
+
tries a thousand variants will find one with a great backtest. The number of trials is
|
|
89
|
+
the input to correcting for that (deflated Sharpe); without it the gate cannot tell
|
|
90
|
+
search luck from signal.
|
|
91
|
+
|
|
92
|
+
### AS013
|
|
93
|
+
**No exit rule** · warning
|
|
94
|
+
|
|
95
|
+
Positions close only through stop rules or rebalancing.
|
|
96
|
+
|
|
97
|
+
### AS014
|
|
98
|
+
**Intraday indicator on a too-coarse primary timeframe** · error
|
|
99
|
+
|
|
100
|
+
Indicators such as `DAY_HIGH` or `MINUTES_SINCE_OPEN` measure within a session. On a
|
|
101
|
+
daily strategy there is nothing inside the bar to measure.
|
|
102
|
+
|
|
103
|
+
### AS015
|
|
104
|
+
**Indicator defined but never used** · warning
|
|
105
|
+
|
|
106
|
+
Usually a leftover from editing, or an entry/exit rule that references the wrong alias.
|
|
107
|
+
|
|
108
|
+
## Score rules
|
|
109
|
+
|
|
110
|
+
### AS101
|
|
111
|
+
**Duplicate symbol in submission** · error
|
|
112
|
+
|
|
113
|
+
### AS102
|
|
114
|
+
**Every score is null** · error
|
|
115
|
+
|
|
116
|
+
### AS103
|
|
117
|
+
**asOf is in the future** · error
|
|
118
|
+
|
|
119
|
+
`asOf` is the last trading day whose information the scores used. A future date means
|
|
120
|
+
the producer's clock or calendar is wrong, and every downstream timing is suspect.
|
|
121
|
+
|
|
122
|
+
### AS104
|
|
123
|
+
**Zeros look like missing values** · warning
|
|
124
|
+
|
|
125
|
+
At least 20% of scores are exactly `0` and none are `null`. If `0` means "no data",
|
|
126
|
+
send `null`: in a cross-sectional ranking `0` is a real position, and those symbols
|
|
127
|
+
will be bought or sold as if the model had an opinion about them.
|
|
128
|
+
|
|
129
|
+
### AS105
|
|
130
|
+
**Weights sum above 1** · error
|
|
131
|
+
|
|
132
|
+
Target weights must sum to at most 1; the remainder is cash. Leverage is a runtime and
|
|
133
|
+
account decision, not a field in the submission.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Runtime agent API (v1)
|
|
2
|
+
|
|
3
|
+
What a runtime exposes to agents and SDKs. The reference runtime (EasyQuant) implements it
|
|
4
|
+
under `/api/agent/v1`. Authenticate every request with an API key created in the runtime's
|
|
5
|
+
account page:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Authorization: Bearer eqk_<keyId>_<secret>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
An API key can submit documents, run evaluations and read results. It **cannot** place
|
|
12
|
+
orders, operate accounts or manage keys; the runtime rejects it everywhere outside this
|
|
13
|
+
prefix.
|
|
14
|
+
|
|
15
|
+
| Method & path | Success | Other responses |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `GET /whoami` | 200 identity, contract version, what the key can and cannot do | 401 invalid / revoked / expired key |
|
|
18
|
+
| `POST /artifacts` — body: an `artifact` document | 201 `{artifactId, warnings}` | 422 `{issues}` (same codes as the local validator) · 400 unusable universe |
|
|
19
|
+
| `GET /artifacts` | 200 your submissions, newest first, with the latest verdict | |
|
|
20
|
+
| `POST /artifacts/{id}/evaluate` | 202 `{evaluationId, status}` | 429 daily evaluation quota used up · 503 queue full |
|
|
21
|
+
| `GET /artifacts/{id}/gate-result` | 200 `gate-result` document | 202 still running · 409 `{status: FAILED, error}` |
|
|
22
|
+
| `POST /artifacts/{id}/promote` — body optional: `{name}` | 201 `{strategyId, created, enabled: false}` · 200 if already promoted | 400 gate not passed · runtime product rules (market, pool size, names) apply as in its UI |
|
|
23
|
+
|
|
24
|
+
## Evaluation
|
|
25
|
+
|
|
26
|
+
The runtime picks the windows; the submitter cannot. The reference runtime runs **one**
|
|
27
|
+
continuous backtest and reports statistics for two segments of it, so positions carry
|
|
28
|
+
across the boundary and indicators warm up once:
|
|
29
|
+
|
|
30
|
+
| Strategy timeframe | In-sample | Out-of-sample |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `1d`, `1w` | 4 years | the most recent 1 year |
|
|
33
|
+
| intraday | 18 months | the most recent 6 months |
|
|
34
|
+
|
|
35
|
+
Performance figures are recomputed by the runtime (`computedBy: PLATFORM`) and annualised
|
|
36
|
+
on trading time (A-shares 242 days a year, Hong Kong 247, US 252; crypto 24×7). Checks beyond
|
|
37
|
+
the basic in-sample return / drawdown / Sharpe thresholds:
|
|
38
|
+
|
|
39
|
+
Each check names what its number is in `metric` (`excessReturnVsIndex`, `sharpe`,
|
|
40
|
+
`deflatedSharpeProbability`, ...). Read it rather than inferring from the code: the same check can
|
|
41
|
+
change measure.
|
|
42
|
+
|
|
43
|
+
- `GATE_OUT_OF_SAMPLE` — the out-of-sample segment must **beat the market index over the same
|
|
44
|
+
period** (`metric: excessReturnVsIndex`, a fraction, threshold 0) and stay within the drawdown limit. A single
|
|
45
|
+
year in a falling market makes absolute Sharpe look bad without saying anything about the
|
|
46
|
+
strategy; relative performance does. Markets without a benchmark index in the runtime fall
|
|
47
|
+
back to an absolute Sharpe floor, and the hint says so.
|
|
48
|
+
- `GATE_MULTIPLE_TESTING` — Deflated Sharpe on the in-sample segment using `producer.searchTrials`;
|
|
49
|
+
the reference runtime passes it at 0.90. For a daily strategy (4-year in-sample) that is roughly an
|
|
50
|
+
annualised Sharpe of 0.64 with 1 trial, 0.90 with 2, 1.24 with 5 and 1.43 with 10: every extra
|
|
51
|
+
candidate you tried raises the bar. The gate only promotes to paper trading, which is the real
|
|
52
|
+
out-of-sample test.
|
|
53
|
+
- `GATE_LOOKAHEAD` — the structural look-ahead checks passed at intake.
|
|
54
|
+
|
|
55
|
+
"Out-of-sample" here means *chosen by the platform*, not *unseen at submission*: recent
|
|
56
|
+
market data is public. The only truly unseen period is the one after you submit, which is
|
|
57
|
+
what paper trading is for.
|
|
58
|
+
|
|
59
|
+
## Promotion
|
|
60
|
+
|
|
61
|
+
`promote` turns a gate-passed artifact into a paper-trading strategy in your runtime
|
|
62
|
+
account. It is created **disabled**; you start it yourself in the runtime's UI.
|
|
63
|
+
|
|
64
|
+
The reference runtime stores strategies with plain values only: on intake, `dsl.params` is
|
|
65
|
+
inlined (`{"ref": "x"}` becomes the value, or `{"const": value}` where an operand is expected)
|
|
66
|
+
and dropped. The promoted strategy therefore carries no `params`; your submitted document, with
|
|
67
|
+
its parameters, stays attached to the artifact.
|
|
68
|
+
|
|
69
|
+
## Python
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from alphaspec import Client
|
|
73
|
+
|
|
74
|
+
c = Client() # ALPHASPEC_BASE_URL, ALPHASPEC_API_KEY
|
|
75
|
+
aid = c.submit(doc)["artifactId"] # validates locally first
|
|
76
|
+
c.evaluate(aid)
|
|
77
|
+
gate = c.wait(aid) # polls until done
|
|
78
|
+
if gate["passed"]:
|
|
79
|
+
c.promote(aid, name="my strategy")
|
|
80
|
+
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# AlphaSpec 0.1 — semantics
|
|
2
|
+
|
|
3
|
+
The JSON Schemas in `schema/0.1/` define the shape of each document. This page defines
|
|
4
|
+
what the fields **mean**, where the shape alone cannot. Where this page and a runtime
|
|
5
|
+
disagree, the runtime is non-compliant.
|
|
6
|
+
|
|
7
|
+
## 1. Documents
|
|
8
|
+
|
|
9
|
+
Every document has `contractVersion` and `kind`.
|
|
10
|
+
|
|
11
|
+
| kind | Written by | Purpose |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `artifact` | strategy author / agent | a complete declarative strategy (L2) |
|
|
14
|
+
| `score` | model / research pipeline | cross-sectional scores or target weights (L1) |
|
|
15
|
+
| `gate-result` | runtime | the verdict on a submission |
|
|
16
|
+
| `evidence` | runtime | what happened when it ran |
|
|
17
|
+
|
|
18
|
+
A runtime must refuse a `contractVersion` it does not implement rather than guess.
|
|
19
|
+
|
|
20
|
+
## 2. Time
|
|
21
|
+
|
|
22
|
+
### 2.1 Market-local calendar
|
|
23
|
+
All dates (`asOf`, sample windows) are trading days in the **market's own calendar and
|
|
24
|
+
time zone**: `Asia/Shanghai` for `cn_*`, `America/New_York` for `us_equity`, and so on.
|
|
25
|
+
"Today" for a market is never the server's date.
|
|
26
|
+
|
|
27
|
+
### 2.2 `asOf` for scores
|
|
28
|
+
A score with `asOf = T` may use information available at T's close and nothing later.
|
|
29
|
+
It is executed no earlier than the next session after T. A runtime receiving a score
|
|
30
|
+
after its rebalance cutoff for T+1 must say what it did (skipped, used it late) in
|
|
31
|
+
evidence; it must not silently trade on stale scores.
|
|
32
|
+
|
|
33
|
+
### 2.3 Bars
|
|
34
|
+
A bar is identified by its **end**: the 1d bar of T covers T's whole session and becomes
|
|
35
|
+
visible only after the session closes. A 15m bar labelled 10:00 covers 09:45–10:00.
|
|
36
|
+
|
|
37
|
+
### 2.4 `barPolicy`
|
|
38
|
+
On an indicator whose `timeframe` is coarser than the artifact's primary timeframe:
|
|
39
|
+
|
|
40
|
+
- `CLOSED` (default): the indicator sees only completed bars of its timeframe. At 10:00
|
|
41
|
+
on day T, a daily indicator sees days up to T-1.
|
|
42
|
+
- `LIVE`: the indicator includes the forming bar, updated with intraday data.
|
|
43
|
+
|
|
44
|
+
`LIVE` is meaningful in live trading, and look-ahead in a backtest unless the runtime
|
|
45
|
+
rebuilds the forming bar strictly from data before each evaluation point. Version 0.1
|
|
46
|
+
forbids it for higher timeframes (rule AS003).
|
|
47
|
+
|
|
48
|
+
## 3. Instruments
|
|
49
|
+
|
|
50
|
+
### 3.1 Identity
|
|
51
|
+
An instrument is `(market, symbol)`. On `cn_*` and `hk_*` markets the venue suffix is
|
|
52
|
+
part of the symbol (`600000.SH`); elsewhere the symbol is the venue's own ticker
|
|
53
|
+
(`AAPL`, `BTCUSDT`).
|
|
54
|
+
|
|
55
|
+
### 3.2 Units
|
|
56
|
+
Quantities in evidence are in `caliber.volumeUnit`. Derivatives are counted in
|
|
57
|
+
contracts; notional = quantity × price × contract multiplier, and
|
|
58
|
+
`caliber.multiplierApplied` states whether reported notionals already include it.
|
|
59
|
+
Monetary fields are in `caliber.currency`.
|
|
60
|
+
|
|
61
|
+
## 4. Rule tree (artifact `dsl`)
|
|
62
|
+
|
|
63
|
+
- `indicators` maps aliases to indicator instances. Rules reference them as
|
|
64
|
+
`{"ind": "alias"}`. `close` is a built-in alias.
|
|
65
|
+
- Operands are `{"ind"}`, `{"const"}`, `{"ref"}`, inline arithmetic
|
|
66
|
+
`{"op": "SUB", "left", "right"}`, or rule statistics `{"op": "COUNT" | "BARS_SINCE", "rule", "bars"}`.
|
|
67
|
+
**A bare number is not an operand**; write `{"const": 0}`.
|
|
68
|
+
- Scalar settings (`period`, `bars`, `tolerancePct`, ...) take a number, `{"const"}` or `{"ref"}`.
|
|
69
|
+
- `{"ref": "name"}` resolves against `dsl.params`. Put anything you intend to tune there.
|
|
70
|
+
- Logical nodes: `AND`/`OR` take `left`/`right` rules; `NOT` and `DAY_LATCH` take `rule`.
|
|
71
|
+
- Comparisons: `GT GTE LT LTE EQ NEQ CROSS_UP CROSS_DOWN` take `left`/`right` operands.
|
|
72
|
+
- Temporal: `HOLD_FOR` (held on each of the last N bars), `WITHIN` (held on at least one
|
|
73
|
+
of the last N bars), `SEQUENCE` (`then` holds now and `first` held within the previous
|
|
74
|
+
N bars), `DAY_LATCH` (stays true for the rest of the session once true).
|
|
75
|
+
- Level events: `TOUCH BREAK RECLAIM RETEST HOLD` against any operand as `level`.
|
|
76
|
+
|
|
77
|
+
Entry fires on the bar where `entry` evaluates true; how and at what price the order is
|
|
78
|
+
placed is the runtime's execution model and is reported in evidence, not specified here.
|
|
79
|
+
|
|
80
|
+
## 5. Gates
|
|
81
|
+
|
|
82
|
+
A gate result with `computedBy: "SELF_REPORTED"` carries numbers the submitter supplied.
|
|
83
|
+
Public rankings and any automatic promotion to live trading must use `PLATFORM` results
|
|
84
|
+
only. Additional checks for generated output (`producer.kind` `AI_AGENT` or
|
|
85
|
+
`FACTOR_MINER`):
|
|
86
|
+
|
|
87
|
+
- `GATE_OUT_OF_SAMPLE`: the most recent segment of the runtime's evaluation, judged relative to
|
|
88
|
+
the market over the same period (beat the index, stay within the drawdown limit).
|
|
89
|
+
- `GATE_MULTIPLE_TESTING`: Sharpe deflated by `producer.searchTrials`.
|
|
90
|
+
- `GATE_LOOKAHEAD`: the structural checks of section 2 hold.
|
|
91
|
+
|
|
92
|
+
Deflation alone does not catch leakage; it is necessary, not sufficient.
|
|
93
|
+
|
|
94
|
+
## 6. What a document must never contain
|
|
95
|
+
|
|
96
|
+
- Orders, accounts, broker routes. A spec document states intent; execution goes through
|
|
97
|
+
the runtime's single order path, the same one a human uses.
|
|
98
|
+
- Code, or strings that are executed.
|
|
99
|
+
- Performance figures as trusted input.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractVersion": "0.1",
|
|
3
|
+
"kind": "artifact",
|
|
4
|
+
"title": "EMA 20/60 crossover",
|
|
5
|
+
"note": "The smallest useful artifact: two indicators, one entry, one exit, a fixed symbol list.",
|
|
6
|
+
"market": "us_equity",
|
|
7
|
+
"timeframe": "1d",
|
|
8
|
+
"dsl": {
|
|
9
|
+
"version": 1,
|
|
10
|
+
"indicators": {
|
|
11
|
+
"fast": { "type": "EMA", "period": 20 },
|
|
12
|
+
"slow": { "type": "EMA", "period": 60 }
|
|
13
|
+
},
|
|
14
|
+
"entry": { "type": "CROSS_UP", "left": { "ind": "fast" }, "right": { "ind": "slow" } },
|
|
15
|
+
"exit": { "type": "CROSS_DOWN", "left": { "ind": "fast" }, "right": { "ind": "slow" } }
|
|
16
|
+
},
|
|
17
|
+
"universe": { "mode": "SYMBOLS", "symbols": ["AAPL", "MSFT", "NVDA"] },
|
|
18
|
+
"riskProfile": { "maxSymbolExposurePct": 20, "maxTotalExposurePct": 60 },
|
|
19
|
+
"producer": { "kind": "HUMAN", "name": "example" }
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractVersion": "0.1",
|
|
3
|
+
"kind": "artifact",
|
|
4
|
+
"title": "RSI mean reversion with named parameters",
|
|
5
|
+
"note": "Thresholds live in dsl.params and are referenced with {\"ref\": ...}. A parameter scan or an agent iterating on this artifact changes one number in one place, and the diff says exactly that.",
|
|
6
|
+
"market": "crypto_spot",
|
|
7
|
+
"timeframe": "1h",
|
|
8
|
+
"dsl": {
|
|
9
|
+
"version": 1,
|
|
10
|
+
"params": { "rsiPeriod": 14, "oversold": 28, "exitLevel": 55 },
|
|
11
|
+
"indicators": {
|
|
12
|
+
"rsi": { "type": "RSI", "period": { "ref": "rsiPeriod" } }
|
|
13
|
+
},
|
|
14
|
+
"entry": { "type": "CROSS_UP", "left": { "ind": "rsi" }, "right": { "ref": "oversold" } },
|
|
15
|
+
"exit": { "type": "GTE", "left": { "ind": "rsi" }, "right": { "ref": "exitLevel" } }
|
|
16
|
+
},
|
|
17
|
+
"universe": { "mode": "SYMBOLS", "symbols": ["BTCUSDT", "ETHUSDT"] },
|
|
18
|
+
"riskProfile": { "maxOrderNotional": 5000, "maxDailyOrders": 12 },
|
|
19
|
+
"producer": {
|
|
20
|
+
"kind": "AI_AGENT",
|
|
21
|
+
"name": "example-agent@0.1.0",
|
|
22
|
+
"modelId": "claude-opus-5-5",
|
|
23
|
+
"searchTrials": 64
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractVersion": "0.1",
|
|
3
|
+
"kind": "artifact",
|
|
4
|
+
"title": "Daily trend filter, 15-minute pullback entry",
|
|
5
|
+
"note": "Multi-timeframe without look-ahead: the daily EMA is read with barPolicy CLOSED, i.e. only from completed daily bars. With LIVE, a backtest would see today's close at 10:00 (rule AS003 rejects that).",
|
|
6
|
+
"market": "hk_stock",
|
|
7
|
+
"timeframe": "15m",
|
|
8
|
+
"dsl": {
|
|
9
|
+
"version": 1,
|
|
10
|
+
"indicators": {
|
|
11
|
+
"dailyClose": { "type": "PRICE", "field": "CLOSE", "timeframe": "1d", "barPolicy": "CLOSED" },
|
|
12
|
+
"dailyEma": { "type": "EMA", "period": 50, "timeframe": "1d", "barPolicy": "CLOSED" },
|
|
13
|
+
"price": { "type": "PRICE", "field": "CLOSE" },
|
|
14
|
+
"ema20": { "type": "EMA", "period": 20 }
|
|
15
|
+
},
|
|
16
|
+
"entry": {
|
|
17
|
+
"type": "AND",
|
|
18
|
+
"left": { "type": "GT", "left": { "ind": "dailyClose" }, "right": { "ind": "dailyEma" } },
|
|
19
|
+
"right": { "type": "CROSS_UP", "left": { "ind": "price" }, "right": { "ind": "ema20" } }
|
|
20
|
+
},
|
|
21
|
+
"exit": { "type": "LT", "left": { "ind": "dailyClose" }, "right": { "ind": "dailyEma" } }
|
|
22
|
+
},
|
|
23
|
+
"universe": { "mode": "SYMBOLS", "symbols": ["00700.HK", "09988.HK"] },
|
|
24
|
+
"producer": { "kind": "HUMAN", "name": "example" }
|
|
25
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractVersion": "0.1",
|
|
3
|
+
"kind": "artifact",
|
|
4
|
+
"title": "Channel breakout, then retest within 10 bars",
|
|
5
|
+
"note": "Temporal composition: SEQUENCE requires the breakout first and the successful retest afterwards. Level events (BREAK, RETEST) take any operand as the level, here a 20-day Donchian upper band.",
|
|
6
|
+
"market": "cn_stock",
|
|
7
|
+
"timeframe": "1d",
|
|
8
|
+
"dsl": {
|
|
9
|
+
"version": 1,
|
|
10
|
+
"params": {
|
|
11
|
+
"retestBars": 10
|
|
12
|
+
},
|
|
13
|
+
"indicators": {
|
|
14
|
+
"upper": {
|
|
15
|
+
"type": "DONCHIAN_UPPER",
|
|
16
|
+
"period": 20
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"entry": {
|
|
20
|
+
"type": "SEQUENCE",
|
|
21
|
+
"first": {
|
|
22
|
+
"type": "BREAK",
|
|
23
|
+
"level": {
|
|
24
|
+
"ind": "upper"
|
|
25
|
+
},
|
|
26
|
+
"direction": "UP",
|
|
27
|
+
"minVolumeRatio": 1.5
|
|
28
|
+
},
|
|
29
|
+
"then": {
|
|
30
|
+
"type": "RETEST",
|
|
31
|
+
"level": {
|
|
32
|
+
"ind": "upper"
|
|
33
|
+
},
|
|
34
|
+
"direction": "UP",
|
|
35
|
+
"tolerancePct": 1.0
|
|
36
|
+
},
|
|
37
|
+
"bars": {
|
|
38
|
+
"ref": "retestBars"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"exit": {
|
|
42
|
+
"type": "BREAK",
|
|
43
|
+
"level": {
|
|
44
|
+
"ind": "upper"
|
|
45
|
+
},
|
|
46
|
+
"direction": "DOWN",
|
|
47
|
+
"tolerancePct": 3.0
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"universe": {
|
|
51
|
+
"mode": "UNIVERSE",
|
|
52
|
+
"universeId": "csi300"
|
|
53
|
+
},
|
|
54
|
+
"producer": {
|
|
55
|
+
"kind": "HUMAN",
|
|
56
|
+
"name": "example"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractVersion": "0.1",
|
|
3
|
+
"kind": "artifact",
|
|
4
|
+
"title": "Pullback after a limit-up streak (China extension)",
|
|
5
|
+
"note": "Uses LIMIT_UP_DAYS from the ext.cn profile. Market rules are not removed from the spec, they are scoped: the same artifact on us_equity is rejected by AS007 because price limits do not exist there.",
|
|
6
|
+
"market": "cn_stock",
|
|
7
|
+
"timeframe": "5m",
|
|
8
|
+
"dsl": {
|
|
9
|
+
"version": 1,
|
|
10
|
+
"params": { "drawdownFactor": 0.65 },
|
|
11
|
+
"indicators": {
|
|
12
|
+
"streak": { "type": "LIMIT_UP_DAYS", "lookbackDays": 10, "limitDays": 3, "matchMode": "AT_LEAST" },
|
|
13
|
+
"dailyHigh": { "type": "HIGHEST", "in": { "ind": "high1d" }, "period": 10, "timeframe": "1d", "barPolicy": "CLOSED" },
|
|
14
|
+
"high1d": { "type": "PRICE", "field": "HIGH", "timeframe": "1d", "barPolicy": "CLOSED" },
|
|
15
|
+
"drawdownLine": { "type": "MUL", "left": { "ind": "dailyHigh" }, "right": { "ref": "drawdownFactor" } },
|
|
16
|
+
"price": { "type": "PRICE", "field": "CLOSE" },
|
|
17
|
+
"ema20": { "type": "EMA", "period": 20 }
|
|
18
|
+
},
|
|
19
|
+
"entry": {
|
|
20
|
+
"type": "AND",
|
|
21
|
+
"left": {
|
|
22
|
+
"type": "AND",
|
|
23
|
+
"left": { "type": "GT", "left": { "ind": "streak" }, "right": { "const": 0 } },
|
|
24
|
+
"right": { "type": "LTE", "left": { "ind": "price" }, "right": { "ind": "drawdownLine" } }
|
|
25
|
+
},
|
|
26
|
+
"right": { "type": "CROSS_UP", "left": { "ind": "price" }, "right": { "ind": "ema20" } }
|
|
27
|
+
},
|
|
28
|
+
"exit": { "type": "CROSS_DOWN", "left": { "ind": "price" }, "right": { "ind": "ema20" } }
|
|
29
|
+
},
|
|
30
|
+
"universe": { "mode": "ALL_MARKET" },
|
|
31
|
+
"riskProfile": { "maxSymbolExposurePct": 8, "maxTotalExposurePct": 60, "maxImpactSlippageBps": 30 },
|
|
32
|
+
"producer": { "kind": "HUMAN", "name": "example" }
|
|
33
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractVersion": "0.1",
|
|
3
|
+
"kind": "score",
|
|
4
|
+
"asOf": "2026-09-30",
|
|
5
|
+
"market": "cn_stock",
|
|
6
|
+
"scoreName": "lgbm-v7",
|
|
7
|
+
"direction": "DESC",
|
|
8
|
+
"scores": [
|
|
9
|
+
{ "symbol": "600519.SH", "score": 1.8423 },
|
|
10
|
+
{ "symbol": "000858.SZ", "score": 1.5107 },
|
|
11
|
+
{ "symbol": "601318.SH", "score": null },
|
|
12
|
+
{ "symbol": "300750.SZ", "score": -0.9912 }
|
|
13
|
+
],
|
|
14
|
+
"execution": { "topN": 30, "weighting": "SCORE_PROPORTIONAL", "universePolicy": "SUBMITTED",
|
|
15
|
+
"riskProfile": { "maxSymbolExposurePct": 5, "maxTotalExposurePct": 80 } },
|
|
16
|
+
"producer": { "kind": "INSTITUTION", "name": "example-desk", "searchTrials": 1 }
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractVersion": "0.1",
|
|
3
|
+
"kind": "score",
|
|
4
|
+
"asOf": "2026-09-30",
|
|
5
|
+
"market": "us_equity",
|
|
6
|
+
"scoreName": "risk-parity-sleeve",
|
|
7
|
+
"weights": [
|
|
8
|
+
{ "symbol": "SPY", "weight": 0.40 },
|
|
9
|
+
{ "symbol": "TLT", "weight": 0.35 },
|
|
10
|
+
{ "symbol": "GLD", "weight": 0.15 }
|
|
11
|
+
],
|
|
12
|
+
"producer": { "kind": "HUMAN", "name": "example" }
|
|
13
|
+
}
|