IQ Option API with Python (iqoptionapi) — Connect, Trade and check_win
How to connect to IQ Option from Python using the community iqoptionapi library: log in, read candles, send orders and read the result with check_win_v4. Plus a free open-source bot that already wraps it all.
🤖 Get the free IQ Option bot (API ready)
Open-source Python bot using iqoptionapi. Edit it by chatting with ChatGPT/Claude — no coding. Free, no spam.
Is there an official IQ Option API?
No. IQ Option has no official public API. The community uses the open-source iqoptionapi library, which talks to the same WebSocket the platform uses. It is unofficial — use a demo (practice) account and be aware of ban risk on real accounts.
Install iqoptionapi the right way (virtual environment)
The most common reason the example above fails is the install itself. pip install iqoptionapi downloads the package with that name on PyPI, which is version 0.5, uploaded in October 2016. That release has no stable_api module, so from iqoptionapi.stable_api import IQ_Option fails with ModuleNotFoundError. The community code that has check_win_v4 is maintained on GitHub and must be installed from there:
- Create an isolated environment in your project folder:
python -m venv .venv - Activate it:
.venv\Scripts\activateon Windows,source .venv/bin/activateon Linux/macOS. - If you installed the old package, remove it:
pip uninstall iqoptionapi - Install from GitHub over HTTPS:
pip install -U git+https://github.com/iqoptionapi/iqoptionapi.git(requires Git). Without Git, use the ZIP link the project README gives:pip install -U https://github.com/iqoptionapi/iqoptionapi/archive/refs/heads/master.zip - Test the import:
python -c "from iqoptionapi.stable_api import IQ_Option"— no output means it worked.
Why a virtual environment: the library pins websocket-client==0.56, a very old version. Inside .venv that pin cannot break other Python projects on the same machine. Also ignore the git+git:// command still printed in the project README: GitHub permanently disabled the unencrypted git:// protocol on March 15, 2022, so only the https:// form works.
Connect with Python — minimal example
Login, read candles, buy and read the result with check_win_v4:
# pip install -U git+https://github.com/iqoptionapi/iqoptionapi.git (NOT the PyPI package — see install section)
import time
from iqoptionapi.stable_api import IQ_Option
api = IQ_Option("you@email.com", "yourpass")
api.connect()
api.change_balance("PRACTICE") # always demo first
candles = api.get_candles("EURUSD", 60, 100, time.time())
ok, order_id = api.buy(1, "EURUSD", "call", 1) # 1 = 1-minute expiry
result, profit = api.check_win_v4(order_id) # ("win" | "loose" | "equal", profit)check_win_v4 returns a tuple: a status string — "win", "loose" (the library's own spelling) or "equal" — and the profit as a number (the net gain on a win, minus the stake on a loss, 0 on a tie). It works for binary/turbo options only and waits for the result with no timeout.
Useful iqoptionapi methods
What each call actually returns (checked against the stable_api.py source of the GitHub version, 7.1.1):
| Method | What it does | Returns / watch out |
|---|---|---|
connect() | Logs in and opens the WebSocket | (True, None) on success, (False, reason) on failure, (False, "2FA") when an SMS code is required |
connect_2fa(code) | Finishes the login with the SMS code | Same tuple as connect() |
change_balance(mode) | Selects the account: "PRACTICE", "REAL" or "TOURNAMENT" | Any other text (e.g. "DEMO") logs an error and calls exit(1) — your script simply stops |
get_balance() | Balance of the selected account | A number |
get_candles(asset, interval, count, endtime) | History; interval in seconds (60 = M1), endtime as a Unix timestamp | List of candle dicts ("from" = candle start). Unknown asset prints Asset … not found on consts |
get_all_open_time() | Which assets are open now | Nested dict: [type][asset]["open"] = True/False, type such as "turbo", "binary", "digital" |
get_all_profit() | Payout per asset | Fractions: {"turbo": 0.85, ...} means 85% |
buy(amount, asset, "call"/"put", minutes) | Opens a binary/turbo option | (True, order_id) or (False, message); after 5 s without confirmation it logs buy late 5 sec and returns (False, None) |
check_win_v4(order_id) | Waits until the order closes | ("win" | "loose" | "equal", profit) — blocks with no timeout; binary/turbo only |
buy_digital_spot() / check_win_digital_v2() | Digital-option equivalents | Use these for digital orders; check_win_v4 never returns for them |
check_connect() | Is the WebSocket alive? | False when the socket has closed |
Common errors and how to fix them
| Symptom | Likely cause | Fix |
|---|---|---|
ModuleNotFoundError: No module named 'iqoptionapi.stable_api' | The 2016 PyPI package (0.5) is installed | pip uninstall iqoptionapi, then install from GitHub as shown above |
pip fails on a git+git:// URL | GitHub no longer serves git:// | Use git+https:// |
| Import works in one terminal and not in another | pip installed into a different Python than the one running the script | Activate the venv and use python -m pip install ...; check python --version (library README: 3.7+; our bot: 3.12+) |
connect() returns (False, reason) | Wrong e-mail/password or blocked login | Print reason; log in once in the browser with the same credentials |
reason == "2FA" | Two-factor login by SMS is enabled | api.connect_2fa(input("SMS code: ")) |
Script exits right after change_balance | Mode text other than PRACTICE/REAL/TOURNAMENT | Use exactly "PRACTICE" |
Asset EURUSD-op not found on consts | Asset missing from constants.ACTIVES | Inject the ID (see the "-op" section below) or use a listed name |
check_win_v4 never returns | Digital order, or the WebSocket dropped before the result arrived | Use check_win_digital_v2 for digital; monitor check_connect() |
check_connect() is False after some hours | Network drop or expired session | Call api.connect() again, then change_balance("PRACTICE") again before the next order |
Check the payout before every order (the math)
get_all_profit() gives the payout as a fraction, and that single number decides the minimum win rate you need: break-even = 1 / (1 + payout). Expected result per $1 traded = p × payout − (1 − p), where p is your win rate.
| Payout | Break-even win rate | Result per $1 at 56% wins |
|---|---|---|
| 0.90 (90%) | 52.6% | +$0.064 |
| 0.85 (85%) | 54.1% | +$0.036 |
| 0.80 (80%) | 55.6% | +$0.008 |
| 0.70 (70%) | 58.8% | −$0.048 |
The same 56% win rate goes from a small profit to a steady loss just because payout fell from 85% to 70%. In our own test on real M1 forex candles, the best strategies held ~57–61% out of sample and nothing came close to 70% (full results); on OTC assets the outcome was statistically random at ~50% (why OTC is random). A bot should therefore skip any asset whose payout puts break-even above what the strategy has shown on demo.
Good practices before you automate
- Keep the password out of the code: read it from environment variables —
IQ_Option(os.environ["IQ_EMAIL"], os.environ["IQ_PASSWORD"])— and never commit a file with credentials to GitHub. - Do not type your password into closed .exe files or "robot websites": the library's own README warns that scammers have stolen IQ Option passwords this way. Open-source code runs on your PC and you can read what it does with the password.
- PRACTICE by default: call
change_balance("PRACTICE")at start-up and switch to"REAL"only through an explicit setting, never as the default. - Check before buying:
get_all_open_time()for the asset,get_all_profit()for the payout, thenbuy(). - One candle request per closed candle is enough for M1 strategies; a tight loop only re-downloads the same data.
- Log every order_id with its check_win_v4 result, so you can compare your real win rate with the break-even table above.
Skip the setup: get the ready-made bot
Our IaTraderPro Bot already uses iqoptionapi and adds 13 ready strategies, a visual Streamlit dashboard, payout filter, daily stop loss/win and configurable martingale — open source, so you read and change the code. It runs on IQ Option demo (PRACTICE) and real accounts — always start on demo.
Modify it with AI — no coding
Paste bot.py into ChatGPT or Claude, describe the strategy you want, get working code back. Paste, test on demo, done.
FAQ
Is it official? No — community library. Use demo first.
What does check_win_v4 do? Waits for a binary/turbo order to close and returns a tuple (status, profit).
Account ban risk? Automation carries risk on real accounts; test on demo and read the terms.
Is it free? Yes — the bot is free and open source. It also supports Quotex.
REAL forex on IQ Option: the "-op" assets (2026 discovery)
IQ Option's legacy API looked dead for real forex: turbo/binary only on OTC and digitals disabled. But in 2026 IQ launched assets with the -op suffix (e.g. USDJPY-op, EURUSD-op) — real forex as binary options, with 2 to 15-minute expirations.
The technical catch: iqoptionapi doesn't list these assets because they don't exist in the library's constants.ACTIVES. The fix (our bot does it automatically) is to inject the "-op" IDs into the dictionary at startup. Two practical notes: verified accounts get broader access to "-op" assets, and payout should be read with a fallback (1 − commission) when the API doesn't return it.
→ Trading from India? Read this first: is Quotex legal in India?
How to inject the "-op" assets (working code)
The library ships a static asset dictionary, so the new real-forex instruments are invisible until you add them. Our bot does this at startup:
# Make the real-forex "-op" assets visible to iqoptionapi
from iqoptionapi import constants
from iqoptionapi.stable_api import IQ_Option
OP_ASSETS = {"USDJPY-op": 1807, "EURUSD-op": 1806, "GBPJPY-op": 1811}
constants.ACTIVES.update(OP_ASSETS) # IDs vary by account/region — read them from the API
api = IQ_Option("you@email.com", "yourpass")
api.connect()
api.change_balance("PRACTICE") # demo first, always
# payout fallback: some -op assets do not return profit via the usual call
def payout(api, asset):
d = api.get_all_profit().get(asset, {})
p = d.get("binary") or d.get("turbo")
return p # None = no payout returned: skip the asset (iqoptionapi has no get_commission() method)
ok, order_id = api.buy(1, "USDJPY-op", "call", 15) # 15-minute binary
| Expiry | Availability | Notes |
|---|---|---|
| 2 min | EURUSD-op and some majors | Fastest; not available on every pair |
| 5 / 10 min | Most -op assets | Blitz-style; the library cannot buy blitz directly |
| 15 min | USDJPY-op, GBPJPY-op | Standard binary — what our bot uses in production |
Two practical notes from running this live: a verified account gets broader access to the -op list, and the asset set changes by region — always read the live list instead of hard-coding it permanently.
⚠️ Binary options involve high risk and can result in total loss. Educational content, not investment advice. No bot guarantees profit. Always test on a demo account first.