Metadata-Version: 2.4
Name: portiqa
Version: 0.1.0
Summary: Official Python client for the PORTIQA Portfolio Analysis API
Author-email: PORTIQA <hello@portiqa.com>
License-Expression: MIT
Project-URL: Homepage, https://portiqa.ai
Project-URL: Documentation, https://portiqa.ai/docs/
Project-URL: Source, https://github.com/portiqa/portiqa-python
Project-URL: Issues, https://github.com/portiqa/portiqa-python/issues
Project-URL: Changelog, https://github.com/portiqa/portiqa-python/blob/main/CHANGELOG.md
Project-URL: Security, https://github.com/portiqa/portiqa-python/security/policy
Keywords: api,portfolio,portiqa,sdk
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# PORTIQA Python

`portiqa` is the dependency-free Python client for the PORTIQA Portfolio
Analysis API. It sends typed portfolio inputs to
`POST https://portiqa.ai/evaluate` and returns typed response models. All
scoring and analysis stays on the PORTIQA service; this package contains no
scoring logic.

## Requirements

- Python 3.9 or newer
- A PORTIQA API key from the [PORTIQA dashboard](https://portiqa.ai/user/profile)

## Installation

Install the official package from PyPI:

```bash
python -m pip install portiqa
```

For editable local development from a clone:

```bash
python -m pip install -e .
```

## Quick start

Store the key outside your source code:

```bash
export PORTIQA_API_KEY="ptq_your_api_key"
```

PowerShell:

```powershell
$env:PORTIQA_API_KEY = "ptq_your_api_key"
```

Then evaluate a portfolio:

```python
from portiqa import EvaluationRequest, PortiqaClient, Position

client = PortiqaClient(timeout=20.0)
request = EvaluationRequest(
    risk_level="medium",
    cash_balance=5_000,
    positions=(
        Position(ticker="AAPL", market_value=25_000),
        Position(ticker="MSFT", market_value=22_000),
        Position(ticker="NVDA", market_value=8_000),
    ),
)

response = client.evaluate(request)
print(response.evaluation.score)
print(response.evaluation.status)
```

You can pass the key directly when an environment variable is not suitable:

```python
client = PortiqaClient(api_key="ptq_your_api_key", timeout=10.0)
```

An explicit `api_key` takes precedence over `PORTIQA_API_KEY`. Never hard-code
or commit a real key.

## Models

Each `Position` requires a ticker and at least one of:

- `market_value`: the value already known for the position; or
- `amount`: the number of units, which PORTIQA combines with its latest
  available close price when `market_value` is absent.

`risk_level` accepts `"low"`, `"medium"`, or `"high"`. Position values and the
cash balance must be finite, non-negative numbers. Invalid local inputs raise
`ValidationError` before any request is made.

Stable response fields are typed, while the complete server response remains
available through `response.raw` and `response.evaluation.raw`. Newly added API
fields are therefore accessible without waiting for an SDK release.

## Errors and timeouts

All SDK exceptions inherit from `PortiqaError`:

| Exception | Meaning |
| --- | --- |
| `ConfigurationError` | The API key or timeout is invalid. |
| `ValidationError` | A request model is invalid. |
| `APITimeoutError` | The configured timeout elapsed. |
| `APIConnectionError` | The service could not be reached. |
| `InvalidResponseError` | A success response was not valid PORTIQA JSON. |
| `BadRequestError` | HTTP 400. |
| `AuthenticationError` | HTTP 401. |
| `SubscriptionError` | HTTP 402. |
| `RequestTooLargeError` | HTTP 413. |
| `RateLimitError` | HTTP 429. |
| `ServerError` | HTTP 5xx. |
| `APIStatusError` | Any other non-success HTTP status. |

```python
from portiqa import APITimeoutError, PortiqaError, RateLimitError

try:
    response = client.evaluate(request)
except RateLimitError as exc:
    print(f"Limit reached (HTTP {exc.status_code})")
except APITimeoutError:
    print("PORTIQA did not respond before the configured timeout")
except PortiqaError as exc:
    print(f"PORTIQA request failed: {exc}")
```

The timeout defaults to 20 seconds. The client does not retry automatically,
leaving retry and backoff policy under the caller's control.

## Development

The tests use standard-library mocks and never contact the live API:

```bash
python -m unittest discover -s tests -v
```

See the [API reference](https://portiqa.ai/docs/api-reference.html),
[OpenAPI specification](https://portiqa.ai/docs/openapi.yaml), and
[security policy](https://github.com/portiqa/portiqa-python/security/policy)
for more information.

PORTIQA output is quantitative information, not investment advice. See the
[financial disclaimer](https://portiqa.ai/legal/disclaimer.html).

## License

Released under the
[MIT License](https://github.com/portiqa/portiqa-python/blob/main/LICENSE).
