Metadata-Version: 2.4
Name: iqair
Version: 1.0.0
Summary: Unofficial Python wrapper for IQ Option's websocket trading API
Home-page: https://github.com/omerhrr/iqair
Author: Bz
Author-email: pyomerhrr@gmail.com
License: MIT
Project-URL: Documentation, https://github.com/omerhrr/iqair/blob/master/docs/USAGE.md
Project-URL: Source, https://github.com/omerhrr/iqair
Project-URL: Issue Tracker, https://github.com/omerhrr/iqair/issues
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
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 :: Office/Business :: Financial :: Investment
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31.0
Requires-Dist: websocket-client>=1.9.0
Provides-Extra: agent
Requires-Dist: fastapi>=0.100; extra == "agent"
Requires-Dist: uvicorn>=0.23; extra == "agent"
Requires-Dist: pydantic>=2.0; extra == "agent"
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# iqair

An unofficial Python wrapper for IQ Option's websocket trading API.

This is v1.0 - a ground-up rebuild of an older, long-unmaintained
`iqoptionapi` fork. Every endpoint listed as "implemented" below has been
independently re-verified against the live backend (never assumed from
old code or documentation), typically by capturing real trade traffic
from IQ Option's own web UI (HAR capture) and matching this library's
requests against it byte-for-byte. Where something is confirmed vs.
presumed, the docstring on the relevant method says so explicitly - see
`iqair/broker.py`'s module docstring for the full picture.

**This talks to a real trading account.** Every example below and every
test in `tests/` runs against the PRACTICE balance only - never REAL. Use
your own judgment before pointing this at anything else.

## Install

```
pip install -e .
```

Requires Python 3 and `requests`, `websocket-client` (see `setup.py`).

## Quickstart

```python
from iqair.client import IQOptionClient

api = IQOptionClient("you@example.com", "your-password")
check, reason = api.connect()
if not check:
    raise SystemExit(f"connect failed: {reason}")

api.change_balance("PRACTICE")

# Low-level: place a turbo option directly
check, order_id = api.buy(1, "EURUSD", "call", 1)  # $1, 1-minute turbo
```

### The OOP wrapper (`api.broker`)

For most use cases, `api.broker` is friendlier than the low-level
per-mode methods - one `trade()`/`.close()` interface across every mode:

```python
from iqair.broker import TradeMode, TradeSide

trade = api.broker.trade(
    mode=TradeMode.TURBO,
    asset="EURUSD",
    side=TradeSide.CALL,
    amount=1,
    expiration=1,
)
trade.wait()          # blocks until the trade settles
print(trade.pnl)

# Margin modes (forex/crypto/cfd) need `leverage`; `amount` is margin,
# not stake, for these:
trade = api.broker.trade(
    mode=TradeMode.FOREX,
    asset="EURUSD",
    side=TradeSide.BUY,
    amount=10,       # margin, in dollars
    leverage=100,
)
print(trade.state, trade.pnl)
trade.close()
```

For the full end-to-end guide (every mode, streaming, positions/P&L,
error handling), see [`docs/USAGE.md`](docs/USAGE.md). For finding valid
ticker strings specifically, see [`docs/TICKERS.md`](docs/TICKERS.md) -
the short version is `api.get_asset_metadata()`.

### Using this with an LLM orchestrator / agent

`iqair.agent` wraps the library as flat JSON-in/JSON-out tools for
LLM function-calling (direct import, a generic `call_tool(name, args)`
dispatcher, or an optional HTTP server via `pip install iqair[agent]`).
See [`docs/AGENT.md`](docs/AGENT.md).

## Supported trading modes

| Mode | Open | Close | Notes |
|---|---|---|---|
| Turbo / Binary | ✅ live-verified | ✅ live-verified | `api.buy()` / `api.sell_option()` |
| Digital options | ✅ live-verified | ✅ live-verified | `api.buy_digital_spot()` / `api.close_digital_option()` - resolves a real, currently-tradable instrument server-side rather than constructing one client-side |
| Forex (margin) | ✅ live-verified | ✅ live-verified | `api.buy_forex_market()` / `api.close_margin_position()` |
| Crypto (margin) | ✅ live-verified | ✅ live-verified | `api.buy_crypto_market()` |
| CFD (margin) | ✅ live-verified | ✅ live-verified | `api.buy_cfd_market()` - covers commodities, stocks, indices, AND ETFs; IQ Option has no separate mode for any of these, they're all `marginal-cfd` |

