@coinrithm/mcp-trading 0.7.12 → 0.7.13

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.
package/dist/agent/act.js CHANGED
@@ -1,8 +1,37 @@
1
1
  // Act phase: fetch the quote evidence for an open (the runner does this, never
2
2
  // the model) and execute a validated action (futures / spot / PM) with an
3
3
  // idempotency key.
4
- import { asObj, asNum } from "./extract.js";
4
+ import { asObj, asNum, asStr } from "./extract.js";
5
5
  import { freshnessOf } from "./pmContext.js";
6
+ function fundingQuoteEvidence(value) {
7
+ if (value === null)
8
+ return null;
9
+ if (typeof value !== "object" || value === null)
10
+ return undefined;
11
+ const f = asObj(value);
12
+ const estimatedPerIntervalMusd = Object.prototype.hasOwnProperty.call(f, "estimatedPerIntervalMusd")
13
+ ? (asNum(f.estimatedPerIntervalMusd) ??
14
+ (f.estimatedPerIntervalMusd === null ? null : undefined))
15
+ : undefined;
16
+ return {
17
+ ...(asStr(f.venue) !== undefined ? { venue: asStr(f.venue) } : {}),
18
+ ...(asStr(f.symbol) !== undefined ? { symbol: asStr(f.symbol) } : {}),
19
+ ...(asNum(f.rate) !== undefined ? { rate: asNum(f.rate) } : {}),
20
+ ...(asNum(f.intervalHours) !== undefined
21
+ ? { intervalHours: asNum(f.intervalHours) }
22
+ : {}),
23
+ ...(asStr(f.nextFundingTime) !== undefined
24
+ ? { nextFundingTime: asStr(f.nextFundingTime) }
25
+ : {}),
26
+ ...(asStr(f.asOf) !== undefined ? { asOf: asStr(f.asOf) } : {}),
27
+ ...(estimatedPerIntervalMusd !== undefined
28
+ ? { estimatedPerIntervalMusd }
29
+ : {}),
30
+ ...(asNum(f.annualizedRate) !== undefined
31
+ ? { annualizedRate: asNum(f.annualizedRate) }
32
+ : {}),
33
+ };
34
+ }
6
35
  function coinIdFor(observation, symbol) {
7
36
  return (observation.watch.find((w) => w.symbol.toUpperCase() === symbol.toUpperCase())?.coinId ?? undefined);
8
37
  }
@@ -32,6 +61,9 @@ export async function fetchQuote(client, action, observation, trace) {
32
61
  slug: action.slug,
33
62
  outcomeExternalMarketId: action.outcomeExternalMarketId,
34
63
  stakeMusd: action.stakeMusd,
64
+ ...(action.forecastProbability != null
65
+ ? { forecastProbability: action.forecastProbability }
66
+ : {}),
35
67
  }, trace);
36
68
  }
37
69
  else {
@@ -62,6 +94,9 @@ export async function fetchQuote(client, action, observation, trace) {
62
94
  futuresFeeBps: asNum(asObj(d.executionModel).feeBps),
63
95
  estimatedEntryFeeMusd: asNum(asObj(d.executionModel).estimatedEntryFeeMusd),
64
96
  cashRequiredMusd: asNum(d.cashRequiredMusd),
97
+ ...(Object.prototype.hasOwnProperty.call(d, "funding")
98
+ ? { funding: fundingQuoteEvidence(d.funding) }
99
+ : {}),
65
100
  }
66
101
  : {}),
67
102
  // Freshness lives in the response's `observation` block (anti-look-ahead).
@@ -146,6 +181,7 @@ provenance) {
146
181
  ...(action.forecastProbability != null
147
182
  ? { forecastProbability: action.forecastProbability }
148
183
  : {}),
184
+ ...(action.thesis?.summary ? { thesis: action.thesis.summary } : {}),
149
185
  // Attach runner provenance only when present (byte-identical to before when absent).
150
186
  ...(provenance ? { provenance } : {}),
151
187
  agentTrace: trace,
@@ -91,6 +91,9 @@ export declare class CoinRithmClient {
91
91
  slug: string;
92
92
  outcomeExternalMarketId: string;
93
93
  stakeMusd: number;
94
+ side?: "yes" | "no";
95
+ forecastProbability?: number;
96
+ bankrollMusd?: number;
94
97
  }, trace?: AgentTrace): Promise<ApiResult>;
