menese_strategy
Create and manage automated trading strategies including DCA, Take Profit, and Stop Loss across 19 blockchain networks to optimize cryptocurrency investments.
Instructions
Manage automated trading strategies: DCA (dollar-cost averaging), Take Profit (sell above target), Stop Loss (sell below threshold).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | Action to perform | |
| strategyType | No | Strategy type (required for create) | |
| chain | No | Target chain (required for create) | |
| amount | No | Amount per execution (decimal, for create) | |
| intervalSeconds | No | Interval between DCA executions in seconds (min 60) | |
| maxExecutions | No | Max number of executions | |
| targetPrice | No | Target price in USD (for take_profit/stop_loss) | |
| ruleId | No | Rule ID (for cancel) |
Implementation Reference
- src/tools/strategy.ts:57-144 (handler)The handler logic for 'menese_strategy' tool, managing create, list, and cancel actions for trading strategies.
async ({ action, strategyType, chain, amount, intervalSeconds, maxExecutions, targetPrice, ruleId }) => { const identity = store.get(); if (!identity) { return { content: [{ type: "text" as const, text: "No wallet configured. Use menese_setup first." }], isError: true }; } if (action === "list") { const result = await listStrategies(config, resolveActorIdentity(store)); return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2), }], }; } if (action === "cancel") { if (ruleId == null) { return { content: [{ type: "text" as const, text: "ruleId is required for cancel." }], isError: true }; } const result = await deleteStrategy(config, resolveActorIdentity(store), ruleId); return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2), }], }; } // action === "create" if (!strategyType || !chain || !amount) { return { content: [{ type: "text" as const, text: "strategyType, chain, and amount are required for create." }], isError: true, }; } const chainType = CHAIN_TYPE_MAP[chain]; const ruleType = RULE_TYPE_MAP[strategyType]; if (!chainType || !ruleType) { return { content: [{ type: "text" as const, text: "Invalid chain or strategy type." }], isError: true }; } const decimals = CHAIN_DECIMALS[chain] ?? 18; const triggerPrice = targetPrice ? BigInt(Math.round(parseFloat(targetPrice) * 1_000_000)) : 0n; // Build the Candid Rule record const rule: Record<string, unknown> = { chainType, ruleType, triggerPrice, sizePct: 100n, positionId: 0n, id: 0n, status: { Draft: null }, createdAt: BigInt(Date.now()) * 1_000_000n, apyMigrationConfig: [], lpConfig: [], scheduledConfig: [], volatilityConfig: [], swapAmountDrops: [], swapAmountLamports: [], swapAmountWei: [], dcaConfig: [], }; // Set chain-specific amount field if (chain === "solana") { rule.swapAmountLamports = [parseAmount(amount, 9)]; } else if (chain === "xrp") { rule.swapAmountDrops = [parseAmount(amount, 6)]; } else { rule.swapAmountWei = [parseAmount(amount, decimals)]; } // DCA config if (strategyType === "dca" && intervalSeconds) { rule.dcaConfig = [{ intervalSeconds: BigInt(intervalSeconds), maxExecutions: maxExecutions ? [BigInt(maxExecutions)] : [] }]; } const result = await addStrategy(config, resolveActorIdentity(store), rule); return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2), }], }; }, - src/tools/strategy.ts:38-55 (schema)The input schema for 'menese_strategy', defining parameters for different actions.
description: "Manage automated trading strategies: DCA (dollar-cost averaging), " + "Take Profit (sell above target), Stop Loss (sell below threshold).", inputSchema: { action: z.enum(["create", "list", "cancel"]).describe("Action to perform"), strategyType: z.enum(["dca", "take_profit", "stop_loss"]).optional() .describe("Strategy type (required for create)"), chain: z.enum(SUPPORTED_CHAINS as unknown as [string, ...string[]]).optional() .describe("Target chain (required for create)"), amount: z.string().optional().describe("Amount per execution (decimal, for create)"), intervalSeconds: z.number().min(60).optional() .describe("Interval between DCA executions in seconds (min 60)"), maxExecutions: z.number().min(1).optional() .describe("Max number of executions"), targetPrice: z.string().optional() .describe("Target price in USD (for take_profit/stop_loss)"), ruleId: z.number().optional().describe("Rule ID (for cancel)"), }, - src/tools/strategy.ts:30-146 (registration)Registration function for the 'menese_strategy' tool.
export function registerStrategyTool( server: McpServer, store: IdentityStore, config: MeneseConfig, ): void { server.registerTool( "menese_strategy", { description: "Manage automated trading strategies: DCA (dollar-cost averaging), " + "Take Profit (sell above target), Stop Loss (sell below threshold).", inputSchema: { action: z.enum(["create", "list", "cancel"]).describe("Action to perform"), strategyType: z.enum(["dca", "take_profit", "stop_loss"]).optional() .describe("Strategy type (required for create)"), chain: z.enum(SUPPORTED_CHAINS as unknown as [string, ...string[]]).optional() .describe("Target chain (required for create)"), amount: z.string().optional().describe("Amount per execution (decimal, for create)"), intervalSeconds: z.number().min(60).optional() .describe("Interval between DCA executions in seconds (min 60)"), maxExecutions: z.number().min(1).optional() .describe("Max number of executions"), targetPrice: z.string().optional() .describe("Target price in USD (for take_profit/stop_loss)"), ruleId: z.number().optional().describe("Rule ID (for cancel)"), }, }, async ({ action, strategyType, chain, amount, intervalSeconds, maxExecutions, targetPrice, ruleId }) => { const identity = store.get(); if (!identity) { return { content: [{ type: "text" as const, text: "No wallet configured. Use menese_setup first." }], isError: true }; } if (action === "list") { const result = await listStrategies(config, resolveActorIdentity(store)); return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2), }], }; } if (action === "cancel") { if (ruleId == null) { return { content: [{ type: "text" as const, text: "ruleId is required for cancel." }], isError: true }; } const result = await deleteStrategy(config, resolveActorIdentity(store), ruleId); return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2), }], }; } // action === "create" if (!strategyType || !chain || !amount) { return { content: [{ type: "text" as const, text: "strategyType, chain, and amount are required for create." }], isError: true, }; } const chainType = CHAIN_TYPE_MAP[chain]; const ruleType = RULE_TYPE_MAP[strategyType]; if (!chainType || !ruleType) { return { content: [{ type: "text" as const, text: "Invalid chain or strategy type." }], isError: true }; } const decimals = CHAIN_DECIMALS[chain] ?? 18; const triggerPrice = targetPrice ? BigInt(Math.round(parseFloat(targetPrice) * 1_000_000)) : 0n; // Build the Candid Rule record const rule: Record<string, unknown> = { chainType, ruleType, triggerPrice, sizePct: 100n, positionId: 0n, id: 0n, status: { Draft: null }, createdAt: BigInt(Date.now()) * 1_000_000n, apyMigrationConfig: [], lpConfig: [], scheduledConfig: [], volatilityConfig: [], swapAmountDrops: [], swapAmountLamports: [], swapAmountWei: [], dcaConfig: [], }; // Set chain-specific amount field if (chain === "solana") { rule.swapAmountLamports = [parseAmount(amount, 9)]; } else if (chain === "xrp") { rule.swapAmountDrops = [parseAmount(amount, 6)]; } else { rule.swapAmountWei = [parseAmount(amount, decimals)]; } // DCA config if (strategyType === "dca" && intervalSeconds) { rule.dcaConfig = [{ intervalSeconds: BigInt(intervalSeconds), maxExecutions: maxExecutions ? [BigInt(maxExecutions)] : [] }]; } const result = await addStrategy(config, resolveActorIdentity(store), rule); return { content: [{ type: "text" as const, text: JSON.stringify(result, bigIntReplacer, 2), }], }; }, ); }