All six are also available through `api.broker.trade(mode=TradeMode.*, ...)`.

The old `buy_order()` / `close_position()` / `close_position_v2()`
methods are **confirmed dead** (they send flat, non-namespaced message
names IQ Option's backend no longer responds to at all) and are kept
only for backwards compatibility - they emit a `DeprecationWarning`.
Use the methods in the table above instead.

## Streaming (`api.stream`)

```python
for candle in api.stream.candles("EURUSD", timeframe=60):
    print(candle)

for tick in api.stream.price("EURUSD"):
    print(tick.bid, tick.ask)

for update in api.stream.trade_updates():   # all position-changed events
    print(update)

for event in api.stream.connection():       # connection state changes
    print(event)
```

`api.stream.payout()` and `api.stream.asset_status()` are poll-based
(IQ Option doesn't push these two live) rather than true push streams;
`api.stream.news()` is a documented stub - a live news feed wasn't
captured/confirmed during this project.

Every stream returns a `Subscription` - iterate it directly, or call
`.close()` to unsubscribe early.

## Positions, history, P&L

```python
ok, positions = api.get_positions("digital-option")   # or "turbo-option", "marginal-forex", etc.
ok, history = api.get_position_history_v2("marginal-cfd", limit=10, offset=0)
pnl = api.get_pnl(positions["positions"][0])          # takes a raw position dict
```

Matching a position back to the order id that opened it is not always a
plain equality check - digital and margin positions key `external_id` as
the *position* id, not the order id (order ids live in a separate list).
Use `IQOptionClient.position_matches_order_id()` rather than comparing
`external_id` directly if you're writing your own matching logic;
`get_digital_position()` / `get_margin_position()` / `Trade.refresh()`
already do this correctly.

## Testing

See [`tests/README.md`](tests/README.md) for the full test suite - it
runs against the real backend (PRACTICE balance), gated behind
`IQ_EMAIL`/`IQ_PASSWORD` and opt-in flags (`IQ_ALLOW_TRADE`,
`IQ_ALLOW_DIGITAL`, `IQ_ALLOW_MARGIN`) for anything that places a trade.

```
export IQ_EMAIL="you@example.com"
export IQ_PASSWORD="your-password"
pytest                    # read-only tests
IQ_ALLOW_TRADE=1 IQ_ALLOW_DIGITAL=1 IQ_ALLOW_MARGIN=1 pytest   # everything
```

`.github/workflows/ci.yml` runs the credential-free structural tests
(schema/dispatcher checks, package build, wheel import sanity check) on
every push/PR - it doesn't and can't run the live-backend tests above,
since those need a real account.

## Releasing

Releases publish to PyPI automatically via GitHub Actions (Trusted
Publishing, no stored API token) when a GitHub Release is published -
see [`docs/RELEASING.md`](docs/RELEASING.md) for the one-time setup and
the release checklist.

## Project layout

```
iqair/
  client.py         high-level client (IQOptionClient) - most users start here
  broker.py         OOP wrapper (api.broker) - Trade/TradeMode/TradeSide
  streaming.py       api.stream namespace
  api.py             low-level request/response plumbing
  models.py          typed dataclasses (Position, Candle, etc.)
  ws/                websocket client + per-endpoint request builders
  agent/              LLM tool-calling / orchestrator integration (tools, dispatcher, HTTP server)
docs/
  USAGE.md            full end-to-end usage guide
  AGENT.md            orchestrator / LLM tool-calling integration guide
  TICKERS.md          how to find valid ticker strings per trading mode
  RELEASING.md        PyPI release process
tests/                live-backend test suite (see tests/README.md)
.github/workflows/
  ci.yml               credential-free build + structural tests, on every push/PR
  publish.yml          builds and publishes to PyPI on release (see docs/RELEASING.md)
```

## Disclaimer

This is an unofficial, community-maintained wrapper, not affiliated with
or endorsed by IQ Option. IQ Option's API is undocumented and can change
without notice - endpoints that work today may not tomorrow. Use at your
own risk, and always test against the PRACTICE balance before trusting
anything with real funds.
