Metadata-Version: 2.4
Name: stockapis-bot
Version: 0.3.1
Summary: Trading Bot SDK for StockAPIs - Build custom trading bots with ease
Project-URL: Homepage, https://stockapis.com
Project-URL: Documentation, https://stockapis.com/docs/botclient
Author-email: StockAPIs <dev@stockapis.com>
License: MIT
Keywords: binance,bot,cryptocurrency,futures,grpc,sdk,trading
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: aiohttp>=3.9.0
Requires-Dist: grpcio-tools>=1.60.0
Requires-Dist: grpcio>=1.60.0
Requires-Dist: protobuf>=4.25.0
Requires-Dist: pydantic-settings>=2.7.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: redis>=5.0.0
Requires-Dist: rich>=13.7.0
Requires-Dist: typer>=0.9.0
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == 'dev'
Requires-Dist: mypy>=1.8.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: questionary>=2.1.0; extra == 'dev'
Requires-Dist: ruff>=0.2.0; extra == 'dev'
Requires-Dist: toml>=0.10.0; extra == 'dev'
Requires-Dist: twine>=4.0.0; extra == 'dev'
Provides-Extra: telegram
Requires-Dist: cryptg>=0.4.0; extra == 'telegram'
Requires-Dist: telethon>=1.34.0; extra == 'telegram'
Description-Content-Type: text/markdown

# stockapis-bot

Python SDK for building trading bots with StockAPIs platform.

## Features

- Pydantic v2 typed settings with JSON Schema (auto-sent to Django)
- Deterministic bot_id from name (UUID5 - same name = same ID everywhere)
- gRPC streaming for real-time signals from Django
- Binance Futures testnet/live trading
- Redis pub/sub for event handling
- Telegram channel signal extraction

## Install

```bash
pip install stockapis-bot
```

## Environment

```bash
# Binance TESTNET
BINANCE__API_KEY=your_testnet_api_key
BINANCE__API_SECRET=your_testnet_api_secret
BINANCE__TESTNET=true

# Django gRPC
GRPC__HOST=localhost
GRPC__PORT=50051
GRPC__API_KEY=dev-key

# Redis
REDIS__HOST=localhost
REDIS__PORT=6379
REDIS__CHANNEL=trading_signals

# Telegram Spy
TELEGRAM__API_ID=123456
TELEGRAM__API_HASH=your_api_hash
TELEGRAM__SESSION=1BQA...          # from `telegram-spy auth`
TELEGRAM__CHANNELS=channel1,channel2
```

## Quick Start

```python
from decimal import Decimal
from pydantic import Field
from stockapis_bot import (
    BotClient, BotSettings, ClientConfig, TradingBot, TradingSignal, SignalDecision,
)

# 1. Define settings schema (sent to Django for dynamic form generation)
class ScalperSettings(BotSettings):
    min_confidence: float = Field(default=0.7, ge=0, le=1, description="Min confidence")
    position_size: Decimal = Field(default=Decimal("100"), description="Position USDT")

# 2. Create bot with settings schema
class MyBot(TradingBot):
    settings_schema = ScalperSettings  # Schema sent to Django on registration

    async def on_signal(self, signal: TradingSignal) -> SignalDecision:
        # Access typed settings (updated from Django)
        if signal.confidence < self.settings.min_confidence:
            return SignalDecision.skip("Low confidence")

        qty = str(self.settings.position_size)
        if signal.is_buy_signal:
            return SignalDecision.buy(qty, "High confidence buy")
        elif signal.is_sell_signal:
            return SignalDecision.sell(qty, "High confidence sell")

        return SignalDecision.skip("Unknown signal")

    async def on_start(self) -> None:
        print(f"Bot {self.name} ({self.bot_id}) started")
        print(f"Settings: {self.settings}")

    async def on_stop(self, reason: str) -> None:
        print(f"Bot stopped: {reason}")

# 3. Run - bot_id auto-generated from name (deterministic UUID5)
bot = MyBot(name="my-scalper")
config = ClientConfig.from_settings(
    bot_id=bot.bot_id,
    bot_name=bot.name,
    include_exchange=True,  # Binance from .env
    include_redis=True,     # Redis listener from .env
)
client = BotClient.create(bot, config)  # Schema sent to Django here
await client.run()
```

## Bot Methods

```python
# Trading
await self.buy(symbol, quantity)
await self.sell(symbol, quantity, reduce_only=True)

# Market data
ticker = await self.get_ticker("BTCUSDT")  # ticker.price
balance = await self.get_balance()          # balance.available_usdt

# Utils
qty = await self.calculate_quantity(symbol, usdt_amount=100, leverage=10)
await self.set_leverage(symbol, leverage=20)

# State
self.is_running    # bool
self.is_active     # bool (running + config.active)
self.config        # BotConfig from Django (enabled, active, etc.)
self.settings      # Typed settings (ScalperSettings) - updated from Django
```

## CLI

| Command | Description | Args |
|---------|-------------|------|
| `telegram-spy auth` | Generate session string | `-i API_ID -h API_HASH` |
| `telegram-spy test` | Test session validity | `-i API_ID -h API_HASH -s SESSION` |
| `telegram-spy channels` | List your channels | `-i API_ID -h API_HASH -s SESSION` |
| `telegram-spy run` | Run spy → Redis | reads from env |
| `telegram-spy send` | Send test signal | `BOT__TOKEN` env |

## License

MIT
