@guiie/buda-mcp 1.2.2 → 1.4.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.
- package/CHANGELOG.md +68 -0
- package/PUBLISH_CHECKLIST.md +71 -63
- package/README.md +4 -4
- package/dist/http.js +39 -0
- package/dist/index.js +29 -0
- package/dist/tools/arbitrage.d.ts +35 -0
- package/dist/tools/arbitrage.d.ts.map +1 -0
- package/dist/tools/arbitrage.js +142 -0
- package/dist/tools/balances.d.ts.map +1 -1
- package/dist/tools/balances.js +24 -4
- package/dist/tools/calculate_position_size.d.ts +48 -0
- package/dist/tools/calculate_position_size.d.ts.map +1 -0
- package/dist/tools/calculate_position_size.js +111 -0
- package/dist/tools/compare_markets.d.ts.map +1 -1
- package/dist/tools/compare_markets.js +11 -10
- package/dist/tools/dead_mans_switch.d.ts +84 -0
- package/dist/tools/dead_mans_switch.d.ts.map +1 -0
- package/dist/tools/dead_mans_switch.js +236 -0
- package/dist/tools/market_sentiment.d.ts +30 -0
- package/dist/tools/market_sentiment.d.ts.map +1 -0
- package/dist/tools/market_sentiment.js +104 -0
- package/dist/tools/market_summary.d.ts +43 -0
- package/dist/tools/market_summary.d.ts.map +1 -0
- package/dist/tools/market_summary.js +81 -0
- package/dist/tools/markets.d.ts.map +1 -1
- package/dist/tools/markets.js +4 -2
- package/dist/tools/orderbook.d.ts.map +1 -1
- package/dist/tools/orderbook.js +14 -4
- package/dist/tools/orders.d.ts.map +1 -1
- package/dist/tools/orders.js +41 -3
- package/dist/tools/price_history.d.ts.map +1 -1
- package/dist/tools/price_history.js +5 -43
- package/dist/tools/simulate_order.d.ts +45 -0
- package/dist/tools/simulate_order.d.ts.map +1 -0
- package/dist/tools/simulate_order.js +139 -0
- package/dist/tools/spread.d.ts.map +1 -1
- package/dist/tools/spread.js +10 -8
- package/dist/tools/technical_indicators.d.ts +39 -0
- package/dist/tools/technical_indicators.d.ts.map +1 -0
- package/dist/tools/technical_indicators.js +223 -0
- package/dist/tools/ticker.d.ts.map +1 -1
- package/dist/tools/ticker.js +24 -3
- package/dist/tools/trades.d.ts.map +1 -1
- package/dist/tools/trades.js +17 -3
- package/dist/tools/volume.d.ts.map +1 -1
- package/dist/tools/volume.js +21 -3
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +23 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +68 -0
- package/marketplace/README.md +1 -1
- package/marketplace/claude-listing.md +60 -14
- package/marketplace/gemini-tools.json +183 -9
- package/marketplace/openapi.yaml +335 -119
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/http.ts +44 -0
- package/src/index.ts +34 -0
- package/src/tools/arbitrage.ts +202 -0
- package/src/tools/balances.ts +27 -4
- package/src/tools/calculate_position_size.ts +141 -0
- package/src/tools/compare_markets.ts +11 -10
- package/src/tools/dead_mans_switch.ts +314 -0
- package/src/tools/market_sentiment.ts +141 -0
- package/src/tools/market_summary.ts +124 -0
- package/src/tools/markets.ts +4 -2
- package/src/tools/orderbook.ts +15 -4
- package/src/tools/orders.ts +45 -4
- package/src/tools/price_history.ts +5 -57
- package/src/tools/simulate_order.ts +182 -0
- package/src/tools/spread.ts +10 -8
- package/src/tools/technical_indicators.ts +282 -0
- package/src/tools/ticker.ts +27 -3
- package/src/tools/trades.ts +18 -3
- package/src/tools/volume.ts +24 -3
- package/src/types.ts +12 -0
- package/src/utils.ts +73 -0
- package/test/unit.ts +758 -0
package/src/tools/ticker.ts
CHANGED
|
@@ -3,13 +3,16 @@ import { z } from "zod";
|
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { MemoryCache, CACHE_TTL } from "../cache.js";
|
|
5
5
|
import { validateMarketId } from "../validation.js";
|
|
6
|
+
import { flattenAmount } from "../utils.js";
|
|
6
7
|
import type { TickerResponse } from "../types.js";
|
|
7
8
|
|
|
8
9
|
export const toolSchema = {
|
|
9
10
|
name: "get_ticker",
|
|
10
11
|
description:
|
|
11
|
-
"
|
|
12
|
-
"24h volume, and price change over 24h and 7d."
|
|
12
|
+
"Returns the current market snapshot for a Buda.com market: last traded price, best bid, " +
|
|
13
|
+
"best ask, 24h volume, and price change over 24h and 7d. All prices are floats in the quote " +
|
|
14
|
+
"currency (e.g. CLP for BTC-CLP). price_variation_24h is a decimal fraction (0.012 = +1.2%). " +
|
|
15
|
+
"Example: 'What is the current Bitcoin price in Chilean pesos?'",
|
|
13
16
|
inputSchema: {
|
|
14
17
|
type: "object" as const,
|
|
15
18
|
properties: {
|
|
@@ -47,8 +50,29 @@ export function register(server: McpServer, client: BudaClient, cache: MemoryCac
|
|
|
47
50
|
CACHE_TTL.TICKER,
|
|
48
51
|
() => client.get<TickerResponse>(`/markets/${id}/ticker`),
|
|
49
52
|
);
|
|
53
|
+
|
|
54
|
+
const t = data.ticker;
|
|
55
|
+
const lastPrice = flattenAmount(t.last_price);
|
|
56
|
+
const minAsk = flattenAmount(t.min_ask);
|
|
57
|
+
const maxBid = flattenAmount(t.max_bid);
|
|
58
|
+
const volume = flattenAmount(t.volume);
|
|
59
|
+
|
|
60
|
+
const result = {
|
|
61
|
+
market_id: t.market_id,
|
|
62
|
+
last_price: lastPrice.value,
|
|
63
|
+
last_price_currency: lastPrice.currency,
|
|
64
|
+
min_ask: minAsk.value,
|
|
65
|
+
min_ask_currency: minAsk.currency,
|
|
66
|
+
max_bid: maxBid.value,
|
|
67
|
+
max_bid_currency: maxBid.currency,
|
|
68
|
+
volume: volume.value,
|
|
69
|
+
volume_currency: volume.currency,
|
|
70
|
+
price_variation_24h: parseFloat(t.price_variation_24h),
|
|
71
|
+
price_variation_7d: parseFloat(t.price_variation_7d),
|
|
72
|
+
};
|
|
73
|
+
|
|
50
74
|
return {
|
|
51
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
75
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
52
76
|
};
|
|
53
77
|
} catch (err) {
|
|
54
78
|
const msg =
|
package/src/tools/trades.ts
CHANGED
|
@@ -8,8 +8,10 @@ import type { TradesResponse } from "../types.js";
|
|
|
8
8
|
export const toolSchema = {
|
|
9
9
|
name: "get_trades",
|
|
10
10
|
description:
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"Returns recent trade history for a Buda.com market as typed objects. Each entry has " +
|
|
12
|
+
"timestamp_ms (integer), amount (float, base currency), price (float, quote currency), " +
|
|
13
|
+
"and direction ('buy' or 'sell'). " +
|
|
14
|
+
"Example: 'What was the last executed price for BTC-CLP and was it a buy or sell?'",
|
|
13
15
|
inputSchema: {
|
|
14
16
|
type: "object" as const,
|
|
15
17
|
properties: {
|
|
@@ -73,8 +75,21 @@ export function register(server: McpServer, client: BudaClient, _cache: MemoryCa
|
|
|
73
75
|
Object.keys(params).length > 0 ? params : undefined,
|
|
74
76
|
);
|
|
75
77
|
|
|
78
|
+
const t = data.trades;
|
|
79
|
+
const result = {
|
|
80
|
+
timestamp: t.timestamp,
|
|
81
|
+
last_timestamp: t.last_timestamp,
|
|
82
|
+
market_id: t.market_id,
|
|
83
|
+
entries: t.entries.map(([tsMs, amount, price, direction]) => ({
|
|
84
|
+
timestamp_ms: parseInt(tsMs, 10),
|
|
85
|
+
amount: parseFloat(amount),
|
|
86
|
+
price: parseFloat(price),
|
|
87
|
+
direction,
|
|
88
|
+
})),
|
|
89
|
+
};
|
|
90
|
+
|
|
76
91
|
return {
|
|
77
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
92
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
78
93
|
};
|
|
79
94
|
} catch (err) {
|
|
80
95
|
const msg =
|
package/src/tools/volume.ts
CHANGED
|
@@ -3,13 +3,15 @@ import { z } from "zod";
|
|
|
3
3
|
import { BudaClient, BudaApiError } from "../client.js";
|
|
4
4
|
import { MemoryCache } from "../cache.js";
|
|
5
5
|
import { validateMarketId } from "../validation.js";
|
|
6
|
+
import { flattenAmount } from "../utils.js";
|
|
6
7
|
import type { VolumeResponse } from "../types.js";
|
|
7
8
|
|
|
8
9
|
export const toolSchema = {
|
|
9
10
|
name: "get_market_volume",
|
|
10
11
|
description:
|
|
11
|
-
"
|
|
12
|
-
"
|
|
12
|
+
"Returns 24h and 7-day transacted volume for a Buda.com market, split by buy (bid) and sell (ask) side. " +
|
|
13
|
+
"All volume values are floats in the base currency (e.g. BTC for BTC-CLP). " +
|
|
14
|
+
"Example: 'How much Bitcoin was sold on BTC-CLP in the last 24 hours?'",
|
|
13
15
|
inputSchema: {
|
|
14
16
|
type: "object" as const,
|
|
15
17
|
properties: {
|
|
@@ -44,8 +46,27 @@ export function register(server: McpServer, client: BudaClient, _cache: MemoryCa
|
|
|
44
46
|
const data = await client.get<VolumeResponse>(
|
|
45
47
|
`/markets/${market_id.toLowerCase()}/volume`,
|
|
46
48
|
);
|
|
49
|
+
|
|
50
|
+
const v = data.volume;
|
|
51
|
+
const ask24 = flattenAmount(v.ask_volume_24h);
|
|
52
|
+
const ask7d = flattenAmount(v.ask_volume_7d);
|
|
53
|
+
const bid24 = flattenAmount(v.bid_volume_24h);
|
|
54
|
+
const bid7d = flattenAmount(v.bid_volume_7d);
|
|
55
|
+
|
|
56
|
+
const result = {
|
|
57
|
+
market_id: v.market_id,
|
|
58
|
+
ask_volume_24h: ask24.value,
|
|
59
|
+
ask_volume_24h_currency: ask24.currency,
|
|
60
|
+
ask_volume_7d: ask7d.value,
|
|
61
|
+
ask_volume_7d_currency: ask7d.currency,
|
|
62
|
+
bid_volume_24h: bid24.value,
|
|
63
|
+
bid_volume_24h_currency: bid24.currency,
|
|
64
|
+
bid_volume_7d: bid7d.value,
|
|
65
|
+
bid_volume_7d_currency: bid7d.currency,
|
|
66
|
+
};
|
|
67
|
+
|
|
47
68
|
return {
|
|
48
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
69
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
49
70
|
};
|
|
50
71
|
} catch (err) {
|
|
51
72
|
const msg =
|
package/src/types.ts
CHANGED
|
@@ -133,3 +133,15 @@ export interface OrdersResponse {
|
|
|
133
133
|
total_pages: number;
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
|
+
|
|
137
|
+
// ----- OHLCV Candles -----
|
|
138
|
+
|
|
139
|
+
export interface OhlcvCandle {
|
|
140
|
+
time: string;
|
|
141
|
+
open: number;
|
|
142
|
+
high: number;
|
|
143
|
+
low: number;
|
|
144
|
+
close: number;
|
|
145
|
+
volume: number;
|
|
146
|
+
trade_count: number;
|
|
147
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { Amount, OhlcvCandle } from "./types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Flattens a Buda API Amount tuple [value_string, currency] into a typed object.
|
|
5
|
+
* All numeric strings are cast to float via parseFloat.
|
|
6
|
+
*/
|
|
7
|
+
export function flattenAmount(amount: Amount): { value: number; currency: string } {
|
|
8
|
+
return { value: parseFloat(amount[0]), currency: amount[1] };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns a liquidity rating based on the bid/ask spread percentage.
|
|
13
|
+
* < 0.3% → "high"
|
|
14
|
+
* 0.3–1% → "medium"
|
|
15
|
+
* > 1% → "low"
|
|
16
|
+
*/
|
|
17
|
+
export function getLiquidityRating(spreadPct: number): "high" | "medium" | "low" {
|
|
18
|
+
if (spreadPct < 0.3) return "high";
|
|
19
|
+
if (spreadPct <= 1.0) return "medium";
|
|
20
|
+
return "low";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const PERIOD_MS: Record<string, number> = {
|
|
24
|
+
"1h": 60 * 60 * 1000,
|
|
25
|
+
"4h": 4 * 60 * 60 * 1000,
|
|
26
|
+
"1d": 24 * 60 * 60 * 1000,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Aggregates raw Buda trade entries (newest-first) into OHLCV candles for the given period.
|
|
31
|
+
* Entries must be in the format [timestamp_ms, amount, price, direction].
|
|
32
|
+
* Returns candles sorted ascending by bucket start time.
|
|
33
|
+
*/
|
|
34
|
+
export function aggregateTradesToCandles(
|
|
35
|
+
entries: [string, string, string, string][],
|
|
36
|
+
period: string,
|
|
37
|
+
): OhlcvCandle[] {
|
|
38
|
+
const periodMs = PERIOD_MS[period];
|
|
39
|
+
if (!periodMs) throw new Error(`Unknown period: ${period}`);
|
|
40
|
+
|
|
41
|
+
const sorted = [...entries].sort(([a], [b]) => parseInt(a, 10) - parseInt(b, 10));
|
|
42
|
+
const buckets = new Map<number, OhlcvCandle>();
|
|
43
|
+
|
|
44
|
+
for (const [tsMs, amount, price] of sorted) {
|
|
45
|
+
const ts = parseInt(tsMs, 10);
|
|
46
|
+
const bucketStart = Math.floor(ts / periodMs) * periodMs;
|
|
47
|
+
const p = parseFloat(price);
|
|
48
|
+
const v = parseFloat(amount);
|
|
49
|
+
|
|
50
|
+
if (!buckets.has(bucketStart)) {
|
|
51
|
+
buckets.set(bucketStart, {
|
|
52
|
+
time: new Date(bucketStart).toISOString(),
|
|
53
|
+
open: p,
|
|
54
|
+
high: p,
|
|
55
|
+
low: p,
|
|
56
|
+
close: p,
|
|
57
|
+
volume: v,
|
|
58
|
+
trade_count: 1,
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
const candle = buckets.get(bucketStart)!;
|
|
62
|
+
if (p > candle.high) candle.high = p;
|
|
63
|
+
if (p < candle.low) candle.low = p;
|
|
64
|
+
candle.close = p;
|
|
65
|
+
candle.volume = parseFloat((candle.volume + v).toFixed(8));
|
|
66
|
+
candle.trade_count++;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return Array.from(buckets.entries())
|
|
71
|
+
.sort(([a], [b]) => a - b)
|
|
72
|
+
.map(([, candle]) => candle);
|
|
73
|
+
}
|