@coinrithm/mcp-trading 0.1.8 → 0.3.0

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 (62) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +43 -19
  3. package/dist/agent/act.d.ts +4 -0
  4. package/dist/agent/act.js +114 -0
  5. package/dist/agent/capabilityGuard.d.ts +2 -0
  6. package/dist/agent/capabilityGuard.js +131 -0
  7. package/dist/agent/cli.d.ts +21 -0
  8. package/dist/agent/cli.js +382 -0
  9. package/dist/agent/client.d.ts +107 -0
  10. package/dist/agent/client.js +173 -0
  11. package/dist/agent/decision.d.ts +137 -0
  12. package/dist/agent/decision.js +118 -0
  13. package/dist/agent/decisionValidator.d.ts +16 -0
  14. package/dist/agent/decisionValidator.js +215 -0
  15. package/dist/agent/engine.d.ts +10 -0
  16. package/dist/agent/engine.js +16 -0
  17. package/dist/agent/extract.d.ts +4 -0
  18. package/dist/agent/extract.js +5 -0
  19. package/dist/agent/frontmatter.d.ts +5 -0
  20. package/dist/agent/frontmatter.js +19 -0
  21. package/dist/agent/index.d.ts +2 -0
  22. package/dist/agent/index.js +10 -0
  23. package/dist/agent/indicators.d.ts +44 -0
  24. package/dist/agent/indicators.js +135 -0
  25. package/dist/agent/manifest.d.ts +15 -0
  26. package/dist/agent/manifest.js +40 -0
  27. package/dist/agent/mergeRules.d.ts +11 -0
  28. package/dist/agent/mergeRules.js +82 -0
  29. package/dist/agent/observe.d.ts +7 -0
  30. package/dist/agent/observe.js +244 -0
  31. package/dist/agent/prompt.d.ts +3 -0
  32. package/dist/agent/prompt.js +76 -0
  33. package/dist/agent/providers.d.ts +25 -0
  34. package/dist/agent/providers.js +143 -0
  35. package/dist/agent/resolve.d.ts +11 -0
  36. package/dist/agent/resolve.js +499 -0
  37. package/dist/agent/runEvidence.d.ts +6 -0
  38. package/dist/agent/runEvidence.js +23 -0
  39. package/dist/agent/runner.d.ts +19 -0
  40. package/dist/agent/runner.js +280 -0
  41. package/dist/agent/skill.d.ts +12 -0
  42. package/dist/agent/skill.js +136 -0
  43. package/dist/agent/skillValidator.d.ts +7 -0
  44. package/dist/agent/skillValidator.js +123 -0
  45. package/dist/agent/state.d.ts +7 -0
  46. package/dist/agent/state.js +96 -0
  47. package/dist/agent/strictLint.d.ts +3 -0
  48. package/dist/agent/strictLint.js +165 -0
  49. package/dist/agent/templates.d.ts +14 -0
  50. package/dist/agent/templates.js +192 -0
  51. package/dist/agent/types.d.ts +286 -0
  52. package/dist/agent/types.js +88 -0
  53. package/dist/agent/util.d.ts +13 -0
  54. package/dist/agent/util.js +116 -0
  55. package/dist/agent/version.d.ts +11 -0
  56. package/dist/agent/version.js +16 -0
  57. package/dist/client.d.ts +162 -0
  58. package/dist/http.d.ts +2 -0
  59. package/dist/index.d.ts +2 -0
  60. package/dist/tools.d.ts +3 -0
  61. package/dist/version.d.ts +1 -0
  62. package/package.json +78 -67