95
98
  openFutures(body: {
96
99
  coinId: string;
@@ -133,6 +136,7 @@ export declare class CoinRithmClient {
133
136
  stakeMusd: number;
134
137
  idempotencyKey: string;
135
138
  forecastProbability?: number;
139
+ thesis?: string;
136
140
  provenance?: ProvenanceReport;
137
141
  agentTrace?: AgentTrace;
138
142
  }): Promise<ApiResult>;
@@ -19,9 +19,9 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
19
19
  marginMusd?: any;
20
20
  stopLossPrice?: any;
21
21
  takeProfitPrice?: any;
22
+ thesis?: import("./types.js").Thesis | undefined;
22
23
  confidence?: any;
23
24
  rationaleSummary?: string | undefined;
24
- thesis?: import("./types.js").Thesis | undefined;
25
25
  }, {
26
26
  symbol: string;
27
27
  side: "long" | "short";
@@ -30,9 +30,9 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
30
30
  marginMusd?: unknown;
31
31
  stopLossPrice?: unknown;
32
32
  takeProfitPrice?: unknown;
33
+ thesis?: any;
33
34
  confidence?: unknown;
34
35
  rationaleSummary?: string | undefined;
35
- thesis?: any;
36
36
  }>, z.ZodObject<{
37
37
  type: z.ZodLiteral<"futures_close">;
38
38
  positionId: z.ZodEffects<z.ZodTypeAny, any, unknown>;
@@ -44,16 +44,16 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
44
44
  type: "futures_close";
45
45
  positionId?: any;
46
46
  fraction?: any;
47
+ thesis?: import("./types.js").Thesis | undefined;
47
48
  confidence?: any;
48
49
  rationaleSummary?: string | undefined;
49
- thesis?: import("./types.js").Thesis | undefined;
50
50
  }, {
51
51
  type: "futures_close";
52
52
  positionId?: unknown;
53
53
  fraction?: unknown;
54
+ thesis?: any;
54
55
  confidence?: unknown;
55
56
  rationaleSummary?: string | undefined;
56
- thesis?: any;
57
57
  }>, z.ZodObject<{
58
58
  type: z.ZodLiteral<"futures_set_sltp">;
59
59
  positionId: z.ZodEffects<z.ZodTypeAny, any, unknown>;
@@ -67,17 +67,17 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
67
67
  stopLossPrice?: any;
68
68
  takeProfitPrice?: any;
69
69
  positionId?: any;
70
+ thesis?: import("./types.js").Thesis | undefined;
70
71
  confidence?: any;
71
72
  rationaleSummary?: string | undefined;
72
- thesis?: import("./types.js").Thesis | undefined;
73
73
  }, {
74
74
  type: "futures_set_sltp";
75
75
  stopLossPrice?: unknown;
76
76
  takeProfitPrice?: unknown;
77
77
  positionId?: unknown;
78
+ thesis?: any;
78
79
  confidence?: unknown;
79
80
  rationaleSummary?: string | undefined;
80
- thesis?: any;
81
81
  }>, z.ZodObject<{
82
82
  type: z.ZodLiteral<"spot_order">;
83
83
  symbol: z.ZodString;
@@ -97,9 +97,9 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
97
97
  quantity?: any;
98
98
  limitPrice?: any;
99
99
  stopPrice?: any;
100
+ thesis?: import("./types.js").Thesis | undefined;
100
101
  confidence?: any;
101
102
  rationaleSummary?: string | undefined;
102
- thesis?: import("./types.js").Thesis | undefined;
103
103
  }, {
104
104
  symbol: string;
105
105
  side: "buy" | "sell";
@@ -108,9 +108,9 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
108
108
  quantity?: unknown;
109
109
  limitPrice?: unknown;
110
110
  stopPrice?: unknown;
111
+ thesis?: any;
111
112
  confidence?: unknown;
112
113
  rationaleSummary?: string | undefined;
113
- thesis?: any;
114
114
  }>, z.ZodObject<{
115
115
  type: z.ZodLiteral<"spot_cancel">;
116
116
  orderId: z.ZodEffects<z.ZodTypeAny, any, unknown>;
@@ -119,16 +119,16 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
119
119
  thesis: z.ZodOptional<z.ZodEffects<z.ZodAny, import("./types.js").Thesis | undefined, any>>;
120
120
  }, "strict", z.ZodTypeAny, {
121
121
  type: "spot_cancel";
122
+ thesis?: import("./types.js").Thesis | undefined;
122
123
  confidence?: any;
123
124
  rationaleSummary?: string | undefined;
124
125
  orderId?: any;
125
- thesis?: import("./types.js").Thesis | undefined;
126
126
  }, {
127
127
  type: "spot_cancel";
128
+ thesis?: any;
128
129
  confidence?: unknown;
129
130
  rationaleSummary?: string | undefined;
130
131
  orderId?: unknown;
131
- thesis?: any;
132
132
  }>, z.ZodObject<{
133
133
  type: z.ZodLiteral<"pm_open">;
134
134
  ref: z.ZodOptional<z.ZodString>;
@@ -147,9 +147,9 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
147
147
  outcomeExternalMarketId?: string | undefined;
148
148
  stakeMusd?: any;
149
149
  forecastProbability?: number | undefined;
150
+ thesis?: import("./types.js").Thesis | undefined;
150
151
  confidence?: any;
151
152
  rationaleSummary?: string | undefined;
152
- thesis?: import("./types.js").Thesis | undefined;
153
153
  ref?: string | undefined;
154
154
  }, {
155
155
  type: "pm_open";
@@ -158,9 +158,9 @@ export declare const actionSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<
158
158
  outcomeExternalMarketId?: string | undefined;
159
159
  stakeMusd?: unknown;
160
160
  forecastProbability?: any;
161
+ thesis?: any;
161
162
  confidence?: unknown;
162
163
  rationaleSummary?: string | undefined;
163
- thesis?: any;
164
164
  ref?: string | undefined;
165
165
  }>]>;
