@quantish/agent 0.1.0 → 0.1.2
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/index.js +155 -7
- package/package.json +1 -2
package/dist/index.js
CHANGED
|
@@ -2566,7 +2566,150 @@ You can work with the local filesystem:
|
|
|
2566
2566
|
- When writing code, follow existing patterns and conventions
|
|
2567
2567
|
- For dangerous operations (rm, sudo), explain what you're doing
|
|
2568
2568
|
|
|
2569
|
-
You help users build trading bots and agents by combining coding skills with trading capabilities
|
|
2569
|
+
You help users build trading bots and agents by combining coding skills with trading capabilities.
|
|
2570
|
+
|
|
2571
|
+
## Building Standalone Trading Bots
|
|
2572
|
+
|
|
2573
|
+
When users ask you to create trading bots or agents that run independently (not through this CLI), here's how to integrate with the Quantish MCP API:
|
|
2574
|
+
|
|
2575
|
+
### MCP API Endpoint
|
|
2576
|
+
\`\`\`
|
|
2577
|
+
POST https://quantish-sdk-production.up.railway.app/mcp/execute
|
|
2578
|
+
\`\`\`
|
|
2579
|
+
|
|
2580
|
+
### Authentication
|
|
2581
|
+
\`\`\`
|
|
2582
|
+
Header: x-api-key: <QUANTISH_API_KEY>
|
|
2583
|
+
\`\`\`
|
|
2584
|
+
The API key is stored in the user's environment as QUANTISH_API_KEY. Always read from env vars, never hardcode.
|
|
2585
|
+
|
|
2586
|
+
### Request Format (JSON-RPC 2.0)
|
|
2587
|
+
\`\`\`javascript
|
|
2588
|
+
const response = await fetch('https://quantish-sdk-production.up.railway.app/mcp/execute', {
|
|
2589
|
+
method: 'POST',
|
|
2590
|
+
headers: {
|
|
2591
|
+
'Content-Type': 'application/json',
|
|
2592
|
+
'x-api-key': process.env.QUANTISH_API_KEY
|
|
2593
|
+
},
|
|
2594
|
+
body: JSON.stringify({
|
|
2595
|
+
jsonrpc: '2.0',
|
|
2596
|
+
method: 'tools/call',
|
|
2597
|
+
params: {
|
|
2598
|
+
name: 'tool_name',
|
|
2599
|
+
arguments: { /* tool args */ }
|
|
2600
|
+
},
|
|
2601
|
+
id: Date.now()
|
|
2602
|
+
})
|
|
2603
|
+
});
|
|
2604
|
+
\`\`\`
|
|
2605
|
+
|
|
2606
|
+
### Response Format
|
|
2607
|
+
\`\`\`javascript
|
|
2608
|
+
// Success response structure:
|
|
2609
|
+
{
|
|
2610
|
+
"jsonrpc": "2.0",
|
|
2611
|
+
"result": {
|
|
2612
|
+
"content": [{
|
|
2613
|
+
"type": "text",
|
|
2614
|
+
"text": "{\\"key\\": \\"value\\"}" // JSON string - parse this!
|
|
2615
|
+
}]
|
|
2616
|
+
},
|
|
2617
|
+
"id": 123
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
// Parse the inner JSON:
|
|
2621
|
+
const data = await response.json();
|
|
2622
|
+
const result = JSON.parse(data.result.content[0].text);
|
|
2623
|
+
\`\`\`
|
|
2624
|
+
|
|
2625
|
+
### Key Trading Tools (require QUANTISH_API_KEY)
|
|
2626
|
+
- \`get_balances\`: Returns { usdc, nativeUsdc, matic } for EOA and Safe wallets
|
|
2627
|
+
- \`get_positions\`: Returns array of current share holdings with market info
|
|
2628
|
+
- \`place_order\`: Place order. Args: { conditionId, tokenId, side: "BUY"|"SELL", price: 0.01-0.99, size: number }
|
|
2629
|
+
- \`cancel_order\`: Cancel order. Args: { orderId }
|
|
2630
|
+
- \`get_orders\`: List orders. Args: { status?: "LIVE"|"FILLED"|"CANCELLED" }
|
|
2631
|
+
- \`get_orderbook\`: Get bids/asks. Args: { tokenId }
|
|
2632
|
+
- \`get_price\`: Get midpoint price. Args: { tokenId }
|
|
2633
|
+
- \`get_deposit_addresses\`: Get addresses to fund wallet
|
|
2634
|
+
- \`transfer_usdc\`: Send USDC. Args: { toAddress, amount }
|
|
2635
|
+
|
|
2636
|
+
### Key Discovery Tools (free, no auth required)
|
|
2637
|
+
Discovery uses a different endpoint with an embedded public key:
|
|
2638
|
+
\`\`\`
|
|
2639
|
+
POST https://quantish.live/mcp/execute
|
|
2640
|
+
Header: X-API-Key: qm_ueQeqrmvZyHtR1zuVbLYkhx0fKyVAuV8
|
|
2641
|
+
\`\`\`
|
|
2642
|
+
|
|
2643
|
+
- \`search_markets\`: Find markets. Args: { query, limit?, platform?: "polymarket"|"kalshi"|"all" }
|
|
2644
|
+
- \`get_market_details\`: Get market info. Args: { platform, marketId }
|
|
2645
|
+
- \`get_trending_markets\`: Popular markets. Args: { limit?, platform? }
|
|
2646
|
+
- \`find_arbitrage\`: Find arb opportunities. Args: { minProfitPercent?, type? }
|
|
2647
|
+
|
|
2648
|
+
### Important: Token IDs and Condition IDs
|
|
2649
|
+
When placing orders, you need:
|
|
2650
|
+
- \`conditionId\`: The market's condition ID (from market details)
|
|
2651
|
+
- \`tokenId\`: The specific outcome's token ID (YES or NO token from market.tokens array)
|
|
2652
|
+
|
|
2653
|
+
Example flow:
|
|
2654
|
+
1. search_markets({ query: "bitcoin" }) \u2192 get market list
|
|
2655
|
+
2. get_market_details({ platform: "polymarket", marketId: "..." }) \u2192 get tokens array
|
|
2656
|
+
3. Extract tokenId for YES/NO outcome you want
|
|
2657
|
+
4. place_order({ conditionId, tokenId, side: "BUY", price: 0.55, size: 100 })
|
|
2658
|
+
|
|
2659
|
+
### Bot Code Template (Node.js)
|
|
2660
|
+
\`\`\`javascript
|
|
2661
|
+
#!/usr/bin/env node
|
|
2662
|
+
require('dotenv').config();
|
|
2663
|
+
|
|
2664
|
+
const MCP_URL = 'https://quantish-sdk-production.up.railway.app/mcp/execute';
|
|
2665
|
+
const API_KEY = process.env.QUANTISH_API_KEY;
|
|
2666
|
+
|
|
2667
|
+
async function callTool(name, args = {}) {
|
|
2668
|
+
const response = await fetch(MCP_URL, {
|
|
2669
|
+
method: 'POST',
|
|
2670
|
+
headers: {
|
|
2671
|
+
'Content-Type': 'application/json',
|
|
2672
|
+
'x-api-key': API_KEY
|
|
2673
|
+
},
|
|
2674
|
+
body: JSON.stringify({
|
|
2675
|
+
jsonrpc: '2.0',
|
|
2676
|
+
method: 'tools/call',
|
|
2677
|
+
params: { name, arguments: args },
|
|
2678
|
+
id: Date.now()
|
|
2679
|
+
})
|
|
2680
|
+
});
|
|
2681
|
+
|
|
2682
|
+
const data = await response.json();
|
|
2683
|
+
if (data.error) throw new Error(data.error.message);
|
|
2684
|
+
|
|
2685
|
+
try {
|
|
2686
|
+
return JSON.parse(data.result.content[0].text);
|
|
2687
|
+
} catch {
|
|
2688
|
+
return data.result.content[0].text;
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
// Example: Monitor price and alert
|
|
2693
|
+
async function monitorPrice(tokenId, threshold) {
|
|
2694
|
+
const result = await callTool('get_price', { tokenId });
|
|
2695
|
+
console.log(\`Price: \${result.mid}\`);
|
|
2696
|
+
if (parseFloat(result.mid) > threshold) {
|
|
2697
|
+
console.log('ALERT: Price crossed threshold!');
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
// Run every 60 seconds
|
|
2702
|
+
setInterval(() => monitorPrice(process.env.TOKEN_ID, 0.5), 60000);
|
|
2703
|
+
\`\`\`
|
|
2704
|
+
|
|
2705
|
+
### Bot Best Practices
|
|
2706
|
+
1. **Environment Variables**: Always use process.env for API keys
|
|
2707
|
+
2. **Error Handling**: Wrap all API calls in try/catch
|
|
2708
|
+
3. **Rate Limiting**: Poll at 30-60 second intervals minimum
|
|
2709
|
+
4. **Logging**: Log all trades with timestamps for debugging
|
|
2710
|
+
5. **Testing**: Test with small amounts first
|
|
2711
|
+
6. **Graceful Shutdown**: Handle SIGINT to clean up
|
|
2712
|
+
7. **.env.example**: Always create a template for required env vars`;
|
|
2570
2713
|
var Agent = class {
|
|
2571
2714
|
anthropic;
|
|
2572
2715
|
mcpClient;
|
|
@@ -2774,6 +2917,7 @@ ${userMessage}`;
|
|
|
2774
2917
|
const toolResults = [];
|
|
2775
2918
|
for (const toolUse of toolUses) {
|
|
2776
2919
|
this.config.onToolCall?.(toolUse.name, toolUse.input);
|
|
2920
|
+
await new Promise((resolve2) => setImmediate(resolve2));
|
|
2777
2921
|
const { result, source } = await this.executeTool(
|
|
2778
2922
|
toolUse.name,
|
|
2779
2923
|
toolUse.input
|
|
@@ -3092,7 +3236,7 @@ import { useState, useCallback, useRef, useEffect } from "react";
|
|
|
3092
3236
|
import { Box, Text, useApp, useInput } from "ink";
|
|
3093
3237
|
import TextInput from "ink-text-input";
|
|
3094
3238
|
import Spinner from "ink-spinner";
|
|
3095
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3239
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3096
3240
|
function formatTokenCount(count) {
|
|
3097
3241
|
if (count < 1e3) return String(count);
|
|
3098
3242
|
if (count < 1e5) return `${(count / 1e3).toFixed(1)}k`;
|
|
@@ -3569,18 +3713,22 @@ Stopped ${count} background process${count > 1 ? "es" : ""}.`);
|
|
|
3569
3713
|
msg.role === "system" && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { color: "gray", italic: true, children: msg.content }) })
|
|
3570
3714
|
] }, i)) }),
|
|
3571
3715
|
currentToolCalls.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, marginLeft: 2, children: currentToolCalls.map((tc, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3572
|
-
/* @__PURE__ */
|
|
3573
|
-
|
|
3574
|
-
|
|
3716
|
+
/* @__PURE__ */ jsx(Box, { children: tc.pending ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3717
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: /* @__PURE__ */ jsx(Spinner, { type: "dots" }) }),
|
|
3718
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
|
|
3575
3719
|
" ",
|
|
3576
3720
|
tc.name
|
|
3577
|
-
] })
|
|
3721
|
+
] }),
|
|
3722
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: formatArgs(tc.args) }),
|
|
3723
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", dimColor: true, children: " Running..." })
|
|
3724
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3725
|
+
/* @__PURE__ */ jsxs(Text, { color: tc.success ? "green" : "red", children: [
|
|
3578
3726
|
tc.success ? "\u2713" : "\u2717",
|
|
3579
3727
|
" ",
|
|
3580
3728
|
tc.name
|
|
3581
3729
|
] }),
|
|
3582
3730
|
/* @__PURE__ */ jsx(Text, { color: "gray", children: formatArgs(tc.args) })
|
|
3583
|
-
] }),
|
|
3731
|
+
] }) }),
|
|
3584
3732
|
!tc.pending && tc.result && /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "gray", dimColor: true, children: [
|
|
3585
3733
|
"\u2192 ",
|
|
3586
3734
|
formatResult(tc.result, 100)
|
package/package.json
CHANGED