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,259 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openalpha-dev.github.io/alphaspec/schema/0.1/artifact.schema.json",
4
+ "title": "AlphaSpec Strategy Artifact (L2)",
5
+ "description": "A complete, declarative strategy: rule tree, parameters, universe and risk overrides. Contains no code; everything here can be validated before it runs.",
6
+ "type": "object",
7
+ "required": ["contractVersion", "kind", "title", "market", "timeframe", "dsl", "producer"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "contractVersion": { "$ref": "common.schema.json#/$defs/contractVersion" },
11
+ "kind": { "const": "artifact" },
12
+ "title": { "type": "string", "minLength": 1, "maxLength": 120 },
13
+ "note": { "type": "string", "maxLength": 2000 },
14
+
15
+ "market": { "$ref": "common.schema.json#/$defs/marketId" },
16
+ "timeframe": { "$ref": "common.schema.json#/$defs/timeframe", "description": "Primary timeframe: the bar series the rule tree is evaluated on." },
17
+
18
+ "templateKey": {
19
+ "type": "string",
20
+ "pattern": "^[A-Z0-9_]+$",
21
+ "description": "Optional. Names a runtime template this artifact instantiates. Omit it for a self-contained rule tree."
22
+ },
23
+ "templateRevision": { "type": "integer", "minimum": 1, "description": "Pins the template revision so a template edit cannot silently change this artifact's meaning." },
24
+
25
+ "signalMode": {
26
+ "type": "string",
27
+ "enum": ["AUTO", "FACTOR_ONLY", "RULE_ONLY", "FACTOR_AND_RULE", "FACTOR_OR_RULE"],
28
+ "default": "AUTO",
29
+ "description": "How factor ranking and the rule tree combine. AUTO lets the runtime infer it from what is present."
30
+ },
31
+
32
+ "dsl": { "$ref": "#/$defs/dsl" },
33
+ "riskProfile": { "$ref": "common.schema.json#/$defs/riskProfile" },
34
+ "universe": { "$ref": "#/$defs/universe" },
35
+ "factorBindings": { "type": "array", "items": { "$ref": "#/$defs/factorBinding" } },
36
+ "producer": { "$ref": "common.schema.json#/$defs/producer" }
37
+ },
38
+
39
+ "$defs": {
40
+ "dsl": {
41
+ "type": "object",
42
+ "required": ["version", "indicators", "entry"],
43
+ "additionalProperties": false,
44
+ "properties": {
45
+ "version": { "const": 1 },
46
+ "params": {
47
+ "type": "object",
48
+ "description": "Named constants referenced from anywhere in the tree as {\"ref\": \"name\"}. This is what parameter scans vary.",
49
+ "additionalProperties": { "type": ["number", "string", "boolean"] }
50
+ },
51
+ "indicators": {
52
+ "type": "object",
53
+ "minProperties": 1,
54
+ "description": "Alias -> indicator. Aliases are referenced from rules as {\"ind\": \"alias\"}.",
55
+ "propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" },
56
+ "additionalProperties": { "$ref": "#/$defs/indicator" }
57
+ },
58
+ "entry": { "$ref": "#/$defs/rule" },
59
+ "exit": { "$ref": "#/$defs/rule" }
60
+ }
61
+ },
62
+
63
+ "indicator": {
64
+ "type": "object",
65
+ "required": ["type"],
66
+ "description": "One indicator instance. 'type' must exist in the indicator catalog (catalog/indicators.json); the remaining keys are that type's parameters.",
67
+ "properties": {
68
+ "type": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" },
69
+ "timeframe": { "$ref": "common.schema.json#/$defs/timeframe", "description": "Defaults to the artifact's primary timeframe." },
70
+ "barPolicy": {
71
+ "type": "string",
72
+ "enum": ["CLOSED", "LIVE"],
73
+ "default": "CLOSED",
74
+ "description": "For an indicator on a higher timeframe than the primary one: CLOSED uses only completed higher-timeframe bars; LIVE uses the still-forming bar. LIVE on a higher timeframe is look-ahead in a backtest and is rejected by rule AS003."
75
+ },
76
+ "in": { "$ref": "#/$defs/operand" },
77
+ "left": { "$ref": "#/$defs/operand" },
78
+ "right": { "$ref": "#/$defs/operand" }
79
+ },
80
+ "additionalProperties": true
81
+ },
82
+
83
+ "operand": {
84
+ "description": "Something that yields a number series. Constants are written {\"const\": 0}; a bare number is not an operand (the reference runtime would compile it to nothing).",
85
+ "oneOf": [
86
+ {
87
+ "type": "object", "required": ["ind"], "additionalProperties": false,
88
+ "properties": { "ind": { "type": "string", "minLength": 1 } }
89
+ },
90
+ {
91
+ "type": "object", "required": ["const"], "additionalProperties": false,
92
+ "properties": { "const": { "type": "number" } }
93
+ },
94
+ { "$ref": "common.schema.json#/$defs/paramRef" },
95
+ {
96
+ "type": "object", "required": ["op", "left"], "additionalProperties": false,
97
+ "description": "Inline arithmetic. ABS is unary (no right).",
98
+ "properties": {
99
+ "op": { "enum": ["ADD", "SUB", "MUL", "DIV", "ABS", "MAX", "MIN"] },
100
+ "left": { "$ref": "#/$defs/operand" },
101
+ "right": { "$ref": "#/$defs/operand" }
102
+ }
103
+ },
104
+ {
105
+ "type": "object", "required": ["op", "rule"], "additionalProperties": false,
106
+ "description": "COUNT = how many of the last N bars satisfied rule; BARS_SINCE = bars since rule last held.",
107
+ "properties": {
108
+ "op": { "enum": ["COUNT", "BARS_SINCE"] },
109
+ "rule": { "$ref": "#/$defs/rule" },
110
+ "bars": { "$ref": "common.schema.json#/$defs/number" }
111
+ }
112
+ }
113
+ ]
114
+ },
115
+
116
+ "rule": {
117
+ "type": "object",
118
+ "required": ["type"],
119
+ "description": "A boolean node. Comparison nodes take operands; logical nodes take rules.",
120
+ "properties": {
121
+ "type": {
122
+ "enum": [
123
+ "AND", "OR", "NOT",
124
+ "GT", "GTE", "LT", "LTE", "EQ", "NEQ", "CROSS_UP", "CROSS_DOWN",
125
+ "HOLD_FOR", "WITHIN", "SEQUENCE", "DAY_LATCH",
126
+ "TOUCH", "BREAK", "RECLAIM", "RETEST", "HOLD",
127
+ "VOL_BREAK", "MOM_BREAK", "GAP_UP", "GAP_DOWN"
128
+ ]
129
+ }
130
+ },
131
+ "allOf": [
132
+ {
133
+ "if": { "properties": { "type": { "enum": ["AND", "OR"] } } },
134
+ "then": {
135
+ "required": ["left", "right"],
136
+ "properties": { "left": { "$ref": "#/$defs/rule" }, "right": { "$ref": "#/$defs/rule" } }
137
+ }
138
+ },
139
+ {
140
+ "if": { "properties": { "type": { "enum": ["NOT", "DAY_LATCH"] } } },
141
+ "then": { "required": ["rule"], "properties": { "rule": { "$ref": "#/$defs/rule" } } }
142
+ },
143
+ {
144
+ "if": { "properties": { "type": { "enum": ["GT", "GTE", "LT", "LTE", "EQ", "NEQ", "CROSS_UP", "CROSS_DOWN"] } } },
145
+ "then": {
146
+ "required": ["left", "right"],
147
+ "properties": { "left": { "$ref": "#/$defs/operand" }, "right": { "$ref": "#/$defs/operand" } }
148
+ }
149
+ },
150
+ {
151
+ "if": { "properties": { "type": { "enum": ["HOLD_FOR", "WITHIN"] } } },
152
+ "then": {
153
+ "required": ["rule"],
154
+ "description": "HOLD_FOR: rule held on each of the last N bars. WITHIN: rule held on at least one of the last N bars. bars defaults to 3.",
155
+ "properties": { "rule": { "$ref": "#/$defs/rule" }, "bars": { "$ref": "common.schema.json#/$defs/number" } }
156
+ }
157
+ },
158
+ {
159
+ "if": { "properties": { "type": { "const": "SEQUENCE" } } },
160
+ "then": {
161
+ "required": ["first", "then"],
162
+ "description": "'then' holds now, and 'first' held within the preceding N bars.",
163
+ "properties": {
164
+ "first": { "$ref": "#/$defs/rule" },
165
+ "then": { "$ref": "#/$defs/rule" },
166
+ "bars": { "$ref": "common.schema.json#/$defs/number" }
167
+ }
168
+ }
169
+ },
170
+ {
171
+ "if": { "properties": { "type": { "enum": ["TOUCH", "BREAK", "RECLAIM", "RETEST", "HOLD"] } } },
172
+ "then": {
173
+ "required": ["level"],
174
+ "description": "Price-vs-level events. level is any operand (a support line, a moving average, a pivot).",
175
+ "properties": {
176
+ "level": { "$ref": "#/$defs/operand" },
177
+ "direction": { "enum": ["UP", "DOWN"] },
178
+ "bars": { "$ref": "common.schema.json#/$defs/number" },
179
+ "tolerancePct": { "$ref": "common.schema.json#/$defs/number" },
180
+ "price": { "enum": ["CLOSE", "HIGH", "LOW"] },
181
+ "minVolumeRatio": { "$ref": "common.schema.json#/$defs/number" },
182
+ "maxVolumeRatio": { "$ref": "common.schema.json#/$defs/number" },
183
+ "volumeBaseline": { "enum": ["PRIOR_BARS", "SAME_TIME"] },
184
+ "volumeBars": { "$ref": "common.schema.json#/$defs/number" },
185
+ "volumeDays": { "$ref": "common.schema.json#/$defs/number" }
186
+ }
187
+ }
188
+ },
189
+ {
190
+ "if": { "properties": { "type": { "const": "VOL_BREAK" } } },
191
+ "then": {
192
+ "required": ["price", "atr", "multiplier"],
193
+ "properties": {
194
+ "price": { "$ref": "#/$defs/operand" },
195
+ "atr": { "$ref": "#/$defs/operand" },
196
+ "multiplier": { "$ref": "common.schema.json#/$defs/number" },
197
+ "period": { "$ref": "common.schema.json#/$defs/number" },
198
+ "direction": { "enum": ["UP", "DOWN"] }
199
+ }
200
+ }
201
+ },
202
+ {
203
+ "if": { "properties": { "type": { "const": "MOM_BREAK" } } },
204
+ "then": {
205
+ "required": ["fast", "slow"],
206
+ "properties": {
207
+ "fast": { "$ref": "#/$defs/operand" },
208
+ "slow": { "$ref": "#/$defs/operand" },
209
+ "atr": { "$ref": "#/$defs/operand" },
210
+ "price": { "$ref": "#/$defs/operand" },
211
+ "atrThreshold": { "$ref": "common.schema.json#/$defs/number" }
212
+ }
213
+ }
214
+ },
215
+ {
216
+ "if": { "properties": { "type": { "enum": ["GAP_UP", "GAP_DOWN"] } } },
217
+ "then": {
218
+ "required": ["ind", "threshold"],
219
+ "properties": {
220
+ "ind": { "$ref": "#/$defs/operand" },
221
+ "threshold": { "$ref": "common.schema.json#/$defs/number" },
222
+ "atr": { "$ref": "#/$defs/operand" },
223
+ "atrMultiplier": { "$ref": "common.schema.json#/$defs/number" }
224
+ }
225
+ }
226
+ }
227
+ ]
228
+ },
229
+
230
+ "universe": {
231
+ "type": "object",
232
+ "required": ["mode"],
233
+ "additionalProperties": false,
234
+ "description": "Which instruments the strategy runs on. The three modes are mutually exclusive.",
235
+ "properties": {
236
+ "mode": { "enum": ["SYMBOLS", "UNIVERSE", "ALL_MARKET"] },
237
+ "symbols": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "common.schema.json#/$defs/symbol" } },
238
+ "universeId": { "type": ["string", "integer"], "description": "A named universe defined in the runtime." }
239
+ },
240
+ "allOf": [
241
+ { "if": { "properties": { "mode": { "const": "SYMBOLS" } } }, "then": { "required": ["symbols"], "not": { "required": ["universeId"] } } },
242
+ { "if": { "properties": { "mode": { "const": "UNIVERSE" } } }, "then": { "required": ["universeId"], "not": { "required": ["symbols"] } } },
243
+ { "if": { "properties": { "mode": { "const": "ALL_MARKET" } } }, "then": { "not": { "anyOf": [ { "required": ["symbols"] }, { "required": ["universeId"] } ] } } }
244
+ ]
245
+ },
246
+
247
+ "factorBinding": {
248
+ "type": "object",
249
+ "required": ["factor", "direction"],
250
+ "additionalProperties": false,
251
+ "properties": {
252
+ "factor": { "type": ["string", "integer"], "description": "Factor identifier in the runtime's factor library." },
253
+ "direction": { "$ref": "common.schema.json#/$defs/direction" },
254
+ "weight": { "type": "number", "default": 1 },
255
+ "topN": { "type": "integer", "minimum": 1, "description": "Cross-sectional selection size (FACTOR_ONLY)." }
256
+ }
257
+ }
258
+ }
259
+ }
@@ -0,0 +1,96 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openalpha-dev.github.io/alphaspec/schema/0.1/common.schema.json",
4
+ "title": "AlphaSpec common definitions",
5
+ "$defs": {
6
+ "contractVersion": {
7
+ "const": "0.1",
8
+ "description": "Contract version. Every document carries it so a runtime can refuse what it does not understand instead of guessing."
9
+ },
10
+
11
+ "marketId": {
12
+ "type": "string",
13
+ "pattern": "^[a-z][a-z0-9_]*$",
14
+ "description": "Market identifier, lower snake case (e.g. cn_stock, hk_stock, us_equity, crypto_spot). The registry of known ids lives in docs/MARKETS.md; runtimes may support a subset and must reject ids they do not know.",
15
+ "examples": ["cn_stock", "cn_etf", "cn_future", "cn_option", "cn_convbond", "hk_stock", "us_equity", "crypto_spot"]
16
+ },
17
+
18
+ "timeframe": {
19
+ "type": "string",
20
+ "enum": ["tick", "1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w"],
21
+ "description": "Bar period. Canonical spellings only: '1h' not '60m'. 'tick' means event-driven evaluation on every market-data frame and cannot be bar-backtested."
22
+ },
23
+
24
+ "symbol": {
25
+ "type": "string",
26
+ "minLength": 1,
27
+ "maxLength": 64,
28
+ "description": "Instrument code as the market spells it. For markets where the venue disambiguates the code (cn_*, hk_stock) the venue suffix is part of the identity: 600000.SH, 00700.HK. A bare code there is a different series, not a shorthand."
29
+ },
30
+
31
+ "number": {
32
+ "description": "A scalar setting: a literal number, {\"const\": n}, or a reference to a key in dsl.params.",
33
+ "oneOf": [
34
+ { "type": "number" },
35
+ { "type": "object", "required": ["const"], "additionalProperties": false, "properties": { "const": { "type": "number" } } },
36
+ { "$ref": "#/$defs/paramRef" }
37
+ ]
38
+ },
39
+
40
+ "paramRef": {
41
+ "type": "object",
42
+ "required": ["ref"],
43
+ "additionalProperties": false,
44
+ "properties": { "ref": { "type": "string", "minLength": 1 } }
45
+ },
46
+
47
+ "producer": {
48
+ "type": "object",
49
+ "required": ["kind", "name"],
50
+ "additionalProperties": false,
51
+ "description": "Who produced this document and how. Needed for multiple-testing correction and for diffing iterations.",
52
+ "properties": {
53
+ "kind": { "type": "string", "enum": ["HUMAN", "AI_AGENT", "INSTITUTION", "FACTOR_MINER"] },
54
+ "name": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Tool, agent or team name with version, e.g. my-agent@0.3.1." },
55
+ "modelId": { "type": "string", "description": "Model identifier when kind=AI_AGENT." },
56
+ "searchTrials": {
57
+ "type": "integer",
58
+ "minimum": 1,
59
+ "description": "How many candidates were evaluated before this one was submitted. Input to multiple-testing correction (deflated Sharpe). Required for AI_AGENT and FACTOR_MINER. Under-reporting loosens the gate; runtimes should cross-check it against their own call logs."
60
+ },
61
+ "parent": { "type": "string", "description": "Identifier of the previous iteration, for diffs." }
62
+ }
63
+ },
64
+
65
+ "riskProfile": {
66
+ "type": "object",
67
+ "additionalProperties": false,
68
+ "description": "Per-strategy risk overrides. Anything omitted inherits the runtime's account-level settings. Percentages are 0-100, notionals are in the instrument's quote currency.",
69
+ "properties": {
70
+ "maxOrderQty": { "type": "number", "exclusiveMinimum": 0 },
71
+ "maxOrderNotional": { "type": "number", "exclusiveMinimum": 0 },
72
+ "maxDailyOrders": { "type": "integer", "minimum": 1 },
73
+ "maxDailyNotional": { "type": "number", "exclusiveMinimum": 0 },
74
+ "maxPositionQtyPerSymbol": { "type": "number", "exclusiveMinimum": 0 },
75
+ "maxTotalExposurePct": { "type": "number", "minimum": 0, "maximum": 100 },
76
+ "maxSymbolExposurePct": { "type": "number", "minimum": 0, "maximum": 100 },
77
+ "maxIndustryExposurePct": { "type": "number", "minimum": 0, "maximum": 100 },
78
+ "maxThemeExposurePct": { "type": "number", "minimum": 0, "maximum": 100 },
79
+ "maxIndustryExposurePctMap": { "type": "object", "additionalProperties": { "type": "number", "minimum": 0, "maximum": 100 } },
80
+ "maxThemeExposurePctMap": { "type": "object", "additionalProperties": { "type": "number", "minimum": 0, "maximum": 100 } },
81
+ "maxImpactSlippageBps": { "type": "number", "minimum": 0 },
82
+ "maxImpactBlockOnInsufficientDepth": { "type": "boolean" },
83
+ "portfolioMaxDailyNotional": { "type": "number", "exclusiveMinimum": 0 },
84
+ "optionQuoteMaxAgeSeconds": { "type": "integer", "minimum": 0 },
85
+ "optionQuoteMaxSpreadBps": { "type": "number", "minimum": 0 },
86
+ "optionMinQuoteSize": { "type": "number", "minimum": 0 }
87
+ }
88
+ },
89
+
90
+ "direction": {
91
+ "type": "string",
92
+ "enum": ["ASC", "DESC"],
93
+ "description": "Ranking direction. DESC = higher is better. Required with no default: a flipped direction raises no error, it just loses money for a long time."
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,152 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openalpha-dev.github.io/alphaspec/schema/0.1/evidence.schema.json",
4
+ "title": "AlphaSpec Execution Evidence",
5
+ "description": "What actually happened when a strategy ran: rejections, fills, slippage, risk hits, the ledger, and whether the pipeline ran at all. Every number states its caliber, because an unlabeled number is worse than none for an agent consuming it.",
6
+ "type": "object",
7
+ "required": ["contractVersion", "kind", "subject", "window", "caliber"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "contractVersion": { "$ref": "common.schema.json#/$defs/contractVersion" },
11
+ "kind": { "const": "evidence" },
12
+
13
+ "subject": {
14
+ "type": "object",
15
+ "required": ["mode"],
16
+ "additionalProperties": false,
17
+ "properties": {
18
+ "strategy": { "type": "string" },
19
+ "artifact": { "type": "string" },
20
+ "account": { "type": "string" },
21
+ "mode": {
22
+ "enum": ["BACKTEST", "PAPER", "LIVE"],
23
+ "description": "The mode the orders actually ran in, derived from the account that holds the positions, not from configuration."
24
+ }
25
+ }
26
+ },
27
+
28
+ "window": {
29
+ "type": "object",
30
+ "required": ["from", "to"],
31
+ "additionalProperties": false,
32
+ "properties": {
33
+ "from": { "type": "string", "format": "date" },
34
+ "to": { "type": "string", "format": "date" },
35
+ "timezone": { "type": "string", "description": "IANA zone of the market, e.g. Asia/Shanghai, America/New_York." }
36
+ }
37
+ },
38
+
39
+ "caliber": {
40
+ "type": "object",
41
+ "required": ["slippageBasis", "feeIncluded", "volumeUnit", "currency"],
42
+ "additionalProperties": false,
43
+ "properties": {
44
+ "slippageBasis": { "enum": ["VS_SIGNAL_PRICE", "VS_ARRIVAL_PRICE", "VS_VWAP"] },
45
+ "feeIncluded": { "type": "boolean", "description": "Whether pnl and average prices include fees." },
46
+ "priceSource": { "enum": ["TICK", "BAR_1M", "BAR_1D", "SNAPSHOT"] },
47
+ "volumeUnit": {
48
+ "enum": ["SHARE", "LOT", "CONTRACT"],
49
+ "description": "Quantities are in this unit. Derivatives quantities are contracts; notional = qty x price x multiplier."
50
+ },
51
+ "multiplierApplied": { "type": "boolean", "description": "Whether notionals and pnl already include the contract multiplier." },
52
+ "currency": { "type": "string", "pattern": "^[A-Z]{3,5}$", "description": "Currency of every monetary field in this document." }
53
+ }
54
+ },
55
+
56
+ "rejects": {
57
+ "type": "array",
58
+ "items": {
59
+ "type": "object",
60
+ "required": ["category", "code", "count"],
61
+ "additionalProperties": false,
62
+ "properties": {
63
+ "category": { "enum": ["STRATEGY", "UNIVERSE", "RISK", "BROKER", "MARKET_DATA"] },
64
+ "code": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$", "description": "Runtime-specific reason code. Runtimes publish their code list." },
65
+ "count": { "type": "integer", "minimum": 0 },
66
+ "message": { "type": "string", "description": "Original message, not normalized." },
67
+ "hint": { "type": "string", "description": "What to change." }
68
+ }
69
+ }
70
+ },
71
+
72
+ "executionQuality": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "properties": {
76
+ "orders": { "type": "integer", "minimum": 0 },
77
+ "fillRatePct": { "type": "number" },
78
+ "rejectRatePct": { "type": "number" },
79
+ "avgSlippageBps": { "type": "number" },
80
+ "p95SlippageBps": { "type": "number" },
81
+ "paperVsLiveDiffBps": { "type": "number", "description": "Average gap between paper and live fills for the same signals." }
82
+ }
83
+ },
84
+
85
+ "targetDeviation": {
86
+ "type": "array",
87
+ "description": "For score/weights submissions: where the actual portfolio differs from the target and why.",
88
+ "items": {
89
+ "type": "object",
90
+ "required": ["symbol", "reason"],
91
+ "additionalProperties": false,
92
+ "properties": {
93
+ "symbol": { "$ref": "common.schema.json#/$defs/symbol" },
94
+ "targetWeight": { "type": "number" },
95
+ "actualWeight": { "type": "number" },
96
+ "reason": {
97
+ "enum": ["LOT_ROUNDING", "PRICE_LIMIT", "SETTLEMENT_RULE", "RISK_REJECT", "MIN_FEE_FLOOR", "NOT_IN_UNIVERSE", "NO_PRICE", "HALTED", "OTHER"]
98
+ }
99
+ }
100
+ }
101
+ },
102
+
103
+ "riskHits": {
104
+ "type": "array",
105
+ "items": {
106
+ "type": "object",
107
+ "required": ["code", "count", "blocking"],
108
+ "additionalProperties": false,
109
+ "properties": {
110
+ "code": { "type": "string" },
111
+ "count": { "type": "integer", "minimum": 0 },
112
+ "blocking": { "type": "boolean" }
113
+ }
114
+ }
115
+ },
116
+
117
+ "ledger": {
118
+ "type": "array",
119
+ "items": {
120
+ "type": "object",
121
+ "required": ["ts", "symbol", "side", "qty", "price"],
122
+ "additionalProperties": false,
123
+ "properties": {
124
+ "ts": { "type": "string", "format": "date-time" },
125
+ "symbol": { "$ref": "common.schema.json#/$defs/symbol" },
126
+ "side": { "enum": ["BUY", "SELL"] },
127
+ "qty": { "type": "number" },
128
+ "price": { "type": "number" },
129
+ "fee": { "type": "number" },
130
+ "realizedPnl": { "type": "number" },
131
+ "trigger": { "type": "string", "description": "Why the order was placed: ENTRY, EXIT, STOP_LOSS, TAKE_PROFIT, REBALANCE ..." }
132
+ }
133
+ }
134
+ },
135
+
136
+ "pipeline": {
137
+ "type": "array",
138
+ "description": "Answers 'did it run when it should have', not only 'was the output right'.",
139
+ "items": {
140
+ "type": "object",
141
+ "required": ["stage", "status"],
142
+ "additionalProperties": false,
143
+ "properties": {
144
+ "stage": { "type": "string" },
145
+ "status": { "enum": ["OK", "DEGRADED", "ABSENT", "FAILED"] },
146
+ "at": { "type": "string", "format": "date-time" },
147
+ "violations": { "type": "array", "items": { "type": "string" } }
148
+ }
149
+ }
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,55 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openalpha-dev.github.io/alphaspec/schema/0.1/gate-result.schema.json",
4
+ "title": "AlphaSpec Gate Result",
5
+ "description": "What a runtime returns after judging a submitted artifact or score series. Produced by the runtime, never by the submitter.",
6
+ "type": "object",
7
+ "required": ["contractVersion", "kind", "passed", "computedBy", "checks"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "contractVersion": { "$ref": "common.schema.json#/$defs/contractVersion" },
11
+ "kind": { "const": "gate-result" },
12
+ "subject": { "type": "string", "description": "Identifier of the judged artifact or score series." },
13
+ "passed": { "type": "boolean" },
14
+ "computedBy": {
15
+ "enum": ["PLATFORM", "SELF_REPORTED"],
16
+ "description": "PLATFORM: performance figures were recomputed by the runtime. SELF_REPORTED: they came from the submitter. Public rankings must accept PLATFORM only."
17
+ },
18
+ "sample": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "properties": {
22
+ "inSampleFrom": { "type": "string", "format": "date" },
23
+ "inSampleTo": { "type": "string", "format": "date" },
24
+ "outOfSampleFrom": { "type": "string", "format": "date", "description": "Chosen by the runtime and not visible at submission time." },
25
+ "outOfSampleTo": { "type": "string", "format": "date" }
26
+ }
27
+ },
28
+ "checks": {
29
+ "type": "array",
30
+ "description": "One entry per criterion, so a failure can be diffed and explained, not just reported.",
31
+ "items": {
32
+ "type": "object",
33
+ "required": ["code", "passed"],
34
+ "additionalProperties": false,
35
+ "properties": {
36
+ "code": {
37
+ "enum": [
38
+ "GATE_MIN_RETURN", "GATE_MAX_DRAWDOWN", "GATE_MIN_SHARPE",
39
+ "GATE_OUT_OF_SAMPLE", "GATE_MULTIPLE_TESTING", "GATE_LOOKAHEAD",
40
+ "GATE_COST_SENSITIVITY", "GATE_CAPACITY", "GATE_MARKETABILITY"
41
+ ]
42
+ },
43
+ "metric": {
44
+ "type": "string",
45
+ "description": "What `actual` and `threshold` measure, so a reader never infers it from the code. One check can switch measures (out-of-sample is judged on excess return when the runtime has a benchmark index, on Sharpe when it has not). Values used by the reference runtime: totalReturn, maxDrawdown, sharpe, excessReturnVsIndex, deflatedSharpeProbability, structural. Returns and drawdowns are fractions (0.05 = 5%)."
46
+ },
47
+ "passed": { "type": "boolean" },
48
+ "actual": { "type": ["number", "string", "null"] },
49
+ "threshold": { "type": ["number", "string", "null"] },
50
+ "hint": { "type": "string", "description": "What to change to pass, in plain language." }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openalpha-dev.github.io/alphaspec/schema/0.1/score.schema.json",
4
+ "title": "AlphaSpec Score Submission (L1)",
5
+ "description": "Cross-sectional output of any model (pandas, LightGBM, PyTorch, an LLM pipeline) handed to an execution runtime. You keep your research stack; the runtime handles sizing, rebalancing, risk, execution and the ledger. Carries either 'scores' (the runtime ranks and weights) or 'weights' (portfolio construction already done).",
6
+ "type": "object",
7
+ "required": ["contractVersion", "kind", "asOf", "market", "scoreName", "producer"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "contractVersion": { "$ref": "common.schema.json#/$defs/contractVersion" },
11
+ "kind": { "const": "score" },
12
+ "asOf": {
13
+ "type": "string",
14
+ "format": "date",
15
+ "description": "The last trading day whose information was used, in the market's local calendar. A score with asOf=T may use T's close and nothing later, and is executed no earlier than the next session. This is where look-ahead enters if anywhere."
16
+ },
17
+ "market": { "$ref": "common.schema.json#/$defs/marketId" },
18
+ "scoreName": { "type": "string", "minLength": 1, "maxLength": 120, "description": "Model or signal name. Submissions with the same scoreName form one time series." },
19
+ "direction": { "$ref": "common.schema.json#/$defs/direction" },
20
+
21
+ "scores": {
22
+ "type": "array",
23
+ "minItems": 1,
24
+ "items": {
25
+ "type": "object",
26
+ "required": ["symbol", "score"],
27
+ "additionalProperties": false,
28
+ "properties": {
29
+ "symbol": { "$ref": "common.schema.json#/$defs/symbol" },
30
+ "score": {
31
+ "type": ["number", "null"],
32
+ "description": "null = no valid score today (halted, missing data). Never use 0 for 'unknown': 0 is a real rank position."
33
+ }
34
+ }
35
+ }
36
+ },
37
+
38
+ "weights": {
39
+ "type": "array",
40
+ "minItems": 1,
41
+ "description": "Target portfolio weights in [0,1]. Sum must be <= 1; the remainder is cash.",
42
+ "items": {
43
+ "type": "object",
44
+ "required": ["symbol", "weight"],
45
+ "additionalProperties": false,
46
+ "properties": {
47
+ "symbol": { "$ref": "common.schema.json#/$defs/symbol" },
48
+ "weight": { "type": "number", "minimum": 0, "maximum": 1 }
49
+ }
50
+ }
51
+ },
52
+
53
+ "execution": {
54
+ "type": "object",
55
+ "additionalProperties": false,
56
+ "description": "Optional portfolio-construction settings. Omitted fields use the runtime defaults.",
57
+ "properties": {
58
+ "topN": { "type": "integer", "minimum": 1 },
59
+ "weighting": { "enum": ["EQUAL", "SCORE_PROPORTIONAL", "INV_VOL"] },
60
+ "universePolicy": {
61
+ "enum": ["SUBMITTED", "INTERSECT_UNIVERSE"],
62
+ "description": "SUBMITTED: trade only from the submitted symbols. INTERSECT_UNIVERSE: intersect with the runtime-side universe; symbols dropped by the intersection must be reported back as evidence, never silently discarded."
63
+ },
64
+ "riskProfile": { "$ref": "common.schema.json#/$defs/riskProfile" }
65
+ }
66
+ },
67
+
68
+ "producer": { "$ref": "common.schema.json#/$defs/producer" }
69
+ },
70
+
71
+ "oneOf": [
72
+ { "required": ["scores", "direction"], "not": { "required": ["weights"] } },
73
+ {
74
+ "required": ["weights"],
75
+ "not": { "anyOf": [ { "required": ["scores"] } ] },
76
+ "properties": { "execution": { "properties": { "topN": false, "weighting": false } } }
77
+ }
78
+ ]
79
+ }