Metadata-Version: 2.4
Name: signalnet-sdk
Version: 0.1.4
Summary: Python SDK for the SignalNet quant signal aggregation platform
Project-URL: Homepage, https://signalnet.xyz
Project-URL: Repository, https://github.com/2manslkh/signal-mono
Project-URL: Documentation, https://docs.signalnet.xyz/python-sdk
Author-email: SignalNet <team@signalnet.xyz>
License-Expression: MIT
Keywords: data-science,quant,signals,tournament,trading
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: pandas>=1.5.0
Requires-Dist: pyarrow>=12.0
Requires-Dist: pydantic>=2.0
Requires-Dist: requests>=2.28.0
Description-Content-Type: text/markdown

# SignalNet Python SDK

Official Python client for the [SignalNet](https://signalnet.xyz) quant signal aggregation platform.

## Installation

```bash
pip install signalnet-sdk
```

## Quick Start

```python
from signalnet import SignalNet
import pandas as pd

# Initialize the client
sn = SignalNet(api_key="sn_your_api_key")

# Get the current round
current = sn.get_current_round()
print(f"Round {current.id} — status: {current.status}")

# Download features and build predictions
features = sn.download_features(round_id=current.id)
# ... your model here ...

# Submit predictions
predictions = pd.DataFrame({
    "stock_id": features["stock_id"],
    "signal": your_model.predict(features),
})
result = sn.submit(round_id=current.id, predictions=predictions, stake=500)
print(f"Submission {result.id}: {result.status}")
```

## Configuration

| Parameter | Env Variable | Default |
|-----------|-------------|---------|
| `api_key` | `SIGNALNET_API_KEY` | — |
| `base_url` | `SIGNALNET_API_URL` | `http://localhost:4000/api` |

```python
# Explicit config
sn = SignalNet(api_key="sn_...", base_url="https://api.signalnet.xyz")

# Or via environment variables
# export SIGNALNET_API_KEY=sn_...
# export SIGNALNET_API_URL=https://api.signalnet.xyz
sn = SignalNet()
```

## Local Data Cache

Downloaded data is automatically cached as **Parquet** files in `~/.signalnet/data/`. Parquet is 5–10× smaller than CSV, preserves dtypes, and loads instantly on subsequent calls.

```
~/.signalnet/
└── data/
    ├── rounds/
    │   ├── 1/features.parquet
    │   └── 2/features.parquet
    └── training/
        ├── features.parquet
        └── targets.parquet
```

```python
# First call downloads from API and caches as parquet
features = sn.download_features(round_id=1)
# [SignalNet] Downloading features for round 1... done (12.4 MB → 2.1 MB parquet)

# Second call loads from cache instantly
features = sn.download_features(round_id=1)
# [SignalNet] Using cached features for round 1 (2.1 MB)

# Force re-download
features = sn.download_features(round_id=1, force=True)

# Cache management
print(sn.cache_info())
# {'cache_dir': '/home/user/.signalnet/data', 'total_size': 2148576,
#  'total_size_human': '2.0 MB', 'round_features': [1, 2], 'training_files': ['features']}

sn.clear_cache()
```

Configure cache location:
```python
sn = SignalNet(api_key="sn_...", cache_dir="/tmp/sn-cache")
# or: export SIGNALNET_CACHE_DIR=/tmp/sn-cache
```

## API Reference

### Rounds

#### `get_current_round() → Round`
Get the current active round.

#### `get_rounds(limit=None, offset=None, status=None) → list[Round]`
List tournament rounds with optional filters.

#### `get_round(round_id) → Round`
Get details for a specific round.

#### `get_round_results(round_id) → list[RoundResult]`
Get the leaderboard/results for a resolved round.

### Tournaments

#### `get_tournaments() → list[Tournament]`
List all tournaments.

#### `get_tournament(slug_or_id) → Tournament`
Get a tournament by slug (e.g. `"genesis"`) or ID.

### Data Downloads

#### `download_features(round_id, *, force=False) → pd.DataFrame`
Download feature data for a round. Returns a pandas DataFrame. Cached as Parquet locally.

#### `download_training_data(data_type, *, force=False) → pd.DataFrame`
Download training data. `data_type` must be `"features"` or `"targets"`. Cached as Parquet locally.

### Cache Management

#### `cache_info() → dict`
Return cache stats: directory, total size, cached round IDs, and training files.

#### `clear_cache()`
Delete all locally cached data files.

### Submissions

#### `submit(round_id, predictions, stake=0) → SubmissionResponse`
Submit predictions for a round.

- `predictions`: a DataFrame with columns `stock_id` and `signal`
- `stake`: amount to stake (default 0)

#### `get_my_submission(round_id) → dict`
Get your submission for a specific round.

### User

#### `get_me() → User`
Get the authenticated user's profile.

#### `get_my_scores() → list[ScoreEntry]`
Get your score history across rounds.

#### `create_api_key(name=None) → ApiKey`
Create a new API key.

#### `list_api_keys() → list[ApiKey]`
List all your API keys.

## Error Handling

All errors inherit from `SignalNetError`:

```python
from signalnet import SignalNet, SignalNetError
from signalnet.exceptions import AuthenticationError, NotFoundError, RateLimitError

sn = SignalNet(api_key="sn_...")

try:
    r = sn.get_round(999)
except NotFoundError:
    print("Round not found")
except AuthenticationError:
    print("Bad API key")
except RateLimitError:
    print("Slow down!")
except SignalNetError as e:
    print(f"API error {e.status_code}: {e}")
```

| Exception | HTTP Status |
|-----------|------------|
| `AuthenticationError` | 401, 403 |
| `NotFoundError` | 404 |
| `ValidationError` | 400, 422 |
| `RateLimitError` | 429 |
| `ServerError` | 5xx |

## Models

All response models are Pydantic v2 `BaseModel` subclasses with `extra="allow"`, so new API fields won't break existing code.

- `Round` — tournament round
- `Tournament` — tournament info
- `RoundResult` — leaderboard entry
- `SubmissionResponse` — submission confirmation
- `User` — user profile
- `ScoreEntry` — score history entry
- `ApiKey` — API key info

## License

MIT
