alphaspec 0.2.0__tar.gz → 0.3.0__tar.gz
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-0.2.0 → alphaspec-0.3.0}/CHANGELOG.md +26 -1
- {alphaspec-0.2.0 → alphaspec-0.3.0}/PKG-INFO +2 -2
- {alphaspec-0.2.0 → alphaspec-0.3.0}/docs/ROADMAP.md +11 -12
- {alphaspec-0.2.0 → alphaspec-0.3.0}/docs/RUNTIME_API.md +60 -4
- {alphaspec-0.2.0 → alphaspec-0.3.0}/docs/SPEC.md +16 -6
- {alphaspec-0.2.0 → alphaspec-0.3.0}/pyproject.toml +1 -1
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.2/artifact.schema.json +2 -2
- alphaspec-0.3.0/schema/0.3/artifact.schema.json +847 -0
- alphaspec-0.3.0/schema/0.3/capabilities.schema.json +230 -0
- alphaspec-0.3.0/schema/0.3/common.schema.json +96 -0
- alphaspec-0.3.0/schema/0.3/evidence.schema.json +152 -0
- alphaspec-0.3.0/schema/0.3/gate-result.schema.json +154 -0
- alphaspec-0.3.0/schema/0.3/score.schema.json +79 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/skills/alphaspec/SKILL.md +5 -3
- {alphaspec-0.2.0 → alphaspec-0.3.0}/src/alphaspec/__init__.py +1 -1
- {alphaspec-0.2.0 → alphaspec-0.3.0}/src/alphaspec/_resources.py +2 -2
- {alphaspec-0.2.0 → alphaspec-0.3.0}/src/alphaspec/cli.py +92 -5
- {alphaspec-0.2.0 → alphaspec-0.3.0}/src/alphaspec/client.py +33 -3
- {alphaspec-0.2.0 → alphaspec-0.3.0}/src/alphaspec/mcp_server.py +30 -6
- {alphaspec-0.2.0 → alphaspec-0.3.0}/src/alphaspec/validate.py +7 -2
- {alphaspec-0.2.0 → alphaspec-0.3.0}/tests/test_client.py +60 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/tests/test_examples.py +21 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/tests/test_mcp_server.py +2 -1
- {alphaspec-0.2.0 → alphaspec-0.3.0}/.github/workflows/ci.yml +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/.github/workflows/pages.yml +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/.github/workflows/release.yml +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/.gitignore +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/LICENSE +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/README.md +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/README.zh-CN.md +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/catalog/i18n/en.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/catalog/indicators.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/README.md +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as001-unresolved-indicator.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as002-unresolved-param.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as003-htf-live-lookahead.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as004-indicator-cycle.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as005-unknown-type.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as006-unknown-param.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as007-cn-indicator-on-us-market.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as008-primary-only-timeframe-ignored.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as009-finer-than-primary.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as010-tick-timeframe.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as011-missing-suffix.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as012-ai-without-search-trials.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as013-exits-replace-exit-rule.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as013-no-exit.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as014-intraday-on-daily.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as015-unused-indicator.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as016-arm-without-trailing.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as017-entry-above-symbol-cap.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as017-not-for-atr-risk.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as018-scale-in-no-room.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as101-duplicate-symbol.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as102-all-null.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as103-asof-future.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as104-zero-as-missing.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/as105-weights-over-one.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-bare-number-operand.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-exit-zero.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-fill-timing-unknown.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-no-code-fields.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-noncanonical-timeframe.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-not-uses-rule.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-scale-in-averaging-down.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-score-without-direction.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-scores-and-weights.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-sizing-unsupported-mode.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-sizing-without-target.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-trade-settings-in-0.1.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/schema-universe-mode-conflict.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/score-valid.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/valid-minimal.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/valid-sizing-atr-pyramid.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/conformance/cases/valid-trade-settings.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/docs/MARKETS.md +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/docs/RULES.md +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/artifacts/01-ema-cross-us-equity.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/artifacts/02-rsi-reversion-params.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/artifacts/03-mtf-trend-pullback.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/artifacts/04-breakout-retest-sequence.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/artifacts/05-cn-limit-up-pullback.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/artifacts/06-trend-with-trade-settings.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/scores/01-model-scores-cn-stock.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/examples/scores/02-target-weights-us-equity.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.1/artifact.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.1/common.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.1/evidence.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.1/gate-result.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.1/score.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.2/common.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.2/evidence.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.2/gate-result.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/schema/0.2/score.schema.json +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/src/alphaspec/lints.py +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/tests/test_cli_reference.py +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/tests/test_conformance.py +0 -0
- {alphaspec-0.2.0 → alphaspec-0.3.0}/tools/export_indicator_catalog.py +0 -0
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-10-12
|
|
4
|
+
|
|
5
|
+
- Contract 0.3 (`schema/0.3/`): new `capabilities` document kind; `gate-result.tradeSettings` reports the exits,
|
|
6
|
+
sizing and execution an evaluation actually used and every value the runtime defaulted. Artifacts are unchanged
|
|
7
|
+
from 0.2.
|
|
8
|
+
- Validator accepts 0.1, 0.2 and 0.3; a kind that does not exist in the declared version is `UNSUPPORTED_KIND`.
|
|
9
|
+
- Client / CLI / MCP: `capabilities`, `strategies`, `export` (`export_strategy`), and `promote --target`
|
|
10
|
+
(`target_strategy_id`) to publish a passing modification as a new version of an existing strategy.
|
|
11
|
+
- RUNTIME_API: the capabilities endpoint, submission checks (`RUNTIME_*` codes, no quota used), export and
|
|
12
|
+
write-back. Skill: check capabilities before writing; export–edit–resubmit flow.
|
|
13
|
+
- Reference runtime: markets whose history does not cover the evaluation window are rejected at submission
|
|
14
|
+
instead of being backtested on a silently shorter in-sample; symbols with no bars in the window are rejected.
|
|
15
|
+
|
|
16
|
+
## 0.2.1 — 2026-10-11
|
|
17
|
+
|
|
18
|
+
Semantics clarified to match what a runtime can apply the same way in backtests and live trading:
|
|
19
|
+
|
|
20
|
+
- `exits.minHoldDays` counts **trading days** (entry day = 0; weekends and holidays excluded) and holds back
|
|
21
|
+
`dsl.exit` as well as the other exits. 0.2.0 said calendar days and left `dsl.exit` free.
|
|
22
|
+
- `sizing.scaleIn` add-ons are filled per `execution.fillTiming` (next open under `NEXT_OPEN`), and never on a bar
|
|
23
|
+
that also closes the position. 0.2.0 said "at the close of the triggering bar".
|
|
24
|
+
- Reference runtime: backtests and live trading now apply both rules identically; live pyramiding honours
|
|
25
|
+
`maxTotalPct`; live minimum holding is counted from the start of the current position, not the first time the
|
|
26
|
+
symbol was ever held.
|
|
27
|
+
|
|
3
28
|
## 0.2.0 — 2026-10-11
|
|
4
29
|
|
|
5
30
|
- Contract 0.2 (`schema/0.2/`): trade settings in three optional artifact blocks.
|
|
6
31
|
- `exits`: stop loss, take profit, trailing stop with activation, ATR stop / take profit, minimum holding days
|
|
7
|
-
(
|
|
32
|
+
(see 0.2.1), no-new-high exit.
|
|
8
33
|
- `sizing`: `FIXED_PCT` or `ATR_RISK` per entry, `maxHoldings`, pyramiding `scaleIn`.
|
|
9
34
|
- `execution`: fill timing (`NEXT_OPEN` / `BAR_CLOSE`).
|
|
10
35
|
Semantics in SPEC §4a.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: alphaspec
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: The auditable contract between alpha and execution: JSON schemas, a validator and lint rules for declarative trading strategies.
|
|
5
5
|
Project-URL: Homepage, https://github.com/openalpha-dev/alphaspec
|
|
6
6
|
Project-URL: Documentation, https://github.com/openalpha-dev/alphaspec#readme
|
|
7
7
|
Project-URL: Changelog, https://github.com/openalpha-dev/alphaspec/blob/main/CHANGELOG.md
|
|
8
|
-
Project-URL: Schemas, https://openalpha-dev.github.io/alphaspec/schema/0.
|
|
8
|
+
Project-URL: Schemas, https://openalpha-dev.github.io/alphaspec/schema/0.3/
|
|
9
9
|
Author: OpenAlpha contributors
|
|
10
10
|
License-Expression: Apache-2.0
|
|
11
11
|
License-File: LICENSE
|
|
@@ -37,14 +37,15 @@ Everything a strategy needs beyond its signal, in three optional blocks next to
|
|
|
37
37
|
|
|
38
38
|
The per-symbol cap stays where it was, `riskProfile.maxSymbolExposurePct`.
|
|
39
39
|
|
|
40
|
-
## 0.3 — Capabilities
|
|
40
|
+
## 0.3 — Capabilities and round trip (done)
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
-
|
|
42
|
+
- `capabilities` document: per market, whether daily / intraday history covers the evaluation
|
|
43
|
+
window (and why not), usable indicator profiles, promotability, out-of-sample benchmark,
|
|
44
|
+
evaluation windows and quota. `alphaspec capabilities`, MCP `get_capabilities`; the Skill reads it first.
|
|
45
|
+
- Runtimes reject at submission what they cannot run (`RUNTIME_*` codes), without using quota.
|
|
46
|
+
- `gate-result.tradeSettings`: the exits, sizing and execution actually used, and every default.
|
|
47
|
+
- Export: a runtime exports a strategy it holds as an artifact; a passing modification can be
|
|
48
|
+
promoted as a new version of it (`targetStrategyId`).
|
|
48
49
|
|
|
49
50
|
## 0.4 — Direction and derivatives
|
|
50
51
|
|
|
@@ -64,9 +65,7 @@ A runtime publishes what it can do so an agent can plan before it writes:
|
|
|
64
65
|
- Whole-market universes with filters (listing age, liquidity, market cap, exclusions).
|
|
65
66
|
- Dynamic universes defined by screening conditions and re-evaluated on a schedule.
|
|
66
67
|
|
|
67
|
-
##
|
|
68
|
+
## Evidence
|
|
68
69
|
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
- **Evidence**: execution evidence (rejections, slippage, fills, drift from target) returned as
|
|
72
|
-
`evidence` documents for promoted strategies.
|
|
70
|
+
- Execution evidence (rejections, slippage, fills, drift from target) returned as `evidence`
|
|
71
|
+
documents for promoted strategies.
|
|
@@ -14,12 +14,50 @@ prefix.
|
|
|
14
14
|
|
|
15
15
|
| Method & path | Success | Other responses |
|
|
16
16
|
|---|---|---|
|
|
17
|
-
| `GET /whoami` | 200 identity, `contractVersion` (latest) and `contractVersions` (all accepted), what the key can and cannot do | 401 invalid / revoked / expired key |
|
|
18
|
-
| `
|
|
17
|
+
| `GET /whoami` | 200 identity, `contractVersion` (latest) and `contractVersions` (all accepted), today's `evaluationQuota`, what the key can and cannot do | 401 invalid / revoked / expired key |
|
|
18
|
+
| `GET /capabilities` | 200 `capabilities` document (contract 0.3): what can be evaluated and promoted right now | |
|
|
19
|
+
| `POST /artifacts` — body: an `artifact` document | 201 `{artifactId, warnings}` | 422 `{issues}` (validator codes, plus `RUNTIME_*` codes below) · 400 unusable universe |
|
|
19
20
|
| `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
|
+
| `POST /artifacts/{id}/evaluate` | 202 `{evaluationId, status}` | 422 `{issues}` the runtime cannot run it (not counted against the quota) · 429 daily evaluation quota used up · 503 queue full |
|
|
21
22
|
| `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 (
|
|
23
|
+
| `POST /artifacts/{id}/promote` — body optional: `{name, targetStrategyId}` | 201 `{strategyId, created, enabled: false}` · 200 if already promoted · 200 `{updated: true}` with `targetStrategyId` | 400 gate not passed, market not promotable, or target's market / universe differs · runtime product rules (pool size, names) apply as in its UI |
|
|
24
|
+
| `GET /strategies` | 200 your existing strategies | |
|
|
25
|
+
| `GET /strategies/{id}/alphaspec` | 200 `{document, issues}` — an artifact you can edit and resubmit | 422 `{document, issues}` exported but does not validate (e.g. a factor strategy before 0.4) |
|
|
26
|
+
|
|
27
|
+
## Capabilities
|
|
28
|
+
|
|
29
|
+
`GET /capabilities` is computed from the runtime's live market data and changes as data is added. For
|
|
30
|
+
every market it says whether the **daily** and **intraday** evaluation windows are covered by history
|
|
31
|
+
(and, when not, how much history exists versus how much the window needs), which indicator profiles an
|
|
32
|
+
evaluation can use there, whether a passing strategy can be promoted, and which index the out-of-sample
|
|
33
|
+
segment is compared against. Read it before writing a document; the Skill does.
|
|
34
|
+
|
|
35
|
+
The reference runtime's rules:
|
|
36
|
+
|
|
37
|
+
- A market is evaluable on a timeframe tier when its bars reach back to the start of that tier's
|
|
38
|
+
in-sample window and are current. Today that is China A-shares, ETFs on daily bars; other markets
|
|
39
|
+
have months, not years, of history and are declared not evaluable until it is backfilled.
|
|
40
|
+
- Indicator profiles: `core` everywhere; `ext.cn` on `cn_*`; `ext.data` on `cn_stock` (the fundamentals and
|
|
41
|
+
index datasets cover A-shares only); `ext.l2` nowhere (it needs order-book data a bar backtest does not have).
|
|
42
|
+
- Out-of-sample benchmark: CSI 300 for `cn_stock`, `cn_etf`, `cn_convbond`; other markets are judged on an
|
|
43
|
+
absolute Sharpe floor.
|
|
44
|
+
- Promotable markets: `cn_stock`, `cn_etf`, `cn_convbond`. Other evaluable markets return a gate result
|
|
45
|
+
but cannot be promoted.
|
|
46
|
+
|
|
47
|
+
### Checks at submission
|
|
48
|
+
|
|
49
|
+
These run on `POST /artifacts` and again before `evaluate` enqueues. Errors reject the document (422)
|
|
50
|
+
and do not use the evaluation quota.
|
|
51
|
+
|
|
52
|
+
| code | severity | meaning |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `RUNTIME_MARKET_UNSUPPORTED` | error | the runtime does not run this market |
|
|
55
|
+
| `RUNTIME_NO_HISTORY` | error | the market's bars do not cover the evaluation window for this timeframe (or `tick`) |
|
|
56
|
+
| `RUNTIME_PROFILE_UNAVAILABLE` | error | an indicator's profile is not usable in an evaluation on this market |
|
|
57
|
+
| `RUNTIME_UNIVERSE_MODE` | error | `ALL_MARKET` or no universe (until 0.4) |
|
|
58
|
+
| `RUNTIME_SYMBOL_NO_DATA` | error | a listed symbol has no bars in the window — almost always a typo |
|
|
59
|
+
| `RUNTIME_SYMBOL_PARTIAL_HISTORY` | warning | a symbol's history starts more than a month after the window does (its in-sample is shorter) |
|
|
60
|
+
| `RUNTIME_NOT_PROMOTABLE` | warning | evaluable, but a passing strategy cannot be promoted on this runtime |
|
|
23
61
|
|
|
24
62
|
## Evaluation
|
|
25
63
|
|
|
@@ -66,6 +104,11 @@ The evaluation backtest and the promoted strategy use the same `exits`, `sizing`
|
|
|
66
104
|
signals. Always send a `sizing` block if position size matters to your result — it usually
|
|
67
105
|
does.
|
|
68
106
|
|
|
107
|
+
The gate result (contract 0.3) reports what was actually used in `tradeSettings`: the effective
|
|
108
|
+
`exits`, `sizing` and `execution`, and under `defaults` every field the runtime filled in. When the
|
|
109
|
+
default sizing cannot be written as an AlphaSpec `sizing` block, `sizing` is absent and the `/sizing`
|
|
110
|
+
default says in words how positions were sized, with the limits that applied.
|
|
111
|
+
|
|
69
112
|
"Out-of-sample" here means *chosen by the platform*, not *unseen at submission*: recent
|
|
70
113
|
market data is public. The only truly unseen period is the one after you submit, which is
|
|
71
114
|
what paper trading is for.
|
|
@@ -81,6 +124,14 @@ and dropped. The promoted strategy therefore carries no `params`; your submitted
|
|
|
81
124
|
its parameters, stays attached to the artifact. Trade settings are carried over unchanged and show
|
|
82
125
|
up in the runtime's strategy builder as its stop, position-size and fill-timing settings.
|
|
83
126
|
|
|
127
|
+
### Updating an existing strategy
|
|
128
|
+
|
|
129
|
+
`GET /strategies/{id}/alphaspec` exports one of your strategies (rules, trade settings, risk limits,
|
|
130
|
+
universe) as an artifact. Edit it, submit it as a new artifact (count it in `searchTrials`), evaluate,
|
|
131
|
+
and promote with `targetStrategyId` to publish it as a new version of that strategy. Market and
|
|
132
|
+
universe must stay the same; change those in the runtime's UI or promote to a new strategy instead.
|
|
133
|
+
Factor strategies and long/short rule sets cannot be exported before contract 0.4.
|
|
134
|
+
|
|
84
135
|
## Python
|
|
85
136
|
|
|
86
137
|
```python
|
|
@@ -92,4 +143,9 @@ c.evaluate(aid)
|
|
|
92
143
|
gate = c.wait(aid) # polls until done
|
|
93
144
|
if gate["passed"]:
|
|
94
145
|
c.promote(aid, name="my strategy")
|
|
146
|
+
|
|
147
|
+
c.capabilities() # what can be evaluated right now
|
|
148
|
+
doc, issues = c.export_strategy(438)
|
|
149
|
+
# ... edit doc, submit, evaluate ...
|
|
150
|
+
c.promote(new_aid, target_strategy_id=438)
|
|
95
151
|
```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# AlphaSpec 0.
|
|
1
|
+
# AlphaSpec 0.3 — semantics
|
|
2
2
|
|
|
3
3
|
The JSON Schemas in `schema/<version>/` define the shape of each document. This page defines
|
|
4
4
|
what the fields **mean**, where the shape alone cannot. Where this page and a runtime
|
|
@@ -14,11 +14,18 @@ Every document has `contractVersion` and `kind`.
|
|
|
14
14
|
| `score` | model / research pipeline | cross-sectional scores or target weights (L1) |
|
|
15
15
|
| `gate-result` | runtime | the verdict on a submission |
|
|
16
16
|
| `evidence` | runtime | what happened when it ran |
|
|
17
|
+
| `capabilities` | runtime | what it can evaluate and promote right now (0.3) |
|
|
17
18
|
|
|
18
19
|
A runtime must refuse a `contractVersion` it does not implement rather than guess.
|
|
19
20
|
Versions are additive: a document is validated against the schemas of the version it
|
|
20
|
-
declares, so a `0.1` document carrying `0.2` fields is rejected, not half-read. Use `0.2`
|
|
21
|
-
when you need trade settings (section 4a).
|
|
21
|
+
declares, so a `0.1` document carrying `0.2` fields is rejected, not half-read. Use `0.2` or
|
|
22
|
+
later when you need trade settings (section 4a). 0.3 adds no artifact fields; it adds the
|
|
23
|
+
`capabilities` document and `tradeSettings` in gate results.
|
|
24
|
+
|
|
25
|
+
A runtime must not accept a document it cannot run as written. When its data or features fall
|
|
26
|
+
short (a market without enough history, an indicator it cannot compute in a backtest), it rejects
|
|
27
|
+
at submission and says why; it publishes those limits in its `capabilities` document so an author
|
|
28
|
+
can check before writing.
|
|
22
29
|
|
|
23
30
|
## 2. Time
|
|
24
31
|
|
|
@@ -99,11 +106,14 @@ Whichever fires first closes the whole position.
|
|
|
99
106
|
| `atrStopMultiplier` | close ≤ entry − k × ATR(14) |
|
|
100
107
|
| `atrTakeProfitMultiplier` | close ≥ entry + k × ATR(14) |
|
|
101
108
|
| `noNewHighDays` | n trading days pass without a new highest close since entry |
|
|
102
|
-
| `minHoldDays` | (modifies
|
|
109
|
+
| `minHoldDays` | (modifies everything, `dsl.exit` included) nothing closes the position until n **trading days** after entry |
|
|
103
110
|
|
|
104
111
|
- Omit a field to leave that exit off. `0` is rejected for the on/off fields: one runtime's
|
|
105
112
|
"disabled" is another's "stop immediately".
|
|
106
|
-
- `minHoldDays` counts
|
|
113
|
+
- `minHoldDays` counts trading days in the market's calendar: the entry day is day 0, weekends and
|
|
114
|
+
holidays do not count, and the meaning is the same on every timeframe (3 on a 5m strategy is three
|
|
115
|
+
trading days). It holds back rule exits too: its purpose is to keep a fresh position from being
|
|
116
|
+
shaken out by short-term noise. Leave it out if the strategy should be free to exit at once.
|
|
107
117
|
|
|
108
118
|
**`sizing`** — how large each position is and how many are held.
|
|
109
119
|
|
|
@@ -112,7 +122,7 @@ Whichever fires first closes the whole position.
|
|
|
112
122
|
| `positionMode` | `FIXED_PCT` (default): each entry buys `targetPctPerOrder`% of current equity. `ATR_RISK`: each entry is sized so one ATR(14) against it costs `targetPctPerOrder`% of equity; no entry while ATR cannot be computed |
|
|
113
123
|
| `targetPctPerOrder` | the percentage above (required when `sizing` is present) |
|
|
114
124
|
| `maxHoldings` | at most n symbols held at once; buys already queued count as held, so signals on the same bar cannot overshoot; further entries are skipped |
|
|
115
|
-
| `scaleIn` | pyramiding: `{maxAddOns, spacingAtr, maxTotalPct}` — add to a winner each time the close is `spacingAtr` × ATR(14) above the last buy, at most `maxAddOns` times; an add-on that would take the symbol above `maxTotalPct`% of equity is skipped |
|
|
125
|
+
| `scaleIn` | pyramiding: `{maxAddOns, spacingAtr, maxTotalPct}` — add to a winner each time the close is `spacingAtr` × ATR(14) above the last buy, at most `maxAddOns` times; an add-on that would take the symbol above `maxTotalPct`% of equity is skipped; filled per `execution.fillTiming`, never on a bar that closes the position |
|
|
116
126
|
|
|
117
127
|
Equity is cash plus the market value of all positions. Every buy rounds down to the market's
|
|
118
128
|
lot and is capped by `riskProfile.maxSymbolExposurePct` and by cash. Without a `sizing`
|
|
@@ -27,7 +27,7 @@ dependencies = [
|
|
|
27
27
|
Homepage = "https://github.com/openalpha-dev/alphaspec"
|
|
28
28
|
Documentation = "https://github.com/openalpha-dev/alphaspec#readme"
|
|
29
29
|
Changelog = "https://github.com/openalpha-dev/alphaspec/blob/main/CHANGELOG.md"
|
|
30
|
-
Schemas = "https://openalpha-dev.github.io/alphaspec/schema/0.
|
|
30
|
+
Schemas = "https://openalpha-dev.github.io/alphaspec/schema/0.3/"
|
|
31
31
|
|
|
32
32
|
[project.optional-dependencies]
|
|
33
33
|
mcp = ["mcp>=1.2"]
|
|
@@ -756,7 +756,7 @@
|
|
|
756
756
|
"type": "integer",
|
|
757
757
|
"minimum": 1,
|
|
758
758
|
"maximum": 365,
|
|
759
|
-
"description": "
|
|
759
|
+
"description": "Trading days after entry during which nothing closes the position: neither the exits above nor dsl.exit. The entry day is day 0; weekends and market holidays do not count, on every timeframe (3 on a 5m strategy is three trading days). Use it to keep a fresh position from being shaken out by short-term noise; omit it if that is not wanted."
|
|
760
760
|
},
|
|
761
761
|
"noNewHighDays": {
|
|
762
762
|
"type": "integer",
|
|
@@ -821,7 +821,7 @@
|
|
|
821
821
|
"maxAddOns",
|
|
822
822
|
"spacingAtr"
|
|
823
823
|
],
|
|
824
|
-
"description": "Pyramiding: add to a winning position each time the close rises spacingAtr × ATR(14) above the last buy price. Each add-on is sized like an entry (positionMode / targetPctPerOrder). Filled at the close
|
|
824
|
+
"description": "Pyramiding: add to a winning position each time the close rises spacingAtr × ATR(14) above the last buy price. Each add-on is sized like an entry (positionMode / targetPctPerOrder). Filled like any other order under execution.fillTiming: at the triggering bar's close (BAR_CLOSE) or at the next bar's open (NEXT_OPEN). No add-on is made on a bar that also closes the position.",
|
|
825
825
|
"properties": {
|
|
826
826
|
"maxAddOns": {
|
|
827
827
|
"type": "integer",
|