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.
Files changed (31) hide show
  1. alphaspec/__init__.py +8 -0
  2. alphaspec/_data/catalog/i18n/en.json +1016 -0
  3. alphaspec/_data/catalog/indicators.json +9790 -0
  4. alphaspec/_data/docs/MARKETS.md +29 -0
  5. alphaspec/_data/docs/RULES.md +133 -0
  6. alphaspec/_data/docs/RUNTIME_API.md +80 -0
  7. alphaspec/_data/docs/SPEC.md +99 -0
  8. alphaspec/_data/examples/artifacts/01-ema-cross-us-equity.json +20 -0
  9. alphaspec/_data/examples/artifacts/02-rsi-reversion-params.json +25 -0
  10. alphaspec/_data/examples/artifacts/03-mtf-trend-pullback.json +25 -0
  11. alphaspec/_data/examples/artifacts/04-breakout-retest-sequence.json +58 -0
  12. alphaspec/_data/examples/artifacts/05-cn-limit-up-pullback.json +33 -0
  13. alphaspec/_data/examples/scores/01-model-scores-cn-stock.json +17 -0
  14. alphaspec/_data/examples/scores/02-target-weights-us-equity.json +13 -0
  15. alphaspec/_data/schema/0.1/artifact.schema.json +259 -0
  16. alphaspec/_data/schema/0.1/common.schema.json +96 -0
  17. alphaspec/_data/schema/0.1/evidence.schema.json +152 -0
  18. alphaspec/_data/schema/0.1/gate-result.schema.json +55 -0
  19. alphaspec/_data/schema/0.1/score.schema.json +79 -0
  20. alphaspec/_data/skills/alphaspec/SKILL.md +93 -0
  21. alphaspec/_resources.py +77 -0
  22. alphaspec/cli.py +360 -0
  23. alphaspec/client.py +146 -0
  24. alphaspec/lints.py +266 -0
  25. alphaspec/mcp_server.py +231 -0
  26. alphaspec/validate.py +108 -0
  27. alphaspec-0.1.0.dist-info/METADATA +322 -0
  28. alphaspec-0.1.0.dist-info/RECORD +31 -0
  29. alphaspec-0.1.0.dist-info/WHEEL +4 -0
  30. alphaspec-0.1.0.dist-info/entry_points.txt +3 -0
  31. 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
+ }