Metadata-Version: 2.4
Name: playtrader-sdk
Version: 0.1.0
Summary: Add your description here
Requires-Python: >=3.12
Requires-Dist: loguru>=0.7.2
Requires-Dist: pydantic>=2.9.0
Requires-Dist: requests>=2.31.0
Provides-Extra: dev
Requires-Dist: pytest>=8.2; extra == 'dev'
Description-Content-Type: text/markdown

# Playtrader SDK

Typed Python client for the Playtrader PocketBase APIs. With nothing more than
``pip install playtrader-sdk`` (PyPI/TestPyPI) or ``pip install
git+https://github.com/hampusadamsson/playtrader-sdk.git`` you get:

- A synchronous `PlaytraderClient` that wraps the `asset`, `history`,
  `portfolio`, `holding`, `transaction`, and `/api/trade` endpoints
- Fully-typed response models (Pydantic) to make agents and humans safer when
  handling data
- Enum-based helpers (`IdentifierType`) for juggling tickers, orderbook ids, and
  PocketBase `Symbol` values

> **Demo API**: All examples target the open instance at
> `https://playtrader.hampusadamsson.com`. Credentials:
> `opencode@opencode.com` / `opencode`, portfolio `4b055zbbu920354`.

## Quick Start

```python
from playtrader import PlaytraderClient
from playtrader.client import IdentifierType

client = PlaytraderClient()

# List assets
assets = client.list_assets(limit=5)
for asset in assets:
    print(asset.ticker, asset.ask_price)

# Fetch history for a ticker (auto-converted from IdentifierType)
hist = client.get_history("ABB", identifier_type=IdentifierType.TICKER, limit=10)
print(hist[0].updt, hist[0].close_price)

# Authenticate and inspect holdings
client.auth("opencode@opencode.com", "opencode")
portfolio = client.get_portfolio("4b055zbbu920354", expand=["holdings"])
print(portfolio.name, portfolio.funds)

# Execute a trade (be sure you're OK with live demo trades!)
# client.buy("4b055zbbu920354", "ABB", 1)
```

## Feature Matrix

| Capability | Methods | Notes |
|------------|---------|-------|
| Asset discovery | `list_assets`, `get_asset`, `get_symbols` | Returns `Asset` models with metadata. |
| Symbol/ticker conversion | `transform_symbols_to_tickers`, `transform_tickers_to_symbols`, `resolve_symbol` | Uses cached metadata, supports explicit `IdentifierType`. |
| Historical candles | `get_history` | Works with tickers, orderbook ids, or explicit Symbol id. |
| Portfolio insights | `get_portfolio`, `get_holdings`, `get_portfolio_history`, `get_transactions`, `get_available_funds` | Requires authentication; returns typed models. |
| Trading | `buy`, `sell` | Wraps `/api/trade`, returns `TradeResponse`. |
| Price snapshots | `get_prices` | Input identifiers normalized to tickers; output keys always tickers. |
| Basket view | `get_omxs30` | Builds a merged dataframe-like payload (`Omxs30Row`). |

## Schema Types

Every response is a Pydantic model living in `playtrader/schemas/`:

| Model | File | Key Fields |
|-------|------|------------|
| `Asset` | `schemas/asset.py` | `ticker`, `orderbook_id`, `ask_price`, `bid_price`, `sector`, `updt`. |
| `HistoryRecord` | `schemas/history.py` | `symbol`, `updt`, `close_price`. |
| `Holding` / `HoldingExpand` | `schemas/holding.py` | `quantity`, `average_purchase_price`, `expand.asset`. |
| `Portfolio` / `PortfolioExpand` | `schemas/portfolio.py` | `funds`, `name`, `holding_ids`, `expand.holdings`. |
| `PortfolioHistoryEntry` | `schemas/portfolio_history.py` | `date`, `value`. |
| `Transaction` / `TransactionExpand` | `schemas/transaction.py` | `action`, `price`, `quantity`, `expand.asset`. |
| `TradeResponse` | `schemas/trade.py` | `status`, `message`, `trade_id`. |
| `Omxs30Row` | `schemas/omxs30.py` | `timestamp`, `prices` (dict of `symbol -> latest value`). |

These models are imported in `playtrader/__init__.py` so that agents can
`from playtrader.schemas import Asset, Portfolio, ...` if they only have access
to the README and the ability to `pip install playtrader-sdk`.

## Identifier Management

The client exposes an `IdentifierType` enum with three values:

- `IdentifierType.TICKER`
- `IdentifierType.SYMBOL` (PocketBase `Symbol`/Orderbook id)
- `IdentifierType.ORDERBOOK`

Most helper methods accept an optional `identifier_type`. If omitted the client
tries `TICKER` first and falls back to `SYMBOL`, mirroring the legacy code in
the repository example.

## Testing Against the Demo API

```bash
uv run --extra dev python -m pytest
```

- All tests talk to the live demo API and use the opencode credentials.
- Real trading tests are skipped unless `PLAYTRADER_ALLOW_TRADE=1` is set.

## Release Management / Wheel Builds

Wheel builds use Hatch via `uv`:

```bash
bash scripts/release.sh
# -> dist/playtrader_sdk-<version>-py3-none-any.whl
```

The script wipes `dist/` and runs `uv build --wheel`, so it’s safe to use in CI
as-is. Upload artifacts with `twine upload dist/*.whl` (or copy them to your
internal registry).

## Helpful References

- `playtrader/client.py`: Detailed docstrings for every public method, with
  examples showing authentication, history lookups, identifier usage, and trades
- `tests/test_playtrader.py`: Live integration tests you can mimic for agents
- [PocketBase records API docs](https://pocketbase.io/docs/api-records/) for raw
  REST details

If your agent only has this README and can run `pip install playtrader-sdk`, it
already has everything needed to authenticate, list assets, fetch history, and
trade against the demo environment. Just import `PlaytraderClient` and follow
the snippets above.

---

# Testing the SDK in a Notebook

uvx --with jupyter --with pandas --with ./dist/playtrader_sdk-0.1.0-py3-none-any.whl jupyter notebook --NotebookApp.token='123'       130 ↵ hampus@pop-os