@@ -0,0 +1,286 @@
1
+ import { IndicatorSet } from "./indicators.js";
2
+ export declare const SPEC_VERSION = "coinrithm.agent.v1";
3
+ export type Venue = "spot" | "futures" | "pm";
4
+ export declare const VENUES: readonly Venue[];
5
+ export declare const ACTION_TYPES: readonly ["futures_open", "futures_close", "futures_set_sltp", "spot_order", "spot_cancel", "pm_open"];
6
+ export type ActionType = (typeof ACTION_TYPES)[number];
7
+ export type ProviderName = "anthropic" | "openai" | "groq" | "nvidia" | "openai-compatible";
8
+ export declare const PROVIDERS: readonly ProviderName[];
9
+ export interface ModelConfig {
10
+ provider: ProviderName;
11
+ name: string;
12
+ baseUrl?: string;
13
+ }
14
+ export interface TriggerConfig {
15
+ cadence: string;
16
+ timezone?: string;
17
+ }
18
+ export interface RiskConfig {
19
+ maxLeverage: number;
20
+ perTradeMarginMusd: number;
21
+ maxConcurrentPositions: number;
22
+ requireStopLoss: boolean;
23
+ watchlist: string[];
24
+ blocklist?: string[];
25
+ }
26
+ export interface LimitsConfig {
27
+ maxTradesPerDay: number;
28
+ maxWritesPerCycle: number;
29
+ maxDailyLossMusd: number;
30
+ maxOpenMarginMusd: number;
31
+ }
32
+ export interface AbstentionConfig {
33
+ onStaleData: boolean;
34
+ onWeakSignal: boolean;
35
+ onMissingQuote: boolean;
36
+ onInsufficientBalance: boolean;
37
+ minConfidence: number;
38
+ }
39
+ export interface SyncConfig {
40
+ requirePollBeforeWrite: boolean;
41
+ }
42
+ export interface KillSwitchConfig {
43
+ maxDrawdownMusd: number;
44
+ maxConsecutiveRejects: number;
45
+ maxConsecutiveModelFailures: number;
46
+ onRateLimitPressure: boolean;
47
+ }
48
+ export declare const OBJECTIVE_PRIMARIES: readonly ["realized_pnl", "risk_adjusted", "drawdown_control", "calibration"];
49
+ export type ObjectivePrimary = (typeof OBJECTIVE_PRIMARIES)[number];
50
+ export interface ObjectiveConfig {
51
+ primary: ObjectivePrimary;
52
+ secondary: string[];
53
+ horizon?: string;
54
+ }
55
+ export declare const ALLOWED_CAPABILITIES: readonly ["websearch", "indicators"];
56
+ export type Capability = (typeof ALLOWED_CAPABILITIES)[number];
57
+ export interface AgentSpec {
58
+ name: string;
59
+ description: string;
60
+ spec: string;
61
+ trigger: TriggerConfig;
62
+ model?: ModelConfig;
63
+ venues: Venue[];
64
+ risk: RiskConfig;
65
+ limits: LimitsConfig;
66
+ abstention: AbstentionConfig;
67
+ sync: SyncConfig;
68
+ killSwitch: KillSwitchConfig;
69
+ objective?: ObjectiveConfig;
70
+ capabilities: Capability[];
71
+ }
72
+ export interface ParsedSkill {
73
+ spec: AgentSpec;
74
+ body: string;
75
+ raw: Record<string, unknown>;
76
+ }
77
+ export interface ValidationResult {
78
+ valid: boolean;
79
+ code?: string;
80
+ reason?: string;
81
+ }
82
+ export declare const ok: () => ValidationResult;
83
+ export declare const fail: (code: string, reason: string) => ValidationResult;
84
+ export interface Freshness {
85
+ status: string;
86
+ ageSeconds?: number;
87
+ }
88
+ export interface WatchEntry {
89
+ symbol: string;
90
+ coinId: string | null;
91
+ name?: string;
92
+ priceUsd?: number;
93
+ change1h?: number;
94
+ change24h?: number;
95
+ change7d?: number;
96
+ freshness?: Freshness;
97
+ indicators?: IndicatorSet;
98
+ }
99
+ export interface OpenPosition {
100
+ venue: Venue;
101
+ id: number;
102
+ coinId?: string;
103
+ symbol?: string;
104
+ side?: string;
105
+ status?: string;
106
+ marginMusd?: number;
107
+ unrealizedPnlMusd?: number;
108
+ }
109
+ export interface SpotOrder {
110
+ id: number;
111
+ coinId?: string;
112
+ symbol?: string;
113
+ side?: string;
114
+ orderType?: string;
115
+ quantity?: number;
116
+ status?: string;
117
+ }
118
+ export interface PmPosition {
119
+ id: number;
120
+ source?: string;
121
+ slug?: string;
122
+ outcomeExternalMarketId?: string;
123
+ stakeMusd?: number;
124
+ status?: string;
125
+ }
126
+ export interface PmMarket {
127
+ source: string;
128
+ slug: string;
129
+ outcomeExternalMarketId: string;
130
+ title?: string;
131
+ freshness?: Freshness;
132
+ }
133
+ export interface Observation {
134
+ asOf: string;
135
+ scopes: string[];
136
+ cashAvailableMusd: number | null;
137
+ equityMusd: number | null;
138
+ openPositions: OpenPosition[];
139
+ openOrders: SpotOrder[];
140
+ pmPositions: PmPosition[];
141
+ pmMarkets: PmMarket[];
142
+ watch: WatchEntry[];
143
+ syncCursor: string | null;
144
+ newClosedTrades: Array<Record<string, unknown>>;
145
+ polledBeforeWrite: boolean;
146
+ }
147
+ export type ProposedAction = {
148
+ type: "futures_open";
149
+ symbol: string;
150
+ side: "long" | "short";
151
+ leverage: number;
152
+ marginMusd: number;
153
+ stopLossPrice?: number | null;
154
+ takeProfitPrice?: number | null;
155
+ confidence?: number;
156
+ rationaleSummary?: string;
157
+ } | {
158
+ type: "futures_close";
159
+ positionId: number;
160
+ fraction?: number;
161
+ confidence?: number;
162
+ rationaleSummary?: string;
163
+ } | {
164
+ type: "futures_set_sltp";
165
+ positionId: number;
166
+ stopLossPrice?: number | null;
167
+ takeProfitPrice?: number | null;
168
+ } | {
169
+ type: "spot_order";
170
+ symbol: string;
171
+ side: "buy" | "sell";
172
+ orderType: "market" | "limit" | "stop";
173
+ quantity: number;
174
+ limitPrice?: number;
175
+ stopPrice?: number;
176
+ confidence?: number;
177
+ rationaleSummary?: string;
178
+ } | {
179
+ type: "spot_cancel";
180
+ orderId: number;
181
+ } | {
182
+ type: "pm_open";
183
+ source: string;
184
+ slug: string;
185
+ outcomeExternalMarketId: string;
186
+ stakeMusd: number;
187
+ confidence?: number;
188
+ rationaleSummary?: string;
189
+ };
190
+ export type ActionVenue = Venue;
191
+ export declare function actionVenue(a: ProposedAction): ActionVenue;
192
+ export declare function isWriteAction(a: ProposedAction): boolean;
193
+ export declare function isOpenAction(a: ProposedAction): a is Extract<ProposedAction, {
194
+ type: "futures_open" | "spot_order" | "pm_open";
195
+ }>;
196
+ export declare function spotBuyCost(action: Extract<ProposedAction, {
197
+ type: "spot_order";
198
+ }>, quote?: QuoteEvidence): number | undefined;
199
+ export interface Decision {
200
+ decision: "skip" | "act";
201
+ reason?: string;
202
+ confidence?: number;
203
+ actions: ProposedAction[];
204
+ }
205
+ export interface QuoteEvidence {
206
+ eligible: boolean;
207
+ blockReasons?: unknown;
208
+ entryPrice?: number;
209
+ liquidationPrice?: number;
210
+ executionPrice?: number;
211
+ estimatedCostMusd?: number;
212
+ freshness?: Freshness;
213
+ }
214
+ export interface RunState {
215
+ runId: string;
216
+ cyclesRun: number;
217
+ writesToday: number;
218
+ realizedPnlMusd: number;
219
+ peakRealizedMusd: number;
220
+ consecutiveRejectCycles: number;
221
+ consecutiveModelFailures: number;
222
+ rateLimitHits: number;
223
+ disabled: boolean;
224
+ disabledReason?: string;
225
+ dayKey: string;
226
+ cursor: string | null;
227
+ seen: string[];
228
+ realizedPnlTodayMusd: number;
229
+ consecutiveExecFailures: number;
230
+ intentSeq: Record<string, number>;
231
+ }
232
+ export interface AgentTrace {
233
+ runId?: string;
234
+ decisionId?: string;
235
+ strategyLabel?: string;
236
+ confidence?: number;
237
+ rationaleSummary?: string;
238
+ }
239
+ export interface ApiResult {
240
+ ok: boolean;
241
+ status: number;
242
+ data: unknown;
243
+ retryAfterSeconds?: number;
244
+ rateLimitRemaining?: number;
245
+ ledgerEventId?: string | null;
246
+ }
247
+ export interface PlannedAction {
248
+ action: ProposedAction;
249
+ accepted: boolean;
250
+ code?: string;
251
+ reason?: string;
252
+ quote?: QuoteEvidence;
253
+ executed?: boolean;
254
+ result?: unknown;
255
+ }
256
+ export interface CycleResult {
257
+ decision: "skip" | "act";
258
+ skipReason?: string;
259
+ planned: PlannedAction[];
260
+ modelFailed?: boolean;
261
+ disabled?: boolean;
262
+ disabledReason?: string;
263
+ live: boolean;
264
+ }
265
+ export interface ResolveIssue {
266
+ code: string;
267
+ message: string;
268
+ path?: string;
269
+ }
270
+ export interface Provenance {
271
+ sources: Record<string, string>;
272
+ mergeOrder: string[];
273
+ includeOrder: string[];
274
+ }
275
+ export interface ResolvedAgent {
276
+ inputPath: string;
277
+ isDirectory: boolean;
278
+ rawFrontmatter: Record<string, unknown>;
279
+ mergedProse: string;
280
+ proseParts: Array<{
281
+ source: string;
282
+ text: string;
283
+ }>;
284
+ provenance: Provenance;
285
+ contentHashes: Record<string, string>;
286
+ }
@@ -0,0 +1,88 @@
1
+ // Core types for the CoinRithm public agent runner.
2
+ //
3
+ // An "agent" is a single SKILL.md: machine-read frontmatter (the AgentSpec
4
+ // types here) plus a plain-language strategy body. The runner reads the spec,
5
+ // wakes on cadence, asks a model for proposed actions, validates them against
6
+ // these caps, and acts via the CoinRithm paper API. Nothing here touches real
7
+ // money.
8
+ export const SPEC_VERSION = "coinrithm.agent.v1";
9
+ export const VENUES = ["spot", "futures", "pm"];
10
+ // The runner's live action vocabulary — the capability set the drift guard
11
+ // checks authored prose against. MUST mirror the ProposedAction union below and
12
+ // the zod schema in decision.ts. A test ("ACTION_TYPES stays in lockstep with
13
+ // the decision schema", capabilityGuard.test.ts) derives the literal set from
14
+ // decision.ts's actionSchema and asserts equality, so the two cannot drift.
15
+ export const ACTION_TYPES = [
16
+ "futures_open",
17
+ "futures_close",
18
+ "futures_set_sltp",
19
+ "spot_order",
20
+ "spot_cancel",
21
+ "pm_open",
22
+ ];
23
+ export const PROVIDERS = [
24
+ "anthropic",
25
+ "openai",
26
+ "groq",
27
+ "nvidia",
28
+ "openai-compatible",
29
+ ];
30
+ // What the agent declares it is optimizing for — so two similar-looking agents
31
+ // are distinguishable and the scorecard/Arena can read intent.
32
+ export const OBJECTIVE_PRIMARIES = [
33
+ "realized_pnl",
34
+ "risk_adjusted",
35
+ "drawdown_control",
36
+ "calibration",
37
+ ];
38
+ // Opt-in capabilities beyond CoinRithm market reads + paper execution.
39
+ // RESERVED in v1: declared + validated here, wired into the runner in a later
40
+ // slice. `websearch` = external lookups (an injection surface + a cost — it can
41
+ // inform reasoning but NEVER widen a cap, since caps live in the runner);
42
+ // `indicators` = runner-computed RSI/MACD/etc. fed into the observation.
43
+ export const ALLOWED_CAPABILITIES = ["websearch", "indicators"];
44
+ export const ok = () => ({ valid: true });
45
+ export const fail = (code, reason) => ({
46
+ valid: false,
47
+ code,
48
+ reason,
49
+ });
50
+ export function actionVenue(a) {
51
+ if (a.type.startsWith("futures"))
52
+ return "futures";
53
+ if (a.type.startsWith("spot"))
54
+ return "spot";
55
+ return "pm";
56
+ }
57
+ export function isWriteAction(a) {
58
+ // Every proposed action mutates state (set-sltp/cancel included). The model
59
+ // never proposes a read; reads are the runner's job during observe.
60
+ return true;
61
+ }
62
+ export function isOpenAction(a) {
63
+ return (a.type === "futures_open" || a.type === "spot_order" || a.type === "pm_open");
64
+ }
65
+ // Gross mUSD a spot BUY consumes. The validator (per-trade cap + balance gate)
66
+ // and the runner (running-cash decrement) BOTH size with this one function so
67
+ // they can never diverge. Sizing: limit -> limitPrice*qty, stop -> stopPrice*qty,
68
+ // market -> the server-computed `estimatedCostMusd` (preferred) or
69
+ // executionPrice*qty. Returns undefined when no price is available (e.g. an
70
+ // unpriced market quote) so callers FAIL CLOSED instead of treating it as $0.
71
+ export function spotBuyCost(action, quote) {
72
+ if (action.orderType === "limit") {
73
+ return typeof action.limitPrice === "number"
74
+ ? action.limitPrice * action.quantity
75
+ : undefined;
76
+ }
77
+ if (action.orderType === "stop") {
78
+ return typeof action.stopPrice === "number"
79
+ ? action.stopPrice * action.quantity
80
+ : undefined;
81
+ }
82
+ // market: prefer the server's gross notional, else derive from the fill price.
83
+ if (typeof quote?.estimatedCostMusd === "number")
84
+ return quote.estimatedCostMusd;
85
+ return typeof quote?.executionPrice === "number"
86
+ ? quote.executionPrice * action.quantity
87
+ : undefined;
88
+ }
@@ -0,0 +1,13 @@
1
+ export declare const sleep: (ms: number) => Promise<void>;
2
+ export declare function parseCadenceMs(cadence: unknown): number | null;
3
+ export declare function dayKey(d?: Date): string;
4
+ export declare function envFlag(value: string | undefined): boolean;
5
+ export declare function scanForSecrets(value: unknown, pathPrefix?: string, findings?: string[]): string[];
6
+ export declare function shortId(): string;
7
+ export declare function normalizeContent(text: string): string;
8
+ export declare function sha256(text: string): string;
9
+ export declare function toPosix(p: string): string;
10
+ export declare function isPathInside(parent: string, child: string): boolean;
11
+ export declare function boundTail(text: string, maxLines: number, maxBytes: number): string;
12
+ export declare function stableStringify(value: unknown): string;
13
+ export declare function sortDeep(value: unknown): unknown;
@@ -0,0 +1,116 @@
1
+ // Small dependency-free helpers shared across the runner.
2
+ import { createHash } from "node:crypto";
3
+ import { resolve as resolvePath, relative as relativePath, isAbsolute } from "node:path";
4
+ export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5
+ // Parse a cadence string ("30s", "15m", "1h", "4h", "1d") to milliseconds.
6
+ // Returns null for anything unparseable so the skill validator can reject it.
7
+ export function parseCadenceMs(cadence) {
8
+ if (typeof cadence !== "string")
9
+ return null;
10
+ const m = /^\s*(\d+)\s*(s|m|h|d)\s*$/i.exec(cadence);
11
+ if (!m)
12
+ return null;
13
+ const n = Number(m[1]);
14
+ if (!Number.isFinite(n) || n <= 0)
15
+ return null;
16
+ const unit = m[2].toLowerCase();
17
+ const mult = unit === "s" ? 1000 : unit === "m" ? 60_000 : unit === "h" ? 3_600_000 : 86_400_000;
18
+ return n * mult;
19
+ }
20
+ // A UTC day key (YYYY-MM-DD) for resetting per-day counters.
21
+ export function dayKey(d = new Date()) {
22
+ return d.toISOString().slice(0, 10);
23
+ }
24
+ // Truthy reading of an opt-in env flag (1/true/yes/on, case-insensitive).
25
+ export function envFlag(value) {
26
+ return ["1", "true", "yes", "on"].includes((value ?? "").trim().toLowerCase());
27
+ }
28
+ // Deep-scan a parsed frontmatter object for anything that looks like a secret.
29
+ // The skill file is meant to be committable and shareable; a real key must
30
+ // NEVER live in it (keys are supplied at runtime via env / encrypted store).
31
+ // Returns a list of human-readable findings (empty = clean).
32
+ const SECRET_KEY_RE = /(^|[_.-])(api[_-]?key|secret|token|password|passwd|bearer|authorization|private[_-]?key)($|[_.-])/i;
33
+ const SECRET_VALUE_RE = /(crk_live_[a-z0-9_]+|sk-[a-z0-9-]{16,}|sk_live_[a-z0-9]{16,}|ghp_[a-z0-9]{20,}|bearer\s+[a-z0-9._-]{12,}|AIza[a-z0-9_-]{20,})/i;
34
+ export function scanForSecrets(value, pathPrefix = "", findings = []) {
35
+ if (value == null)
36
+ return findings;
37
+ if (typeof value === "string") {
38
+ if (SECRET_VALUE_RE.test(value)) {
39
+ findings.push(`value at "${pathPrefix || "(root)"}" looks like a secret/credential`);
40
+ }
41
+ return findings;
42
+ }
43
+ if (Array.isArray(value)) {
44
+ value.forEach((v, i) => scanForSecrets(v, `${pathPrefix}[${i}]`, findings));
45
+ return findings;
46
+ }
47
+ if (typeof value === "object") {
48
+ for (const [k, v] of Object.entries(value)) {
49
+ const here = pathPrefix ? `${pathPrefix}.${k}` : k;
50
+ if (SECRET_KEY_RE.test(k)) {
51
+ findings.push(`field "${here}" must not appear in a skill file (secret-like key)`);
52
+ }
53
+ scanForSecrets(v, here, findings);
54
+ }
55
+ }
56
+ return findings;
57
+ }
58
+ // Short random id (for runId/decisionId/idempotencyKey suffixes).
59
+ export function shortId() {
60
+ // randomUUID is available in Node 18+ (globalThis.crypto).
61
+ return crypto.randomUUID().slice(0, 8);
62
+ }
63
+ // ── Resolver helpers (cross-platform-deterministic) ──────────────────────────
64
+ // Normalize file content for hashing: CRLF/CR -> LF, strip trailing whitespace,
65
+ // so a Windows checkout and a Linux checkout of the same file hash identically.
66
+ export function normalizeContent(text) {
67
+ return text
68
+ .replace(/^/, "") // strip UTF-8 BOM (Windows editors add it)
69
+ .replace(/\r\n/g, "\n")
70
+ .replace(/\r/g, "\n")
71
+ .replace(/\s+$/, "");
72
+ }
73
+ // SHA-256 of normalized content — the manifest lock's per-file contentHash.
74
+ export function sha256(text) {
75
+ return ("sha256:" + createHash("sha256").update(normalizeContent(text), "utf8").digest("hex"));
76
+ }
77
+ // Canonical POSIX path (forward slashes) so the lock is byte-identical on
78
+ // Windows and Linux.
79
+ export function toPosix(p) {
80
+ return p.replace(/\\/g, "/");
81
+ }
82
+ // True iff `child` resolves to a location strictly inside `parent`
83
+ // (path-traversal guard). A `$ref` that escapes the agent folder is rejected.
84
+ export function isPathInside(parent, child) {
85
+ const rel = relativePath(resolvePath(parent), resolvePath(child));
86
+ return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
87
+ }
88
+ // Keep only the most-recent slice of a (possibly large) memory file so a growing
89
+ // journal never blows the model context / the user's token budget.
90
+ export function boundTail(text, maxLines, maxBytes) {
91
+ let lines = text.split("\n");
92
+ if (lines.length > maxLines)
93
+ lines = lines.slice(-maxLines);
94
+ let out = lines.join("\n");
95
+ if (Buffer.byteLength(out, "utf8") > maxBytes) {
96
+ out = Buffer.from(out, "utf8").subarray(-maxBytes).toString("utf8");
97
+ }
98
+ return out;
99
+ }
100
+ // Deterministic JSON: recursively sort object keys so two runs over the same
101
+ // inputs produce a byte-identical manifest.lock.json.
102
+ export function stableStringify(value) {
103
+ return JSON.stringify(sortDeep(value), null, 2);
104
+ }
105
+ export function sortDeep(value) {
106
+ if (Array.isArray(value))
107
+ return value.map(sortDeep);
108
+ if (value && typeof value === "object") {
109
+ const out = {};
110
+ for (const k of Object.keys(value).sort()) {
111
+ out[k] = sortDeep(value[k]);
112
+ }
113
+ return out;
114
+ }
115
+ return value;
116
+ }
@@ -0,0 +1,11 @@
1
+ export declare const RUNNER_VERSION = "0.1.0";
2
+ export declare const RESOLVER_VERSION = "1";
3
+ export declare const MANIFEST_SCHEMA = "coinrithm.manifest.v1";
4
+ export declare const COINRITHM_API: {
5
+ readonly kind: "coinrithm-agent-api";
6
+ readonly baseUrl: "https://api.coinrithm.com";
7
+ readonly mcpUrl: "https://mcp.coinrithm.com/mcp";
8
+ readonly openapiVersion: "1.4.0";
9
+ readonly mcpPackage: "@coinrithm/mcp-trading";
10
+ readonly mcpVersion: "0.3.0";
11
+ };
@@ -0,0 +1,16 @@
1
+ // Versions stamped into manifest.lock.json so a resolved agent is reproducible
2
+ // only against the exact compile that produced it.
3
+ export const RUNNER_VERSION = "0.1.0";
4
+ export const RESOLVER_VERSION = "1";
5
+ export const MANIFEST_SCHEMA = "coinrithm.manifest.v1";
6
+ // The CoinRithm execution surface a generated agent talks to. Written into
7
+ // functionality/coinrithm.yaml as a version PIN; the CLI warns when an agent's
8
+ // pin lags this, but never blocks self-host use.
9
+ export const COINRITHM_API = {
10
+ kind: "coinrithm-agent-api",
11
+ baseUrl: "https://api.coinrithm.com",
12
+ mcpUrl: "https://mcp.coinrithm.com/mcp",
13
+ openapiVersion: "1.4.0",
14
+ mcpPackage: "@coinrithm/mcp-trading",
15
+ mcpVersion: "0.3.0",
16
+ };
@@ -0,0 +1,162 @@
1
+ export declare const DEFAULT_BASE_URL = "https://api.coinrithm.com";
2
+ export declare function log(...args: unknown[]): void;
3
+ export interface ClientConfig {
4
+ apiKey?: string;
5
+ baseUrl: string;
6
+ }
7
+ export interface AgentTrace {
8
+ runId?: string;
9
+ decisionId?: string;
10
+ strategyLabel?: string;
11
+ confidence?: number;
12
+ rationaleSummary?: string;
13
+ }
14
+ export declare function loadConfig(): ClientConfig;
15
+ export declare function loadHttpConfig(): ClientConfig;
16
+ export declare function bearerFromHeader(value: string | string[] | undefined): string | undefined;
17
+ export interface ApiResult {
18
+ ok: boolean;
19
+ status: number;
20
+ ledgerEventId?: string | null;
21
+ ledgerStatus?: string | null;
22
+ data: unknown;
23
+ }
24
+ type TraceableBody<T extends Record<string, unknown>> = T & {
25
+ agentTrace?: AgentTrace;
26
+ };
27
+ export declare class CoinRithmClient {
28
+ private readonly defaultApiKey?;
29
+ private readonly baseUrl;
30
+ constructor(config: ClientConfig);
31
+ private request;
32
+ whoami(apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
33
+ getPortfolio(query?: {
34
+ fiat?: string;
35
+ locale?: string;
36
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
37
+ getWallet(query?: {
38
+ coinId?: string;
39
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
40
+ resolveSymbol(query: {
41
+ q: string;
42
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
43
+ getEquityCurve(query?: {
44
+ days?: number;
45
+ granularity?: "daily" | "realized";
46
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
47
+ getMyTrades(query?: {
48
+ venue?: string;
49
+ limit?: number;
50
+ updatedSince?: string;
51
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
52
+ getMarketContext(coinId: string, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
53
+ getCandles(coinId: string, query?: {
54
+ range?: "1H" | "1D" | "1W" | "1M" | "3M";
55
+ fiat?: string;
56
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
57
+ discoverPmMarkets(query?: {
58
+ q?: string;
59
+ source?: "all" | "kalshi" | "polymarket";
60
+ limit?: number;
61
+ offset?: number;
62
+ sort?: string;
63
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
64
+ getPerformance(apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
65
+ getLedger(query?: {
66
+ venue?: string;
67
+ eventType?: string;
68
+ runId?: string;
69
+ decisionId?: string;
70
+ status?: string;
71
+ from?: string;
72
+ to?: string;
73
+ limit?: number;
74
+ offset?: number;
75
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
76
+ exportLedger(query?: {
77
+ venue?: string;
78
+ eventType?: string;
79
+ runId?: string;
80
+ decisionId?: string;
81
+ status?: string;
82
+ from?: string;
83
+ to?: string;
84
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
85
+ getArenaLeaderboard(query?: {
86
+ page?: number;
87
+ pageSize?: number;
88
+ window?: "7d" | "30d" | "all";
89
+ }, apiKey?: string): Promise<ApiResult>;
90
+ getArenaAgent(handle: string, apiKey?: string): Promise<ApiResult>;
91
+ listOpenOrders(query?: {
92
+ coinId?: string;
93
+ limit?: number;
94
+ updatedSince?: string;
95
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
96
+ getFuturesPositions(query?: {
97
+ updatedSince?: string;
98
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
99
+ getPmPositions(query?: {
100
+ updatedSince?: string;
101
+ }, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
102
+ futuresQuote(body: {
103
+ coinId: string;
104
+ side: string;
105
+ leverage: number;
106
+ marginMusd: number;
107
+ } & {
108
+ agentTrace?: AgentTrace;
109
+ }, apiKey?: string): Promise<ApiResult>;
110
+ pmQuote(body: {
111
+ source: string;
112
+ slug: string;
113
+ outcomeExternalMarketId: string;
114
+ stakeMusd: number;
115
+ } & {
116
+ agentTrace?: AgentTrace;
117
+ }, apiKey?: string): Promise<ApiResult>;
118
+ spotQuote(body: {
119
+ coinId: string;
120
+ side: string;
121
+ quantity: number;
122
+ } & {
123
+ agentTrace?: AgentTrace;
124
+ }, apiKey?: string): Promise<ApiResult>;
125
+ placeSpotOrder(body: TraceableBody<{
126
+ coinId: string;
127
+ side: string;
128
+ orderType: string;
129
+ quantity: number;
130
+ limitPrice?: number;
131
+ stopPrice?: number;
132
+ idempotencyKey: string;
133
+ }>, apiKey?: string): Promise<ApiResult>;
134
+ cancelSpotOrder(orderId: number, apiKey?: string, agentTrace?: AgentTrace): Promise<ApiResult>;
135
+ openFuturesPosition(body: TraceableBody<{
136
+ coinId: string;
137
+ side: string;
138
+ leverage: number;
139
+ marginMusd: number;
140
+ idempotencyKey: string;
141
+ stopLossPrice?: number | null;
142
+ takeProfitPrice?: number | null;
143
+ }>, apiKey?: string): Promise<ApiResult>;
144
+ setFuturesSlTp(body: TraceableBody<{
145
+ positionId: number;
146
+ stopLossPrice?: number | null;
147
+ takeProfitPrice?: number | null;
148
+ }>, apiKey?: string): Promise<ApiResult>;
149
+ closeFuturesPosition(body: TraceableBody<{
150
+ positionId: number;
151
+ fraction?: number;
152
+ idempotencyKey: string;
153
+ }>, apiKey?: string): Promise<ApiResult>;
154
+ openPmPosition(body: TraceableBody<{
155
+ source: string;
156
+ slug: string;
157
+ outcomeExternalMarketId: string;
158
+ stakeMusd: number;
159
+ idempotencyKey: string;
160
+ }>, apiKey?: string): Promise<ApiResult>;
161
+ }
162
+ export {};