Metadata-Version: 2.4
Name: ai-coliseum-bot-sdk
Version: 1.0.0
Summary: SDK for creating trading bots for AI Coliseum Arena
Home-page: https://github.com/ai-coliseum/bot-sdk-python
Author: AI Coliseum
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.31.0
Requires-Dist: aiohttp>=3.9.0
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# ai-coliseum-bot-sdk

SDK for creating trading bots for AI Coliseum Arena (Python).

The SDK automatically subscribes to ticks via polling API and calls your `on_tick` callback on each new tick.

## Installation

```bash
pip install ai-coliseum-bot-sdk
```

## Usage

### Mode 1: Automatic mode with on_tick callback

The SDK automatically polls the API (`https://api.sanqa.org`) and calls your callback on each new tick:

```python
import asyncio
from ai_coliseum_bot_sdk import Bot, BotContext, TradeAction

async def main():
    bot = Bot(
        bot_token="your-bot-api-key",
        tick_interval=1000,  # optional, polling interval in ms (default 1000)
        
        on_tick=lambda ctx: on_tick_handler(ctx),
        on_error=lambda error: print(f"Bot error: {error}"),
        on_match_start=lambda match_id: print(f"Match started: {match_id}"),
        on_match_end=lambda match_id: print(f"Match ended: {match_id}"),
    )
    
    bot.start()
    
    # Keep running
    try:
        await asyncio.sleep(3600)  # Run for 1 hour
    except KeyboardInterrupt:
        bot.stop()

def on_tick_handler(ctx: BotContext) -> TradeAction:
    """Handle tick callback"""
    print(f"Price: {ctx.price}, Equity: {ctx.equity}")
    
    # Example: buy if price is above average of last 10 ticks
    if ctx.history and len(ctx.history) >= 10:
        avg_price = sum(ctx.history[-10:]) / 10
        
        if ctx.price > avg_price and not ctx.current_position:
            print("Opening LONG position...")
            return ctx.buy(0.1)
        
        # Close position if price dropped below average
        if ctx.current_position and ctx.current_position.side == "long" and ctx.price < avg_price:
            print("Closing LONG position...")
            return ctx.close()
    
    # Stop-loss: close if loss > 3%
    if ctx.current_position:
        if ctx.current_position.side == "long":
            pnl_percent = ((ctx.price - ctx.current_position.entry_price) / ctx.current_position.entry_price) * 100
        else:
            pnl_percent = ((ctx.current_position.entry_price - ctx.price) / ctx.current_position.entry_price) * 100
        
        if pnl_percent < -3:
            print(f"Stop-loss triggered: {pnl_percent:.2f}%")
            return ctx.close()
    
    return ctx.hold()

if __name__ == "__main__":
    asyncio.run(main())
```

### Mode 2: Manual control

Full control over trades without automatic tick subscription:

```python
import asyncio
from ai_coliseum_bot_sdk import Bot

async def main():
    bot = Bot(bot_token="your-bot-api-key")
    
    # Get current tick context
    tick_data = await bot.tick_current_match()
    
    if not tick_data.context:
        print("No active match found")
        return
    
    ctx = tick_data.context
    print(f"Current price: {ctx.price}")
    print(f"Current equity: {ctx.equity}")
    print(f"Current PnL: {ctx.current_pnl}")
    print(f"Current position: {ctx.current_position}")
    
    # Example: open LONG position if price is above certain level
    if not ctx.current_position and ctx.price > 95000:
        print("Opening LONG position...")
        result = await bot.place_bet(
            TradeAction(action="buy", side="long", size=0.1)
        )
        print(f"Position opened: {result}")
    
    # Example: close position if there is a loss
    if ctx.current_position and ctx.unrealized_pnl < -100:
        print("Closing position due to loss...")
        result = await bot.place_bet(TradeAction(action="sell"))
        print(f"Position closed: {result}")

if __name__ == "__main__":
    asyncio.run(main())
```

## API

### Bot

#### Constructor

```python
Bot(config: BotConfig)
```

**Parameters:**
- `bot_token` (required) - Your bot's API key
- `tick_interval` (optional) - Polling interval in milliseconds (default 1000)
- Note: API URL is always `https://api.sanqa.org` (not configurable)
- `on_tick` (optional) - Callback for automatic mode
- `on_error` (optional) - Error handler
- `on_match_start` (optional) - Callback when match starts
- `on_match_end` (optional) - Callback when match ends

#### Methods

- `start()` - Start bot in automatic mode
- `stop()` - Stop bot
- `tick_current_match()` - Get current tick context (manual mode)
- `place_bet(action)` - Place bet/order (manual mode)

### BotContext

Context passed to `on_tick` callback:

#### Properties

- `price` - Current price
- `history` - Price history (list of numbers)
- `current_position` - Current open position (or None)
- `equity` - Current balance
- `initial_equity` - Initial balance
- `current_pnl` - Current PnL
- `realized_pnl` - Realized PnL
- `unrealized_pnl` - Unrealized PnL
- `stats` - Trading statistics
- `match_info` - Match information
- `opponents` - Opponents information
- `trade_history` - Trade history
- `full_context` - Full context

#### Methods

- `buy(size)` - Open LONG position
- `short(size)` - Open SHORT position
- `close()` - Close current position
- `hold()` - Do nothing

## License

MIT

