Skip to content

[P0] ton-trading-bot: 3 critical tools documented but missing from exported API (get_open_positions, close_position, close_all_positions) #188

Description

@labtgbot

Summary

The ton-trading-bot plugin documentation, README, and manifest declare 42 tools (including ton_trading_get_open_positions, ton_trading_close_position, and ton_trading_close_all_positions). However, the current index.js does not export these three tools in the tools(sdk) array. This creates a critical gap: the plugin's internal logic for position management exists (closeOpenPosition, formatOpenPosition, closeTradeJournalEntry), but agents and automation workflows cannot access it through the public API.

Impact

  • Monitoring is broken: ton_trading_get_open_positions is unavailable, so automated monitoring cannot retrieve the current open position list.
  • Automation is blocked: Scheduled tasks, stop-loss checks, and take-profit logic that depend on enumerating or closing positions are forced to use workarounds (e.g., direct DB access or journal hacks).
  • Documentation is misleading: Users see these tools listed in the README and manifest, but calls fail with "tool not found".
  • Violates single source of truth: The plugin already tracks positions in trade_journal with status = 'open' | 'closing' | 'closed' | 'close_failed', but this state is inaccessible to the agent.

Environment

  • Plugin: ton-trading-bot
  • Version: 2.4.1
  • File: plugins/ton-trading-bot/index.js
  • SDK: >=1.0.0

Evidence

  1. manifest.json lists all 42 tools, including the three missing ones.
  2. README.md documents schemas for ton_trading_get_open_positions, ton_trading_close_position, and ton_trading_close_all_positions.
  3. index.js contains helper functions formatOpenPosition, closeOpenPosition, and closeTradeJournalEntry that are fully capable of supporting these tools.
  4. The exported tools(sdk) array does not include the three position-management tools.

Reproduction

// This call fails because the tool is not registered:
await sdk.call('ton_trading_get_open_positions', { mode: 'simulation' });
// Error: tool not found

Proposed Fix

1. Export ton_trading_get_open_positions

{
  name: "ton_trading_get_open_positions",
  description: "List open real or simulation positions from the trade journal.",
  category: "data-bearing",
  parameters: {
    type: "object",
    properties: {
      mode: { type: "string", enum: ["real", "simulation", "all"], default: "all" },
      limit: { type: "integer", minimum: 1, maximum: 100, default: 50 }
    }
  },
  execute: async (params, _context) => {
    const { mode = "all", limit = 50 } = params;
    try {
      const modeFilter = mode === "all" ? null : mode;
      const query = modeFilter
        ? "SELECT * FROM trade_journal WHERE status = 'open' AND mode = ? ORDER BY timestamp DESC LIMIT ?"
        : "SELECT * FROM trade_journal WHERE status = 'open' ORDER BY timestamp DESC LIMIT ?";
      const rows = modeFilter
        ? sdk.db.prepare(query).all(modeFilter, limit)
        : sdk.db.prepare(query).all(limit);
      return {
        success: true,
        data: {
          positions: rows.map(formatOpenPosition),
          count: rows.length,
          mode: modeFilter ?? "all"
        }
      };
    } catch (err) {
      sdk.log.error(`ton_trading_get_open_positions failed: ${err.message}`);
      return { success: false, error: String(err.message).slice(0, 500) };
    }
  }
}

2. Export ton_trading_close_position

{
  name: "ton_trading_close_position",
  description: "Close one open position by trade ID using simulation quote or real reverse swap.",
  category: "action",
  parameters: {
    type: "object",
    required: ["trade_id", "mode"],
    properties: {
      trade_id: { type: "integer" },
      mode: { type: "string", enum: ["real", "simulation"] },
      amount: { type: "number" },
      slippage: { type: "number" },
      dex: { type: "string" },
      exit_price_usd: { type: "number" },
      note: { type: "string" }
    }
  },
  execute: async (params, context) => {
    const { trade_id, mode, ...rest } = params;
    try {
      const entry = sdk.db.prepare("SELECT * FROM trade_journal WHERE id = ? AND status = 'open' AND mode = ?").get(trade_id, mode);
      if (!entry) {
        return { success: false, error: `Position ${trade_id} not found or already closed` };
      }
      return await closeOpenPosition(sdk, entry, rest, context);
    } catch (err) {
      sdk.log.error(`ton_trading_close_position failed: ${err.message}`);
      return { success: false, error: String(err.message).slice(0, 500) };
    }
  }
}

3. Export ton_trading_close_all_positions

{
  name: "ton_trading_close_all_positions",
  description: "Close all open positions for a selected real or simulation mode.",
  category: "action",
  parameters: {
    type: "object",
    required: ["mode"],
    properties: {
      mode: { type: "string", enum: ["real", "simulation"] },
      slippage: { type: "number" },
      dex: { type: "string" },
      exit_price_usd: { type: "number" },
      note: { type: "string" }
    }
  },
  execute: async (params, context) => {
    const { mode, ...rest } = params;
    try {
      const rows = sdk.db.prepare("SELECT * FROM trade_journal WHERE status = 'open' AND mode = ?").all(mode);
      const results = [];
      for (const entry of rows) {
        const result = await closeOpenPosition(sdk, entry, rest, context);
        results.push({ trade_id: entry.id, ...result });
      }
      return {
        success: true,
        data: {
          closed: results.length,
          results
        }
      };
    } catch (err) {
      sdk.log.error(`ton_trading_close_all_positions failed: ${err.message}`);
      return { success: false, error: String(err.message).slice(0, 500) };
    }
  }
}

4. Add tests

Create plugins/ton-trading-bot/tests/open-positions.test.js covering:

  • get_open_positions returns only status = 'open' trades
  • get_open_positions respects mode filter (real, simulation, all)
  • close_position transitions status from 'open''closed'
  • close_position fails gracefully on already-closed trade
  • close_all_positions closes all open trades for given mode
  • close_all_positions respects claim/compare-and-swap logic (no double-close)

Acceptance Criteria

  • ton_trading_get_open_positions is callable and returns open positions in simulation mode
  • ton_trading_close_position closes a single open simulation position and updates P&L correctly
  • ton_trading_close_all_positions closes all open positions for a given mode atomically
  • All three tools appear in the plugin's exported tool list and match README schema
  • Unit tests pass for each tool
  • No regression in existing tools (ton_trading_get_portfolio_summary, ton_trading_check_stop_loss, etc.)

Related

  • plugins/ton-trading-bot/README.md — declares the missing tools
  • plugins/ton-trading-bot/manifest.json — lists the missing tools
  • plugins/ton-trading-bot/index.js — contains internal logic (closeOpenPosition, formatOpenPosition) but no exported tools

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions