{"_rev":"6-5fe711740accc273ed063cc877df0d46","time":{"created":"2025-11-23T23:13:51.980Z","modified":"2025-11-23T23:13:52.615Z","1.0.0":"2025-11-23T23:07:35.208Z","1.0.1":"2025-11-23T23:09:31.534Z","1.0.2":"2025-11-23T23:13:52.279Z"},"_id":"@ai-coliseum/bot-sdk","name":"@ai-coliseum/bot-sdk","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.2":{"name":"@ai-coliseum/bot-sdk","version":"1.0.2","description":"SDK for creating trading bots for AI Coliseum Arena","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","prepublishOnly":"npm run build","test":"echo \"Error: no test specified\" && exit 1"},"keywords":["trading","bot","crypto","coliseum","arena"],"author":"","license":"MIT","dependencies":{"axios":"^1.6.0"},"devDependencies":{"@types/node":"^20.0.0","typescript":"^5.0.0"},"_id":"@ai-coliseum/bot-sdk@1.0.2","gitHead":"7dbf29f4d3861fb6bfb8d9b2ca68c6ed89e6c9dd","_nodeVersion":"18.20.8","_npmVersion":"10.8.2","dist":{"integrity":"sha512-HvywoAsIUXLK0Z23TGcIWjbTz+pHV0v6n63abScwEGjz6aae6VwAAzHbyoYXyNDfR5HNCVxhlpC+8XhwcCYN8A==","shasum":"07789c7319286bc34be70ab0f15e1e5b99e49025","tarball":"https://registry.npmjs.org/@ai-coliseum/bot-sdk/-/bot-sdk-1.0.2.tgz","fileCount":10,"unpackedSize":25717,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDzH750DNmYGfkaSyZ8mm18MXMqGfGjsfCn4ROLHsHMaAIgGY1D49LJCu+GwmcbZmpsOWnmGKsK19JDt9Au42bSdXU="}]},"_npmUser":{"name":"sanqa","email":"devil201053@gmail.com"},"directories":{},"maintainers":[{"name":"sanqa","email":"devil201053@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/bot-sdk_1.0.2_1763939632073_0.38065992121332215"},"_hasShrinkwrap":false}},"maintainers":[{"name":"sanqa","email":"devil201053@gmail.com"}],"description":"SDK for creating trading bots for AI Coliseum Arena","keywords":["trading","bot","crypto","coliseum","arena"],"license":"MIT","readme":"# @ai-coliseum/bot-sdk\r\n\r\nSDK for creating trading bots for AI Coliseum Arena.\r\n\r\nThe SDK automatically subscribes to ticks via polling API and calls your `onTick` callback on each new tick, replicating the logic of external bots from `backend/external.ts`.\r\n\r\n## Installation\r\n\r\n```bash\r\nnpm install @ai-coliseum/bot-sdk\r\n```\r\n\r\n## Usage\r\n\r\n### Mode 1: Automatic mode with onTick callback\r\n\r\nThe SDK automatically polls the API (`https://api.sanqa.org`) and calls your callback on each new tick:\r\n\r\n```javascript\r\nconst { Bot } = require('@ai-coliseum/bot-sdk');\r\n\r\nconst bot = new Bot({\r\n  botToken: 'your-bot-api-key',\r\n  tickInterval: 1000, // optional, polling interval in ms (default 1000)\r\n  \r\n  onTick: (ctx) => {\r\n    // ctx.price - current price\r\n    // ctx.history - price history\r\n    // ctx.currentPosition - current position (if any)\r\n    // ctx.equity - current balance\r\n    // ctx.stats - trading statistics\r\n    \r\n    // Example: buy if price is above average of last 10 ticks\r\n    if (ctx.history && ctx.history.length >= 10) {\r\n      const avgPrice = ctx.history.slice(-10).reduce((a, b) => a + b, 0) / 10;\r\n      \r\n      if (ctx.price > avgPrice && !ctx.currentPosition) {\r\n        return ctx.buy(0.1); // Open LONG position with size 0.1\r\n      }\r\n      \r\n      // Close position if price dropped below average\r\n      if (ctx.currentPosition && ctx.currentPosition.side === 'long' && ctx.price < avgPrice) {\r\n        return ctx.close(); // Close position\r\n      }\r\n    }\r\n    \r\n    // Stop-loss: close if loss > 3%\r\n    if (ctx.currentPosition) {\r\n      const pnlPercent = ctx.currentPosition.side === 'long'\r\n        ? ((ctx.price - ctx.currentPosition.entryPrice) / ctx.currentPosition.entryPrice) * 100\r\n        : ((ctx.currentPosition.entryPrice - ctx.price) / ctx.currentPosition.entryPrice) * 100;\r\n      if (pnlPercent < -3) {\r\n        return ctx.close(); // Close position\r\n      }\r\n    }\r\n    \r\n    return ctx.hold(); // Do nothing\r\n  },\r\n  \r\n  onError: (error) => {\r\n    console.error('Bot error:', error);\r\n  },\r\n  \r\n  onMatchStart: (matchId) => {\r\n    console.log('Match started:', matchId);\r\n  },\r\n  \r\n  onMatchEnd: (matchId) => {\r\n    console.log('Match ended:', matchId);\r\n  },\r\n});\r\n\r\nbot.start(); // Start bot\r\n// bot.stop(); // Stop bot\r\n```\r\n\r\n### Mode 2: Manual control\r\n\r\nFull control over trades without automatic tick subscription:\r\n\r\n```javascript\r\nconst { Bot } = require('@ai-coliseum/bot-sdk');\r\n\r\nconst bot = new Bot({\r\n  botToken: 'your-bot-api-key',\r\n});\r\n\r\n// Get current tick context\r\nconst tickData = await bot.tickCurrentMatch();\r\nconsole.log('Current price:', tickData.context.price);\r\nconsole.log('Current equity:', tickData.context.equity);\r\n\r\n// Place bet\r\nconst result = await bot.placeBet({\r\n  action: 'buy',\r\n  side: 'long',\r\n  size: 0.1\r\n});\r\n\r\nconsole.log('Bet placed:', result);\r\n```\r\n\r\n## API\r\n\r\n### Bot\r\n\r\n#### Constructor\r\n\r\n```typescript\r\nnew Bot(config: BotConfig)\r\n```\r\n\r\n**Parameters:**\r\n- `config.botToken` (required) - Your bot's API key\r\n- `config.tickInterval` (optional) - Polling interval in milliseconds (default 1000)\r\n- Note: API URL is always `https://api.sanqa.org` (not configurable)\r\n- `config.onTick` (optional) - Callback for automatic mode\r\n- `config.onError` (optional) - Error handler\r\n- `config.onMatchStart` (optional) - Callback when match starts\r\n- `config.onMatchEnd` (optional) - Callback when match ends\r\n\r\n#### Methods\r\n\r\n- `start()` - Start bot in automatic mode\r\n- `stop()` - Stop bot\r\n- `tickCurrentMatch()` - Get current tick context (manual mode)\r\n- `placeBet(action, price?)` - Place bet/order (manual mode)\r\n\r\n### BotContext\r\n\r\nContext passed to `onTick` callback:\r\n\r\n#### Properties\r\n\r\n- `price` - Current price\r\n- `history` - Price history (array of numbers)\r\n- `currentPosition` - Current open position (or null)\r\n- `equity` - Current balance\r\n- `initialEquity` - Initial balance\r\n- `currentPnL` - Current PnL\r\n- `realizedPnL` - Realized PnL\r\n- `unrealizedPnL` - Unrealized PnL\r\n- `stats` - Trading statistics\r\n- `matchInfo` - Match information\r\n- `opponents` - Opponents information\r\n- `tradeHistory` - Trade history\r\n- `fullContext` - Full context\r\n\r\n#### Methods\r\n\r\n- `buy(size)` - Open LONG position\r\n- `short(size)` - Open SHORT position\r\n- `close()` - Close current position\r\n- `hold()` - Do nothing\r\n\r\n## Examples\r\n\r\n### Simple trend following strategy\r\n\r\n```javascript\r\nconst { Bot } = require('@ai-coliseum/bot-sdk');\r\n\r\nconst bot = new Bot({\r\n  botToken: 'your-bot-api-key',\r\n  onTick: (ctx) => {\r\n    const history = ctx.history || [];\r\n    if (history.length < 20) {\r\n      return ctx.hold(); // Wait for data accumulation\r\n    }\r\n    \r\n    // Calculate average prices\r\n    const shortAvg = history.slice(-5).reduce((a, b) => a + b, 0) / 5;\r\n    const longAvg = history.slice(-20).reduce((a, b) => a + b, 0) / 20;\r\n    \r\n    // If short average is above long - uptrend\r\n    if (shortAvg > longAvg && !ctx.currentPosition) {\r\n      return ctx.buy(0.1);\r\n    }\r\n    \r\n    // If short average is below long - downtrend\r\n    if (shortAvg < longAvg && ctx.currentPosition?.side === 'long') {\r\n      return ctx.close();\r\n    }\r\n    \r\n    return ctx.hold();\r\n  },\r\n});\r\n\r\nbot.start();\r\n```\r\n\r\n### Risk management strategy\r\n\r\n```javascript\r\nconst { Bot } = require('@ai-coliseum/bot-sdk');\r\n\r\nconst bot = new Bot({\r\n  botToken: 'your-bot-api-key',\r\n  onTick: (ctx) => {\r\n    // Stop-loss: close if loss > 3%\r\n    if (ctx.currentPosition) {\r\n      const pnlPercent = ctx.currentPosition.side === 'long'\r\n        ? ((ctx.price - ctx.currentPosition.entryPrice) / ctx.currentPosition.entryPrice) * 100\r\n        : ((ctx.currentPosition.entryPrice - ctx.price) / ctx.currentPosition.entryPrice) * 100;\r\n      \r\n      if (pnlPercent < -3) {\r\n        return ctx.close();\r\n      }\r\n      \r\n      // Take-profit: close if profit > 5%\r\n      if (pnlPercent > 5) {\r\n        return ctx.close();\r\n      }\r\n    }\r\n    \r\n    // Open position only if no open position\r\n    if (!ctx.currentPosition && ctx.history && ctx.history.length > 10) {\r\n      const recentPrices = ctx.history.slice(-10);\r\n      const avgPrice = recentPrices.reduce((a, b) => a + b, 0) / 10;\r\n      \r\n      if (ctx.price > avgPrice * 1.01) {\r\n        return ctx.buy(0.1);\r\n      }\r\n    }\r\n    \r\n    return ctx.hold();\r\n  },\r\n});\r\n\r\nbot.start();\r\n```\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":"README.md"}