@adaptic/utils 0.0.1031 → 0.0.1033

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 (44) hide show
  1. package/dist/index.cjs +631 -208
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.mjs +627 -209
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/types/__tests__/indicator-parity/generate.d.ts +64 -0
  6. package/dist/types/__tests__/indicator-parity/generate.d.ts.map +1 -0
  7. package/dist/types/__tests__/indicator-parity/record.d.ts +144 -0
  8. package/dist/types/__tests__/indicator-parity/record.d.ts.map +1 -0
  9. package/dist/types/__tests__/indicator-parity/reference.d.ts +92 -0
  10. package/dist/types/__tests__/indicator-parity/reference.d.ts.map +1 -0
  11. package/dist/types/__tests__/indicator-parity/series.d.ts +64 -0
  12. package/dist/types/__tests__/indicator-parity/series.d.ts.map +1 -0
  13. package/dist/types/__tests__/indicator-parity/subjects.d.ts +55 -0
  14. package/dist/types/__tests__/indicator-parity/subjects.d.ts.map +1 -0
  15. package/dist/types/__tests__/support/statistic.d.ts +18 -0
  16. package/dist/types/__tests__/support/statistic.d.ts.map +1 -0
  17. package/dist/types/alpaca/trading/order-utils.d.ts.map +1 -1
  18. package/dist/types/index.d.ts +1 -0
  19. package/dist/types/index.d.ts.map +1 -1
  20. package/dist/types/llm/circuit-breaker.d.ts +18 -1
  21. package/dist/types/llm/circuit-breaker.d.ts.map +1 -1
  22. package/dist/types/llm/fallback-chain.d.ts.map +1 -1
  23. package/dist/types/llm/index.d.ts +3 -1
  24. package/dist/types/llm/index.d.ts.map +1 -1
  25. package/dist/types/llm/rate-guard.d.ts +82 -9
  26. package/dist/types/llm/rate-guard.d.ts.map +1 -1
  27. package/dist/types/llm/structured-content.d.ts +73 -0
  28. package/dist/types/llm/structured-content.d.ts.map +1 -0
  29. package/dist/types/llm/transports/gateway.d.ts.map +1 -1
  30. package/dist/types/metrics-calcs.d.ts +25 -0
  31. package/dist/types/metrics-calcs.d.ts.map +1 -1
  32. package/dist/types/performance-metrics.d.ts +16 -4
  33. package/dist/types/performance-metrics.d.ts.map +1 -1
  34. package/dist/types/sample-statistic.d.ts +123 -0
  35. package/dist/types/sample-statistic.d.ts.map +1 -0
  36. package/dist/types/schemas/alpaca-schemas.d.ts.map +1 -1
  37. package/dist/types/strategy-metrics.d.ts +38 -16
  38. package/dist/types/strategy-metrics.d.ts.map +1 -1
  39. package/dist/types/trading-policy/schemas/effective-policy.schema.d.ts +18 -18
  40. package/dist/types/trading-policy/schemas/model-prefs.schema.d.ts +24 -24
  41. package/dist/types/trading-policy/schemas/policy-mutation.schema.d.ts +36 -36
  42. package/dist/types/types/alpaca-types.d.ts +36 -5
  43. package/dist/types/types/alpaca-types.d.ts.map +1 -1
  44. package/package.json +3 -1
@@ -8,7 +8,10 @@
8
8
  * provider's circuit breaker, fail over to a more expensive leg, and keep doing
9
9
  * so — converting a self-inflicted pacing problem into a permanent routing
10
10
  * change nobody chose. Pacing at the client is what keeps the breaker measuring
11
- * the provider rather than measuring us.
11
+ * the provider rather than measuring us. The same reasoning bounds the guard
12
+ * from the other side: a client held far BELOW the provider's ceiling refuses
13
+ * calls the provider would have served, and the chain answers those refusals by
14
+ * failing over — the same unchosen routing change, arrived at by under-driving.
12
15
  *
13
16
  * Two distinct bounds are applied because they fail differently. The rate bound
14
17
  * (requests per minute) protects the provider's published ceiling. The
@@ -17,16 +20,51 @@
17
20
  * every one of them blows its latency budget and the fan-out produces a hundred
18
21
  * timeouts instead of a queue.
19
22
  *
20
- * Limits live in `provider-limits.json`, not here. A rate limit discovered
21
- * during an incident should be correctable by config, not by a release.
23
+ * Each guard is keyed by the unit its provider enforces limits in. A provider
24
+ * that publishes its ceilings per model gets one independent guard per model.
25
+ * Sharing one guard across its models would enforce a ceiling the provider does
26
+ * not impose, and — when a chain's primary and secondary are served by the same
27
+ * provider — would refuse the secondary at exactly the moment the primary's
28
+ * queue is full, so the fallback that exists for that moment is never reached.
29
+ *
30
+ * Limits live in `provider-limits.json` rather than in code, each beside the
31
+ * source it was transcribed from, so a published ceiling and a conservative
32
+ * guess can never be mistaken for one another in review. The file is bundled
33
+ * at build time: changing a limit is a release of this package, not a runtime
34
+ * switch.
22
35
  *
23
36
  * @module llm/rate-guard
24
37
  */
38
+ /** Where a limit came from: a provider's documented ceiling, or a deliberate under-estimate of an unknown one. */
39
+ export type ProviderLimitBasis = "published" | "conservative-default";
40
+ /**
41
+ * The unit a provider enforces its limits in.
42
+ *
43
+ * `model` means each of the provider's models has its own ceilings, so the
44
+ * client keeps one guard per model; `provider` means one guard covers every
45
+ * model the provider serves.
46
+ */
47
+ export type ProviderLimitScope = "provider" | "model";
25
48
  /** Limits for one provider. */
26
49
  export interface ProviderLimits {
27
50
  /** Whether these numbers were transcribed from a provider doc or chosen conservatively. */
28
- readonly basis: "published" | "conservative-default";
51
+ readonly basis: ProviderLimitBasis;
52
+ /** The unit the provider enforces its limits in. Absent means `provider`. */
53
+ readonly scope?: ProviderLimitScope;
54
+ /**
55
+ * Where a per-model scope was read from, when the entry's numbers are not
56
+ * themselves published. The unit is a claim about the provider and carries
57
+ * the same burden of proof as a number.
58
+ */
59
+ readonly scope_source?: string | null;
29
60
  readonly requests_per_minute: number;
61
+ /**
62
+ * Provenance of `requests_per_minute` when it differs from `basis`. A provider
63
+ * can publish a concurrency ceiling and no per-minute ceiling at all; the
64
+ * per-minute number is then the client's own choice and must not borrow the
65
+ * published label of the bound that was transcribed.
66
+ */
67
+ readonly requests_per_minute_basis?: ProviderLimitBasis;
30
68
  readonly max_concurrent: number;
31
69
  readonly acquire_timeout_ms: number;
32
70
  /** Where a published limit was read from. Null while the basis is a conservative default. */
@@ -50,6 +88,28 @@ export declare function limitsInventory(): {
50
88
  provider: string;
51
89
  limits: ProviderLimits;
52
90
  }[];
91
+ /** Which guard a call is held by, and how its caller can stop waiting. */
92
+ export interface GuardCallScope {
93
+ /**
94
+ * The model the call is addressed to. Selects the guard for a provider whose
95
+ * limits apply per model; ignored for a provider whose limits apply per
96
+ * provider.
97
+ */
98
+ readonly modelId?: string;
99
+ /**
100
+ * The caller's cancellation. A caller that stops waiting leaves the queue at
101
+ * once rather than holding its place until its wait budget runs out, and a
102
+ * permit freed after it has gone goes to a caller that is still waiting.
103
+ */
104
+ readonly signal?: AbortSignal;
105
+ }
106
+ /** What a refusal says about the call it refused. */
107
+ interface RefusalDetail {
108
+ /** The model whose guard refused the call, for a provider whose limits apply per model. */
109
+ readonly modelId?: string;
110
+ /** Whether the caller stopped waiting before the guard's own budget ran out. */
111
+ readonly abandoned?: boolean;
112
+ }
53
113
  /**
54
114
  * Thrown when a caller could not acquire a slot within its budget.
55
115
  *
@@ -61,12 +121,17 @@ export declare class RateGuardTimeoutError extends Error {
61
121
  readonly provider: string;
62
122
  /** Which of the two bounds the caller waited on. */
63
123
  readonly bound: "rate" | "concurrency";
124
+ /** The model whose guard refused the call, when the provider's limits apply per model. */
125
+ readonly modelId: string | undefined;
126
+ /** Whether the caller stopped waiting before the guard's own wait budget ran out. */
127
+ readonly abandoned: boolean;
64
128
  /**
65
129
  * @param provider The provider.
66
130
  * @param bound Which bound was binding.
67
- * @param waitedMs How long the caller waited.
131
+ * @param waitedMs How long the caller was prepared to wait.
132
+ * @param detail The model, and whether the caller left before the budget ran out.
68
133
  */
69
- constructor(provider: string, bound: "rate" | "concurrency", waitedMs: number);
134
+ constructor(provider: string, bound: "rate" | "concurrency", waitedMs: number, detail?: RefusalDetail);
70
135
  }
71
136
  /**
72
137
  * Run a call under a provider's rate and concurrency guards.
@@ -86,13 +151,20 @@ export declare class RateGuardTimeoutError extends Error {
86
151
  * @param provider The provider key.
87
152
  * @param call The work to run once admitted.
88
153
  * @param maxWaitMs Ceiling on queue time; the configured guard timeout applies when lower.
154
+ * @param scope The model the call addresses, and the caller's cancellation.
89
155
  * @returns The call's result.
90
- * @throws {RateGuardTimeoutError} When neither bound admitted the call in time.
156
+ * @throws {RateGuardTimeoutError} When neither bound admitted the call in time,
157
+ * or the caller stopped waiting first.
91
158
  */
92
- export declare function withProviderGuards<T>(provider: string, call: () => Promise<T>, maxWaitMs?: number): Promise<T>;
159
+ export declare function withProviderGuards<T>(provider: string, call: () => Promise<T>, maxWaitMs?: number, scope?: GuardCallScope): Promise<T>;
93
160
  /** Observable guard state, for dashboards and tests. */
