Metadata-Version: 2.4
Name: vanda-api
Version: 1.0.1
Summary: Official Python SDK for Vanda Analytics Data API
Project-URL: Homepage, https://gitlab.com/yourusername/vanda-api
Project-URL: Documentation, https://gitlab.com/yourusername/vanda-api#readme
Project-URL: Repository, https://gitlab.com/yourusername/vanda-api
Project-URL: Issues, https://gitlab.com/yourusername/vanda-api/-/issues
Author-email: Jonathan Aina <Jonathan.Aina@vanda.com>
License: MIT
License-File: LICENSE
Keywords: analytics,api,finance,market-data,retail-trading,vanda
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
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: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27.0
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == 'dev'
Requires-Dist: mypy>=1.5.0; extra == 'dev'
Requires-Dist: pandas-stubs>=2.0.0; extra == 'dev'
Requires-Dist: pre-commit>=3.3.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: respx>=0.20.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Provides-Extra: pandas
Requires-Dist: pandas>=1.5.0; extra == 'pandas'
Description-Content-Type: text/markdown

# Vanda Analytics Data API SDK

Official Python SDK for the Vanda Analytics Data API.

## Installation

```bash
pip install vanda-api
```

For pandas support:

```bash
pip install vanda-api[pandas]
```

## Quick Start

### Synchronous Client

```python
from datetime import date
from vanda import VandaClient

with VandaClient(token="YOUR_TOKEN_HERE") as client:
    data = client.series.get_timeseries(
        symbol="TSLA",
        start_date=date(2025, 12, 1),
        end_date=date(2025, 12, 31),
        fields=["retail_net_turnover", "retail_buy_turnover"],
    )
    print(f"Retrieved {len(data)} records")

# For transformation option
with VandaClient(token="YOUR_TOKEN_HERE") as client:
    data = client.series.get_timeseries(
        symbol="TSLA",
        start_date=date(2025, 12, 1),
        end_date=date(2025, 12, 31),
        fields=["retail_net_turnover", "retail_buy_turnover"],
        transformation="moving_avg",
        window="5",
        is_full_history=True,
    )
    print(f"Retrieved {len(data)} records")

# For transformation and normalisation option
with VandaClient(token="YOUR_TOKEN_HERE") as client:
    data = client.series.get_timeseries(
        symbol="TSLA",
        start_date=date(2025, 12, 1),
        end_date=date(2025, 12, 31),
        fields=["retail_net_turnover", "retail_buy_turnover"],
        transformation="moving_avg",
        window="5",
        normalisation="percentile_rank",
        normalisation_period="1y",
        is_full_history=True,
    )
    print(f"Retrieved {len(data)} records")
```

```python
from vanda import VandaClient

# Pass credentials directly
with VandaClient(email="your_email@example.com", password="your_password") as client:
    data = client.series.get_timeseries(
        symbol="TSLA",
        start_date="2025-12-01",
        end_date="2025-12-31",
        fields=["retail_net_turnover"],
    )

# For transformation option
with VandaClient(email="your_email@example.com", password="your_password") as client:
    data = client.series.get_timeseries(
        symbol="TSLA",
        start_date="2025-12-01",
        end_date="2025-12-31",
        fields=["retail_net_turnover"],
        transformation="moving_avg",
        window="5",
        is_full_history=True,
    )

# For transformation and normalisation option
with VandaClient(email="your_email@example.com", password="your_password") as client:
    data = client.series.get_timeseries(
        symbol="TSLA",
        start_date="2025-12-01",
        end_date="2025-12-31",
        fields=["retail_net_turnover"],
        transformation="moving_avg",
        window="5",
        normalisation="percentile_rank",
        normalisation_period="1y",
        is_full_history=True,
    )

```

### Recommended to use environment variables

```python
export VANDA_LOGIN_EMAIL="your_email@example.com"
export VANDA_PASSWORD="your_password"
```

### Asynchronous Client

```python
import asyncio
from datetime import date
from vanda import AsyncVandaClient

async def main():
    async with AsyncVandaClient(token="YOUR_TOKEN_HERE") as client:
        data = await client.series.get_timeseries(
            symbol="TSLA",
            start_date=date(2025, 12, 1),
            end_date=date(2025, 12, 31),
            fields=["retail_net_turnover"],
        )
        print(f"Retrieved {len(data)} records")

    async with AsyncVandaClient(token="YOUR_TOKEN_HERE") as client:
        data = await client.series.get_timeseries(
            symbol="TSLA",
            start_date=date(2025, 12, 1),
            end_date=date(2025, 12, 31),
            fields=["retail_net_turnover"],
            transformation="moving_avg",
            window="5",
            normalisation="percentile_rank",
            normalisation_period="1y",
            is_full_history=True,
        )
        print(f"Retrieved {len(data)} records")


asyncio.run(main())
```