166
166
  export declare const DECISION_JSON_SCHEMA: {
@@ -1,6 +1,6 @@
1
1
  export { runCycle, type RunnerDeps } from "./runner.js";
2
2
  export { DECISION_INPUT_MAX_BYTES, sanitizeDecisionInputRecord, type DecisionInputRecord, } from "./decisionReceipt.js";
3
- export { selectProvider, providerForRoute, type ProviderEnv, type Provider, type DecideInput, type DecideResult, type DecideRouteAttempt, type DecideRouteMeta, } from "./providers.js";
3
+ export { selectProvider, providerForRoute, classifyProviderFailure, type ProviderEnv, type Provider, type DecideInput, type DecideResult, type DecideRouteAttempt, type DecideRouteMeta, } from "./providers.js";
4
4
  export { parseDecision } from "./decision.js";
5
5
  export { chatShapeFor, buildChatBody, type ChatShape, } from "./providerCapabilities.js";
6
6
  export { probeDecisionContract, type ProbeRoute, type ProbeDecisionResult, } from "./decisionProbe.js";
@@ -7,7 +7,7 @@
7
7
  // stable engine pieces, never the CLI.
8
8
  export { runCycle } from "./runner.js";
9
9
  export { DECISION_INPUT_MAX_BYTES, sanitizeDecisionInputRecord, } from "./decisionReceipt.js";
10
- export { selectProvider, providerForRoute, } from "./providers.js";
10
+ export { selectProvider, providerForRoute, classifyProviderFailure, } from "./providers.js";
11
11
  export { parseDecision } from "./decision.js";
12
12
  // Reliability slice A: the declarative request-capability table and the
13
13
  // representative decision probe (route eligibility = a REAL parsed decision,
@@ -90,8 +90,10 @@ async function fetchCandleContext(client, coinId, trace) {
90
90
  }
91
91
  if (!cr.ok)
92
92
  return { indicators: null };
93
- // Endpoint shape: { candles: [{ t, o, h, l, c, v }] } ascending (oldest first).
93
+ // Endpoint shape: { candles: [{ t, o, h, l, c, v, vm }] } ascending (oldest first).
94
94
  const candles = [];
95
+ let latestVolume;
96
+ let latestVolumeMissingVenues;
95
97
  for (const raw of asArr(asObj(cr.data).candles)) {
96
98
  const c = asObj(raw);
97
99
  const open = asNum(c.o);
@@ -100,12 +102,22 @@ async function fetchCandleContext(client, coinId, trace) {
100
102
  const close = asNum(c.c);
101
103
  if (open == null || high == null || low == null || close == null)
102
104
  continue;
103
- candles.push({ open, high, low, close, volume: asNum(c.v) ?? undefined });
105
+ const volume = asNum(c.v);
106
+ candles.push({ open, high, low, close, volume: volume ?? undefined });
107
+ latestVolume = volume != null && volume >= 0 ? volume : undefined;
108
+ const coverage = asNum(c.vm);
109
+ latestVolumeMissingVenues =
110
+ latestVolume != null &&
111
+ coverage != null &&
112
+ Number.isInteger(coverage) &&
113
+ coverage >= 0
114
+ ? coverage
115
+ : undefined;
104
116
  }
105
- const lastVolume = candles.length > 0 ? candles[candles.length - 1].volume : undefined;
106
117
  return {
107
118
  indicators: computeIndicators(candles),
108
- volume24hUsd: typeof lastVolume === "number" && lastVolume > 0 ? lastVolume : undefined,
119
+ volume24hUsd: latestVolume,
120
+ volumeMissingVenues: latestVolumeMissingVenues,
109
121
  };
110
122
  }
111
123
  // The fundamentals leg of a watch entry, read from the /market context the
@@ -141,6 +153,12 @@ async function enrichFromCandles(client, entry, coinId, trace) {
141
153
  volume24hUsd: cc.volume24hUsd,
142
154
  };
143
155
  }