94
161
  export interface GuardSnapshot {
162
+ /** The guard's identity: the provider, or `provider/model` for a per-model guard. */
163
+ readonly key: string;
95
164
  readonly provider: string;
165
+ /** The model this guard covers, for a provider whose limits apply per model. */
166
+ readonly modelId: string | undefined;
167
+ readonly scope: ProviderLimitScope;
96
168
  readonly basis: ProviderLimits["basis"];
97
169
  readonly requestsPerMinute: number;
98
170
  readonly maxConcurrent: number;
@@ -104,7 +176,7 @@ export interface GuardSnapshot {
104
176
  /**
105
177
  * Inspect the guards currently in use.
106
178
  *
107
- * @returns A snapshot per provider that has been used, sorted by provider.
179
+ * @returns A snapshot per guard that has been used, sorted by guard key.
108
180
  */
109
181
  export declare function guardSnapshots(): GuardSnapshot[];
110
182
  /**
@@ -116,4 +188,5 @@ export declare function guardSnapshots(): GuardSnapshot[];
116
188
  * @returns void
117
189
  */
118
190
  export declare function resetProviderGuards(): void;
191
+ export {};
119
192
  //# sourceMappingURL=rate-guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-guard.d.ts","sourceRoot":"","sources":["../../../src/llm/rate-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAYH,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,sBAAsB,CAAC;IACrD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAE1D;AAED,uFAAuF;AACvF,wBAAgB,eAAe,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,EAAE,CAIhF;AAED;;;;;GAKG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,yDAAyD;IACzD,SAAgB,QAAQ,EAAE,MAAM,CAAC;IAEjC,oDAAoD;IACpD,SAAgB,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC;IAE9C;;;;OAIG;gBACgB,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,QAAQ,EAAE,MAAM;CASrF;AAgID;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CAsBZ;AAED,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACxC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,aAAa,EAAE,CAiBhD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C"}
1
+ {"version":3,"file":"rate-guard.d.ts","sourceRoot":"","sources":["../../../src/llm/rate-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Interpretation of a model's answer to a structured (JSON) request.
3
+ *
4
+ * A JSON request is a promise about the answer's SHAPE, and providers keep it
5
+ * in different ways. An OpenAI-compatible host given `json_object` constrains
6
+ * its decoder, so its answer is bare JSON. A provider with no schema-less JSON
7
+ * mode — Anthropic, reached through the gateway, supports structured output
8
+ * only against a caller-supplied schema — receives nothing but the prompt's
9
+ * instructions for a `json` request, and a model following them commonly
10
+ * returns the object inside one markdown code fence. The fence is presentation,
11
+ * not content: the object inside it is the answer the model gave.
12
+ *
13
+ * So exactly ONE enclosing fence is removed before parsing, and nothing else is
14
+ * forgiven. Prose before or after the fence, two fenced blocks, a fence that
15
+ * never closes (a truncated answer), and a fence declaring another language all
16
+ * still fail. Each of those is an answer whose meaning a parser would have to
17
+ * guess, and a guessed object is a decision made on data no model produced.
18
+ *
19
+ * Content that is not fenced is parsed exactly as it always was: JSON cannot
20
+ * begin with a backtick, so every answer that parsed before this unwrapping
21
+ * existed takes the same path and yields the same value.
22
+ *
23
+ * @module llm/structured-content
24
+ */
25
+ import type { LlmResponseFormat, LlmUsageRecord } from "./types";
26
+ /** A response format that promises structured content. */
27
+ export type StructuredResponseFormat = Exclude<LlmResponseFormat, "text">;
28
+ /**
29
+ * Thrown when a provider answered a structured request with content that does
30
+ * not parse.
31
+ *
32
+ * Carries the usage the provider billed for that answer. The tokens were spent
33
+ * whether or not the content parsed, and a chain that dropped them would report
34
+ * a failed attempt as free — understating spend by exactly the calls that went
35
+ * wrong.
36
+ */
37
+ export declare class LlmResponseFormatError extends Error {
38
+ /** The format the caller asked for. */
39
+ readonly responseFormat: "json" | "json_schema";
40
+ /** What the provider billed for the answer that did not parse. */
41
+ readonly usage: LlmUsageRecord;
42
+ /** Whether the answer sat inside one enclosing fence that was removed before parsing. */
43
+ readonly fenced: boolean;
44
+ /**
45
+ * @param responseFormat The format the caller asked for.
46
+ * @param usage What the provider billed for the answer.
47
+ * @param fenced Whether one enclosing fence was removed before parsing.
48
+ * @param cause The parser's own complaint.
49
+ */
50
+ constructor(responseFormat: "json" | "json_schema", usage: LlmUsageRecord, fenced: boolean, cause: unknown);
51
+ }
52
+ /**
53
+ * The body of the one markdown fence that encloses an answer, if exactly one does.
54
+ *
55
+ * @param text The model's answer.
56
+ * @returns The fenced body, or null when the answer is not wholly one fenced block.
57
+ */
58
+ export declare function unwrapSingleJsonFence(text: string): string | null;
59
+ /**
60
+ * Parse a model's answer to a structured request.
61
+ *
62
+ * A JSON format that does not parse is an error, not an empty object. Returning
63
+ * a default here would hand the caller a well-typed value that means nothing,
64
+ * and the failure would surface much later as a decision made on absent data.
65
+ *
66
+ * @param content The raw content of the model's message.
67
+ * @param responseFormat The structured format the caller asked for.
68
+ * @param usage What the provider billed for this answer, carried on failure.
69
+ * @returns The parsed value.
70
+ * @throws {LlmResponseFormatError} When the content is not JSON, fenced or not.
71
+ */
72
+ export declare function parseStructuredContent<T>(content: unknown, responseFormat: StructuredResponseFormat, usage: LlmUsageRecord): T;
73
+ //# sourceMappingURL=structured-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured-content.d.ts","sourceRoot":"","sources":["../../../src/llm/structured-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEjE,0DAA0D;AAC1D,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;AAW1E;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,uCAAuC;IACvC,SAAgB,cAAc,EAAE,MAAM,GAAG,aAAa,CAAC;IAEvD,kEAAkE;IAClE,SAAgB,KAAK,EAAE,cAAc,CAAC;IAEtC,yFAAyF;IACzF,SAAgB,MAAM,EAAE,OAAO,CAAC;IAEhC;;;;;OAKG;gBAED,cAAc,EAAE,MAAM,GAAG,aAAa,EACtC,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,OAAO;CAYjB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EACtC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,wBAAwB,EACxC,KAAK,EAAE,cAAc,GACpB,CAAC,CAaH"}
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../../src/llm/transports/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EAGpB,MAAM,UAAU,CAAC;AAQlB,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,MAAM,CAAC;CACjE;AAED;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD;;;OAGG;gBACgB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAMnD;AAED,4DAA4D;AAC5D,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,uBAAuB;IACvB,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,8DAA8D;IAC9D,SAAgB,SAAS,EAAE,OAAO,CAAC;IAEnC;;;OAGG;gBACgB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAMhD;AAwDD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,sBAAsB,GAC7B,YAAY,CA0Dd"}
1
+ {"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../../../../src/llm/transports/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,mBAAmB,EAGpB,MAAM,UAAU,CAAC;AAQlB,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,MAAM,CAAC;CACjE;AAED;;;;;;;;GAQG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD;;;OAGG;gBACgB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAMnD;AAED,4DAA4D;AAC5D,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,uBAAuB;IACvB,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,8DAA8D;IAC9D,SAAgB,SAAS,EAAE,OAAO,CAAC;IAEnC;;;OAGG;gBACgB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAMhD;AAwDD;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,sBAAsB,GAC7B,YAAY,CA8Dd"}
@@ -1,6 +1,31 @@
1
1
  import { Bar, BenchmarkBar } from "./types/alpaca-types";
2
2
  import { types } from "@adaptic/backend";
3
3
  import { CalculateBetaResult, TradeMetrics } from "./types";
4
+ /**
5
+ * Beta of a portfolio against a benchmark, from paired period returns.
6
+ *
7
+ * Non-finite rows are dropped pairwise — a return that is `NaN` on either leg
8
+ * cannot contribute to a covariance — and the count that survives is reported
9
+ * as the cohort rather than discarded. That reporting is the point: silently
10
+ * computing a beta on the 12 rows that happened to be clean, and returning it
11
+ * with the same shape as a beta over all 900, is how a statistic measured on
12
+ * one population gets applied to another.
13
+ *
14
+ * When beta cannot be computed the result is the unavailable branch, never a
15
+ * numeric stand-in. A beta of `0` asserts that the portfolio does not move with
16
+ * the market, which is a strong and consequential claim; emitting it to mean
17
+ * "we could not tell" makes every alpha derived from it wrong by the whole
18
+ * benchmark term.
19
+ *
20
+ * @param portfolioReturns - Portfolio period returns.
21
+ * @param benchmarkReturns - Benchmark period returns, index-aligned to the portfolio.
22
+ * @returns The beta components with their cohort, or a typed unavailable result.
23
+ * @example
24
+ * const result = calculateBetaFromReturns([0.05, -0.02, 0.03], [0.03, -0.01, 0.02]);
25
+ * if (result.available) {
26
+ * // result.value.beta, alongside result.sampleCount and result.coverage
27
+ * }
28
+ */
4
29
  export declare function calculateBetaFromReturns(portfolioReturns: number[], benchmarkReturns: number[]): CalculateBetaResult;
5
30
  /**
6
31
  * Calculate max drawdown taking position type into account
@@ -1 +1 @@
1
- {"version":3,"file":"metrics-calcs.d.ts","sourceRoot":"","sources":["../../src/metrics-calcs.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAsJ5D,wBAAgB,wBAAwB,CACtC,gBAAgB,EAAE,MAAM,EAAE,EAC1B,gBAAgB,EAAE,MAAM,EAAE,GACzB,mBAAmB,CA4FrB;AAgQD;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,GAAG,EAAE,EAChB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC,CAmCjB;AA8CD,wBAA8B,iBAAiB,CAC7C,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,SAAS,EAAE,GAAG,EAAE,EAChB,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,YAAY,CAAC,CA0DvB"}
1
+ {"version":3,"file":"metrics-calcs.d.ts","sourceRoot":"","sources":["../../src/metrics-calcs.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AA0I5D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,wBAAwB,CACtC,gBAAgB,EAAE,MAAM,EAAE,EAC1B,gBAAgB,EAAE,MAAM,EAAE,GACzB,mBAAmB,CA6FrB;AA6QD;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,GAAG,EAAE,EAChB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC,CAmCjB;AA8CD,wBAA8B,iBAAiB,CAC7C,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,SAAS,EAAE,GAAG,EAAE,EAChB,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,YAAY,CAAC,CA0DvB"}
@@ -78,10 +78,22 @@ export declare function alignReturnsByDate(portfolioHistory: PortfolioHistory, b
78
78
  alignedBenchmarkReturns: number[];
79
79
  };
80
80
  /**
81
- * Calculates the beta of the portfolio compared to a benchmark.
82
- * @param portfolioReturns - Array of portfolio returns.
83
- * @param benchmarkReturns - Array of benchmark returns.
84
- * @returns An object containing beta and intermediate calculations.
81
+ * Beta of a portfolio against a benchmark, from paired period returns.
82
+ *
83
+ * The two series are index-aligned pairs by contract: every mean, covariance
84
+ * and variance below is taken over the SAME row set. A length mismatch is
85
+ * therefore reported as invalid input rather than absorbed, because dividing
86
+ * one series' sum by the other series' length produces a mean of a population
87
+ * that does not exist — a number with no cohort, which is the failure this
88
+ * return type exists to make impossible.
89
+ *
90
+ * An uncomputable beta is returned as the unavailable branch, never as `0`.
91
+ * Zero beta is a claim of no market exposure, and downstream alpha attributes
92
+ * the entire benchmark move to the strategy when it believes that claim.
93
+ *
94
+ * @param portfolioReturns - Portfolio period returns.
95
+ * @param benchmarkReturns - Benchmark period returns, index-aligned to the portfolio.
96
+ * @returns The beta components with their cohort, or a typed unavailable result.
85
97
  */
86
98
  export declare function calculateBetaFromReturns(portfolioReturns: number[], benchmarkReturns: number[]): CalculateBetaResult;
87
99
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"performance-metrics.d.ts","sourceRoot":"","sources":["../../src/performance-metrics.ts"],"names":[],"mappings":"AASA,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,YAAY,EACZ,mBAAmB,EAEnB,uBAAuB,EACvB,UAAU,EAEX,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC7B,MAAM,uBAAuB,CAAC;AAgD/B;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,SAAS,EACT,MAAM,EACN,aAAa,GACd,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiF3C;AAwBD;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,CAAC,CA2CjB;AAqMD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,gBAAgB,EAAE,wBAAwB,EAC1C,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAiOD;AAkCD,UAAU,cAAc;IACtB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CACrB,GACL,cAAc,CAuHhB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,GAAE,MAAU,GACnB,MAAM,CAGR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAchE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,gBAAgB,EAAE,gBAAgB,EAClC,aAAa,EAAE,YAAY,EAAE,GAC5B;IAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAAC,uBAAuB,EAAE,MAAM,EAAE,CAAA;CAAE,CAiF1E;AAkFD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,gBAAgB,EAAE,MAAM,EAAE,EAC1B,gBAAgB,EAAE,MAAM,EAAE,GACzB,mBAAmB,CAoErB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,gBAAgB,EAAE,wBAAwB,EAC1C,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,CAmHjB;AA+BD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;CAChD,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAsB1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,MAAM,EACN,MAAM,EACN,SAAS,EACT,aAAa,GACd,EAAE,4BAA4B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA0J5D"}
1
+ {"version":3,"file":"performance-metrics.d.ts","sourceRoot":"","sources":["../../src/performance-metrics.ts"],"names":[],"mappings":"AASA,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,wBAAwB,EACxB,YAAY,EACZ,mBAAmB,EAEnB,uBAAuB,EACvB,UAAU,EAEX,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC7B,MAAM,uBAAuB,CAAC;AAqD/B;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,EAC1C,SAAS,EACT,MAAM,EACN,aAAa,GACd,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiF3C;AAwBD;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,CAAC,CA2CjB;AAqMD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,gBAAgB,EAAE,wBAAwB,EAC1C,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CA+OD;AAkCD,UAAU,cAAc;IACtB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CACrB,GACL,cAAc,CAuHhB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,GAAE,MAAU,GACnB,MAAM,CAGR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAchE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,gBAAgB,EAAE,gBAAgB,EAClC,aAAa,EAAE,YAAY,EAAE,GAC5B;IAAE,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAAC,uBAAuB,EAAE,MAAM,EAAE,CAAA;CAAE,CAiF1E;AAkFD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,gBAAgB,EAAE,MAAM,EAAE,EAC1B,gBAAgB,EAAE,MAAM,EAAE,GACzB,mBAAmB,CA2ErB;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,gBAAgB,EAAE,wBAAwB,EAC1C,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,CAmHjB;AA+BD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;CAChD,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAsB1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAAC,EAC5C,MAAM,EACN,MAAM,EACN,SAAS,EACT,aAAa,GACd,EAAE,4BAA4B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA0J5D"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * A measured statistic and the cohort it was measured on, carried as one
3
+ * inseparable value.
4
+ *
5
+ * A ratio is meaningless without the population it was taken over: the same
6
+ * `0.42` is a strong result on 2,000 trades and noise on five, and a `0.0`
7
+ * returned because nothing could be computed is indistinguishable from a `0.0`
8
+ * that was genuinely measured. Both confusions are the same error — a number
9
+ * read apart from its unit and its cohort — and both have produced wrong
10
+ * conclusions from correct arithmetic.
11
+ *
12
+ * This type removes the option. Every statistic shaped by a population carries
13
+ * `sampleCount` (how many observations actually entered the computation) and
14
+ * `coverage` (what fraction of the observations the caller offered were usable),
15
+ * on BOTH branches: an unavailable statistic still reports how much data it
16
+ * saw, because "we had nothing" and "we had 900 rows and still could not
17
+ * compute it" are different facts with different responses.
18
+ *
19
+ * Absence is a branch of the union rather than a sentinel value. There is no
20
+ * number a caller can read without first proving the statistic exists, which is
21
+ * what keeps an unknown from silently becoming a zero on its way to a decision.
22
+ *
23
+ * @module sample-statistic
24
+ */
25
+ /**
26
+ * Why a statistic could not be computed from the observations offered.
27
+ *
28
+ * The distinctions are the point: a caller that cannot tell "too few rows" from
29
+ * "the rows were unusable" from "the population is degenerate" cannot tell a
30
+ * warm-up from a data outage from a genuinely constant series, and will treat
31
+ * all three the same way.
32
+ */
33
+ export type StatisticUnavailableReason =
34
+ /** Fewer usable observations than the computation requires. */
35
+ "insufficient_samples"
36
+ /** Observations were offered but none survived validation (non-finite, unpaired). */
37
+ | "no_usable_samples"
38
+ /** Enough usable observations, but the population cannot support the statistic
39
+ * (a zero-variance denominator, an undefined ratio). */
40
+ | "degenerate_population"
41
+ /** The request itself is malformed — mismatched series lengths, a non-positive window. */
42
+ | "invalid_input";
43
+ /**
44
+ * How many observations a statistic was actually computed from, against how
45
+ * many the caller offered.
46
+ *
47
+ * `coverage` is the ratio that makes silent row-dropping visible: a function
48
+ * that filters non-finite rows and reports only the surviving statistic hides
49
+ * the size of what it discarded, and a statistic computed on 12% of the
50
+ * requested window is a different claim from the same number computed on all
51
+ * of it.
52
+ */
53
+ export interface SampleCohort {
54
+ /** Observations that entered the computation. Never negative. */
55
+ readonly sampleCount: number;
56
+ /** Observations the caller offered, or the window width the caller asked for. */
57
+ readonly requestedCount: number;
58
+ /** `sampleCount / requestedCount`, clamped to [0, 1]; `0` when nothing was requested. */
59
+ readonly coverage: number;
60
+ }
61
+ /** A statistic that was computed, carrying the cohort it was computed on. */
62
+ export interface AvailableStatistic<T> extends SampleCohort {
63
+ readonly available: true;
64
+ /** The measured value. */
65
+ readonly value: T;
66
+ }
67
+ /** A statistic that could not be computed, still carrying what data was seen. */
68
+ export interface UnavailableStatistic extends SampleCohort {
69
+ readonly available: false;
70
+ /** Which class of failure prevented the computation. */
71
+ readonly reason: StatisticUnavailableReason;
72
+ /** Human-readable specifics, for logs and error messages. Never parsed. */
73
+ readonly detail: string;
74
+ }
75
+ /**
76
+ * A statistic that either exists with its cohort, or does not exist and says
77
+ * why — never a number standing in for an unknown.
78
+ */
79
+ export type SampleStatistic<T> = AvailableStatistic<T> | UnavailableStatistic;
80
+ /**
81
+ * Build the cohort descriptor for a computation.
82
+ *
83
+ * `coverage` is derived here rather than supplied, so it cannot drift from the
84
+ * counts it claims to summarise. A zero request yields zero coverage: no
85
+ * observations were asked for, so none were covered, and the alternative (`1`)
86
+ * would report a vacuous computation as fully covered.
87
+ *
88
+ * @param requestedCount - Observations offered, or the window width requested.
89
+ * @param sampleCount - Observations that entered the computation.
90
+ * @returns The cohort descriptor with `coverage` derived from the two counts.
91
+ * @throws When either count is negative or non-finite, which is a programming
92
+ * error rather than a data condition.
93
+ */
94
+ export declare function sampleCohort(requestedCount: number, sampleCount: number): SampleCohort;
95
+ /**
96
+ * Wrap a computed value with its cohort.
97
+ *
98
+ * @param value - The measured statistic.
99
+ * @param cohort - The cohort it was measured on.
100
+ * @returns The available branch of {@link SampleStatistic}.
101
+ */
102
+ export declare function availableStatistic<T>(value: T, cohort: SampleCohort): AvailableStatistic<T>;
103
+ /**
104
+ * Record that a statistic could not be computed, and what was seen instead.
105
+ *
106
+ * @param reason - Which class of failure prevented the computation.
107
+ * @param detail - Specifics for logs; never machine-parsed.
108
+ * @param cohort - What data was available when the attempt was abandoned.
109
+ * @returns The unavailable branch of {@link SampleStatistic}.
110
+ */
111
+ export declare function unavailableStatistic(reason: StatisticUnavailableReason, detail: string, cohort: SampleCohort): UnavailableStatistic;
112
+ /**
113
+ * Narrow a statistic to its available branch.
114
+ *
115
+ * Exists so consumers in other packages can discriminate without restating the
116
+ * predicate, and so the discriminant stays a single named concept if the shape
117
+ * ever grows a third branch.
118
+ *
119
+ * @param statistic - The statistic to test.
120
+ * @returns Whether the statistic carries a value.
121
+ */
122
+ export declare function isAvailable<T>(statistic: SampleStatistic<T>): statistic is AvailableStatistic<T>;
123
+ //# sourceMappingURL=sample-statistic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample-statistic.d.ts","sourceRoot":"","sources":["../../src/sample-statistic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,0BAA0B;AACpC,+DAA+D;AAC7D,sBAAsB;AACxB,qFAAqF;GACnF,mBAAmB;AACrB;yDACyD;GACvD,uBAAuB;AACzB,0FAA0F;GACxF,eAAe,CAAC;AAEpB;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iFAAiF;IACjF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB,CAAC,CAAC,CAAE,SAAQ,YAAY;IACzD,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,0BAA0B;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED,iFAAiF;AACjF,MAAM,WAAW,oBAAqB,SAAQ,YAAY;IACxD,QAAQ,CAAC,SAAS,EAAE,KAAK,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,oBAAoB,CAAC;AAE9E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,GAClB,YAAY,CAkBd;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,KAAK,EAAE,CAAC,EACR,MAAM,EAAE,YAAY,GACnB,kBAAkB,CAAC,CAAC,CAAC,CAEvB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,0BAA0B,EAClC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,GACnB,oBAAoB,CAEtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,GAC5B,SAAS,IAAI,kBAAkB,CAAC,CAAC,CAAC,CAEpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"alpaca-schemas.d.ts","sourceRoot":"","sources":["../../../src/schemas/alpaca-schemas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,iDAAiD;AACjD,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+CrC,CAAC;AAIH,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmB/B,CAAC;AAEH,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAAgC,CAAC;AAqDxE,uCAAuC;AACvC,eAAO,MAAM,iBAAiB,EAAE,CAAC,CAAC,OAiChC,CAAC;AAEH,2CAA2C;AAC3C,eAAO,MAAM,uBAAuB,uDAA6B,CAAC;AAIlE,4CAA4C;AAC5C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS1B,CAAC;AAEH,0CAA0C;AAC1C,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI7C,CAAC;AAEH,sCAAsC;AACtC,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzC,CAAC;AAIH,gCAAgC;AAChC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU5B,CAAC;AAEH,wCAAwC;AACxC,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAG3C,CAAC;AAIH,gCAAgC;AAChC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;EAQ5B,CAAC;AAEH,wCAAwC;AACxC,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAG3C,CAAC;AAUH,gCAAgC;AAChC,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYlC,CAAC;AAEH,+BAA+B;AAC/B,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGnC,CAAC;AAIH,4CAA4C;AAC5C,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;EAO/C,CAAC;AAIH,sCAAsC;AACtC,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBzC,CAAC"}
1
+ {"version":3,"file":"alpaca-schemas.d.ts","sourceRoot":"","sources":["../../../src/schemas/alpaca-schemas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,iDAAiD;AACjD,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+CrC,CAAC;AAIH,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmB/B,CAAC;AAEH,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAAgC,CAAC;AAsDxE,uCAAuC;AACvC,eAAO,MAAM,iBAAiB,EAAE,CAAC,CAAC,OAiChC,CAAC;AAEH,2CAA2C;AAC3C,eAAO,MAAM,uBAAuB,uDAA6B,CAAC;AAIlE,4CAA4C;AAC5C,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS1B,CAAC;AAEH,0CAA0C;AAC1C,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAI7C,CAAC;AAEH,sCAAsC;AACtC,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzC,CAAC;AAIH,gCAAgC;AAChC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU5B,CAAC;AAEH,wCAAwC;AACxC,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAG3C,CAAC;AAIH,gCAAgC;AAChC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;EAQ5B,CAAC;AAEH,wCAAwC;AACxC,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAG3C,CAAC;AAUH,gCAAgC;AAChC,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYlC,CAAC;AAEH,+BAA+B;AAC/B,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGnC,CAAC;AAIH,4CAA4C;AAC5C,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;EAO/C,CAAC;AAIH,sCAAsC;AACtC,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBzC,CAAC"}
@@ -4,62 +4,84 @@
4
4
  * Conventions:
5
5
  * - tradePnls / tradeReturns is an array of per-trade realised P&L or return
6
6
  * (positive = win, negative = loss, zero = breakeven).
7
- * - All "rolling*" functions return null when fewer than `windowSize` trades exist.
7
+ * - Every statistic here is a ratio or a mean over a WINDOW, so every one is
8
+ * returned as a {@link SampleStatistic}: the value cannot be read without the
9
+ * `sampleCount` it was taken over and the `coverage` of the window that was
10
+ * asked for. A hit-rate is a different claim on 5 trades than on 500, and a
11
+ * window that could only be half-filled is a different cohort from a full
12
+ * one — a caller holding a bare number can tell neither apart.
13
+ * - A window that cannot support the statistic returns the unavailable branch
14
+ * with a reason, never a numeric stand-in. Zero is a measurement.
8
15
  * - All public functions reject non-finite inputs (NaN, Infinity) by throwing.
9
16
  * Callers must pre-validate or filter their inputs.
10
17
  */
18
+ import { type SampleStatistic } from "./sample-statistic";
11
19
  /**
12
20
  * Rolling expectancy: mean P&L over the most-recent `windowSize` trades.
13
21
  *
14
22
  * @param tradePnls - Array of per-trade realised P&L values.
15
23
  * @param windowSize - Number of most-recent trades to include. Must be a positive integer.
16
- * @returns Mean P&L of the last `windowSize` trades, or null when fewer than `windowSize` exist.
24
+ * @returns Mean P&L of the last `windowSize` trades with its cohort, or a typed
25
+ * unavailable result when fewer than `windowSize` trades exist.
17
26
  * @throws When `windowSize` is not a positive integer or any input is non-finite.
18
27
  */
19
- export declare function calculateRollingExpectancy(tradePnls: number[], windowSize: number): number | null;
28
+ export declare function calculateRollingExpectancy(tradePnls: number[], windowSize: number): SampleStatistic<number>;
20
29
  /**
21
30
  * Rolling hit-rate: fraction of strictly-positive P&L trades in the most-recent
22
31
  * `windowSize` trades. Zero P&L counts as non-win.
23
32
  *
24
33
  * @param tradePnls - Array of per-trade realised P&L values.
25
34
  * @param windowSize - Number of most-recent trades to include. Must be a positive integer.
26
- * @returns Fraction of winning trades in the window, or null when fewer than `windowSize` exist.
35
+ * @returns Fraction of winning trades in the window with its cohort, or a typed
36
+ * unavailable result when fewer than `windowSize` trades exist.
27
37
  * @throws When `windowSize` is not a positive integer or any input is non-finite.
28
38
  */
29
- export declare function calculateRollingHitRate(tradePnls: number[], windowSize: number): number | null;
39
+ export declare function calculateRollingHitRate(tradePnls: number[], windowSize: number): SampleStatistic<number>;
30
40
  /**
31
41
  * Rolling profit factor: sum(wins) / |sum(losses)| over the most-recent `windowSize` trades.
32
42
  *
33
43
  * Edge cases:
34
- * - no losses and at least one win → +Infinity
35
- * - no wins and no losses (all zeros) → 0
36
- * - fewer than windowSize trades → null
44
+ * - no losses and at least one win → +Infinity (an unbounded but real ratio)
45
+ * - no wins and no losses (all zeros) → unavailable: `0 / 0` is undefined, and a
46
+ * window of breakeven trades has no profit factor rather than a profit factor
47
+ * of zero
48
+ * - fewer than windowSize trades → unavailable
37
49
  *
38
50
  * @param tradePnls - Array of per-trade realised P&L values.
39
51
  * @param windowSize - Number of most-recent trades to include. Must be a positive integer.
40
- * @returns Profit factor for the rolling window, or null when fewer than `windowSize` exist.
52
+ * @returns Profit factor for the rolling window with its cohort, or a typed
53
+ * unavailable result.
41
54
  * @throws When `windowSize` is not a positive integer or any input is non-finite.
42
55
  */
43
- export declare function calculateRollingProfitFactor(tradePnls: number[], windowSize: number): number | null;
56
+ export declare function calculateRollingProfitFactor(tradePnls: number[], windowSize: number): SampleStatistic<number>;
44
57
  /**
45
58
  * Rolling Sortino: delegate to `calculateSortino` over the most-recent `windowSize` returns.
46
59
  *
47
60
  * @param tradeReturns - Array of per-trade return values.
48
61
  * @param windowSize - Number of most-recent trades to include. Must be a positive integer.
49
62
  * @param riskFreeRate - Risk-free rate to subtract from returns (default 0).
50
- * @returns Sortino ratio for the rolling window, or null when fewer than `windowSize` exist.
63
+ * @returns Sortino ratio for the rolling window with its cohort, or a typed
64
+ * unavailable result.
51
65
  * @throws When `windowSize` is not a positive integer or any input is non-finite.
52
66
  */
53
- export declare function calculateRollingSortino(tradeReturns: number[], windowSize: number, riskFreeRate?: number): number | null;
67
+ export declare function calculateRollingSortino(tradeReturns: number[], windowSize: number, riskFreeRate?: number): SampleStatistic<number>;
54
68
  /**
55
69
  * Z-score of live-expectancy vs backtest-expectancy, scaled by the backtest stddev.
56
70
  * Positive Z = live outperforming; negative Z = live underperforming.
57
71
  *
58
- * @param liveExpectancy - Mean P&L per trade in the live window.
72
+ * The live expectancy is taken as a {@link SampleStatistic} rather than a bare
73
+ * number so the z-score inherits the cohort it was actually derived from. A
74
+ * z-score is a statement about how surprising a sample mean is, and how
75
+ * surprising it is depends entirely on how many trades produced it — quoting
76
+ * the z alone is the exact substitution this type exists to block. An
77
+ * unavailable live expectancy yields an unavailable z, because there is no
78
+ * mean to compare.
79
+ *
80
+ * @param liveExpectancy - Mean P&L per trade in the live window, with its cohort.
59
81
  * @param backtestExpectancy - Mean P&L per trade from the calibration backtest.
60
82
  * @param backtestStddev - Stddev of per-trade P&L in the backtest. Must be > 0.
61
- * @returns Z-score measuring divergence between live and backtest performance.
62
- * @throws When any input is non-finite or `backtestStddev` is not positive.
83
+ * @returns Z-score measuring live-vs-backtest divergence, carrying the live cohort.
84
+ * @throws When the backtest inputs are non-finite or `backtestStddev` is not positive.
63
85
  */
64
- export declare function calculateBacktestDivergenceZ(liveExpectancy: number, backtestExpectancy: number, backtestStddev: number): number;
86
+ export declare function calculateBacktestDivergenceZ(liveExpectancy: SampleStatistic<number>, backtestExpectancy: number, backtestStddev: number): SampleStatistic<number>;
65
87
  //# sourceMappingURL=strategy-metrics.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"strategy-metrics.d.ts","sourceRoot":"","sources":["../../src/strategy-metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAkBH;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAMf;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAOf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CASf;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EAAE,EACtB,UAAU,EAAE,MAAM,EAClB,YAAY,SAAI,GACf,MAAM,GAAG,IAAI,CAKf;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,EACtB,kBAAkB,EAAE,MAAM,EAC1B,cAAc,EAAE,MAAM,GACrB,MAAM,CAQR"}
1
+ {"version":3,"file":"strategy-metrics.d.ts","sourceRoot":"","sources":["../../src/strategy-metrics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAwC5B;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,GACjB,eAAe,CAAC,MAAM,CAAC,CAezB;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,GACjB,eAAe,CAAC,MAAM,CAAC,CAgBzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EAAE,EACnB,UAAU,EAAE,MAAM,GACjB,eAAe,CAAC,MAAM,CAAC,CAyBzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EAAE,EACtB,UAAU,EAAE,MAAM,EAClB,YAAY,SAAI,GACf,eAAe,CAAC,MAAM,CAAC,CAuBzB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,eAAe,CAAC,MAAM,CAAC,EACvC,kBAAkB,EAAE,MAAM,EAC1B,cAAc,EAAE,MAAM,GACrB,eAAe,CAAC,MAAM,CAAC,CAqBzB"}