```python
import asyncio
from vanda import AsyncVandaClient

async def main():
    async with AsyncVandaClient(email="your_email@example.com", password="your_password") as client:
        data = await client.series.get_timeseries(
            symbol="TSLA",
            start_date="2025-12-01",
            end_date="2025-12-31",
            fields=["retail_net_turnover"],
        )

    async with AsyncVandaClient(email="your_email@example.com", password="your_password") as client:
        data = await client.series.get_timeseries(
            symbol="TSLA",
            start_date="2025-12-01",
            end_date="2025-12-31",
            fields=["retail_net_turnover"],
            transformation="moving_avg",
            window="5",
            normalisation="percentile_rank",
            normalisation_period="1y",
            is_full_history=True,
        )

asyncio.run(main())
```

### Recommended to use environment variables

```python
export VANDA_LOGIN_EMAIL="your_email@example.com"
export VANDA_PASSWORD="your_password"
```

## Authentication

Set your API token via environment variable:

```bash
export VANDA_API_TOKEN="your_token_here"
```

or

```bash
export VANDA_LOGIN_EMAIL="your_email@example.com"
export VANDA_PASSWORD="your_password"
```

Or pass directly:

```python
client = VandaClient(token="your_token_here")
```

or

```python
client = VandaClient(email="your_email@example.com", password="your_password")
```

## Features

- Sync and async clients with consistent interfaces
- Automatic retry with exponential backoff
- Comprehensive error handling
- Job polling for async operations
- Export utilities (CSV, JSONL)
- Optional pandas support
- Type hints throughout

## API Methods

### Timeseries Data

- `get_timeseries()` - Get timeseries for a single symbol
- `get_timeseries_many()` - Get timeseries for multiple symbols
- `get_leaderboard()` - Get ranked leaderboard data

### Bulk Operations

- `bulk_securities()` - Bulk fetch securities data
- `get_daily_snapshot()` - Get daily snapshot for many securities

### Job Management

- `create_bulk_securities_job()` - Create async job
- `poll_job()` - Poll job until completion
- `get_job_status()` - Get job status
- `export_job_result()` - Export job result to file
- `stream_job_result()` - Stream job result to file

### Export Operations

- `export_timeseries()` - Export timeseries to file

### Metadata

- `list_fields()` - List available fields
- `list_intervals()` - List available intervals
- `list_securities()` - List available securities

### Aggregates Timeseries Data
- `get_timeseries()` - Get timeseries for multiple aggregate id's
- `get_constituents()` - Get constituents using Vanda identifier

## Examples

See `examples/` directory for complete usage examples.

## Requirements

- Python 3.9+
- httpx

## Development

```bash
git clone https://gitlab.com/yourusername/vanda-api.git
cd vanda-api
python -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
pre-commit install
pytest
```

# Migration Guides

## Migration Guide (from v1.0.0 to v1.0.1)

Version **1.0.1** introduces a standardized response format across multiple APIs and adds support for transformations and normalisations in timeseries endpoints.

### Breaking Change

The following APIs no longer return a list directly. They now return a dictionary containing the records under a `data` key.

Affected APIs:

```python
client.series.get_timeseries()
client.series.get_timeseries_many()
client.series.get_leaderboard()
client.series.list_securities()
client.series.bulk_securities()
client.series.get_daily_snapshot()

client.aggregates.get_constituents()
```

---

## Response Format Changes

### Previous Response Format (v1.0.0)

```python
response = client.series.get_timeseries(...)

print(type(response))
# list
```

Example response:

```json
[
  {
    "date": "2024-01-01",
    "value": 123
  }
]
```

### New Response Format (v1.0.1)

```python
response = client.series.get_timeseries(...)

print(type(response))
# dict
```

Example response:

```json
{
  "data": [
    {
      "date": "2024-01-01",
      "value": 123
    }
  ]
}
```

The same response structure applies to:

* `get_timeseries()`
* `get_leaderboard()`
* `list_securities()`
* `bulk_securities()`
* `get_daily_snapshot()`
* `get_constituents()`

---

## Accessing Data

### Before

```python
response = client.series.get_timeseries(...)

for row in response:
    print(row)
```

### After

```python
response = client.series.get_timeseries(...)

for row in response["data"]:
    print(row)
```

---

## `get_timeseries_many()` Response Format

`client.series.get_timeseries_many()` returns results grouped by symbol.

### Previous Response Format (v1.0.0)

```json
[
  {
    "symbol": "AAPL",
    "data": [...]
  },
  {
    "symbol": "MSFT",
    "data": [...]
  }
]
```

### New Response Format (v1.0.1)

```json
{
  "data": [
    {
      "symbol": "AAPL",
      "data": [
        {
          "date": "2024-01-01",
          "retail_net_flow": 12345
        }
      ],
      "transformation": {}
    },
    {
      "symbol": "MSFT",
      "data": [
        {
          "date": "2024-01-01",
          "retail_net_flow": 67890
        }
      ],
      "transformation": {}
    }
  ]
}
```

### Accessing Data

```python
response = client.series.get_timeseries_many(...)

for security in response["data"]:
    symbol = security["symbol"]

    for row in security["data"]:
        print(symbol, row)
```

---

## Transformation Metadata

When a transformation and/or normalisation is requested, additional metadata is returned in the `transformation` field.

Example:

```python
response = client.series.get_timeseries(
    symbol="AAPL",
    start_date="2024-01-01",
    end_date="2024-12-31",
    fields=["retail_net_flow"],
    transformation="moving_avg",
    window=20,
)
```

Response:

```json
{
  "data": [
    {
      "date": "2024-01-01",
      "retail_net_flow": 12345
    }
  ],
  "transformation": {
    "results": {
      "data": [
        {
          "date": "2024-01-01",
          "value": 12000
        }
      ]
    }
  }
}
```

---

## New Features

## Additional Parameters

The following optional parameters have been added to:

```python
client.series.get_timeseries()
client.series.get_timeseries_many()
```

### Transformations

```python
transformation="moving_avg"
window=5
```

Supported values:

```python
transformation="rolling_sum"
transformation="moving_avg"
```

### Normalisations

```python
normalisation="percentile_rank"
normalisation_period="1y"
```

Supported values:

```python
normalisation="zscore"
normalisation="percentile_rank"
```

### Supported Normalisation Periods

```python
normalisation_period="3m"
normalisation_period="6m"
normalisation_period="1y"
normalisation_period="2y"
normalisation_period="5y"
normalisation_period="Expanding"
normalisation_period="All"
```

### Full History Support

```python
is_full_history=True
```

---

## Supported Window Values

```python
window=5      # 1 Week
window=20     # 1 Month
window=30     # ~2 Months
window=60     # 3 Months
window=90     # 4 Months
window=120    # 6 Months
window=252    # 1 Year
```

---

## Summary

### Changed

* Standardized API responses to return dictionaries containing a `data` field.
* Added support for transformation metadata in responses.
* `get_timeseries_many()` now returns symbol-grouped results within the top-level `data` field.

### Added

* Transformations (`rolling_sum`, `moving_avg`)
* Normalisations (`zscore`, `percentile_rank`)
* Normalisation periods
* `is_full_history` support


## Migration Guide (From v0.1.2 to v1.0.0)
Old:
client.get_timeseries()
client.get_timeseries_many()
client.get_leaderboard()
client.create_bulk_securities_job()
client.bulk_securities()
client.get_daily_snapshot()
client.get_job()
client.get_job_status()
client.poll_job()
client.wait_for_job()
client.export_job_result()
client.stream_job_result()
client.export_timeseries()
client.list_fields()
client.list_intervals()
client.list_securities()

New:
client.series.get_timeseries()
client.series.get_timeseries_many()
client.series.get_leaderboard()
client.series.create_bulk_securities_job()
client.series.bulk_securities()
client.series.get_daily_snapshot()
client.series.get_job()
client.series.get_job_status()
client.series.poll_job()
client.series.wait_for_job()
client.series.export_job_result()
client.series.stream_job_result()
client.series.export_timeseries()
client.series.list_fields()
client.series.list_intervals()
client.series.list_securities()

## License

MIT License - see LICENSE file for details.

## Support

For issues and questions, please open an issue on GitLab.