156
+ if (cc.volumeMissingVenues != null) {
157
+ entry.fundamentals = {
158
+ ...(entry.fundamentals ?? {}),
159
+ volumeMissingVenues: cc.volumeMissingVenues,
160
+ };
161
+ }
144
162
  }
145
163
  const HEADLINES_PER_COIN = 3;
146
164
  const HEADLINE_TITLE_CHARS = 110;
@@ -316,6 +334,14 @@ export async function observe(client, spec, state, trace) {
316
334
  // and could not tell a winner from a small loser before a manual close.
317
335
  // Tolerant fallbacks keep older/mocked shapes working.
318
336
  const coin = asObj(p.coin);
337
+ const fundingPaidMusd = Object.prototype.hasOwnProperty.call(p, "fundingPaidMusd")
338
+ ? (asNum(p.fundingPaidMusd) ??
339
+ (p.fundingPaidMusd === null ? null : undefined))
340
+ : undefined;
341
+ const fundingAppliedThrough = Object.prototype.hasOwnProperty.call(p, "fundingAppliedThrough")
342
+ ? (asStr(p.fundingAppliedThrough) ??
343
+ (p.fundingAppliedThrough === null ? null : undefined))
344
+ : undefined;
319
345
  return {
320
346
  venue: "futures",
321
347
  id: Number(asNum(p.id) ?? p.id),
@@ -327,6 +353,10 @@ export async function observe(client, spec, state, trace) {
327
353
  leverage: asNum(p.leverage),
328
354
  marginMusd: asNum(p.marginMusd),
329
355
  unrealizedPnlMusd: asNum(p.unrealizedPnlMusd),
356
+ ...(fundingPaidMusd !== undefined ? { fundingPaidMusd } : {}),
357
+ ...(fundingAppliedThrough !== undefined
358
+ ? { fundingAppliedThrough }
359
+ : {}),
330
360
  entryPrice: asNum(p.entryPrice),
331
361
  markPrice: asNum(p.markPrice),
332
362
  liquidationPrice: asNum(p.liquidationPrice),
@@ -338,6 +338,10 @@ export function buildUserPrompt(obs, journal, opts = {}) {
338
338
  if (brokenTheses.length > 0) {
339
339
  lines.push("", "## Positions whose thesis is INVALIDATED this cycle", ...brokenTheses.map((b) => `- ${b}`));
340
340
  }
341
+ if (obs.openPositions.some((p) => p.fundingPaidMusd !== undefined ||
342
+ p.fundingAppliedThrough !== undefined)) {
343
+ lines.push("Futures funding shown in the position is already reflected in margin and balances; do not deduct it again when judging available capital or PnL.");
344
+ }
341
345
  // Settlement-feedback loop: surface the agent's recently-RESOLVED PM bets so the
342
346
  // model can reflect and adapt. Reflective context only — never a new action.
343
347
  if (hasPm)
@@ -52,6 +52,10 @@ export interface ProviderEnv {
52
52
  GEMINI_API_KEY?: string;
53
53
  MODEL_API_KEY?: string;
54
54
  }
55
+ /** Keep direct and routed cycle evidence consistent about NVIDIA backpressure. */
56
+ export declare function classifyProviderFailure(result: Extract<DecideResult, {
57
+ ok: false;
58
+ }>): "capacity" | "permanent" | "transient";
55
59
  export declare function selectProvider(spec: AgentSpec, env: ProviderEnv, fetchFn?: typeof fetch): Provider;
56
60
  export declare function providerForRoute(route: {
57
61
  provider: ProviderName;
@@ -29,6 +29,16 @@ const GEMINI_BASE_URL = "https://generativelanguage.googleapis.com/v1beta/openai
29
29
  // MUST stay below the scheduler's RUN_LOCK_SECONDS and HEARTBEAT_STALE_MS.
30
30
  const DEFAULT_TIMEOUT_MS = 300_000;
31
31
  const RETRYABLE_SERVER_STATUSES = new Set([500, 502, 503, 504]);
32
+ /** Keep direct and routed cycle evidence consistent about NVIDIA backpressure. */
33
+ export function classifyProviderFailure(result) {
34
+ if (result.status === 429 ||
35
+ (result.status === 503 &&
36
+ /resourceexhausted|worker local total request limit/i.test(result.error ?? "")))
37
+ return "capacity";
38
+ if (result.status === 404 || result.status === 410)
39
+ return "permanent";
40
+ return "transient";
41
+ }
32
42
  // Per-route request quirks (reasoning toggles, token param, temperature) live
33
43
  // in the capability table — providerCapabilities.ts is the single source; this
34
44
  // module only assembles and sends.
@@ -332,15 +342,11 @@ class SameModelRetryProvider {
332
342
  error: res.error,
333
343
  status: res.status,
334
344
  retryAfterMs: res.retryAfterMs,
335
- ...(res.status !== undefined
336
- ? {
337
- failureClass: res.status === 429
338
- ? "capacity"
339
- : res.status >= 500
340
- ? "transient"
341
- : "permanent",
342
- }
343
- : {}),
345
+ failureClass: classifyProviderFailure(res) === "capacity"
346
+ ? "capacity"
347
+ : res.status !== undefined && res.status < 500
348
+ ? "permanent"
349
+ : "transient",
344
350
  }
345
351
  : {}),
346
352
  });
@@ -350,7 +356,7 @@ class SameModelRetryProvider {
350
356
  // or a certificate that returned text passed the trading-decision parser.
351
357
  ...result,
352
358
  route: {
353
- policyVersion: "coinrithm.configured-same-model-retry.v1",
359
+ policyVersion: "coinrithm.configured-same-model-retry.v2",
354
360
  profile: "configured",
355
361
  effectiveProvider: this.provider,
356
362
  effectiveModel: this.model,
@@ -2,6 +2,7 @@
2
2
  // spot, futures, and prediction markets. Dry-run never writes. Live uses
3
3
  // idempotency keys + agentTrace and exports run evidence. The client + provider
4
4
  // are injected so the loop is fully unit-testable with no network/model calls.
5
+ import { classifyProviderFailure } from "./providers.js";
5
6
  import { COINRITHM_API } from "./version.js";
6
7
  import { spotBuyCost, DEFAULT_TRIGGER_POLICY, } from "./types.js";
7
8
  import { usesCapitalSizing, prepareCapitalAction, validateCapitalAction, capitalCashCost, } from "./capitalSizing.js";
@@ -727,7 +728,7 @@ async function runCycleCore(deps, capture) {
727
728
  // only capacity failures. Treat that exactly like a local capacity defer:
728
729
  // no action, no fallback invented here, and no model-failure streak that
729
730
  // could stop an otherwise healthy agent after repeated quota pressure.
730
- const capacityOnlyFailure = (!route && res.status === 429) ||
731
+ const capacityOnlyFailure = (!route && classifyProviderFailure(res) === "capacity") ||
731
732
  (!!route?.attempts?.length &&
732
733
  route.attempts.every((attempt) => attempt.failureClass === "capacity"));
733
734
  if (res.deferred || !actualCallMade || capacityOnlyFailure) {
@@ -50,37 +50,37 @@ const PRESETS = {
50
50
  modelFail: 5,
51
51
  },
52
52
  };
53
- const THESIS_BODY = `# Momentum Futures — strategy
54
-
55
- You operate a CoinRithm **paper-trading** futures account (50,000 virtual mUSD).
56
- Everything here is simulated; it is not financial advice and never touches real
57
- money. Edit this prose freely (any language) — it is your agent's borders.
58
-
59
- ## Each cycle
60
-
61
- 1. Ground yourself: read your portfolio and open positions first. Never assume
62
- balances or what is already open.
63
- 2. Scan the watchlist. A candidate is a coin whose short and medium momentum
64
- agree (both up, or both down) and is not already an open position.
65
- 3. Pick the strongest candidate and commit when the read is clear — even a
66
- moderate-confidence one — sized small with a stop. Skip only when the signals
67
- contradict or the data is stale; a quiet tape where your edge is still real
68
- is an act, not a skip.
69
- 4. Quote before you open. Read the liquidation price and confirm it is sane. If
70
- the quote is not eligible, relay the reason and stop.
71
- 5. Open small and protected: enter in the trend direction and set a stop-loss at
72
- open. Place the take-profit a touch wider than the stop.
73
- 6. Stay in sync: poll your trades for any stop / take-profit / liquidation that
74
- fired while you were not looking, and react to what actually happened.
75
-
76
- The hard caps (leverage, margin, watchlist) live in the config blocks above and
53
+ const THESIS_BODY = `# Momentum Futures — strategy
54
+
55
+ You operate a CoinRithm **paper-trading** futures account (50,000 virtual mUSD).
56
+ Everything here is simulated; it is not financial advice and never touches real
57
+ money. Edit this prose freely (any language) — it is your agent's borders.
58
+
59
+ ## Each cycle
60
+
61
+ 1. Ground yourself: read your portfolio and open positions first. Never assume
62
+ balances or what is already open.
63
+ 2. Scan the watchlist. A candidate is a coin whose short and medium momentum
64
+ agree (both up, or both down) and is not already an open position.
65
+ 3. Pick the strongest candidate and commit when the read is clear — even a
66
+ moderate-confidence one — sized small with a stop. Skip only when the signals
67
+ contradict or the data is stale; a quiet tape where your edge is still real
68
+ is an act, not a skip.
69
+ 4. Quote before you open. Read the liquidation price and confirm it is sane. If
70
+ the quote is not eligible, relay the reason and stop.
71
+ 5. Open small and protected: enter in the trend direction and set a stop-loss at
72
+ open. Place the take-profit a touch wider than the stop.
73
+ 6. Stay in sync: poll your trades for any stop / take-profit / liquidation that
74
+ fired while you were not looking, and react to what actually happened.
75
+
76
+ The hard caps (leverage, margin, watchlist) live in the config blocks above and
77
77
  are enforced by the runner — change them there, not in this prose.`;
78
- const PERSONA_STUB = `# Persona
79
-
80
- Decisive and in character. Acts on a clear read — even a moderate-confidence one
81
- — sized small and protected with a stop, and skips only when the read is
82
- contradictory or the data is stale. States its reasoning plainly in its own
83
- voice, and never frames paper results as real-money advice.
78
+ const PERSONA_STUB = `# Persona
79
+
80
+ Decisive and in character. Acts on a clear read — even a moderate-confidence one
81
+ — sized small and protected with a stop, and skips only when the read is
82
+ contradictory or the data is stale. States its reasoning plainly in its own
83
+ voice, and never frames paper results as real-money advice.
84
84
  `;
85
85
  export function buildAgentObject(name, preset) {
86
86
  const p = PRESETS[preset];
@@ -153,6 +153,7 @@ export interface CoinFundamentals {
153
153
  marketCapRank?: number;
154
154
  marketCapUsd?: number;
155
155
  volume24hUsd?: number;
156
+ volumeMissingVenues?: number;
156
157
  headlines?: Array<{
157
158
  title: string;
158
159
  at?: string;
@@ -171,6 +172,8 @@ export interface OpenPosition {
171
172
  leverage?: number;
172
173
  marginMusd?: number;
173
174
  unrealizedPnlMusd?: number;
175
+ fundingPaidMusd?: number | null;
176
+ fundingAppliedThrough?: string | null;
174
177
  entryPrice?: number;
175
178
  markPrice?: number;
176
179
  liquidationPrice?: number;
@@ -397,10 +400,21 @@ export interface QuoteEvidence {
397
400
  futuresFeeBps?: number;
398
401
  estimatedEntryFeeMusd?: number;
399
402
  cashRequiredMusd?: number;
403
+ funding?: FuturesFundingQuoteEvidence | null;
400
404
  freshness?: Freshness;
401
405
  openBlocked?: boolean;
402
406
  openBlockReasons?: unknown;
403
407
  }
408
+ export interface FuturesFundingQuoteEvidence {
409
+ venue?: string;
410
+ symbol?: string;
411
+ rate?: number;
412
+ intervalHours?: number;
413
+ nextFundingTime?: string;
414
+ asOf?: string;
415
+ estimatedPerIntervalMusd?: number | null;
416
+ annualizedRate?: number;
417
+ }
404
418
  export interface RunState {
405
419
  runId: string;
406
420
  cyclesRun: number;
package/dist/client.d.ts CHANGED
@@ -64,7 +64,11 @@ export declare class CoinRithmClient {
64
64
  getPublicPmEvent(source: string, slug: string, query?: {
65
65
  fiat?: string;
66
66
  }): Promise<ApiResult>;
67
+ /** Best-effort anonymous interest marker for an explicitly viewed open event. */
68
+ markPublicPmEventViewed(source: string, slug: string): Promise<ApiResult>;
67
69
  getPublicPmWhales(): Promise<ApiResult>;
70
+ getPublicPmWhaleWallets(window?: "7d" | "30d", source?: "polymarket" | "limitless" | "myriad"): Promise<ApiResult>;
71
+ getPublicPmWhaleWallet(source: string, wallet: string): Promise<ApiResult>;
68
72
  getPublicPmMatches(query?: {
69
73
  limit?: number;
70
74
  offset?: number;
@@ -168,6 +172,8 @@ export declare class CoinRithmClient {
168
172
  outcomeExternalMarketId: string;
169
173
  side?: "yes" | "no";
170
174
  stakeMusd: number;
175
+ forecastProbability?: number;
176
+ bankrollMusd?: number;
171
177
  } & {
172
178
  agentTrace?: AgentTrace;
173
179
  }, apiKey?: string): Promise<ApiResult>;
@@ -215,6 +221,7 @@ export declare class CoinRithmClient {
215
221
  stakeMusd: number;
216
222
  idempotencyKey: string;
217
223
  forecastProbability?: number;
224
+ thesis?: string;
218
225
  provenance?: ProvenanceReport;
219
226
  }>, apiKey?: string): Promise<ApiResult>;
220
227
  reportPmOpportunity(body: TraceableBody<{
package/dist/client.js CHANGED
@@ -216,9 +216,52 @@ export class CoinRithmClient {
216
216
  getPublicPmEvent(source, slug, query) {
217
217
  return this.publicRequest(`/api/prediction-markets/events/${encodeURIComponent(source)}/${encodeURIComponent(slug)}`, query);
218
218
  }
219
+ /** Best-effort anonymous interest marker for an explicitly viewed open event. */
220
+ markPublicPmEventViewed(source, slug) {
221
+ const path = `/api/prediction-markets/events/${encodeURIComponent(source)}/${encodeURIComponent(slug)}/view`;
222
+ const controller = new AbortController();
223
+ const timer = setTimeout(() => controller.abort(), 1000);
224
+ return fetch(this.baseUrl + path, {
225
+ method: "POST",
226
+ headers: { Accept: "application/json" },
227
+ signal: controller.signal,
228
+ })
229
+ .then(async (res) => {
230
+ const text = await res.text();
231
+ let data = text;
232
+ if (text) {
233
+ try {
234
+ data = JSON.parse(text);
235
+ }
236
+ catch {
237
+ // leave as text
238
+ }
239
+ }
240
+ return { ok: res.ok, status: res.status, data };
241
+ })
242
+ .catch((err) => ({
243
+ ok: false,
244
+ status: 0,
245
+ data: {
246
+ error: err instanceof DOMException && err.name === "AbortError"
247
+ ? "timeout"
248
+ : "network_error",
249
+ },
250
+ }))
251
+ .finally(() => clearTimeout(timer));
252
+ }
219
253
  getPublicPmWhales() {
220
254
  return this.publicRequest("/api/prediction-markets/whales");
221
255
  }
256
+ getPublicPmWhaleWallets(window, source) {
257
+ return this.publicRequest("/api/prediction-markets/whales/wallets", {
258
+ ...(window ? { window } : {}),
259
+ ...(source ? { source } : {}),
260
+ });
261
+ }
262
+ getPublicPmWhaleWallet(source, wallet) {
263
+ return this.publicRequest(`/api/prediction-markets/whales/wallets/${encodeURIComponent(source)}/${encodeURIComponent(wallet)}`);
264
+ }
222
265
  // Cross-venue disagreement clusters (approved event matches, graph-clustered).
223
266
  getPublicPmMatches(query) {
224
267
  return this.publicRequest("/api/prediction-markets/matches/public", query);
@@ -1,6 +1,6 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
2
  import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
3
- export declare const COMPLETION_TOOL_NAMES: readonly ["whoami", "get_portfolio", "get_wallet", "list_open_orders", "get_positions", "resolve_symbol", "get_equity_curve", "get_my_trades", "get_market_context", "get_candles", "discover_pm_markets", "get_performance", "get_agent_ledger", "export_agent_ledger", "export_run_evidence", "get_arena_leaderboard", "get_arena_agent", "futures_quote", "pm_quote", "spot_quote", "place_spot_order", "cancel_spot_order", "open_futures_position", "set_futures_sl_tp", "close_futures_position", "open_pm_position", "report_pm_opportunity", "pm_data_overview", "pm_data_sources", "pm_data_sources_health", "pm_data_events", "pm_data_event", "pm_data_whales", "pm_data_disagreements", "pm_data_calibration", "pm_data_canonical", "pm_data_volume_history", "get_crypto_movers"];
3
+ export declare const COMPLETION_TOOL_NAMES: readonly ["whoami", "get_portfolio", "get_wallet", "list_open_orders", "get_positions", "resolve_symbol", "get_equity_curve", "get_my_trades", "get_market_context", "get_candles", "discover_pm_markets", "get_performance", "get_agent_ledger", "export_agent_ledger", "export_run_evidence", "get_arena_leaderboard", "get_arena_agent", "futures_quote", "pm_quote", "spot_quote", "place_spot_order", "cancel_spot_order", "open_futures_position", "set_futures_sl_tp", "close_futures_position", "open_pm_position", "report_pm_opportunity", "pm_data_overview", "pm_data_sources", "pm_data_sources_health", "pm_data_events", "pm_data_event", "pm_data_whales", "pm_data_whale_wallets", "pm_data_whale_wallet", "pm_data_disagreements", "pm_data_calibration", "pm_data_canonical", "pm_data_volume_history", "get_crypto_movers"];
4
4
  type Operation = "initialize" | "tools_list" | "tools_call" | "notification" | "other" | "invalid";
5
5
  type Outcome = "result" | "tool_error" | "protocol_error" | "no_response" | "not_applicable";
6
6
  type ToolName = (typeof COMPLETION_TOOL_NAMES)[number] | "unknown" | null;
@@ -36,6 +36,8 @@ export const COMPLETION_TOOL_NAMES = [
36
36
  "pm_data_events",
37
37
  "pm_data_event",
38
38
  "pm_data_whales",
39
+ "pm_data_whale_wallets",
40
+ "pm_data_whale_wallet",
39
41
  "pm_data_disagreements",
40
42
  "pm_data_calibration",
41
43
  "pm_data_canonical",
package/dist/tools.d.ts CHANGED
@@ -14,6 +14,8 @@ export declare function compactPublicPmEvents(data: unknown): unknown;
14
14
  */
15
15
  export declare function compactPublicPmEvent(data: unknown): unknown;
16
16
  export declare function compactPublicPmWhales(data: unknown, limit: number): unknown;
17
+ export declare function compactPublicPmWhaleWallets(data: unknown, limit: number, requestedSource?: string): unknown;
18
+ export declare function compactPublicPmWhaleWalletDetail(data: unknown): unknown;
17
19
  export declare function compactPublicCryptoMovers(data: unknown): unknown;
18
20
  /**
19
21
  * Keep cross-venue disagreement clusters small enough for an agent context