- Add AGENTS.md with coding guidelines for AI agents - Add comprehensive unit tests for Binance adapter (mocked) - Add integration tests for Binance testnet connectivity - Fix pydantic-settings v2 compatibility for nested settings - Fix MarginType enum to handle lowercase API responses - Update Python requirement to 3.12+ (pandas-ta dependency) - Update ruff config to new lint section format - Update PLAN.md to reflect completed milestones 1.1-1.3 32 tests passing with 81% coverage
195 lines
5.0 KiB
Markdown
195 lines
5.0 KiB
Markdown
# AGENTS.md - AI Coding Agent Guidelines for TradeFinder
|
|
|
|
> Automated crypto trading system for BTC/ETH perpetual futures on Binance USDM.
|
|
|
|
## Quick Reference
|
|
|
|
| Task | Command |
|
|
|------|---------|
|
|
| Install | `pip install -e ".[dev]"` or `uv pip install -e ".[dev]"` |
|
|
| Run all tests | `pytest` |
|
|
| Run single test | `pytest tests/test_config.py::TestOrderRequest::test_valid_limit_order -v` |
|
|
| Run test file | `pytest tests/test_config.py -v` |
|
|
| Lint | `ruff check .` |
|
|
| Lint fix | `ruff check . --fix` |
|
|
| Format | `ruff format .` |
|
|
| Type check | `mypy src/` |
|
|
| Full check | `ruff check . && ruff format --check . && mypy src/ && pytest` |
|
|
|
|
---
|
|
|
|
## Build & Environment
|
|
|
|
- **Python**: 3.12+ required (3.12, 3.13 supported) - pandas-ta requires 3.12+
|
|
- **Build system**: `hatchling` with `pyproject.toml`
|
|
- **Prefer `uv`** for faster installs: `uv pip install -e ".[dev]"`
|
|
|
|
```bash
|
|
# Setup
|
|
uv venv .venv --python 3.12 && source .venv/bin/activate
|
|
uv pip install -e ".[dev]"
|
|
```
|
|
|
|
---
|
|
|
|
## Testing (pytest + pytest-asyncio)
|
|
|
|
```bash
|
|
pytest # All tests with coverage
|
|
pytest tests/test_config.py -v # Single file
|
|
pytest tests/test_config.py::TestOrderRequest::test_valid_limit_order -v # Single test
|
|
pytest -k "test_valid" -v # By keyword
|
|
```
|
|
|
|
- `asyncio_mode = "auto"` - no `@pytest.mark.asyncio` needed
|
|
- Test files: `tests/test_*.py`
|
|
- Type hints required: `def test_xxx(self) -> None:`
|
|
|
|
---
|
|
|
|
## Linting & Type Checking
|
|
|
|
**Ruff** (line-length: 100, target: py311):
|
|
- Rules: `E`, `W`, `F`, `I`, `B`, `C4`, `UP` (pycodestyle, pyflakes, isort, bugbear, comprehensions, pyupgrade)
|
|
|
|
**MyPy**: `strict = true`, uses `pydantic.mypy` plugin
|
|
|
|
---
|
|
|
|
## Code Style Guidelines
|
|
|
|
### Imports (isort-ordered)
|
|
```python
|
|
from abc import ABC, abstractmethod # 1. stdlib
|
|
from decimal import Decimal
|
|
|
|
import httpx # 2. third-party
|
|
import structlog
|
|
|
|
from tradefinder.adapters.types import Order # 3. first-party
|
|
```
|
|
|
|
### Type Hints (Required - strict mypy)
|
|
```python
|
|
async def get_balance(self, asset: str = "USDT") -> AccountBalance: ...
|
|
|
|
# Use | for unions, built-in generics
|
|
def cancel_order(self, order_id: str | None = None) -> Order: ...
|
|
list[str] # Not List[str]
|
|
dict[str, Any] # Not Dict[str, Any]
|
|
```
|
|
|
|
### Numeric Values - Always Decimal
|
|
```python
|
|
price = Decimal("50000.00") # String input for precision
|
|
# NEVER: price = 50000.00 # Float loses precision
|
|
```
|
|
|
|
### Data Structures
|
|
```python
|
|
@dataclass
|
|
class Position:
|
|
symbol: str
|
|
quantity: Decimal
|
|
raw: dict[str, Any] = field(default_factory=dict)
|
|
|
|
# Pydantic for config/validation only
|
|
class Settings(BaseSettings): ...
|
|
```
|
|
|
|
### Enums
|
|
```python
|
|
class Side(str, Enum):
|
|
BUY = "BUY"
|
|
SELL = "SELL"
|
|
|
|
params["side"] = request.side.value # Use .value for API
|
|
```
|
|
|
|
### Logging (structlog)
|
|
```python
|
|
logger = structlog.get_logger(__name__)
|
|
logger.info("Order created", order_id=order.id, symbol=symbol)
|
|
# NEVER log secrets: logger.info(f"API Key: {api_key}")
|
|
```
|
|
|
|
### Async Patterns
|
|
```python
|
|
async def connect(self) -> None:
|
|
self._client = httpx.AsyncClient(timeout=30.0)
|
|
|
|
async def disconnect(self) -> None:
|
|
if self._client:
|
|
await self._client.aclose()
|
|
self._client = None
|
|
```
|
|
|
|
### Error Handling
|
|
```python
|
|
class ExchangeError(Exception): pass
|
|
class AuthenticationError(ExchangeError): pass
|
|
|
|
try:
|
|
await self._request(...)
|
|
except httpx.RequestError as e:
|
|
raise ExchangeError(f"Request failed: {e}") from e
|
|
```
|
|
|
|
### Naming Conventions
|
|
| Type | Convention | Example |
|
|
|------|------------|---------|
|
|
| Modules | snake_case | `binance_usdm.py` |
|
|
| Classes | PascalCase | `BinanceUSDMAdapter` |
|
|
| Functions/Variables | snake_case | `get_open_orders` |
|
|
| Constants | UPPER_SNAKE | `MAX_LEVERAGE` |
|
|
| Private | leading underscore | `_client`, `_sign()` |
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
src/tradefinder/
|
|
adapters/ # Exchange connectivity (base.py, binance_usdm.py, types.py)
|
|
core/ # Core engine (config.py)
|
|
data/ # Market data (TODO)
|
|
strategies/ # Trading strategies (TODO)
|
|
ui/ # Streamlit dashboard (TODO)
|
|
tests/
|
|
test_*.py # Test files
|
|
```
|
|
|
|
---
|
|
|
|
## Security Rules (CRITICAL)
|
|
|
|
1. **NEVER commit `.env` or secrets** - `.gitignore` enforces this
|
|
2. **NEVER log API keys** - mask sensitive data
|
|
3. **Use `SecretStr`** for credentials in Pydantic settings
|
|
4. **Use `Decimal`** for all financial values - never `float`
|
|
5. **Validate trading mode** before any exchange operations
|
|
|
|
---
|
|
|
|
## Common Patterns
|
|
|
|
```python
|
|
# Configuration
|
|
from tradefinder.core.config import get_settings
|
|
settings = get_settings()
|
|
|
|
# Creating orders
|
|
request = OrderRequest(
|
|
symbol="BTCUSDT", side=Side.BUY, position_side=PositionSide.LONG,
|
|
order_type=OrderType.LIMIT, quantity=Decimal("0.001"), price=Decimal("50000"),
|
|
)
|
|
request.validate()
|
|
|
|
# Exchange adapter
|
|
adapter = BinanceUSDMAdapter(settings)
|
|
await adapter.connect()
|
|
await adapter.configure_hedge_mode(True)
|
|
await adapter.configure_margin_type("BTCUSDT", MarginType.ISOLATED)
|
|
await adapter.disconnect()
|
|
```
|